diff options
Diffstat (limited to 'contrib/llvm/lib/Support')
143 files changed, 4478 insertions, 1687 deletions
diff --git a/contrib/llvm/lib/Support/AArch64TargetParser.cpp b/contrib/llvm/lib/Support/AArch64TargetParser.cpp index e897137df680..df4caa1f07fd 100644 --- a/contrib/llvm/lib/Support/AArch64TargetParser.cpp +++ b/contrib/llvm/lib/Support/AArch64TargetParser.cpp @@ -1,9 +1,8 @@ //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -89,6 +88,16 @@ bool AArch64::getExtensionFeatures(unsigned Extensions, Features.push_back("+rdm"); if (Extensions & AEK_SVE) Features.push_back("+sve"); + if (Extensions & AEK_SVE2) + Features.push_back("+sve2"); + if (Extensions & AEK_SVE2AES) + Features.push_back("+sve2-aes"); + if (Extensions & AEK_SVE2SM4) + Features.push_back("+sve2-sm4"); + if (Extensions & AEK_SVE2SHA3) + Features.push_back("+sve2-sha3"); + if (Extensions & AEK_BITPERM) + Features.push_back("+bitperm"); if (Extensions & AEK_RCPC) Features.push_back("+rcpc"); diff --git a/contrib/llvm/lib/Support/AMDGPUMetadata.cpp b/contrib/llvm/lib/Support/AMDGPUMetadata.cpp index a04bfc2ea299..5f8102299f47 100644 --- a/contrib/llvm/lib/Support/AMDGPUMetadata.cpp +++ b/contrib/llvm/lib/Support/AMDGPUMetadata.cpp @@ -1,9 +1,8 @@ //===--- AMDGPUMetadata.cpp -------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -66,6 +65,8 @@ struct ScalarEnumerationTraits<ValueKind> { YIO.enumCase(EN, "HiddenDefaultQueue", ValueKind::HiddenDefaultQueue); YIO.enumCase(EN, "HiddenCompletionAction", ValueKind::HiddenCompletionAction); + YIO.enumCase(EN, "HiddenMultiGridSyncArg", + ValueKind::HiddenMultiGridSyncArg); } }; @@ -219,19 +220,5 @@ std::error_code toString(Metadata HSAMetadata, std::string &String) { } } // end namespace HSAMD - -namespace PALMD { - -std::error_code toString(const Metadata &PALMetadata, std::string &String) { - raw_string_ostream Stream(String); - for (auto I = PALMetadata.begin(), E = PALMetadata.end(); I != E; ++I) { - Stream << Twine(I == PALMetadata.begin() ? " 0x" : ",0x"); - Stream << Twine::utohexstr(*I); - } - Stream.flush(); - return std::error_code(); -} - -} // end namespace PALMD } // end namespace AMDGPU } // end namespace llvm diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp index e9e429c8031b..b79baf1834a7 100644 --- a/contrib/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -1,9 +1,8 @@ //===-- APFloat.cpp - Implement APFloat class -----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -114,6 +113,42 @@ namespace llvm { static const fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53, 53 + 53, 128}; + const llvm::fltSemantics &APFloatBase::EnumToSemantics(Semantics S) { + switch (S) { + case S_IEEEhalf: + return IEEEhalf(); + case S_IEEEsingle: + return IEEEsingle(); + case S_IEEEdouble: + return IEEEdouble(); + case S_x87DoubleExtended: + return x87DoubleExtended(); + case S_IEEEquad: + return IEEEquad(); + case S_PPCDoubleDouble: + return PPCDoubleDouble(); + } + llvm_unreachable("Unrecognised floating semantics"); + } + + APFloatBase::Semantics + APFloatBase::SemanticsToEnum(const llvm::fltSemantics &Sem) { + if (&Sem == &llvm::APFloat::IEEEhalf()) + return S_IEEEhalf; + else if (&Sem == &llvm::APFloat::IEEEsingle()) + return S_IEEEsingle; + else if (&Sem == &llvm::APFloat::IEEEdouble()) + return S_IEEEdouble; + else if (&Sem == &llvm::APFloat::x87DoubleExtended()) + return S_x87DoubleExtended; + else if (&Sem == &llvm::APFloat::IEEEquad()) + return S_IEEEquad; + else if (&Sem == &llvm::APFloat::PPCDoubleDouble()) + return S_PPCDoubleDouble; + else + llvm_unreachable("Unknown floating semantics"); + } + const fltSemantics &APFloatBase::IEEEhalf() { return semIEEEhalf; } @@ -199,7 +234,10 @@ readExponent(StringRef::iterator begin, StringRef::iterator end) const unsigned int overlargeExponent = 24000; /* FIXME. */ StringRef::iterator p = begin; - assert(p != end && "Exponent has no digits"); + // Treat no exponent as 0 to match binutils + if (p == end || ((*p == '-' || *p == '+') && (p + 1) == end)) { + return 0; + } isNegative = (*p == '-'); if (*p == '-' || *p == '+') { @@ -4416,8 +4454,9 @@ APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) { return; } if (usesLayout<DoubleAPFloat>(Semantics)) { + const fltSemantics& S = F.getSemantics(); new (&Double) - DoubleAPFloat(Semantics, APFloat(std::move(F), F.getSemantics()), + DoubleAPFloat(Semantics, APFloat(std::move(F), S), APFloat(semIEEEdouble)); return; } diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp index a5f4f98c489a..43173311cd80 100644 --- a/contrib/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -1,9 +1,8 @@ //===-- APInt.cpp - Implement APInt class ---------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -483,10 +482,13 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { APInt tmp(sufficient, StringRef(p, slen), radix); // Compute how many bits are required. If the log is infinite, assume we need - // just bit. + // just bit. If the log is exact and value is negative, then the value is + // MinSignedValue with (log + 1) bits. unsigned log = tmp.logBase2(); if (log == (unsigned)-1) { return isNegative + 1; + } else if (isNegative && tmp.isPowerOf2()) { + return isNegative + log; } else { return isNegative + log + 1; } @@ -1096,6 +1098,8 @@ APInt APInt::sqrt() const { /// however we simplify it to speed up calculating only the inverse, and take /// advantage of div+rem calculations. We also use some tricks to avoid copying /// (potentially large) APInts around. +/// WARNING: a value of '0' may be returned, +/// signifying that no multiplicative inverse exists! APInt APInt::multiplicativeInverse(const APInt& modulo) const { assert(ult(modulo) && "This APInt must be smaller than the modulo"); @@ -1915,12 +1919,19 @@ APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const { } APInt APInt::umul_ov(const APInt &RHS, bool &Overflow) const { - APInt Res = *this * RHS; + if (countLeadingZeros() + RHS.countLeadingZeros() + 2 <= BitWidth) { + Overflow = true; + return *this * RHS; + } - if (*this != 0 && RHS != 0) - Overflow = Res.udiv(RHS) != *this || Res.udiv(*this) != RHS; - else - Overflow = false; + APInt Res = lshr(1) * RHS; + Overflow = Res.isNegative(); + Res <<= 1; + if ((*this)[0]) { + Res += RHS; + if (Res.ult(RHS)) + Overflow = true; + } return Res; } @@ -2923,3 +2934,56 @@ llvm::APIntOps::SolveQuadraticEquationWrap(APInt A, APInt B, APInt C, LLVM_DEBUG(dbgs() << __func__ << ": solution (wrap): " << X << '\n'); return X; } + +/// StoreIntToMemory - Fills the StoreBytes bytes of memory starting from Dst +/// with the integer held in IntVal. +void llvm::StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, + unsigned StoreBytes) { + assert((IntVal.getBitWidth()+7)/8 >= StoreBytes && "Integer too small!"); + const uint8_t *Src = (const uint8_t *)IntVal.getRawData(); + + if (sys::IsLittleEndianHost) { + // Little-endian host - the source is ordered from LSB to MSB. Order the + // destination from LSB to MSB: Do a straight copy. + memcpy(Dst, Src, StoreBytes); + } else { + // Big-endian host - the source is an array of 64 bit words ordered from + // LSW to MSW. Each word is ordered from MSB to LSB. Order the destination + // from MSB to LSB: Reverse the word order, but not the bytes in a word. + while (StoreBytes > sizeof(uint64_t)) { + StoreBytes -= sizeof(uint64_t); + // May not be aligned so use memcpy. + memcpy(Dst + StoreBytes, Src, sizeof(uint64_t)); + Src += sizeof(uint64_t); + } + + memcpy(Dst, Src + sizeof(uint64_t) - StoreBytes, StoreBytes); + } +} + +/// LoadIntFromMemory - Loads the integer stored in the LoadBytes bytes starting +/// from Src into IntVal, which is assumed to be wide enough and to hold zero. +void llvm::LoadIntFromMemory(APInt &IntVal, uint8_t *Src, unsigned LoadBytes) { + assert((IntVal.getBitWidth()+7)/8 >= LoadBytes && "Integer too small!"); + uint8_t *Dst = reinterpret_cast<uint8_t *>( + const_cast<uint64_t *>(IntVal.getRawData())); + + if (sys::IsLittleEndianHost) + // Little-endian host - the destination must be ordered from LSB to MSB. + // The source is ordered from LSB to MSB: Do a straight copy. + memcpy(Dst, Src, LoadBytes); + else { + // Big-endian - the destination is an array of 64 bit words ordered from + // LSW to MSW. Each word must be ordered from MSB to LSB. The source is + // ordered from MSB to LSB: Reverse the word order, but not the bytes in + // a word. + while (LoadBytes > sizeof(uint64_t)) { + LoadBytes -= sizeof(uint64_t); + // May not be aligned so use memcpy. + memcpy(Dst, Src + LoadBytes, sizeof(uint64_t)); + Dst += sizeof(uint64_t); + } + + memcpy(Dst + sizeof(uint64_t) - LoadBytes, Src, LoadBytes); + } +} diff --git a/contrib/llvm/lib/Support/APSInt.cpp b/contrib/llvm/lib/Support/APSInt.cpp index 46c0f70ff66b..7c48880f96ea 100644 --- a/contrib/llvm/lib/Support/APSInt.cpp +++ b/contrib/llvm/lib/Support/APSInt.cpp @@ -1,9 +1,8 @@ //===-- llvm/ADT/APSInt.cpp - Arbitrary Precision Signed Int ---*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,18 +22,18 @@ APSInt::APSInt(StringRef Str) { // (Over-)estimate the required number of bits. unsigned NumBits = ((Str.size() * 64) / 19) + 2; - APInt Tmp(NumBits, Str, /*Radix=*/10); + APInt Tmp(NumBits, Str, /*radix=*/10); if (Str[0] == '-') { unsigned MinBits = Tmp.getMinSignedBits(); if (MinBits > 0 && MinBits < NumBits) Tmp = Tmp.trunc(MinBits); - *this = APSInt(Tmp, /*IsUnsigned=*/false); + *this = APSInt(Tmp, /*isUnsigned=*/false); return; } unsigned ActiveBits = Tmp.getActiveBits(); if (ActiveBits > 0 && ActiveBits < NumBits) Tmp = Tmp.trunc(ActiveBits); - *this = APSInt(Tmp, /*IsUnsigned=*/true); + *this = APSInt(Tmp, /*isUnsigned=*/true); } void APSInt::Profile(FoldingSetNodeID& ID) const { diff --git a/contrib/llvm/lib/Support/ARMAttributeParser.cpp b/contrib/llvm/lib/Support/ARMAttributeParser.cpp index 1f98ac2f40ba..df50fff720cd 100644 --- a/contrib/llvm/lib/Support/ARMAttributeParser.cpp +++ b/contrib/llvm/lib/Support/ARMAttributeParser.cpp @@ -1,9 +1,8 @@ //===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -38,6 +37,7 @@ ARMAttributeParser::DisplayRoutines[] = { ATTRIBUTE_HANDLER(FP_arch), ATTRIBUTE_HANDLER(WMMX_arch), ATTRIBUTE_HANDLER(Advanced_SIMD_arch), + ATTRIBUTE_HANDLER(MVE_arch), ATTRIBUTE_HANDLER(PCS_config), ATTRIBUTE_HANDLER(ABI_PCS_R9_use), ATTRIBUTE_HANDLER(ABI_PCS_RW_data), @@ -133,7 +133,9 @@ void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, static const char *const Strings[] = { "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6", "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M", - "ARM v7E-M", "ARM v8" + "ARM v7E-M", "ARM v8", nullptr, + "ARM v8-M Baseline", "ARM v8-M Mainline", nullptr, nullptr, nullptr, + "ARM v8.1-M Mainline" }; uint64_t Value = ParseInteger(Data, Offset); @@ -214,6 +216,18 @@ void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, PrintAttribute(Tag, Value, ValueDesc); } +void ARMAttributeParser::MVE_arch(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *const Strings[] = { + "Not Permitted", "MVE integer", "MVE integer and float" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { static const char *const Strings[] = { @@ -682,7 +696,7 @@ void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) { } void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section, bool isLittle) { - size_t Offset = 1; + uint64_t Offset = 1; unsigned SectionNumber = 0; while (Offset < Section.size()) { @@ -695,6 +709,12 @@ void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section, bool isLittle) { SW->indent(); } + if (SectionLength == 0 || (SectionLength + Offset) > Section.size()) { + errs() << "invalid subsection length " << SectionLength << " at offset " + << Offset << "\n"; + return; + } + ParseSubsection(Section.data() + Offset, SectionLength); Offset = Offset + SectionLength; diff --git a/contrib/llvm/lib/Support/ARMBuildAttrs.cpp b/contrib/llvm/lib/Support/ARMBuildAttrs.cpp index 8f18e9eb24ed..d0c4fb792cb8 100644 --- a/contrib/llvm/lib/Support/ARMBuildAttrs.cpp +++ b/contrib/llvm/lib/Support/ARMBuildAttrs.cpp @@ -1,9 +1,8 @@ //===-- ARMBuildAttrs.cpp - ARM Build Attributes --------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -29,6 +28,7 @@ const struct { { ARMBuildAttrs::FP_arch, "Tag_FP_arch" }, { ARMBuildAttrs::WMMX_arch, "Tag_WMMX_arch" }, { ARMBuildAttrs::Advanced_SIMD_arch, "Tag_Advanced_SIMD_arch" }, + { ARMBuildAttrs::MVE_arch, "Tag_MVE_arch" }, { ARMBuildAttrs::PCS_config, "Tag_PCS_config" }, { ARMBuildAttrs::ABI_PCS_R9_use, "Tag_ABI_PCS_R9_use" }, { ARMBuildAttrs::ABI_PCS_RW_data, "Tag_ABI_PCS_RW_data" }, diff --git a/contrib/llvm/lib/Support/ARMTargetParser.cpp b/contrib/llvm/lib/Support/ARMTargetParser.cpp index 07294b0c09a3..be948cfc95d4 100644 --- a/contrib/llvm/lib/Support/ARMTargetParser.cpp +++ b/contrib/llvm/lib/Support/ARMTargetParser.cpp @@ -1,9 +1,8 @@ //===-- ARMTargetParser - Parser for ARM target features --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -78,6 +77,7 @@ unsigned ARM::parseArchVersion(StringRef Arch) { case ArchKind::ARMV8R: case ArchKind::ARMV8MBaseline: case ArchKind::ARMV8MMainline: + case ArchKind::ARMV8_1MMainline: return 8; case ArchKind::INVALID: return 0; @@ -94,6 +94,7 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) { case ArchKind::ARMV7EM: case ArchKind::ARMV8MMainline: case ArchKind::ARMV8MBaseline: + case ArchKind::ARMV8_1MMainline: return ProfileKind::M; case ArchKind::ARMV7R: case ArchKind::ARMV8R: @@ -152,6 +153,7 @@ StringRef ARM::getArchSynonym(StringRef Arch) { .Case("v8r", "v8-r") .Case("v8m.base", "v8-m.base") .Case("v8m.main", "v8-m.main") + .Case("v8.1m.main", "v8.1-m.main") .Default(Arch); } @@ -160,77 +162,63 @@ bool ARM::getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features) { if (FPUKind >= FK_LAST || FPUKind == FK_INVALID) return false; - // fp-only-sp and d16 subtarget features are independent of each other, so we - // must enable/disable both. - switch (FPUNames[FPUKind].Restriction) { - case FPURestriction::SP_D16: - Features.push_back("+fp-only-sp"); - Features.push_back("+d16"); - break; - case FPURestriction::D16: - Features.push_back("-fp-only-sp"); - Features.push_back("+d16"); - break; - case FPURestriction::None: - Features.push_back("-fp-only-sp"); - Features.push_back("-d16"); - break; - } - - // FPU version subtarget features are inclusive of lower-numbered ones, so - // enable the one corresponding to this version and disable all that are - // higher. We also have to make sure to disable fp16 when vfp4 is disabled, - // as +vfp4 implies +fp16 but -vfp4 does not imply -fp16. - switch (FPUNames[FPUKind].FPUVer) { - case FPUVersion::VFPV5: - Features.push_back("+fp-armv8"); - break; - case FPUVersion::VFPV4: - Features.push_back("+vfp4"); - Features.push_back("-fp-armv8"); - break; - case FPUVersion::VFPV3_FP16: - Features.push_back("+vfp3"); - Features.push_back("+fp16"); - Features.push_back("-vfp4"); - Features.push_back("-fp-armv8"); - break; - case FPUVersion::VFPV3: - Features.push_back("+vfp3"); - Features.push_back("-fp16"); - Features.push_back("-vfp4"); - Features.push_back("-fp-armv8"); - break; - case FPUVersion::VFPV2: - Features.push_back("+vfp2"); - Features.push_back("-vfp3"); - Features.push_back("-fp16"); - Features.push_back("-vfp4"); - Features.push_back("-fp-armv8"); - break; - case FPUVersion::NONE: - Features.push_back("-vfp2"); - Features.push_back("-vfp3"); - Features.push_back("-fp16"); - Features.push_back("-vfp4"); - Features.push_back("-fp-armv8"); - break; + static const struct FPUFeatureNameInfo { + const char *PlusName, *MinusName; + FPUVersion MinVersion; + FPURestriction MaxRestriction; + } FPUFeatureInfoList[] = { + // We have to specify the + and - versions of the name in full so + // that we can return them as static StringRefs. + // + // Also, the SubtargetFeatures ending in just "sp" are listed here + // under FPURestriction::None, which is the only FPURestriction in + // which they would be valid (since FPURestriction::SP doesn't + // exist). + + {"+fpregs", "-fpregs", FPUVersion::VFPV2, FPURestriction::SP_D16}, + {"+vfp2", "-vfp2", FPUVersion::VFPV2, FPURestriction::None}, + {"+vfp2d16", "-vfp2d16", FPUVersion::VFPV2, FPURestriction::D16}, + {"+vfp2d16sp", "-vfp2d16sp", FPUVersion::VFPV2, FPURestriction::SP_D16}, + {"+vfp2sp", "-vfp2sp", FPUVersion::VFPV2, FPURestriction::None}, + {"+vfp3", "-vfp3", FPUVersion::VFPV3, FPURestriction::None}, + {"+vfp3d16", "-vfp3d16", FPUVersion::VFPV3, FPURestriction::D16}, + {"+vfp3d16sp", "-vfp3d16sp", FPUVersion::VFPV3, FPURestriction::SP_D16}, + {"+vfp3sp", "-vfp3sp", FPUVersion::VFPV3, FPURestriction::None}, + {"+fp16", "-fp16", FPUVersion::VFPV3_FP16, FPURestriction::SP_D16}, + {"+vfp4", "-vfp4", FPUVersion::VFPV4, FPURestriction::None}, + {"+vfp4d16", "-vfp4d16", FPUVersion::VFPV4, FPURestriction::D16}, + {"+vfp4d16sp", "-vfp4d16sp", FPUVersion::VFPV4, FPURestriction::SP_D16}, + {"+vfp4sp", "-vfp4sp", FPUVersion::VFPV4, FPURestriction::None}, + {"+fp-armv8", "-fp-armv8", FPUVersion::VFPV5, FPURestriction::None}, + {"+fp-armv8d16", "-fp-armv8d16", FPUVersion::VFPV5, FPURestriction::D16}, + {"+fp-armv8d16sp", "-fp-armv8d16sp", FPUVersion::VFPV5, FPURestriction::SP_D16}, + {"+fp-armv8sp", "-fp-armv8sp", FPUVersion::VFPV5, FPURestriction::None}, + {"+fullfp16", "-fullfp16", FPUVersion::VFPV5_FULLFP16, FPURestriction::SP_D16}, + {"+fp64", "-fp64", FPUVersion::VFPV2, FPURestriction::D16}, + {"+d32", "-d32", FPUVersion::VFPV2, FPURestriction::None}, + }; + + for (const auto &Info: FPUFeatureInfoList) { + if (FPUNames[FPUKind].FPUVer >= Info.MinVersion && + FPUNames[FPUKind].Restriction <= Info.MaxRestriction) + Features.push_back(Info.PlusName); + else + Features.push_back(Info.MinusName); } - // crypto includes neon, so we handle this similarly to FPU version. - switch (FPUNames[FPUKind].NeonSupport) { - case NeonSupportLevel::Crypto: - Features.push_back("+neon"); - Features.push_back("+crypto"); - break; - case NeonSupportLevel::Neon: - Features.push_back("+neon"); - Features.push_back("-crypto"); - break; - case NeonSupportLevel::None: - Features.push_back("-neon"); - Features.push_back("-crypto"); - break; + static const struct NeonFeatureNameInfo { + const char *PlusName, *MinusName; + NeonSupportLevel MinSupportLevel; + } NeonFeatureInfoList[] = { + {"+neon", "-neon", NeonSupportLevel::Neon}, + {"+crypto", "-crypto", NeonSupportLevel::Crypto}, + }; + + for (const auto &Info: NeonFeatureInfoList) { + if (FPUNames[FPUKind].NeonSupport >= Info.MinSupportLevel) + Features.push_back(Info.PlusName); + else + Features.push_back(Info.MinusName); } return true; @@ -249,7 +237,7 @@ ARM::EndianKind ARM::parseArchEndian(StringRef Arch) { return EndianKind::LITTLE; } - if (Arch.startswith("aarch64")) + if (Arch.startswith("aarch64") || Arch.startswith("aarch64_32")) return EndianKind::LITTLE; return EndianKind::INVALID; @@ -290,8 +278,12 @@ StringRef ARM::getCanonicalArchName(StringRef Arch) { StringRef Error = ""; // Begins with "arm" / "thumb", move past it. - if (A.startswith("arm64")) + if (A.startswith("arm64_32")) + offset = 8; + else if (A.startswith("arm64")) offset = 5; + else if (A.startswith("aarch64_32")) + offset = 10; else if (A.startswith("arm")) offset = 3; else if (A.startswith("thumb")) @@ -417,30 +409,12 @@ bool ARM::getExtensionFeatures(unsigned Extensions, if (Extensions == AEK_INVALID) return false; - if (Extensions & AEK_CRC) - Features.push_back("+crc"); - else - Features.push_back("-crc"); - - if (Extensions & AEK_DSP) - Features.push_back("+dsp"); - else - Features.push_back("-dsp"); - - if (Extensions & AEK_FP16FML) - Features.push_back("+fp16fml"); - else - Features.push_back("-fp16fml"); - - if (Extensions & AEK_RAS) - Features.push_back("+ras"); - else - Features.push_back("-ras"); - - if (Extensions & AEK_DOTPROD) - Features.push_back("+dotprod"); - else - Features.push_back("-dotprod"); + for (const auto AE : ARCHExtNames) { + if ((Extensions & AE.ID) == AE.ID && AE.Feature) + Features.push_back(AE.Feature); + else if (AE.NegFeature) + Features.push_back(AE.NegFeature); + } return getHWDivFeatures(Extensions, Features); } @@ -469,22 +443,99 @@ StringRef ARM::getArchExtName(unsigned ArchExtKind) { return StringRef(); } -StringRef ARM::getArchExtFeature(StringRef ArchExt) { - if (ArchExt.startswith("no")) { - StringRef ArchExtBase(ArchExt.substr(2)); - for (const auto AE : ARCHExtNames) { - if (AE.NegFeature && ArchExtBase == AE.getName()) - return StringRef(AE.NegFeature); - } +static bool stripNegationPrefix(StringRef &Name) { + if (Name.startswith("no")) { + Name = Name.substr(2); + return true; } + return false; +} + +StringRef ARM::getArchExtFeature(StringRef ArchExt) { + bool Negated = stripNegationPrefix(ArchExt); for (const auto AE : ARCHExtNames) { if (AE.Feature && ArchExt == AE.getName()) - return StringRef(AE.Feature); + return StringRef(Negated ? AE.NegFeature : AE.Feature); } return StringRef(); } +static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) { + const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind]; + + // If the input FPU already supports double-precision, then there + // isn't any different FPU we can return here. + // + // The current available FPURestriction values are None (no + // restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs + // and single precision only); there's no value representing + // SP restriction without D16. So this test just means 'is it + // SP only?'. + if (InputFPU.Restriction != ARM::FPURestriction::SP_D16) + return ARM::FK_INVALID; + + // Otherwise, look for an FPU entry with all the same fields, except + // that SP_D16 has been replaced with just D16, representing adding + // double precision and not changing anything else. + for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) { + if (CandidateFPU.FPUVer == InputFPU.FPUVer && + CandidateFPU.NeonSupport == InputFPU.NeonSupport && + CandidateFPU.Restriction == ARM::FPURestriction::D16) { + return CandidateFPU.ID; + } + } + + // nothing found + return ARM::FK_INVALID; +} + +static unsigned getAEKID(StringRef ArchExtName) { + for (const auto AE : ARM::ARCHExtNames) + if (AE.getName() == ArchExtName) + return AE.ID; + return ARM::AEK_INVALID; +} + +bool ARM::appendArchExtFeatures( + StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, + std::vector<StringRef> &Features) { + + size_t StartingNumFeatures = Features.size(); + const bool Negated = stripNegationPrefix(ArchExt); + unsigned ID = getAEKID(ArchExt); + + if (ID == AEK_INVALID) + return false; + + for (const auto AE : ARCHExtNames) { + if (Negated && (AE.ID & ID) == ID && AE.NegFeature) + Features.push_back(AE.NegFeature); + else if (AE.ID == ID && AE.Feature) + Features.push_back(AE.Feature); + } + + if (CPU == "") + CPU = "generic"; + + if (ArchExt == "fp" || ArchExt == "fp.dp") { + unsigned FPUKind; + if (ArchExt == "fp.dp") { + if (Negated) { + Features.push_back("-fp64"); + return true; + } + FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK)); + } else if (Negated) { + FPUKind = ARM::FK_NONE; + } else { + FPUKind = getDefaultFPU(CPU, AK); + } + return ARM::getFPUFeatures(FPUKind, Features); + } + return StartingNumFeatures != Features.size(); +} + StringRef ARM::getHWDivName(unsigned HWDivKind) { for (const auto D : HWDivNames) { if (HWDivKind == D.ID) diff --git a/contrib/llvm/lib/Support/ARMWinEH.cpp b/contrib/llvm/lib/Support/ARMWinEH.cpp index 03c150f1150b..831f95cd4b0b 100644 --- a/contrib/llvm/lib/Support/ARMWinEH.cpp +++ b/contrib/llvm/lib/Support/ARMWinEH.cpp @@ -1,9 +1,8 @@ //===-- ARMWinEH.cpp - Windows on ARM EH Support Functions ------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/Allocator.cpp b/contrib/llvm/lib/Support/Allocator.cpp index f48edac0598c..718d3fc0d8e1 100644 --- a/contrib/llvm/lib/Support/Allocator.cpp +++ b/contrib/llvm/lib/Support/Allocator.cpp @@ -1,9 +1,8 @@ //===--- Allocator.cpp - Simple memory allocation abstraction -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Atomic.cpp b/contrib/llvm/lib/Support/Atomic.cpp index 7328a93052cc..f6865405c2b8 100644 --- a/contrib/llvm/lib/Support/Atomic.cpp +++ b/contrib/llvm/lib/Support/Atomic.cpp @@ -1,9 +1,8 @@ //===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/BinaryStreamError.cpp b/contrib/llvm/lib/Support/BinaryStreamError.cpp index cdc811d78d63..f22523f09ac8 100644 --- a/contrib/llvm/lib/Support/BinaryStreamError.cpp +++ b/contrib/llvm/lib/Support/BinaryStreamError.cpp @@ -1,9 +1,8 @@ //===- BinaryStreamError.cpp - Error extensions for streams -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/BinaryStreamReader.cpp b/contrib/llvm/lib/Support/BinaryStreamReader.cpp index e00527f2519e..b17786593bde 100644 --- a/contrib/llvm/lib/Support/BinaryStreamReader.cpp +++ b/contrib/llvm/lib/Support/BinaryStreamReader.cpp @@ -1,9 +1,8 @@ //===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -11,6 +10,7 @@ #include "llvm/Support/BinaryStreamError.h" #include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/LEB128.h" using namespace llvm; using endianness = llvm::support::endianness; @@ -41,6 +41,36 @@ Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) { return Error::success(); } +Error BinaryStreamReader::readULEB128(uint64_t &Dest) { + SmallVector<uint8_t, 10> EncodedBytes; + ArrayRef<uint8_t> NextByte; + + // Copy the encoded ULEB into the buffer. + do { + if (auto Err = readBytes(NextByte, 1)) + return Err; + EncodedBytes.push_back(NextByte[0]); + } while (NextByte[0] & 0x80); + + Dest = decodeULEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end()); + return Error::success(); +} + +Error BinaryStreamReader::readSLEB128(int64_t &Dest) { + SmallVector<uint8_t, 10> EncodedBytes; + ArrayRef<uint8_t> NextByte; + + // Copy the encoded ULEB into the buffer. + do { + if (auto Err = readBytes(NextByte, 1)) + return Err; + EncodedBytes.push_back(NextByte[0]); + } while (NextByte[0] & 0x80); + + Dest = decodeSLEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end()); + return Error::success(); +} + Error BinaryStreamReader::readCString(StringRef &Dest) { uint32_t OriginalOffset = getOffset(); uint32_t FoundOffset = 0; @@ -146,4 +176,4 @@ BinaryStreamReader::split(uint32_t Off) const { BinaryStreamReader W1{First}; BinaryStreamReader W2{Second}; return std::make_pair(W1, W2); -}
\ No newline at end of file +} diff --git a/contrib/llvm/lib/Support/BinaryStreamRef.cpp b/contrib/llvm/lib/Support/BinaryStreamRef.cpp index bdc0f54bf25a..6bcc504ffad5 100644 --- a/contrib/llvm/lib/Support/BinaryStreamRef.cpp +++ b/contrib/llvm/lib/Support/BinaryStreamRef.cpp @@ -1,9 +1,8 @@ //===- BinaryStreamRef.cpp - ----------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/BinaryStreamWriter.cpp b/contrib/llvm/lib/Support/BinaryStreamWriter.cpp index bfad1280b929..986e18da281d 100644 --- a/contrib/llvm/lib/Support/BinaryStreamWriter.cpp +++ b/contrib/llvm/lib/Support/BinaryStreamWriter.cpp @@ -1,9 +1,8 @@ //===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -12,6 +11,7 @@ #include "llvm/Support/BinaryStreamError.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/LEB128.h" using namespace llvm; @@ -32,6 +32,18 @@ Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { return Error::success(); } +Error BinaryStreamWriter::writeULEB128(uint64_t Value) { + uint8_t EncodedBytes[10] = {0}; + unsigned Size = encodeULEB128(Value, &EncodedBytes[0]); + return writeBytes({EncodedBytes, Size}); +} + +Error BinaryStreamWriter::writeSLEB128(int64_t Value) { + uint8_t EncodedBytes[10] = {0}; + unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]); + return writeBytes({EncodedBytes, Size}); +} + Error BinaryStreamWriter::writeCString(StringRef Str) { if (auto EC = writeFixedString(Str)) return EC; diff --git a/contrib/llvm/lib/Support/BlockFrequency.cpp b/contrib/llvm/lib/Support/BlockFrequency.cpp index 34fcbde23a28..2b63294f3789 100644 --- a/contrib/llvm/lib/Support/BlockFrequency.cpp +++ b/contrib/llvm/lib/Support/BlockFrequency.cpp @@ -1,9 +1,8 @@ //====--------------- lib/Support/BlockFrequency.cpp -----------*- C++ -*-====// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/BranchProbability.cpp b/contrib/llvm/lib/Support/BranchProbability.cpp index 31dee9561f49..195e2d58d8e1 100644 --- a/contrib/llvm/lib/Support/BranchProbability.cpp +++ b/contrib/llvm/lib/Support/BranchProbability.cpp @@ -1,9 +1,8 @@ //===-------------- lib/Support/BranchProbability.cpp -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -89,10 +88,6 @@ static uint64_t scale(uint64_t Num, uint32_t N, uint32_t D) { // Carry. Upper32 += Mid32 < Mid32Partial; - // Check for overflow. - if (Upper32 >= D) - return UINT64_MAX; - uint64_t Rem = (uint64_t(Upper32) << 32) | Mid32; uint64_t UpperQ = Rem / D; diff --git a/contrib/llvm/lib/Support/BuryPointer.cpp b/contrib/llvm/lib/Support/BuryPointer.cpp index 6c988b4a0ab2..435f89010d41 100644 --- a/contrib/llvm/lib/Support/BuryPointer.cpp +++ b/contrib/llvm/lib/Support/BuryPointer.cpp @@ -1,9 +1,8 @@ //===- BuryPointer.cpp - Memory Manipulation/Leak ---------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/COM.cpp b/contrib/llvm/lib/Support/COM.cpp index 97cd085853b0..f37b95ba8651 100644 --- a/contrib/llvm/lib/Support/COM.cpp +++ b/contrib/llvm/lib/Support/COM.cpp @@ -1,9 +1,8 @@ //===-- COM.cpp - Implement COM utility classes -----------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/CRC.cpp b/contrib/llvm/lib/Support/CRC.cpp new file mode 100644 index 000000000000..fd98f3a24003 --- /dev/null +++ b/contrib/llvm/lib/Support/CRC.cpp @@ -0,0 +1,68 @@ +//===--- CRC.cpp - Cyclic Redundancy Check implementation -----------------===// +// +// 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 llvm::crc32 function. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CRC.h" +#include "llvm/Config/config.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Threading.h" +#include <array> + +using namespace llvm; + +#if LLVM_ENABLE_ZLIB == 0 || !HAVE_ZLIB_H +using CRC32Table = std::array<uint32_t, 256>; + +static void initCRC32Table(CRC32Table *Tbl) { + auto Shuffle = [](uint32_t V) { + return (V & 1) ? (V >> 1) ^ 0xEDB88320U : V >> 1; + }; + + for (size_t I = 0; I < Tbl->size(); ++I) { + uint32_t V = Shuffle(I); + V = Shuffle(V); + V = Shuffle(V); + V = Shuffle(V); + V = Shuffle(V); + V = Shuffle(V); + V = Shuffle(V); + (*Tbl)[I] = Shuffle(V); + } +} + +uint32_t llvm::crc32(uint32_t CRC, StringRef S) { + static llvm::once_flag InitFlag; + static CRC32Table Tbl; + llvm::call_once(InitFlag, initCRC32Table, &Tbl); + + const uint8_t *P = reinterpret_cast<const uint8_t *>(S.data()); + size_t Len = S.size(); + CRC ^= 0xFFFFFFFFU; + for (; Len >= 8; Len -= 8) { + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + } + while (Len--) + CRC = Tbl[(CRC ^ *P++) & 0xFF] ^ (CRC >> 8); + return CRC ^ 0xFFFFFFFFU; +} +#else +#include <zlib.h> +uint32_t llvm::crc32(uint32_t CRC, StringRef S) { + return ::crc32(CRC, (const Bytef *)S.data(), S.size()); +} +#endif diff --git a/contrib/llvm/lib/Support/CachePruning.cpp b/contrib/llvm/lib/Support/CachePruning.cpp index a0aa6024b3ed..9813eec0e433 100644 --- a/contrib/llvm/lib/Support/CachePruning.cpp +++ b/contrib/llvm/lib/Support/CachePruning.cpp @@ -1,9 +1,8 @@ //===-CachePruning.cpp - LLVM Cache Directory Pruning ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -36,15 +35,8 @@ struct FileInfo { /// Used to determine which files to prune first. Also used to determine /// set membership, so must take into account all fields. bool operator<(const FileInfo &Other) const { - if (Time < Other.Time) - return true; - else if (Other.Time < Time) - return false; - if (Other.Size < Size) - return true; - else if (Size < Other.Size) - return false; - return Path < Other.Path; + return std::tie(Time, Other.Size, Path) < + std::tie(Other.Time, Size, Other.Path); } }; } // anonymous namespace diff --git a/contrib/llvm/lib/Support/Chrono.cpp b/contrib/llvm/lib/Support/Chrono.cpp index a2626a89eb63..8c28d45d8822 100644 --- a/contrib/llvm/lib/Support/Chrono.cpp +++ b/contrib/llvm/lib/Support/Chrono.cpp @@ -1,9 +1,8 @@ //===- Support/Chrono.cpp - Utilities for Timing Manipulation ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/CodeGenCoverage.cpp b/contrib/llvm/lib/Support/CodeGenCoverage.cpp index 811020e3254a..f39eb7533b43 100644 --- a/contrib/llvm/lib/Support/CodeGenCoverage.cpp +++ b/contrib/llvm/lib/Support/CodeGenCoverage.cpp @@ -1,9 +1,8 @@ //===- lib/Support/CodeGenCoverage.cpp -------------------------------------==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index f7290b54dcf3..25510fa58ff5 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -1,9 +1,8 @@ //===-- CommandLine.cpp - Command line parser implementation --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -55,6 +54,7 @@ template class basic_parser<bool>; template class basic_parser<boolOrDefault>; template class basic_parser<int>; template class basic_parser<unsigned>; +template class basic_parser<unsigned long>; template class basic_parser<unsigned long long>; template class basic_parser<double>; template class basic_parser<float>; @@ -79,6 +79,7 @@ void parser<bool>::anchor() {} void parser<boolOrDefault>::anchor() {} void parser<int>::anchor() {} void parser<unsigned>::anchor() {} +void parser<unsigned long>::anchor() {} void parser<unsigned long long>::anchor() {} void parser<double>::anchor() {} void parser<float>::anchor() {} @@ -87,8 +88,47 @@ void parser<char>::anchor() {} //===----------------------------------------------------------------------===// +static StringRef ArgPrefix = " -"; +static StringRef ArgPrefixLong = " --"; +static StringRef ArgHelpPrefix = " - "; + +static size_t argPlusPrefixesSize(StringRef ArgName) { + size_t Len = ArgName.size(); + if (Len == 1) + return Len + ArgPrefix.size() + ArgHelpPrefix.size(); + return Len + ArgPrefixLong.size() + ArgHelpPrefix.size(); +} + +static StringRef argPrefix(StringRef ArgName) { + if (ArgName.size() == 1) + return ArgPrefix; + return ArgPrefixLong; +} + +// Option predicates... +static inline bool isGrouping(const Option *O) { + return O->getMiscFlags() & cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { + return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || + O->getFormattingFlag() == cl::AlwaysPrefix; +} + + namespace { +class PrintArg { + StringRef ArgName; +public: + PrintArg(StringRef ArgName) : ArgName(ArgName) {} + friend raw_ostream &operator<<(raw_ostream &OS, const PrintArg&); +}; + +raw_ostream &operator<<(raw_ostream &OS, const PrintArg& Arg) { + OS << argPrefix(Arg.ArgName) << Arg.ArgName; + return OS; +} + class CommandLineParser { public: // Globals for name and overview of program. Program name is not a string to @@ -99,6 +139,11 @@ public: // This collects additional help to be printed. std::vector<StringRef> MoreHelp; + // This collects Options added with the cl::DefaultOption flag. Since they can + // be overridden, they are not added to the appropriate SubCommands until + // ParseCommandLineOptions actually runs. + SmallVector<Option*, 4> DefaultOptions; + // This collects the different option categories that have been registered. SmallPtrSet<OptionCategory *, 16> RegisteredOptionCategories; @@ -113,7 +158,8 @@ public: void ResetAllOptionOccurrences(); bool ParseCommandLineOptions(int argc, const char *const *argv, - StringRef Overview, raw_ostream *Errs = nullptr); + StringRef Overview, raw_ostream *Errs = nullptr, + bool LongOptionsUseDoubleDash = false); void addLiteralOption(Option &Opt, SubCommand *SC, StringRef Name) { if (Opt.hasArgStr()) @@ -147,6 +193,11 @@ public: void addOption(Option *O, SubCommand *SC) { bool HadErrors = false; if (O->hasArgStr()) { + // If it's a DefaultOption, check to make sure it isn't already there. + if (O->isDefaultOption() && + SC->OptionsMap.find(O->ArgStr) != SC->OptionsMap.end()) + return; + // Add argument to the argument map! if (!SC->OptionsMap.insert(std::make_pair(O->ArgStr, O)).second) { errs() << ProgramName << ": CommandLine Error: Option '" << O->ArgStr @@ -186,7 +237,12 @@ public: } } - void addOption(Option *O) { + void addOption(Option *O, bool ProcessDefaultOption = false) { + if (!ProcessDefaultOption && O->isDefaultOption()) { + DefaultOptions.push_back(O); + return; + } + if (O->Subs.empty()) { addOption(O, &*TopLevelSubCommand); } else { @@ -202,8 +258,12 @@ public: OptionNames.push_back(O->ArgStr); SubCommand &Sub = *SC; - for (auto Name : OptionNames) - Sub.OptionsMap.erase(Name); + auto End = Sub.OptionsMap.end(); + for (auto Name : OptionNames) { + auto I = Sub.OptionsMap.find(Name); + if (I != End && I->getValue() == O) + Sub.OptionsMap.erase(I); + } if (O->getFormattingFlag() == cl::Positional) for (auto Opt = Sub.PositionalOpts.begin(); @@ -267,8 +327,13 @@ public: if (O->Subs.empty()) updateArgStr(O, NewName, &*TopLevelSubCommand); else { - for (auto SC : O->Subs) - updateArgStr(O, NewName, SC); + if (O->isInAllSubCommands()) { + for (auto SC : RegisteredSubCommands) + updateArgStr(O, NewName, SC); + } else { + for (auto SC : O->Subs) + updateArgStr(O, NewName, SC); + } } } @@ -332,12 +397,21 @@ public: AllSubCommands->reset(); registerSubCommand(&*TopLevelSubCommand); registerSubCommand(&*AllSubCommands); + + DefaultOptions.clear(); } private: SubCommand *ActiveSubCommand; Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value); + Option *LookupLongOption(SubCommand &Sub, StringRef &Arg, StringRef &Value, + bool LongOptionsUseDoubleDash, bool HaveDoubleDash) { + Option *Opt = LookupOption(Sub, Arg, Value); + if (Opt && LongOptionsUseDoubleDash && !HaveDoubleDash && !isGrouping(Opt)) + return nullptr; + return Opt; + } SubCommand *LookupSubCommand(StringRef Name); }; @@ -365,6 +439,26 @@ void Option::setArgStr(StringRef S) { GlobalParser->updateArgStr(this, S); assert((S.empty() || S[0] != '-') && "Option can't start with '-"); ArgStr = S; + if (ArgStr.size() == 1) + setMiscFlag(Grouping); +} + +void Option::addCategory(OptionCategory &C) { + assert(!Categories.empty() && "Categories cannot be empty."); + // Maintain backward compatibility by replacing the default GeneralCategory + // if it's still set. Otherwise, just add the new one. The GeneralCategory + // 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()) + Categories.push_back(&C); +} + +void Option::reset() { + NumOccurrences = 0; + setDefault(); + if (isDefaultOption()) + removeArgument(); } // Initialise the general option category. @@ -374,7 +468,11 @@ void OptionCategory::registerCategory() { GlobalParser->registerCategory(this); } -// A special subcommand representing no subcommand +// A special subcommand representing no subcommand. It is particularly important +// that this ManagedStatic uses constant initailization and not dynamic +// initialization because it is referenced from cl::opt constructors, which run +// dynamically in an arbitrary order. +LLVM_REQUIRE_CONSTANT_INITIALIZATION ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand; // A special subcommand that can be used to put an option into all subcommands. @@ -599,15 +697,6 @@ static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) { return ProvideOption(Handler, Handler->ArgStr, Arg, 0, nullptr, Dummy); } -// Option predicates... -static inline bool isGrouping(const Option *O) { - return O->getFormattingFlag() == cl::Grouping; -} -static inline bool isPrefixedOrGrouping(const Option *O) { - return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || - O->getFormattingFlag() == cl::AlwaysPrefix; -} - // getOptionPred - Check to see if there are any options that satisfy the // specified predicate with names that are the prefixes in Name. This is // checked by progressively stripping characters off of the name, checking to @@ -617,8 +706,9 @@ static inline bool isPrefixedOrGrouping(const Option *O) { static Option *getOptionPred(StringRef Name, size_t &Length, bool (*Pred)(const Option *), const StringMap<Option *> &OptionsMap) { - StringMap<Option *>::const_iterator OMI = OptionsMap.find(Name); + if (OMI != OptionsMap.end() && !Pred(OMI->getValue())) + OMI = OptionsMap.end(); // Loop while we haven't found an option and Name still has at least two // characters in it (so that the next iteration will not be the empty @@ -626,6 +716,8 @@ static Option *getOptionPred(StringRef Name, size_t &Length, while (OMI == OptionsMap.end() && Name.size() > 1) { Name = Name.substr(0, Name.size() - 1); // Chop off the last character. OMI = OptionsMap.find(Name); + if (OMI != OptionsMap.end() && !Pred(OMI->getValue())) + OMI = OptionsMap.end(); } if (OMI != OptionsMap.end() && Pred(OMI->second)) { @@ -652,40 +744,46 @@ HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value, if (!PGOpt) return nullptr; - // If the option is a prefixed option, then the value is simply the - // rest of the name... so fall through to later processing, by - // setting up the argument name flags and value fields. - if (PGOpt->getFormattingFlag() == cl::Prefix || - PGOpt->getFormattingFlag() == cl::AlwaysPrefix) { - Value = Arg.substr(Length); + do { + StringRef MaybeValue = + (Length < Arg.size()) ? Arg.substr(Length) : StringRef(); Arg = Arg.substr(0, Length); assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt); - return PGOpt; - } - // This must be a grouped option... handle them now. Grouping options can't - // have values. - assert(isGrouping(PGOpt) && "Broken getOptionPred!"); + // cl::Prefix options do not preserve '=' when used separately. + // The behavior for them with grouped options should be the same. + if (MaybeValue.empty() || PGOpt->getFormattingFlag() == cl::AlwaysPrefix || + (PGOpt->getFormattingFlag() == cl::Prefix && MaybeValue[0] != '=')) { + Value = MaybeValue; + return PGOpt; + } - do { - // Move current arg name out of Arg into OneArgName. - StringRef OneArgName = Arg.substr(0, Length); - Arg = Arg.substr(Length); - - // Because ValueRequired is an invalid flag for grouped arguments, - // we don't need to pass argc/argv in. - assert(PGOpt->getValueExpectedFlag() != cl::ValueRequired && - "Option can not be cl::Grouping AND cl::ValueRequired!"); + if (MaybeValue[0] == '=') { + Value = MaybeValue.substr(1); + return PGOpt; + } + + // This must be a grouped option. + assert(isGrouping(PGOpt) && "Broken getOptionPred!"); + + // Grouping options inside a group can't have values. + if (PGOpt->getValueExpectedFlag() == cl::ValueRequired) { + ErrorParsing |= PGOpt->error("may not occur within a group!"); + return nullptr; + } + + // Because the value for the option is not required, we don't need to pass + // argc/argv in. int Dummy = 0; - ErrorParsing |= - ProvideOption(PGOpt, OneArgName, StringRef(), 0, nullptr, Dummy); + ErrorParsing |= ProvideOption(PGOpt, Arg, StringRef(), 0, nullptr, Dummy); // Get the next grouping option. + Arg = MaybeValue; PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap); - } while (PGOpt && Length != Arg.size()); + } while (PGOpt); - // Return the last option with Arg cut down to just the last one. - return PGOpt; + // We could not find a grouping option in the remainder of Arg. + return nullptr; } static bool RequiresValue(const Option *O) { @@ -869,6 +967,13 @@ void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver, // QUOTED state means that it's reading a token quoted by double quotes. if (State == QUOTED) { if (C == '"') { + if (I < (E - 1) && Src[I + 1] == '"') { + // Consecutive double-quotes inside a quoted string implies one + // double-quote. + Token.push_back('"'); + I = I + 1; + continue; + } State = UNQUOTED; continue; } @@ -992,41 +1097,84 @@ static bool ExpandResponseFile(StringRef FName, StringSaver &Saver, bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, SmallVectorImpl<const char *> &Argv, bool MarkEOLs, bool RelativeNames) { - unsigned RspFiles = 0; bool AllExpanded = true; + struct ResponseFileRecord { + const char *File; + size_t End; + }; + + // To detect recursive response files, we maintain a stack of files and the + // position of the last argument in the file. This position is updated + // dynamically as we recursively expand files. + SmallVector<ResponseFileRecord, 3> FileStack; + + // Push a dummy entry that represents the initial command line, removing + // the need to check for an empty list. + FileStack.push_back({"", Argv.size()}); // Don't cache Argv.size() because it can change. for (unsigned I = 0; I != Argv.size();) { + while (I == FileStack.back().End) { + // Passing the end of a file's argument list, so we can remove it from the + // stack. + FileStack.pop_back(); + } + const char *Arg = Argv[I]; // Check if it is an EOL marker if (Arg == nullptr) { ++I; continue; } + if (Arg[0] != '@') { ++I; continue; } - // If we have too many response files, leave some unexpanded. This avoids - // crashing on self-referential response files. - if (RspFiles++ > 20) - return false; + const char *FName = Arg + 1; + auto IsEquivalent = [FName](const ResponseFileRecord &RFile) { + return sys::fs::equivalent(RFile.File, FName); + }; + + // Check for recursive response files. + if (std::any_of(FileStack.begin() + 1, FileStack.end(), IsEquivalent)) { + // This file is recursive, so we leave it in the argument stream and + // move on. + AllExpanded = false; + ++I; + continue; + } // Replace this response file argument with the tokenization of its // contents. Nested response files are expanded in subsequent iterations. SmallVector<const char *, 0> ExpandedArgv; - if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv, - MarkEOLs, RelativeNames)) { + if (!ExpandResponseFile(FName, Saver, Tokenizer, ExpandedArgv, MarkEOLs, + RelativeNames)) { // We couldn't read this file, so we leave it in the argument stream and // move on. AllExpanded = false; ++I; continue; } + + for (ResponseFileRecord &Record : FileStack) { + // Increase the end of all active records by the number of newly expanded + // arguments, minus the response file itself. + Record.End += ExpandedArgv.size() - 1; + } + + FileStack.push_back({FName, I + ExpandedArgv.size()}); Argv.erase(Argv.begin() + I); Argv.insert(Argv.begin() + I, ExpandedArgv.begin(), ExpandedArgv.end()); } + + // If successful, the top of the file stack will mark the end of the Argv + // stream. A failure here indicates a bug in the stack popping logic above. + // Note that FileStack may have more than one element at this point because we + // don't have a chance to pop the stack when encountering recursive files at + // the end of the stream, so seeing that doesn't indicate a bug. + assert(FileStack.size() > 0 && Argv.size() == FileStack.back().End); return AllExpanded; } @@ -1071,7 +1219,8 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, bool cl::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs, - const char *EnvVar) { + const char *EnvVar, + bool LongOptionsUseDoubleDash) { SmallVector<const char *, 20> NewArgv; BumpPtrAllocator A; StringSaver Saver(A); @@ -1091,7 +1240,7 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv, // Parse all options. return GlobalParser->ParseCommandLineOptions(NewArgc, &NewArgv[0], Overview, - Errs); + Errs, LongOptionsUseDoubleDash); } void CommandLineParser::ResetAllOptionOccurrences() { @@ -1106,7 +1255,8 @@ void CommandLineParser::ResetAllOptionOccurrences() { bool CommandLineParser::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, - raw_ostream *Errs) { + raw_ostream *Errs, + bool LongOptionsUseDoubleDash) { assert(hasOptions() && "No options specified!"); // Expand response files. @@ -1152,6 +1302,10 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, auto &SinkOpts = ChosenSubCommand->SinkOpts; auto &OptionsMap = ChosenSubCommand->OptionsMap; + for (auto O: DefaultOptions) { + addOption(O, true); + } + if (ConsumeAfterOpt) { assert(PositionalOpts.size() > 0 && "Cannot specify cl::ConsumeAfter without a positional argument!"); @@ -1212,6 +1366,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, std::string NearestHandlerString; StringRef Value; StringRef ArgName = ""; + bool HaveDoubleDash = false; // Check to see if this is a positional argument. This argument is // considered to be positional if it doesn't start with '-', if it is "-" @@ -1249,26 +1404,31 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // option is another positional argument. If so, treat it as an argument, // otherwise feed it to the eating positional. ArgName = StringRef(argv[i] + 1); - // Eat leading dashes. - while (!ArgName.empty() && ArgName[0] == '-') + // Eat second dash. + if (!ArgName.empty() && ArgName[0] == '-') { + HaveDoubleDash = true; ArgName = ArgName.substr(1); + } - Handler = LookupOption(*ChosenSubCommand, ArgName, Value); + Handler = LookupLongOption(*ChosenSubCommand, ArgName, Value, + LongOptionsUseDoubleDash, HaveDoubleDash); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { ProvidePositionalOption(ActivePositionalArg, StringRef(argv[i]), i); continue; // We are done! } - } else { // We start with a '-', must be an argument. ArgName = StringRef(argv[i] + 1); - // Eat leading dashes. - while (!ArgName.empty() && ArgName[0] == '-') + // Eat second dash. + if (!ArgName.empty() && ArgName[0] == '-') { + HaveDoubleDash = true; ArgName = ArgName.substr(1); + } - Handler = LookupOption(*ChosenSubCommand, ArgName, Value); + Handler = LookupLongOption(*ChosenSubCommand, ArgName, Value, + LongOptionsUseDoubleDash, HaveDoubleDash); // Check to see if this "option" is really a prefixed or grouped argument. - if (!Handler) + if (!Handler && !(LongOptionsUseDoubleDash && HaveDoubleDash)) Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, OptionsMap); @@ -1282,12 +1442,12 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, if (!Handler) { if (SinkOpts.empty()) { *Errs << ProgramName << ": Unknown command line argument '" << argv[i] - << "'. Try: '" << argv[0] << " -help'\n"; + << "'. Try: '" << argv[0] << " --help'\n"; if (NearestHandler) { // If we know a near match, report it as well. - *Errs << ProgramName << ": Did you mean '-" << NearestHandlerString - << "'?\n"; + *Errs << ProgramName << ": Did you mean '" + << PrintArg(NearestHandlerString) << "'?\n"; } ErrorParsing = true; @@ -1321,14 +1481,14 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, << ": Not enough positional command line arguments specified!\n" << "Must specify at least " << NumPositionalRequired << " positional argument" << (NumPositionalRequired > 1 ? "s" : "") - << ": See: " << argv[0] << " -help\n"; + << ": See: " << argv[0] << " --help\n"; ErrorParsing = true; } else if (!HasUnlimitedPositionals && PositionalVals.size() > PositionalOpts.size()) { *Errs << ProgramName << ": Too many positional arguments specified!\n" << "Can specify at most " << PositionalOpts.size() - << " positional arguments: See: " << argv[0] << " -help\n"; + << " positional arguments: See: " << argv[0] << " --help\n"; ErrorParsing = true; } else if (!ConsumeAfterOpt) { @@ -1441,7 +1601,7 @@ bool Option::error(const Twine &Message, StringRef ArgName, raw_ostream &Errs) { if (ArgName.empty()) Errs << HelpStr; // Be nice for positional arguments else - Errs << GlobalParser->ProgramName << ": for the -" << ArgName; + Errs << GlobalParser->ProgramName << ": for the " << PrintArg(ArgName); Errs << " option: " << Message << "\n"; return true; @@ -1484,12 +1644,16 @@ static StringRef getValueStr(const Option &O, StringRef DefaultMsg) { // // Return the width of the option tag for printing... -size_t alias::getOptionWidth() const { return ArgStr.size() + 6; } +size_t alias::getOptionWidth() const { + return argPlusPrefixesSize(ArgStr); +} void Option::printHelpStr(StringRef HelpStr, size_t Indent, - size_t FirstLineIndentedBy) { + size_t FirstLineIndentedBy) { + assert(Indent >= FirstLineIndentedBy); std::pair<StringRef, StringRef> Split = HelpStr.split('\n'); - outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n"; + outs().indent(Indent - FirstLineIndentedBy) + << ArgHelpPrefix << Split.first << "\n"; while (!Split.second.empty()) { Split = Split.second.split('\n'); outs().indent(Indent) << Split.first << "\n"; @@ -1498,8 +1662,8 @@ void Option::printHelpStr(StringRef HelpStr, size_t Indent, // Print out the option for the alias. void alias::printOptionInfo(size_t GlobalWidth) const { - outs() << " -" << ArgStr; - printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6); + outs() << PrintArg(ArgStr); + printHelpStr(HelpStr, GlobalWidth, argPlusPrefixesSize(ArgStr)); } //===----------------------------------------------------------------------===// @@ -1511,7 +1675,7 @@ void alias::printOptionInfo(size_t GlobalWidth) const { // Return the width of the option tag for printing... size_t basic_parser_impl::getOptionWidth(const Option &O) const { - size_t Len = O.ArgStr.size(); + size_t Len = argPlusPrefixesSize(O.ArgStr); auto ValName = getValueName(); if (!ValName.empty()) { size_t FormattingLen = 3; @@ -1520,7 +1684,7 @@ size_t basic_parser_impl::getOptionWidth(const Option &O) const { Len += getValueStr(O, ValName).size() + FormattingLen; } - return Len + 6; + return Len; } // printOptionInfo - Print out information about this option. The @@ -1528,7 +1692,7 @@ size_t basic_parser_impl::getOptionWidth(const Option &O) const { // void basic_parser_impl::printOptionInfo(const Option &O, size_t GlobalWidth) const { - outs() << " -" << O.ArgStr; + outs() << PrintArg(O.ArgStr); auto ValName = getValueName(); if (!ValName.empty()) { @@ -1544,7 +1708,7 @@ void basic_parser_impl::printOptionInfo(const Option &O, void basic_parser_impl::printOptionName(const Option &O, size_t GlobalWidth) const { - outs() << " -" << O.ArgStr; + outs() << PrintArg(O.ArgStr); outs().indent(GlobalWidth - O.ArgStr.size()); } @@ -1603,6 +1767,16 @@ bool parser<unsigned>::parse(Option &O, StringRef ArgName, StringRef Arg, return false; } +// parser<unsigned long> implementation +// +bool parser<unsigned long>::parse(Option &O, StringRef ArgName, StringRef Arg, + unsigned long &Value) { + + if (Arg.getAsInteger(0, Value)) + return O.error("'" + Arg + "' value invalid for ulong argument!"); + return false; +} + // parser<unsigned long long> implementation // bool parser<unsigned long long>::parse(Option &O, StringRef ArgName, @@ -1610,7 +1784,7 @@ bool parser<unsigned long long>::parse(Option &O, StringRef ArgName, unsigned long long &Value) { if (Arg.getAsInteger(0, Value)) - return O.error("'" + Arg + "' value invalid for uint argument!"); + return O.error("'" + Arg + "' value invalid for ullong argument!"); return false; } @@ -1652,12 +1826,29 @@ unsigned generic_parser_base::findOption(StringRef Name) { return e; } +static StringRef EqValue = "=<value>"; +static StringRef EmptyOption = "<empty>"; +static StringRef OptionPrefix = " ="; +static size_t OptionPrefixesSize = OptionPrefix.size() + ArgHelpPrefix.size(); + +static bool shouldPrintOption(StringRef Name, StringRef Description, + const Option &O) { + return O.getValueExpectedFlag() != ValueOptional || !Name.empty() || + !Description.empty(); +} + // Return the width of the option tag for printing... size_t generic_parser_base::getOptionWidth(const Option &O) const { if (O.hasArgStr()) { - size_t Size = O.ArgStr.size() + 6; - for (unsigned i = 0, e = getNumOptions(); i != e; ++i) - Size = std::max(Size, getOption(i).size() + 8); + size_t Size = + argPlusPrefixesSize(O.ArgStr) + EqValue.size(); + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + StringRef Name = getOption(i); + if (!shouldPrintOption(Name, getDescription(i), O)) + continue; + size_t NameSize = Name.empty() ? EmptyOption.size() : Name.size(); + Size = std::max(Size, NameSize + OptionPrefixesSize); + } return Size; } else { size_t BaseSize = 0; @@ -1673,20 +1864,46 @@ size_t generic_parser_base::getOptionWidth(const Option &O) const { void generic_parser_base::printOptionInfo(const Option &O, size_t GlobalWidth) const { if (O.hasArgStr()) { - outs() << " -" << O.ArgStr; - Option::printHelpStr(O.HelpStr, GlobalWidth, O.ArgStr.size() + 6); + // When the value is optional, first print a line just describing the + // option without values. + if (O.getValueExpectedFlag() == ValueOptional) { + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + if (getOption(i).empty()) { + outs() << PrintArg(O.ArgStr); + Option::printHelpStr(O.HelpStr, GlobalWidth, + argPlusPrefixesSize(O.ArgStr)); + break; + } + } + } + outs() << PrintArg(O.ArgStr) << EqValue; + Option::printHelpStr(O.HelpStr, GlobalWidth, + EqValue.size() + + argPlusPrefixesSize(O.ArgStr)); for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - size_t NumSpaces = GlobalWidth - getOption(i).size() - 8; - outs() << " =" << getOption(i); - outs().indent(NumSpaces) << " - " << getDescription(i) << '\n'; + StringRef OptionName = getOption(i); + StringRef Description = getDescription(i); + if (!shouldPrintOption(OptionName, Description, O)) + continue; + assert(GlobalWidth >= OptionName.size() + OptionPrefixesSize); + size_t NumSpaces = GlobalWidth - OptionName.size() - OptionPrefixesSize; + outs() << OptionPrefix << OptionName; + if (OptionName.empty()) { + outs() << EmptyOption; + assert(NumSpaces >= EmptyOption.size()); + NumSpaces -= EmptyOption.size(); + } + if (!Description.empty()) + outs().indent(NumSpaces) << ArgHelpPrefix << " " << Description; + outs() << '\n'; } } else { if (!O.HelpStr.empty()) outs() << " " << O.HelpStr << '\n'; for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { - auto Option = getOption(i); - outs() << " -" << Option; + StringRef Option = getOption(i); + outs() << " " << PrintArg(Option); Option::printHelpStr(getDescription(i), GlobalWidth, Option.size() + 8); } } @@ -1700,7 +1917,7 @@ static const size_t MaxOptWidth = 8; // arbitrary spacing for printOptionDiff void generic_parser_base::printGenericOptionDiff( const Option &O, const GenericOptionValue &Value, const GenericOptionValue &Default, size_t GlobalWidth) const { - outs() << " -" << O.ArgStr; + outs() << " " << PrintArg(O.ArgStr); outs().indent(GlobalWidth - O.ArgStr.size()); unsigned NumOpts = getNumOptions(); @@ -1750,6 +1967,7 @@ PRINT_OPT_DIFF(bool) PRINT_OPT_DIFF(boolOrDefault) PRINT_OPT_DIFF(int) PRINT_OPT_DIFF(unsigned) +PRINT_OPT_DIFF(unsigned long) PRINT_OPT_DIFF(unsigned long long) PRINT_OPT_DIFF(double) PRINT_OPT_DIFF(float) @@ -1919,7 +2137,7 @@ public: printSubCommands(Subs, MaxSubLen); outs() << "\n"; outs() << " Type \"" << GlobalParser->ProgramName - << " <subcommand> -help\" to get more help on a specific " + << " <subcommand> --help\" to get more help on a specific " "subcommand"; } @@ -1986,9 +2204,11 @@ protected: // options within categories will also be alphabetically sorted. for (size_t I = 0, E = Opts.size(); I != E; ++I) { Option *Opt = Opts[I].second; - assert(CategorizedOptions.count(Opt->Category) > 0 && - "Option has an unregistered category"); - CategorizedOptions[Opt->Category].push_back(Opt); + for (auto &Cat : Opt->Categories) { + assert(CategorizedOptions.count(Cat) > 0 && + "Option has an unregistered category"); + CategorizedOptions[Cat].push_back(Opt); + } } // Now do printing. @@ -1996,7 +2216,7 @@ protected: Category = SortedCategories.begin(), E = SortedCategories.end(); Category != E; ++Category) { - // Hide empty categories for -help, but show for -help-hidden. + // Hide empty categories for --help, but show for --help-hidden. const auto &CategoryOptions = CategorizedOptions[*Category]; bool IsEmptyCategory = CategoryOptions.empty(); if (!ShowHidden && IsEmptyCategory) @@ -2012,7 +2232,7 @@ protected: else outs() << "\n"; - // When using -help-hidden explicitly state if the category has no + // When using --help-hidden explicitly state if the category has no // options associated with it. if (IsEmptyCategory) { outs() << " This option category has no options.\n"; @@ -2062,11 +2282,11 @@ static HelpPrinterWrapper WrappedHiddenPrinter(UncategorizedHiddenPrinter, static cl::OptionCategory GenericCategory("Generic Options"); // Define uncategorized help printers. -// -help-list is hidden by default because if Option categories are being used -// then -help behaves the same as -help-list. +// --help-list is hidden by default because if Option categories are being used +// then --help behaves the same as --help-list. static cl::opt<HelpPrinter, true, parser<bool>> HLOp( "help-list", - cl::desc("Display list of available options (-help-list-hidden for more)"), + cl::desc("Display list of available options (--help-list-hidden for more)"), cl::location(UncategorizedNormalPrinter), cl::Hidden, cl::ValueDisallowed, cl::cat(GenericCategory), cl::sub(*AllSubCommands)); @@ -2080,10 +2300,13 @@ static cl::opt<HelpPrinter, true, parser<bool>> // behaviour at runtime depending on whether one or more Option categories have // been declared. static cl::opt<HelpPrinterWrapper, true, parser<bool>> - HOp("help", cl::desc("Display available options (-help-hidden for more)"), + HOp("help", cl::desc("Display available options (--help-hidden for more)"), cl::location(WrappedNormalPrinter), cl::ValueDisallowed, cl::cat(GenericCategory), cl::sub(*AllSubCommands)); +static cl::alias HOpA("h", cl::desc("Alias for --help"), cl::aliasopt(HOp), + cl::DefaultOption); + static cl::opt<HelpPrinterWrapper, true, parser<bool>> HHOp("help-hidden", cl::desc("Display all available options"), cl::location(WrappedHiddenPrinter), cl::Hidden, cl::ValueDisallowed, @@ -2108,7 +2331,7 @@ void HelpPrinterWrapper::operator=(bool Value) { // registered then it is useful to show the categorized help instead of // uncategorized help. if (GlobalParser->RegisteredOptionCategories.size() > 1) { - // unhide -help-list option so user can have uncategorized output if they + // unhide --help-list option so user can have uncategorized output if they // want it. HLOp.setHiddenFlag(NotHidden); @@ -2242,21 +2465,21 @@ cl::getRegisteredSubcommands() { void cl::HideUnrelatedOptions(cl::OptionCategory &Category, SubCommand &Sub) { for (auto &I : Sub.OptionsMap) { - if (I.second->Category != &Category && - I.second->Category != &GenericCategory) - I.second->setHiddenFlag(cl::ReallyHidden); + for (auto &Cat : I.second->Categories) { + if (Cat != &Category && + Cat != &GenericCategory) + I.second->setHiddenFlag(cl::ReallyHidden); + } } } void cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories, SubCommand &Sub) { - auto CategoriesBegin = Categories.begin(); - auto CategoriesEnd = Categories.end(); for (auto &I : Sub.OptionsMap) { - if (std::find(CategoriesBegin, CategoriesEnd, I.second->Category) == - CategoriesEnd && - I.second->Category != &GenericCategory) - I.second->setHiddenFlag(cl::ReallyHidden); + for (auto &Cat : I.second->Categories) { + if (find(Categories, Cat) == Categories.end() && Cat != &GenericCategory) + I.second->setHiddenFlag(cl::ReallyHidden); + } } } diff --git a/contrib/llvm/lib/Support/Compression.cpp b/contrib/llvm/lib/Support/Compression.cpp index 95261d4aad23..97d5ffaadf82 100644 --- a/contrib/llvm/lib/Support/Compression.cpp +++ b/contrib/llvm/lib/Support/Compression.cpp @@ -1,9 +1,8 @@ //===--- Compression.cpp - Compression implementation ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/ConvertUTF.cpp b/contrib/llvm/lib/Support/ConvertUTF.cpp index 8f02fae4f558..e24a918c5c89 100644 --- a/contrib/llvm/lib/Support/ConvertUTF.cpp +++ b/contrib/llvm/lib/Support/ConvertUTF.cpp @@ -1,9 +1,8 @@ /*===--- ConvertUTF.c - Universal Character Names conversions ---------------=== * - * The LLVM Compiler Infrastructure - * - * This file is distributed under the University of Illinois Open Source - * License. See LICENSE.TXT for details. + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * *===------------------------------------------------------------------------=*/ /* diff --git a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp index 6cb4f6376250..eb4ead6b46b4 100644 --- a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp +++ b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp @@ -1,9 +1,8 @@ //===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----=== // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp index be4b5c3e01c3..c2459256f8fe 100644 --- a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp @@ -1,9 +1,8 @@ //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp b/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp index bd9f98b0b82d..4675fe3a9401 100644 --- a/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp +++ b/contrib/llvm/lib/Support/DAGDeltaAlgorithm.cpp @@ -1,9 +1,8 @@ //===--- DAGDeltaAlgorithm.cpp - A DAG Minimization Algorithm --*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // The algorithm we use attempts to exploit the dependency information by diff --git a/contrib/llvm/lib/Support/DJB.cpp b/contrib/llvm/lib/Support/DJB.cpp index 905dcf1b7e81..f06af7dfde44 100644 --- a/contrib/llvm/lib/Support/DJB.cpp +++ b/contrib/llvm/lib/Support/DJB.cpp @@ -1,9 +1,8 @@ //===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -58,29 +57,26 @@ static UTF32 foldCharDwarf(UTF32 C) { return sys::unicode::foldCharSimple(C); } -static uint32_t caseFoldingDjbHashCharSlow(StringRef &Buffer, uint32_t H) { - UTF32 C = chopOneUTF32(Buffer); - - C = foldCharDwarf(C); - - std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage; - StringRef Folded = toUTF8(C, Storage); - return djbHash(Folded, H); +static Optional<uint32_t> fastCaseFoldingDjbHash(StringRef Buffer, uint32_t H) { + bool AllASCII = true; + for (unsigned char C : Buffer) { + H = H * 33 + ('A' <= C && C <= 'Z' ? C - 'A' + 'a' : C); + AllASCII &= C <= 0x7f; + } + if (AllASCII) + return H; + return None; } uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) { + if (Optional<uint32_t> Result = fastCaseFoldingDjbHash(Buffer, H)) + return *Result; + + std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage; while (!Buffer.empty()) { - unsigned char C = Buffer.front(); - if (LLVM_LIKELY(C <= 0x7f)) { - // US-ASCII, encoded as one character in utf-8. - // This is by far the most common case, so handle this specially. - if (C >= 'A' && C <= 'Z') - C = 'a' + (C - 'A'); // fold uppercase into lowercase - H = (H << 5) + H + C; - Buffer = Buffer.drop_front(); - continue; - } - H = caseFoldingDjbHashCharSlow(Buffer, H); + UTF32 C = foldCharDwarf(chopOneUTF32(Buffer)); + StringRef Folded = toUTF8(C, Storage); + H = djbHash(Folded, H); } return H; } diff --git a/contrib/llvm/lib/Support/DataExtractor.cpp b/contrib/llvm/lib/Support/DataExtractor.cpp index 0199b300ba72..673bbb4d06f4 100644 --- a/contrib/llvm/lib/Support/DataExtractor.cpp +++ b/contrib/llvm/lib/Support/DataExtractor.cpp @@ -1,9 +1,8 @@ //===-- DataExtractor.cpp -------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -11,6 +10,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/LEB128.h" using namespace llvm; template <typename T> @@ -146,47 +146,29 @@ StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const { } uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { - uint64_t result = 0; - if (Data.empty()) + assert(*offset_ptr <= Data.size()); + + const char *error; + unsigned bytes_read; + uint64_t result = decodeULEB128( + reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read, + reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error); + if (error) return 0; - - unsigned shift = 0; - uint32_t offset = *offset_ptr; - uint8_t byte = 0; - - while (isValidOffset(offset)) { - byte = Data[offset++]; - result |= uint64_t(byte & 0x7f) << shift; - shift += 7; - if ((byte & 0x80) == 0) - break; - } - - *offset_ptr = offset; + *offset_ptr += bytes_read; return result; } int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const { - int64_t result = 0; - if (Data.empty()) + assert(*offset_ptr <= Data.size()); + + const char *error; + unsigned bytes_read; + int64_t result = decodeSLEB128( + reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read, + reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error); + if (error) return 0; - - unsigned shift = 0; - uint32_t offset = *offset_ptr; - uint8_t byte = 0; - - while (isValidOffset(offset)) { - byte = Data[offset++]; - result |= uint64_t(byte & 0x7f) << shift; - shift += 7; - if ((byte & 0x80) == 0) - break; - } - - // Sign bit of byte is 2nd high order bit (0x40) - if (shift < 64 && (byte & 0x40)) - result |= -(1ULL << shift); - - *offset_ptr = offset; + *offset_ptr += bytes_read; return result; } diff --git a/contrib/llvm/lib/Support/Debug.cpp b/contrib/llvm/lib/Support/Debug.cpp index 1a70017fee32..737cd576ed80 100644 --- a/contrib/llvm/lib/Support/Debug.cpp +++ b/contrib/llvm/lib/Support/Debug.cpp @@ -1,9 +1,8 @@ //===-- Debug.cpp - An easy way to add debug output to your code ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/DeltaAlgorithm.cpp b/contrib/llvm/lib/Support/DeltaAlgorithm.cpp index 50ea4e9ce0c6..6aee69f43405 100644 --- a/contrib/llvm/lib/Support/DeltaAlgorithm.cpp +++ b/contrib/llvm/lib/Support/DeltaAlgorithm.cpp @@ -1,9 +1,8 @@ //===--- DeltaAlgorithm.cpp - A Set Minimization Algorithm -----*- C++ -*--===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// #include "llvm/ADT/DeltaAlgorithm.h" diff --git a/contrib/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm/lib/Support/DynamicLibrary.cpp index 530e92d99a90..d23716016fb2 100644 --- a/contrib/llvm/lib/Support/DynamicLibrary.cpp +++ b/contrib/llvm/lib/Support/DynamicLibrary.cpp @@ -1,9 +1,8 @@ //===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Errno.cpp b/contrib/llvm/lib/Support/Errno.cpp index 2149f21281d3..d18231c6ebf5 100644 --- a/contrib/llvm/lib/Support/Errno.cpp +++ b/contrib/llvm/lib/Support/Errno.cpp @@ -1,9 +1,8 @@ //===- Errno.cpp - errno support --------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -12,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Errno.h" -#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Config/config.h" #include "llvm/Support/raw_ostream.h" #include <string.h> diff --git a/contrib/llvm/lib/Support/Error.cpp b/contrib/llvm/lib/Support/Error.cpp index 30bfc3e6d2fb..72bc08af2ddb 100644 --- a/contrib/llvm/lib/Support/Error.cpp +++ b/contrib/llvm/lib/Support/Error.cpp @@ -1,9 +1,8 @@ //===----- lib/Support/Error.cpp - Error and associated utilities ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp index 21712c5c039e..0f13f7a536f1 100644 --- a/contrib/llvm/lib/Support/ErrorHandling.cpp +++ b/contrib/llvm/lib/Support/ErrorHandling.cpp @@ -1,9 +1,8 @@ //===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -187,25 +186,13 @@ static void out_of_memory_new_handler() { llvm::report_bad_alloc_error("Allocation failed"); } -// Installs new handler that causes crash on allocation failure. It does not -// need to be called explicitly, if this file is linked to application, because -// in this case it is called during construction of 'new_handler_installer'. +// Installs new handler that causes crash on allocation failure. It is called by +// InitLLVM. void llvm::install_out_of_memory_new_handler() { - static bool out_of_memory_new_handler_installed = false; - if (!out_of_memory_new_handler_installed) { - std::set_new_handler(out_of_memory_new_handler); - out_of_memory_new_handler_installed = true; - } + std::new_handler old = std::set_new_handler(out_of_memory_new_handler); + (void)old; + assert(old == nullptr && "new-handler already installed"); } - -// Static object that causes installation of 'out_of_memory_new_handler' before -// execution of 'main'. -static class NewHandlerInstaller { -public: - NewHandlerInstaller() { - install_out_of_memory_new_handler(); - } -} new_handler_installer; #endif void llvm::llvm_unreachable_internal(const char *msg, const char *file, diff --git a/contrib/llvm/lib/Support/FileCheck.cpp b/contrib/llvm/lib/Support/FileCheck.cpp index 37986c96c081..e0f17787bdf8 100644 --- a/contrib/llvm/lib/Support/FileCheck.cpp +++ b/contrib/llvm/lib/Support/FileCheck.cpp @@ -1,9 +1,8 @@ //===- FileCheck.cpp - Check that File's Contents match what is expected --===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -25,18 +24,303 @@ using namespace llvm; -/// Parses the given string into the Pattern. -/// -/// \p Prefix provides which prefix is being matched, \p SM provides the -/// SourceMgr used for error reports, and \p LineNumber is the line number in -/// the input file from which the pattern string was read. Returns true in -/// case of an error, false otherwise. -bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix, - SourceMgr &SM, unsigned LineNumber, - const FileCheckRequest &Req) { +void FileCheckNumericVariable::setValue(uint64_t NewValue) { + assert(!Value && "Overwriting numeric variable's value is not allowed"); + Value = NewValue; +} + +void FileCheckNumericVariable::clearValue() { + if (!Value) + return; + Value = None; +} + +Expected<uint64_t> FileCheckNumericVariableUse::eval() const { + Optional<uint64_t> Value = NumericVariable->getValue(); + if (Value) + return *Value; + return make_error<FileCheckUndefVarError>(Name); +} + +Expected<uint64_t> FileCheckASTBinop::eval() const { + Expected<uint64_t> LeftOp = LeftOperand->eval(); + Expected<uint64_t> 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<std::string> FileCheckNumericSubstitution::getResult() const { + Expected<uint64_t> EvaluatedValue = ExpressionAST->eval(); + if (!EvaluatedValue) + return EvaluatedValue.takeError(); + return utostr(*EvaluatedValue); +} + +Expected<std::string> FileCheckStringSubstitution::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 FileCheckPattern::isValidVarNameStart(char C) { + return C == '_' || isalpha(C); +} + +Expected<FileCheckPattern::VariableProperties> +FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) { + if (Str.empty()) + return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name"); + + bool ParsedOneChar = false; + unsigned I = 0; + bool IsPseudo = Str[0] == '@'; + + // Global vars start with '$'. + if (Str[0] == '$' || IsPseudo) + ++I; + + for (unsigned E = Str.size(); I != E; ++I) { + if (!ParsedOneChar && !isValidVarNameStart(Str[I])) + return FileCheckErrorDiagnostic::get(SM, Str, "invalid variable name"); + + // Variable names are composed of alphanumeric characters and underscores. + if (Str[I] != '_' && !isalnum(Str[I])) + break; + ParsedOneChar = true; + } + + 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. +StringRef 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 FileCheckUndefVarError::ID = 0; +char FileCheckErrorDiagnostic::ID = 0; +char FileCheckNotFoundError::ID = 0; + +Expected<FileCheckNumericVariable *> +FileCheckPattern::parseNumericVariableDefinition( + StringRef &Expr, FileCheckPatternContext *Context, + Optional<size_t> LineNumber, const SourceMgr &SM) { + Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM); + if (!ParseVarResult) + return ParseVarResult.takeError(); + StringRef Name = ParseVarResult->Name; + + if (ParseVarResult->IsPseudo) + return FileCheckErrorDiagnostic::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 FileCheckErrorDiagnostic::get( + SM, Name, "string variable with name '" + Name + "' already exists"); + + Expr = Expr.ltrim(SpaceChars); + if (!Expr.empty()) + return FileCheckErrorDiagnostic::get( + SM, Expr, "unexpected characters after numeric variable name"); + + FileCheckNumericVariable *DefinedNumericVariable; + auto VarTableIter = Context->GlobalNumericVariableTable.find(Name); + if (VarTableIter != Context->GlobalNumericVariableTable.end()) + DefinedNumericVariable = VarTableIter->second; + else + DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber); + + return DefinedNumericVariable; +} + +Expected<std::unique_ptr<FileCheckNumericVariableUse>> +FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo, + const SourceMgr &SM) const { + if (IsPseudo && !Name.equals("@LINE")) + return FileCheckErrorDiagnostic::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); + FileCheckNumericVariable *NumericVariable; + if (VarTableIter != Context->GlobalNumericVariableTable.end()) + NumericVariable = VarTableIter->second; + else { + NumericVariable = Context->makeNumericVariable(Name); + Context->GlobalNumericVariableTable[Name] = NumericVariable; + } + + Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber(); + if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber) + return FileCheckErrorDiagnostic::get( + SM, Name, + "numeric variable '" + Name + "' defined on the same line as used"); + + return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable); +} + +Expected<std::unique_ptr<FileCheckExpressionAST>> +FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO, + const SourceMgr &SM) const { + if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) { + // Try to parse as a numeric variable use. + Expected<FileCheckPattern::VariableProperties> ParseVarResult = + parseVariable(Expr, SM); + if (ParseVarResult) + return parseNumericVariableUse(ParseVarResult->Name, + ParseVarResult->IsPseudo, 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. + uint64_t LiteralValue; + if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue)) + return llvm::make_unique<FileCheckExpressionLiteral>(LiteralValue); + + return FileCheckErrorDiagnostic::get(SM, Expr, + "invalid operand format '" + Expr + "'"); +} + +static uint64_t add(uint64_t LeftOp, uint64_t RightOp) { + return LeftOp + RightOp; +} + +static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) { + return LeftOp - RightOp; +} + +Expected<std::unique_ptr<FileCheckExpressionAST>> +FileCheckPattern::parseBinop(StringRef &Expr, + std::unique_ptr<FileCheckExpressionAST> LeftOp, + bool IsLegacyLineExpr, const SourceMgr &SM) const { + Expr = Expr.ltrim(SpaceChars); + if (Expr.empty()) + return std::move(LeftOp); + + // Check if this is a supported operation and select a function to perform + // it. + SMLoc OpLoc = SMLoc::getFromPointer(Expr.data()); + char Operator = popFront(Expr); + binop_eval_t EvalBinop; + switch (Operator) { + case '+': + EvalBinop = add; + break; + case '-': + EvalBinop = sub; + break; + default: + return FileCheckErrorDiagnostic::get( + SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'"); + } + + // Parse right operand. + Expr = Expr.ltrim(SpaceChars); + if (Expr.empty()) + return FileCheckErrorDiagnostic::get(SM, Expr, + "missing operand in expression"); + // The second operand in a legacy @LINE expression is always a literal. + AllowedOperand AO = + IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any; + Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult = + parseNumericOperand(Expr, AO, SM); + if (!RightOpResult) + return RightOpResult; + + Expr = Expr.ltrim(SpaceChars); + return llvm::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp), + std::move(*RightOpResult)); +} + +Expected<std::unique_ptr<FileCheckExpressionAST>> +FileCheckPattern::parseNumericSubstitutionBlock( + StringRef Expr, + Optional<FileCheckNumericVariable *> &DefinedNumericVariable, + bool IsLegacyLineExpr, const SourceMgr &SM) const { + // Parse the numeric variable definition. + DefinedNumericVariable = None; + size_t DefEnd = Expr.find(':'); + if (DefEnd != StringRef::npos) { + StringRef DefExpr = Expr.substr(0, DefEnd); + StringRef UseExpr = Expr.substr(DefEnd + 1); + + UseExpr = UseExpr.ltrim(SpaceChars); + if (!UseExpr.empty()) + return FileCheckErrorDiagnostic::get( + SM, UseExpr, + "unexpected string after variable definition: '" + UseExpr + "'"); + + DefExpr = DefExpr.ltrim(SpaceChars); + Expected<FileCheckNumericVariable *> ParseResult = + parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM); + if (!ParseResult) + return ParseResult.takeError(); + DefinedNumericVariable = *ParseResult; + + return nullptr; + } + + // Parse the expression itself. + Expr = Expr.ltrim(SpaceChars); + // 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<FileCheckExpressionAST>> ParseResult = + parseNumericOperand(Expr, AO, SM); + while (ParseResult && !Expr.empty()) { + ParseResult = + parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM); + // Legacy @LINE expressions only allow 2 operands. + if (ParseResult && IsLegacyLineExpr && !Expr.empty()) + return FileCheckErrorDiagnostic::get( + SM, Expr, + "unexpected characters at end of expression '" + Expr + "'"); + } + if (!ParseResult) + return ParseResult; + return std::move(*ParseResult); +} + +bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix, + SourceMgr &SM, + const FileCheckRequest &Req) { bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot; - this->LineNumber = LineNumber; PatternLoc = SMLoc::getFromPointer(PatternStr.data()); if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines)) @@ -112,95 +396,164 @@ bool FileCheckPattern::ParsePattern(StringRef PatternStr, StringRef Prefix, continue; } - // Named RegEx matches. These are of two forms: [[foo:.*]] which matches .* - // (or some other regex) and assigns it to the FileCheck variable 'foo'. The - // second form is [[foo]] which is a reference to foo. The variable name - // itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject - // it. This is to catch some common errors. + // String and numeric substitution blocks. String 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 work the same way + // as string ones, but start with a '#' sign after the double brackets. + // 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(PatternStr.substr(2), SM); + 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 named regex reference, no ]] found"); + "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; + // 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; + } - StringRef MatchStr = PatternStr.substr(2, End); - PatternStr = PatternStr.substr(End + 4); - - // Get the regex name (e.g. "foo"). - size_t NameEnd = MatchStr.find(':'); - StringRef Name = MatchStr.substr(0, NameEnd); + // Get the name (e.g. "foo") and verify it is well formed. + StringRef OrigMatchStr = MatchStr; + Expected<FileCheckPattern::VariableProperties> ParseVarResult = + parseVariable(MatchStr, SM); + if (!ParseVarResult) { + logAllUnhandledErrors(ParseVarResult.takeError(), errs()); + return true; + } + StringRef Name = ParseVarResult->Name; + bool IsPseudo = ParseVarResult->IsPseudo; - if (Name.empty()) { - SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, - "invalid name in named regex: empty name"); - return true; - } + IsDefinition = (VarEndIdx != StringRef::npos); + if (IsDefinition) { + if ((IsPseudo || !MatchStr.consume_front(":"))) { + SM.PrintMessage(SMLoc::getFromPointer(Name.data()), + SourceMgr::DK_Error, + "invalid name in string variable definition"); + return true; + } - // Verify that the name/expression is well formed. FileCheck currently - // supports @LINE, @LINE+number, @LINE-number expressions. The check here - // is relaxed, more strict check is performed in \c EvaluateExpression. - bool IsExpression = false; - for (unsigned i = 0, e = Name.size(); i != e; ++i) { - if (i == 0) { - if (Name[i] == '$') // Global vars start with '$' - continue; - if (Name[i] == '@') { - if (NameEnd != StringRef::npos) { - SM.PrintMessage(SMLoc::getFromPointer(Name.data()), - SourceMgr::DK_Error, - "invalid name in named regex definition"); - return true; - } - IsExpression = true; - continue; + // 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; } - } - if (Name[i] != '_' && !isalnum(Name[i]) && - (!IsExpression || (Name[i] != '+' && Name[i] != '-'))) { - SM.PrintMessage(SMLoc::getFromPointer(Name.data() + i), - SourceMgr::DK_Error, "invalid name in named regex"); - return true; + DefName = Name; + MatchRegexp = MatchStr; + } else { + if (IsPseudo) { + MatchStr = OrigMatchStr; + IsLegacyLineExpr = IsNumBlock = true; + } else + SubstStr = Name; } } - // Name can't start with a digit. - if (isdigit(static_cast<unsigned char>(Name[0]))) { - SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, - "invalid name in named regex"); - return true; + // Parse numeric substitution block. + std::unique_ptr<FileCheckExpressionAST> ExpressionAST; + Optional<FileCheckNumericVariable *> DefinedNumericVariable; + if (IsNumBlock) { + Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult = + parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, + IsLegacyLineExpr, SM); + if (!ParseResult) { + logAllUnhandledErrors(ParseResult.takeError(), errs()); + return true; + } + ExpressionAST = std::move(*ParseResult); + if (DefinedNumericVariable) { + IsDefinition = true; + DefName = (*DefinedNumericVariable)->getName(); + MatchRegexp = StringRef("[0-9]+"); + } else + SubstStr = MatchStr; } - // Handle [[foo]]. - if (NameEnd == StringRef::npos) { - // Handle variables that were defined earlier on the same line by - // emitting a backreference. - if (VariableDefs.find(Name) != VariableDefs.end()) { - unsigned VarParenNum = VariableDefs[Name]; - if (VarParenNum < 1 || VarParenNum > 9) { - SM.PrintMessage(SMLoc::getFromPointer(Name.data()), + // Handle substitutions: [[foo]] and [[#<foo expr>]]. + if (!IsDefinition) { + // 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(VarParenNum); + AddBackrefToRegEx(CaptureParenGroup); } else { - VariableUses.push_back(std::make_pair(Name, RegExStr.size())); + // Handle substitution of string variables ([[<var>]]) defined in + // previous CHECK patterns, and substitution of expressions. + FileCheckSubstitution *Substitution = + IsNumBlock + ? Context->makeNumericSubstitution( + SubstStr, std::move(ExpressionAST), SubstInsertIdx) + : Context->makeStringSubstitution(SubstStr, SubstInsertIdx); + Substitutions.push_back(Substitution); } continue; } - // Handle [[foo:.*]]. - VariableDefs[Name] = CurParen; + // Handle variable definitions: [[<def>:(...)]] and + // [[#(...)<def>:(...)]]. + if (IsNumBlock) { + FileCheckNumericVariableMatch 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 the 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; + } RegExStr += '('; ++CurParen; - if (AddRegExToRegEx(MatchStr.substr(NameEnd + 1), CurParen, SM)) + if (AddRegExToRegEx(MatchRegexp, CurParen, SM)) return true; RegExStr += ')'; @@ -243,37 +596,8 @@ void FileCheckPattern::AddBackrefToRegEx(unsigned BackrefNum) { RegExStr += Backref; } -/// Evaluates expression and stores the result to \p Value. -/// -/// Returns true on success and false when the expression has invalid syntax. -bool FileCheckPattern::EvaluateExpression(StringRef Expr, std::string &Value) const { - // The only supported expression is @LINE([\+-]\d+)? - if (!Expr.startswith("@LINE")) - return false; - Expr = Expr.substr(StringRef("@LINE").size()); - int Offset = 0; - if (!Expr.empty()) { - if (Expr[0] == '+') - Expr = Expr.substr(1); - else if (Expr[0] != '-') - return false; - if (Expr.getAsInteger(10, Offset)) - return false; - } - Value = llvm::itostr(LineNumber + Offset); - return true; -} - -/// Matches the pattern string against the input buffer \p Buffer -/// -/// This returns the position that is matched or npos if there is no match. If -/// there is a match, the size of the matched string is returned in \p -/// MatchLen. -/// -/// The \p VariableTable StringMap provides the current values of filecheck -/// variables and is updated if this match defines new values. -size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen, - StringMap<StringRef> &VariableTable) const { +Expected<size_t> FileCheckPattern::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; @@ -283,58 +607,76 @@ size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen, // If this is a fixed string pattern, just match it now. if (!FixedStr.empty()) { MatchLen = FixedStr.size(); - return Buffer.find(FixedStr); + size_t Pos = Buffer.find(FixedStr); + if (Pos == StringRef::npos) + return make_error<FileCheckNotFoundError>(); + return Pos; } // Regex match. - // If there are variable uses, we need to create a temporary string with the + // If there are substitutions, we need to create a temporary string with the // actual value. StringRef RegExToMatch = RegExStr; std::string TmpStr; - if (!VariableUses.empty()) { + if (!Substitutions.empty()) { TmpStr = RegExStr; - - unsigned InsertOffset = 0; - for (const auto &VariableUse : VariableUses) { - std::string Value; - - if (VariableUse.first[0] == '@') { - if (!EvaluateExpression(VariableUse.first, Value)) - return StringRef::npos; - } else { - StringMap<StringRef>::iterator it = - VariableTable.find(VariableUse.first); - // If the variable is undefined, return an error. - if (it == VariableTable.end()) - return StringRef::npos; - - // Look up the value and escape it so that we can put it into the regex. - Value += Regex::escape(it->second); + if (LineNumber) + Context->LineVariable->setValue(*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) { + Context->LineVariable->clearValue(); + return Value.takeError(); } // Plop it into the regex at the adjusted offset. - TmpStr.insert(TmpStr.begin() + VariableUse.second + InsertOffset, - Value.begin(), Value.end()); - InsertOffset += Value.size(); + TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset, + Value->begin(), Value->end()); + InsertOffset += Value->size(); } // Match the newly constructed regex. RegExToMatch = TmpStr; + Context->LineVariable->clearValue(); } SmallVector<StringRef, 4> MatchInfo; if (!Regex(RegExToMatch, Regex::Newline).match(Buffer, &MatchInfo)) - return StringRef::npos; + return make_error<FileCheckNotFoundError>(); // Successful regex match. assert(!MatchInfo.empty() && "Didn't get any match"); StringRef FullMatch = MatchInfo[0]; - // If this defines any variables, remember their values. + // If this defines any string variables, remember their values. for (const auto &VariableDef : VariableDefs) { assert(VariableDef.second < MatchInfo.size() && "Internal paren error"); - VariableTable[VariableDef.first] = MatchInfo[VariableDef.second]; + Context->GlobalVariableTable[VariableDef.first] = + MatchInfo[VariableDef.second]; + } + + // If this defines any numeric variables, remember their values. + for (const auto &NumericVariableDef : NumericVariableDefs) { + const FileCheckNumericVariableMatch &NumericVariableMatch = + NumericVariableDef.getValue(); + unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup; + assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error"); + FileCheckNumericVariable *DefinedNumericVariable = + NumericVariableMatch.DefinedNumericVariable; + + StringRef MatchedValue = MatchInfo[CaptureParenGroup]; + uint64_t Val; + if (MatchedValue.getAsInteger(10, Val)) + return FileCheckErrorDiagnostic::get(SM, MatchedValue, + "Unable to represent numeric value"); + DefinedNumericVariable->setValue(Val); } // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after @@ -345,13 +687,7 @@ size_t FileCheckPattern::Match(StringRef Buffer, size_t &MatchLen, return FullMatch.data() - Buffer.data() + MatchStartSkip; } - -/// 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 -FileCheckPattern::ComputeMatchDistance(StringRef Buffer, - const StringMap<StringRef> &VariableTable) const { +unsigned FileCheckPattern::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. // @@ -368,38 +704,36 @@ FileCheckPattern::ComputeMatchDistance(StringRef Buffer, return BufferPrefix.edit_distance(ExampleString); } -void FileCheckPattern::PrintVariableUses(const SourceMgr &SM, StringRef Buffer, - const StringMap<StringRef> &VariableTable, - SMRange MatchRange) const { - // If this was a regular expression using variables, print the current - // variable values. - if (!VariableUses.empty()) { - for (const auto &VariableUse : VariableUses) { +void FileCheckPattern::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); - StringRef Var = VariableUse.first; - if (Var[0] == '@') { - std::string Value; - if (EvaluateExpression(Var, Value)) { - OS << "with expression \""; - OS.write_escaped(Var) << "\" equal to \""; - OS.write_escaped(Value) << "\""; - } else { - OS << "uses incorrect expression \""; - OS.write_escaped(Var) << "\""; - } + 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 FileCheckNotFoundError &E) {}, + // Handled in PrintNoMatch(). + [](const FileCheckErrorDiagnostic &E) {}, + [&](const FileCheckUndefVarError &E) { + if (!UndefSeen) { + OS << "uses undefined variable(s):"; + UndefSeen = true; + } + OS << " "; + E.log(OS); + }); } else { - StringMap<StringRef>::const_iterator it = VariableTable.find(Var); - - // Check for undefined variable references. - if (it == VariableTable.end()) { - OS << "uses undefined variable \""; - OS.write_escaped(Var) << "\""; - } else { - OS << "with variable \""; - OS.write_escaped(Var) << "\" equal to \""; - OS.write_escaped(it->second) << "\""; - } + // Substitution succeeded. Print substituted value. + OS << "with \""; + OS.write_escaped(Substitution->getFromString()) << "\" equal to \""; + OS.write_escaped(*MatchedValue) << "\""; } if (MatchRange.isValid()) @@ -430,9 +764,8 @@ static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, return Range; } -void FileCheckPattern::PrintFuzzyMatch( +void FileCheckPattern::printFuzzyMatch( const SourceMgr &SM, StringRef Buffer, - const StringMap<StringRef> &VariableTable, 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 @@ -454,7 +787,7 @@ void FileCheckPattern::PrintFuzzyMatch( // 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), VariableTable); + unsigned Distance = computeMatchDistance(Buffer.substr(i)); double Quality = Distance + (NumLinesForward / 100.); if (Quality < BestQuality || Best == StringRef::npos) { @@ -478,11 +811,39 @@ void FileCheckPattern::PrintFuzzyMatch( } } -/// 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). Returns the offset of the closing sequence within Str, -/// or npos if it was not found. +Expected<StringRef> +FileCheckPatternContext::getPatternVarValue(StringRef VarName) { + auto VarIter = GlobalVariableTable.find(VarName); + if (VarIter == GlobalVariableTable.end()) + return make_error<FileCheckUndefVarError>(VarName); + + return VarIter->second; +} + +template <class... Types> +FileCheckNumericVariable * +FileCheckPatternContext::makeNumericVariable(Types... args) { + NumericVariables.push_back( + llvm::make_unique<FileCheckNumericVariable>(args...)); + return NumericVariables.back().get(); +} + +FileCheckSubstitution * +FileCheckPatternContext::makeStringSubstitution(StringRef VarName, + size_t InsertIdx) { + Substitutions.push_back( + llvm::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx)); + return Substitutions.back().get(); +} + +FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution( + StringRef ExpressionStr, + std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) { + Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>( + this, ExpressionStr, std::move(ExpressionAST), InsertIdx)); + return Substitutions.back().get(); +} + size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { // Offset keeps track of the current offset within the input Str size_t Offset = 0; @@ -521,11 +882,8 @@ size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) { return StringRef::npos; } -/// Canonicalize whitespaces in the file. Line endings are replaced with -/// UNIX-style '\n'. -StringRef -llvm::FileCheck::CanonicalizeFile(MemoryBuffer &MB, - SmallVectorImpl<char> &OutputBuffer) { +StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB, + SmallVectorImpl<char> &OutputBuffer) { OutputBuffer.reserve(MB.getBufferSize()); for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd(); @@ -581,7 +939,6 @@ Check::FileCheckType &Check::FileCheckType::setCount(int C) { return *this; } -// Get a description of the type. std::string Check::FileCheckType::getDescription(StringRef Prefix) const { switch (Kind) { case Check::CheckNone: @@ -674,7 +1031,7 @@ static size_t SkipWord(StringRef Str, size_t Loc) { return Loc; } -/// Search the buffer for the first prefix in the prefix regular expression. +/// 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: @@ -683,7 +1040,7 @@ static size_t SkipWord(StringRef Str, size_t Loc) { /// 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: +/// \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. @@ -744,13 +1101,24 @@ FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer, return {StringRef(), StringRef()}; } -/// Read the check file, which specifies the sequence of expected strings. -/// -/// The strings are added to the CheckStrings vector. Returns true in case of -/// an error, false otherwise. -bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, - Regex &PrefixRE, - std::vector<FileCheckString> &CheckStrings) { +void FileCheckPatternContext::createLineVariable() { + assert(!LineVariable && "@LINE pseudo numeric variable already created"); + StringRef LineName = "@LINE"; + LineVariable = makeNumericVariable(LineName); + GlobalNumericVariableTable[LineName] = LineVariable; +} + +bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE, + std::vector<FileCheckString> &CheckStrings) { + Error DefineError = + PatternContext.defineCmdlineVariables(Req.GlobalDefines, SM); + if (DefineError) { + logAllUnhandledErrors(std::move(DefineError), errs()); + return true; + } + + PatternContext.createLineVariable(); + std::vector<FileCheckPattern> ImplicitNegativeChecks; for (const auto &PatternString : Req.ImplicitCheckNot) { // Create a buffer with fake command line content in order to display the @@ -764,9 +1132,10 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, CmdLine->getBuffer().substr(Prefix.size(), PatternString.size()); SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); - ImplicitNegativeChecks.push_back(FileCheckPattern(Check::CheckNot)); - ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer, - "IMPLICIT-CHECK", SM, 0, Req); + ImplicitNegativeChecks.push_back( + FileCheckPattern(Check::CheckNot, &PatternContext)); + ImplicitNegativeChecks.back().parsePattern(PatternInBuffer, + "IMPLICIT-CHECK", SM, Req); } std::vector<FileCheckPattern> DagNotMatches = ImplicitNegativeChecks; @@ -827,8 +1196,8 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. - FileCheckPattern P(CheckTy); - if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber, Req)) + FileCheckPattern P(CheckTy, &PatternContext, LineNumber); + if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req)) return true; // Verify that CHECK-LABEL lines do not define or use variables @@ -871,8 +1240,9 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first // prefix as a filler for the error message. if (!DagNotMatches.empty()) { - CheckStrings.emplace_back(FileCheckPattern(Check::CheckEOF), *Req.CheckPrefixes.begin(), - SMLoc::getFromPointer(Buffer.data())); + CheckStrings.emplace_back( + FileCheckPattern(Check::CheckEOF, &PatternContext, LineNumber + 1), + *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data())); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } @@ -897,20 +1267,27 @@ bool llvm::FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat, - int MatchedCount, StringRef Buffer, - StringMap<StringRef> &VariableTable, size_t MatchPos, + 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")) @@ -922,65 +1299,87 @@ static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message); SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here", {MatchRange}); - Pat.PrintVariableUses(SM, Buffer, VariableTable, MatchRange); + Pat.printSubstitutions(SM, Buffer, MatchRange); } static void PrintMatch(bool ExpectedMatch, const SourceMgr &SM, const FileCheckString &CheckStr, int MatchedCount, - StringRef Buffer, StringMap<StringRef> &VariableTable, - size_t MatchPos, size_t MatchLen, FileCheckRequest &Req, + 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, VariableTable, MatchPos, MatchLen, Req, - Diags); + MatchedCount, Buffer, MatchPos, MatchLen, Req, Diags); } static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const FileCheckPattern &Pat, int MatchedCount, - StringRef Buffer, StringMap<StringRef> &VariableTable, - bool VerboseVerbose, - std::vector<FileCheckDiag> *Diags) { - if (!ExpectedMatch && !VerboseVerbose) + 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 FileCheckErrorDiagnostic &E) { E.log(errs()); }); + + // No problem matching the string per se. + if (!MatchErrors) + return; + consumeError(std::move(MatchErrors)); - // Otherwise, we have an error, emit an error message. + // 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. 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); + // 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.PrintVariableUses(SM, Buffer, VariableTable); + Pat.printSubstitutions(SM, Buffer); if (ExpectedMatch) - Pat.PrintFuzzyMatch(SM, Buffer, VariableTable, Diags); + Pat.printFuzzyMatch(SM, Buffer, Diags); } static void PrintNoMatch(bool ExpectedMatch, const SourceMgr &SM, const FileCheckString &CheckStr, int MatchedCount, - StringRef Buffer, StringMap<StringRef> &VariableTable, - bool VerboseVerbose, - std::vector<FileCheckDiag> *Diags) { + StringRef Buffer, bool VerboseVerbose, + std::vector<FileCheckDiag> *Diags, Error MatchErrors) { PrintNoMatch(ExpectedMatch, SM, CheckStr.Prefix, CheckStr.Loc, CheckStr.Pat, - MatchedCount, Buffer, VariableTable, VerboseVerbose, Diags); + MatchedCount, Buffer, VerboseVerbose, Diags, + std::move(MatchErrors)); } -/// Count the number of newlines in the specified range. +/// Counts the number of newlines in the specified range. static unsigned CountNumNewlinesBetween(StringRef Range, const char *&FirstNewLine) { unsigned NumNewLines = 0; @@ -1003,10 +1402,8 @@ static unsigned CountNumNewlinesBetween(StringRef Range, } } -/// Match check string and its "not strings" and/or "dag strings". size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, size_t &MatchLen, - StringMap<StringRef> &VariableTable, FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const { size_t LastPos = 0; @@ -1018,7 +1415,7 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, // 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, VariableTable, Req, Diags); + LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags); if (LastPos == StringRef::npos) return StringRef::npos; } @@ -1033,18 +1430,19 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, StringRef MatchBuffer = Buffer.substr(LastMatchEnd); size_t CurrentMatchLen; // get a match at current start point - size_t MatchPos = Pat.Match(MatchBuffer, CurrentMatchLen, VariableTable); - if (i == 1) - FirstMatchPos = LastPos + MatchPos; + Expected<size_t> MatchResult = Pat.match(MatchBuffer, CurrentMatchLen, SM); // report - if (MatchPos == StringRef::npos) { - PrintNoMatch(true, SM, *this, i, MatchBuffer, VariableTable, - Req.VerboseVerbose, Diags); + if (!MatchResult) { + PrintNoMatch(true, SM, *this, i, MatchBuffer, Req.VerboseVerbose, Diags, + MatchResult.takeError()); return StringRef::npos; } - PrintMatch(true, SM, *this, i, MatchBuffer, VariableTable, MatchPos, - CurrentMatchLen, Req, Diags); + 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; @@ -1079,14 +1477,13 @@ size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer, // If this match had "not strings", verify that they don't exist in the // skipped region. - if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags)) + if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) return StringRef::npos; } return FirstMatchPos; } -/// Verify there is a single line in the given buffer. bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { if (Pat.getCheckTy() != Check::CheckNext && Pat.getCheckTy() != Check::CheckEmpty) @@ -1097,12 +1494,6 @@ bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT"); // Count the number of newlines between the previous match and this one. - assert(Buffer.data() != - SM.getMemoryBuffer(SM.FindBufferContainingLoc( - SMLoc::getFromPointer(Buffer.data()))) - ->getBufferStart() && - "CHECK-NEXT and CHECK-EMPTY can't be the first check in a file"); - const char *FirstNewLine = nullptr; unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); @@ -1132,18 +1523,11 @@ bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const { return false; } -/// Verify there is no newline in the given buffer. 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. - assert(Buffer.data() != - SM.getMemoryBuffer(SM.FindBufferContainingLoc( - SMLoc::getFromPointer(Buffer.data()))) - ->getBufferStart() && - "CHECK-SAME can't be the first check in a file"); - const char *FirstNewLine = nullptr; unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine); @@ -1161,26 +1545,25 @@ bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const { return false; } -/// Verify there's no "not strings" in the given buffer. bool FileCheckString::CheckNot( const SourceMgr &SM, StringRef Buffer, const std::vector<const FileCheckPattern *> &NotStrings, - StringMap<StringRef> &VariableTable, const FileCheckRequest &Req, - std::vector<FileCheckDiag> *Diags) const { + const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const { for (const FileCheckPattern *Pat : NotStrings) { assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!"); size_t MatchLen = 0; - size_t Pos = Pat->Match(Buffer, MatchLen, VariableTable); + Expected<size_t> MatchResult = Pat->match(Buffer, MatchLen, SM); - if (Pos == StringRef::npos) { + if (!MatchResult) { PrintNoMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, - VariableTable, Req.VerboseVerbose, Diags); + Req.VerboseVerbose, Diags, MatchResult.takeError()); continue; } + size_t Pos = *MatchResult; - PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, VariableTable, - Pos, MatchLen, Req, Diags); + PrintMatch(false, SM, Prefix, Pat->getLoc(), *Pat, 1, Buffer, Pos, MatchLen, + Req, Diags); return true; } @@ -1188,11 +1571,9 @@ bool FileCheckString::CheckNot( return false; } -/// Match "dag strings" and their mixed "not strings". size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, std::vector<const FileCheckPattern *> &NotStrings, - StringMap<StringRef> &VariableTable, const FileCheckRequest &Req, std::vector<FileCheckDiag> *Diags) const { if (DagNotStrings.empty()) @@ -1233,19 +1614,20 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // CHECK-DAG group. for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) { StringRef MatchBuffer = Buffer.substr(MatchPos); - size_t MatchPosBuf = Pat.Match(MatchBuffer, MatchLen, VariableTable); + 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 (MatchPosBuf == StringRef::npos) { + if (!MatchResult) { PrintNoMatch(true, SM, Prefix, Pat.getLoc(), Pat, 1, MatchBuffer, - VariableTable, Req.VerboseVerbose, Diags); + 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, - VariableTable, MatchPos, MatchLen, Req, Diags); + 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 @@ -1276,20 +1658,24 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, break; } if (Req.VerboseVerbose) { - 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}); - if (Diags) + // 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, VariableTable, - MatchPos, MatchLen, Req, Diags); + 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 || @@ -1300,7 +1686,7 @@ FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer, // region. StringRef SkippedRegion = Buffer.slice(StartPos, MatchRanges.begin()->Pos); - if (CheckNot(SM, SkippedRegion, NotStrings, VariableTable, Req, Diags)) + if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags)) return StringRef::npos; // Clear "not strings". NotStrings.clear(); @@ -1322,7 +1708,7 @@ static bool ValidateCheckPrefix(StringRef CheckPrefix) { return Validator.match(CheckPrefix); } -bool llvm::FileCheck::ValidateCheckPrefixes() { +bool FileCheck::ValidateCheckPrefixes() { StringSet<> PrefixSet; for (StringRef Prefix : Req.CheckPrefixes) { @@ -1340,12 +1726,7 @@ bool llvm::FileCheck::ValidateCheckPrefixes() { return true; } -// Combines the check prefixes into a single regex so that we can efficiently -// scan for any of the set. -// -// The semantics are that the longest-match wins which matches our regex -// library. -Regex llvm::FileCheck::buildCheckPrefixRegex() { +Regex FileCheck::buildCheckPrefixRegex() { // I don't think there's a way to specify an initial value for cl::list, // so if nothing was specified, add the default if (Req.CheckPrefixes.empty()) @@ -1364,32 +1745,152 @@ Regex llvm::FileCheck::buildCheckPrefixRegex() { return Regex(PrefixRegexStr); } -// Remove local variables from \p VariableTable. Global variables -// (start with '$') are preserved. -static void ClearLocalVars(StringMap<StringRef> &VariableTable) { - SmallVector<StringRef, 16> LocalVars; - for (const auto &Var : VariableTable) - if (Var.first()[0] != '$') - LocalVars.push_back(Var.first()); +Error FileCheckPatternContext::defineCmdlineVariables( + std::vector<std::string> &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; + StringRef Prefix1 = "Global define #"; + StringRef Prefix2 = ": "; + for (StringRef CmdlineDef : CmdlineDefines) + CmdlineDefsDiag += + (Prefix1 + Twine(++I) + Prefix2 + 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()); + + SmallVector<StringRef, 4> CmdlineDefsDiagVec; + CmdlineDefsDiagRef.split(CmdlineDefsDiagVec, '\n', -1 /*MaxSplit*/, + false /*KeepEmpty*/); + for (StringRef CmdlineDefDiag : CmdlineDefsDiagVec) { + unsigned DefStart = CmdlineDefDiag.find(Prefix2) + Prefix2.size(); + StringRef CmdlineDef = CmdlineDefDiag.substr(DefStart); + size_t EqIdx = CmdlineDef.find('='); + if (EqIdx == StringRef::npos) { + Errs = joinErrors( + std::move(Errs), + FileCheckErrorDiagnostic::get( + SM, CmdlineDef, "missing equal sign in global definition")); + continue; + } - for (const auto &Var : LocalVars) - VariableTable.erase(Var); + // Numeric variable definition. + if (CmdlineDef[0] == '#') { + StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1); + Expected<FileCheckNumericVariable *> ParseResult = + FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this, + None, SM); + if (!ParseResult) { + Errs = joinErrors(std::move(Errs), ParseResult.takeError()); + continue; + } + + StringRef CmdlineVal = CmdlineDef.substr(EqIdx + 1); + uint64_t Val; + if (CmdlineVal.getAsInteger(10, Val)) { + Errs = joinErrors(std::move(Errs), + FileCheckErrorDiagnostic::get( + SM, CmdlineVal, + "invalid value in numeric variable definition '" + + CmdlineVal + "'")); + continue; + } + FileCheckNumericVariable *DefinedNumericVariable = *ParseResult; + DefinedNumericVariable->setValue(Val); + + // 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<FileCheckPattern::VariableProperties> ParseVarResult = + FileCheckPattern::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), + FileCheckErrorDiagnostic::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), FileCheckErrorDiagnostic::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; } -/// Check the input to FileCheck provided in the \p Buffer against the \p -/// CheckStrings read from the check file. -/// -/// Returns false if the input fails to satisfy the checks. -bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer, - ArrayRef<FileCheckString> CheckStrings, - std::vector<FileCheckDiag> *Diags) { - bool ChecksFailed = false; +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()); + } - /// VariableTable - This holds all the current filecheck variables. - StringMap<StringRef> VariableTable; + for (const auto &Var : LocalPatternVars) + GlobalVariableTable.erase(Var); + for (const auto &Var : LocalNumericVars) + GlobalNumericVariableTable.erase(Var); +} - for (const auto& Def : Req.GlobalDefines) - VariableTable.insert(StringRef(Def).split('=')); +bool FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer, + ArrayRef<FileCheckString> CheckStrings, + std::vector<FileCheckDiag> *Diags) { + bool ChecksFailed = false; unsigned i = 0, j = 0, e = CheckStrings.size(); while (true) { @@ -1405,10 +1906,10 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer, // 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, VariableTable, Req, Diags); + size_t MatchLabelPos = + CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags); if (MatchLabelPos == StringRef::npos) - // Immediately bail of CHECK-LABEL fails, nothing else we can do. + // Immediately bail if CHECK-LABEL fails, nothing else we can do. return false; CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); @@ -1416,8 +1917,11 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer, ++j; } - if (Req.EnableVarScope) - ClearLocalVars(VariableTable); + // 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]; @@ -1425,8 +1929,8 @@ bool llvm::FileCheck::CheckInput(SourceMgr &SM, StringRef Buffer, // 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, - VariableTable, Req, Diags); + size_t MatchPos = + CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags); if (MatchPos == StringRef::npos) { ChecksFailed = true; diff --git a/contrib/llvm/lib/Support/FileOutputBuffer.cpp b/contrib/llvm/lib/Support/FileOutputBuffer.cpp index b8223126227d..3d6b569f2993 100644 --- a/contrib/llvm/lib/Support/FileOutputBuffer.cpp +++ b/contrib/llvm/lib/Support/FileOutputBuffer.cpp @@ -1,9 +1,8 @@ //===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -76,18 +75,26 @@ private: // output file on commit(). This is used only when we cannot use OnDiskBuffer. class InMemoryBuffer : public FileOutputBuffer { public: - InMemoryBuffer(StringRef Path, MemoryBlock Buf, unsigned Mode) - : FileOutputBuffer(Path), Buffer(Buf), Mode(Mode) {} + InMemoryBuffer(StringRef Path, MemoryBlock Buf, std::size_t BufSize, + unsigned Mode) + : FileOutputBuffer(Path), Buffer(Buf), BufferSize(BufSize), + Mode(Mode) {} uint8_t *getBufferStart() const override { return (uint8_t *)Buffer.base(); } uint8_t *getBufferEnd() const override { - return (uint8_t *)Buffer.base() + Buffer.size(); + return (uint8_t *)Buffer.base() + BufferSize; } - size_t getBufferSize() const override { return Buffer.size(); } + size_t getBufferSize() const override { return BufferSize; } Error commit() override { + if (FinalPath == "-") { + llvm::outs() << StringRef((const char *)Buffer.base(), BufferSize); + llvm::outs().flush(); + return Error::success(); + } + using namespace sys::fs; int FD; std::error_code EC; @@ -95,12 +102,14 @@ public: openFileForWrite(FinalPath, FD, CD_CreateAlways, OF_None, Mode)) return errorCodeToError(EC); raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true); - OS << StringRef((const char *)Buffer.base(), Buffer.size()); + OS << StringRef((const char *)Buffer.base(), BufferSize); return Error::success(); } private: + // Buffer may actually contain a larger memory block than BufferSize OwningMemoryBlock Buffer; + size_t BufferSize; unsigned Mode; }; } // namespace @@ -112,43 +121,42 @@ createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) { Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); if (EC) return errorCodeToError(EC); - return llvm::make_unique<InMemoryBuffer>(Path, MB, Mode); + return llvm::make_unique<InMemoryBuffer>(Path, MB, Size, Mode); } -static Expected<std::unique_ptr<OnDiskBuffer>> -createOnDiskBuffer(StringRef Path, size_t Size, bool InitExisting, - unsigned Mode) { +static Expected<std::unique_ptr<FileOutputBuffer>> +createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) { Expected<fs::TempFile> FileOrErr = fs::TempFile::create(Path + ".tmp%%%%%%%", Mode); if (!FileOrErr) return FileOrErr.takeError(); fs::TempFile File = std::move(*FileOrErr); - if (InitExisting) { - if (auto EC = sys::fs::copy_file(Path, File.FD)) - return errorCodeToError(EC); - } else { #ifndef _WIN32 - // On Windows, CreateFileMapping (the mmap function on Windows) - // automatically extends the underlying file. We don't need to - // extend the file beforehand. _chsize (ftruncate on Windows) is - // pretty slow just like it writes specified amount of bytes, - // so we should avoid calling that function. - if (auto EC = fs::resize_file(File.FD, Size)) { - consumeError(File.discard()); - return errorCodeToError(EC); - } -#endif + // On Windows, CreateFileMapping (the mmap function on Windows) + // automatically extends the underlying file. We don't need to + // extend the file beforehand. _chsize (ftruncate on Windows) is + // pretty slow just like it writes specified amount of bytes, + // so we should avoid calling that function. + if (auto EC = fs::resize_file(File.FD, Size)) { + consumeError(File.discard()); + return errorCodeToError(EC); } +#endif // Mmap it. std::error_code EC; auto MappedFile = llvm::make_unique<fs::mapped_file_region>( - File.FD, fs::mapped_file_region::readwrite, Size, 0, EC); + fs::convertFDToNativeFile(File.FD), fs::mapped_file_region::readwrite, + Size, 0, EC); + + // mmap(2) can fail if the underlying filesystem does not support it. + // If that happens, we fall back to in-memory buffer as the last resort. if (EC) { consumeError(File.discard()); - return errorCodeToError(EC); + return createInMemoryBuffer(Path, Size, Mode); } + return llvm::make_unique<OnDiskBuffer>(Path, std::move(File), std::move(MappedFile)); } @@ -156,6 +164,10 @@ createOnDiskBuffer(StringRef Path, size_t Size, bool InitExisting, // Create an instance of FileOutputBuffer. Expected<std::unique_ptr<FileOutputBuffer>> FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) { + // Handle "-" as stdout just like llvm::raw_ostream does. + if (Path == "-") + return createInMemoryBuffer("-", Size, /*Mode=*/0); + unsigned Mode = fs::all_read | fs::all_write; if (Flags & F_executable) Mode |= fs::all_exe; @@ -163,15 +175,6 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) { fs::file_status Stat; fs::status(Path, Stat); - if ((Flags & F_modify) && Size == size_t(-1)) { - if (Stat.type() == fs::file_type::regular_file) - Size = Stat.getSize(); - else if (Stat.type() == fs::file_type::file_not_found) - return errorCodeToError(errc::no_such_file_or_directory); - else - return errorCodeToError(errc::invalid_argument); - } - // Usually, we want to create OnDiskBuffer to create a temporary file in // the same directory as the destination file and atomically replaces it // by rename(2). @@ -186,7 +189,7 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) { case fs::file_type::regular_file: case fs::file_type::file_not_found: case fs::file_type::status_error: - return createOnDiskBuffer(Path, Size, !!(Flags & F_modify), Mode); + return createOnDiskBuffer(Path, Size, Mode); default: return createInMemoryBuffer(Path, Size, Mode); } diff --git a/contrib/llvm/lib/Support/FileUtilities.cpp b/contrib/llvm/lib/Support/FileUtilities.cpp index 39dbefff5b70..62eb7bfda195 100644 --- a/contrib/llvm/lib/Support/FileUtilities.cpp +++ b/contrib/llvm/lib/Support/FileUtilities.cpp @@ -1,9 +1,8 @@ //===- Support/FileUtilities.cpp - File System Utilities ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/FoldingSet.cpp b/contrib/llvm/lib/Support/FoldingSet.cpp index ee69a64ac97b..ce6f196e1060 100644 --- a/contrib/llvm/lib/Support/FoldingSet.cpp +++ b/contrib/llvm/lib/Support/FoldingSet.cpp @@ -1,9 +1,8 @@ //===-- Support/FoldingSet.cpp - Uniquing Hash Set --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/FormatVariadic.cpp b/contrib/llvm/lib/Support/FormatVariadic.cpp index 1f3505d5f74f..f9e89f69b528 100644 --- a/contrib/llvm/lib/Support/FormatVariadic.cpp +++ b/contrib/llvm/lib/Support/FormatVariadic.cpp @@ -1,9 +1,8 @@ //===- FormatVariadic.cpp - Format string parsing and analysis ----*-C++-*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// #include "llvm/Support/FormatVariadic.h" diff --git a/contrib/llvm/lib/Support/FormattedStream.cpp b/contrib/llvm/lib/Support/FormattedStream.cpp index b0cb06c1daa2..4eb747038bb9 100644 --- a/contrib/llvm/lib/Support/FormattedStream.cpp +++ b/contrib/llvm/lib/Support/FormattedStream.cpp @@ -1,9 +1,8 @@ //===-- llvm/Support/FormattedStream.cpp - Formatted streams ----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/GlobPattern.cpp b/contrib/llvm/lib/Support/GlobPattern.cpp index 4ea110301f16..6011be86d77f 100644 --- a/contrib/llvm/lib/Support/GlobPattern.cpp +++ b/contrib/llvm/lib/Support/GlobPattern.cpp @@ -1,9 +1,8 @@ //===-- GlobPattern.cpp - Glob pattern matcher implementation -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp index 9335daffc3e2..c689a81925d4 100644 --- a/contrib/llvm/lib/Support/GraphWriter.cpp +++ b/contrib/llvm/lib/Support/GraphWriter.cpp @@ -1,9 +1,8 @@ //===- GraphWriter.cpp - Implements GraphWriter support routines ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Hashing.cpp b/contrib/llvm/lib/Support/Hashing.cpp index 7de25cec7371..1b20a670434f 100644 --- a/contrib/llvm/lib/Support/Hashing.cpp +++ b/contrib/llvm/lib/Support/Hashing.cpp @@ -1,9 +1,8 @@ //===-------------- lib/Support/Hashing.cpp -------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp index d5a688c7fb9b..d491912bdc0c 100644 --- a/contrib/llvm/lib/Support/Host.cpp +++ b/contrib/llvm/lib/Support/Host.cpp @@ -1,9 +1,8 @@ //===-- Host.cpp - Implement OS Host Concept --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -193,6 +192,8 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) { .Case("0xd07", "cortex-a57") .Case("0xd08", "cortex-a72") .Case("0xd09", "cortex-a73") + .Case("0xd0a", "cortex-a75") + .Case("0xd0b", "cortex-a76") .Default("generic"); } @@ -236,6 +237,10 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) { .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"); @@ -310,6 +315,8 @@ StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) { Pos += sizeof("machine = ") - 1; unsigned int Id; if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { + if (Id >= 8561 && HaveVectorSupport) + return "arch13"; if (Id >= 3906 && HaveVectorSupport) return "z14"; if (Id >= 2964 && HaveVectorSupport) @@ -331,7 +338,19 @@ StringRef sys::detail::getHostCPUNameForBPF() { #if !defined(__linux__) || !defined(__x86_64__) return "generic"; #else - uint8_t insns[40] __attribute__ ((aligned (8))) = + uint8_t v3_insns[40] __attribute__ ((aligned (8))) = + /* BPF_MOV64_IMM(BPF_REG_0, 0) */ + { 0xb7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_2, 1) */ + 0xb7, 0x2, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_JMP32_REG(BPF_JLT, BPF_REG_0, BPF_REG_2, 1) */ + 0xae, 0x20, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, + /* BPF_MOV64_IMM(BPF_REG_0, 1) */ + 0xb7, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, + /* BPF_EXIT_INSN() */ + 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + uint8_t v2_insns[40] __attribute__ ((aligned (8))) = /* BPF_MOV64_IMM(BPF_REG_0, 0) */ { 0xb7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* BPF_MOV64_IMM(BPF_REG_2, 1) */ @@ -356,10 +375,23 @@ StringRef sys::detail::getHostCPUNameForBPF() { } attr = {}; attr.prog_type = 1; /* BPF_PROG_TYPE_SOCKET_FILTER */ attr.insn_cnt = 5; - attr.insns = (uint64_t)insns; + attr.insns = (uint64_t)v3_insns; attr.license = (uint64_t)"DUMMY"; - int fd = syscall(321 /* __NR_bpf */, 5 /* BPF_PROG_LOAD */, &attr, sizeof(attr)); + int fd = syscall(321 /* __NR_bpf */, 5 /* BPF_PROG_LOAD */, &attr, + sizeof(attr)); + if (fd >= 0) { + close(fd); + return "v3"; + } + + /* Clear the whole attr in case its content changed by syscall. */ + memset(&attr, 0, sizeof(attr)); + attr.prog_type = 1; /* BPF_PROG_TYPE_SOCKET_FILTER */ + attr.insn_cnt = 5; + attr.insns = (uint64_t)v2_insns; + attr.license = (uint64_t)"DUMMY"; + fd = syscall(321 /* __NR_bpf */, 5 /* BPF_PROG_LOAD */, &attr, sizeof(attr)); if (fd >= 0) { close(fd); return "v2"; @@ -637,10 +669,10 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, break; // Skylake: - case 0x4e: // Skylake mobile - case 0x5e: // Skylake desktop - case 0x8e: // Kaby Lake mobile - case 0x9e: // Kaby Lake desktop + case 0x4e: // Skylake mobile + case 0x5e: // Skylake desktop + case 0x8e: // Kaby Lake mobile + case 0x9e: // Kaby Lake desktop *Type = X86::INTEL_COREI7; // "skylake" *Subtype = X86::INTEL_COREI7_SKYLAKE; break; @@ -648,7 +680,12 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, // Skylake Xeon: case 0x55: *Type = X86::INTEL_COREI7; - *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" + if (Features3 & (1 << (X86::FEATURE_AVX512BF16 - 64))) + *Subtype = X86::INTEL_COREI7_COOPERLAKE; // "cooperlake" + else if (Features2 & (1 << (X86::FEATURE_AVX512VNNI - 32))) + *Subtype = X86::INTEL_COREI7_CASCADELAKE; // "cascadelake" + else + *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" break; // Cannonlake: @@ -657,6 +694,20 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, *Subtype = X86::INTEL_COREI7_CANNONLAKE; // "cannonlake" break; + // Icelake: + case 0x7d: + case 0x7e: + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT; // "icelake-client" + break; + + // Icelake Xeon: + case 0x6a: + case 0x6c: + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_ICELAKE_SERVER; // "icelake-server" + break; + case 0x1c: // Most 45 nm Intel Atom processors case 0x26: // 45 nm Atom Lincroft case 0x27: // 32 nm Atom Medfield @@ -682,9 +733,14 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, case 0x7a: *Type = X86::INTEL_GOLDMONT_PLUS; break; + case 0x86: + *Type = X86::INTEL_TREMONT; + break; + case 0x57: *Type = X86::INTEL_KNL; // knl break; + case 0x85: *Type = X86::INTEL_KNM; // knm break; @@ -702,6 +758,12 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, break; } + if (Features3 & (1 << (X86::FEATURE_AVX512BF16 - 64))) { + *Type = X86::INTEL_COREI7; + *Subtype = X86::INTEL_COREI7_COOPERLAKE; + break; + } + if (Features2 & (1 << (X86::FEATURE_AVX512VNNI - 32))) { *Type = X86::INTEL_COREI7; *Subtype = X86::INTEL_COREI7_CASCADELAKE; @@ -892,7 +954,14 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model, break; // "btver2" case 23: *Type = X86::AMDFAM17H; - *Subtype = X86::AMDFAM17H_ZNVER1; + if (Model >= 0x30 && Model <= 0x3f) { + *Subtype = X86::AMDFAM17H_ZNVER2; + break; // "znver2"; 30h-3fh: Zen2 + } + if (Model <= 0x0f) { + *Subtype = X86::AMDFAM17H_ZNVER1; + break; // "znver1"; 00h-0Fh: Zen1 + } break; default: break; // "generic" @@ -1233,8 +1302,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX); + Features["cx8"] = (EDX >> 8) & 1; Features["cmov"] = (EDX >> 15) & 1; Features["mmx"] = (EDX >> 23) & 1; + Features["fxsr"] = (EDX >> 24) & 1; Features["sse"] = (EDX >> 25) & 1; Features["sse2"] = (EDX >> 26) & 1; @@ -1298,6 +1369,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1); Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); + Features["mpx"] = HasLeaf7 && ((EBX >> 14) & 1); // AVX512 is only supported if the OS supports the context save for it. Features["avx512f"] = HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save; Features["avx512dq"] = HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save; @@ -1329,6 +1401,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["cldemote"] = HasLeaf7 && ((ECX >> 25) & 1); Features["movdiri"] = HasLeaf7 && ((ECX >> 27) & 1); Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1); + Features["enqcmd"] = HasLeaf7 && ((ECX >> 29) & 1); // There are two CPUID leafs which information associated with the pconfig // instruction: @@ -1341,6 +1414,9 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { // detecting features using the "-march=native" flag. // For more info, see X86 ISA docs. Features["pconfig"] = HasLeaf7 && ((EDX >> 18) & 1); + bool HasLeaf7Subleaf1 = + MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX); + Features["avx512bf16"] = HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save; bool HasLeafD = MaxLevel >= 0xd && !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX); diff --git a/contrib/llvm/lib/Support/InitLLVM.cpp b/contrib/llvm/lib/Support/InitLLVM.cpp index c008d0455c99..0d7d7fcc8cb6 100644 --- a/contrib/llvm/lib/Support/InitLLVM.cpp +++ b/contrib/llvm/lib/Support/InitLLVM.cpp @@ -1,9 +1,8 @@ //===-- InitLLVM.cpp -----------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -24,6 +23,7 @@ using namespace llvm::sys; InitLLVM::InitLLVM(int &Argc, const char **&Argv) : StackPrinter(Argc, Argv) { sys::PrintStackTraceOnErrorSignal(Argv[0]); + install_out_of_memory_new_handler(); #ifdef _WIN32 // We use UTF-8 as the internal character encoding. On Windows, diff --git a/contrib/llvm/lib/Support/IntEqClasses.cpp b/contrib/llvm/lib/Support/IntEqClasses.cpp index cb6e3a19e8d3..4a976dcefc65 100644 --- a/contrib/llvm/lib/Support/IntEqClasses.cpp +++ b/contrib/llvm/lib/Support/IntEqClasses.cpp @@ -1,9 +1,8 @@ //===-- llvm/ADT/IntEqClasses.cpp - Equivalence Classes of Integers -------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/IntervalMap.cpp b/contrib/llvm/lib/Support/IntervalMap.cpp index e11a7f2eb843..f15c7c9403c3 100644 --- a/contrib/llvm/lib/Support/IntervalMap.cpp +++ b/contrib/llvm/lib/Support/IntervalMap.cpp @@ -1,9 +1,8 @@ //===- lib/Support/IntervalMap.cpp - A sorted interval map ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp b/contrib/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp index e55dcd761809..da6514f7170b 100644 --- a/contrib/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp +++ b/contrib/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp @@ -1,9 +1,8 @@ //===----------------- ItaniumManglingCanonicalizer.cpp -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -22,6 +21,7 @@ using namespace llvm; using llvm::itanium_demangle::ForwardTemplateReference; using llvm::itanium_demangle::Node; using llvm::itanium_demangle::NodeKind; +using llvm::itanium_demangle::StringView; namespace { struct FoldingSetNodeIDBuilder { diff --git a/contrib/llvm/lib/Support/JSON.cpp b/contrib/llvm/lib/Support/JSON.cpp index 07a556814915..95e5ed654277 100644 --- a/contrib/llvm/lib/Support/JSON.cpp +++ b/contrib/llvm/lib/Support/JSON.cpp @@ -1,9 +1,8 @@ //=== JSON.cpp - JSON value, parsing and serialization - C++ -----------*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===---------------------------------------------------------------------===// @@ -561,9 +560,6 @@ std::string fixUTF8(llvm::StringRef S) { return Res; } -} // namespace json -} // namespace llvm - static void quote(llvm::raw_ostream &OS, llvm::StringRef S) { OS << '\"'; for (unsigned char C : S) { @@ -594,106 +590,129 @@ static void quote(llvm::raw_ostream &OS, llvm::StringRef S) { OS << '\"'; } -enum IndenterAction { - Indent, - Outdent, - Newline, - Space, -}; - -// Prints JSON. The indenter can be used to control formatting. -template <typename Indenter> -void llvm::json::Value::print(raw_ostream &OS, const Indenter &I) const { - switch (Type) { - case T_Null: +void llvm::json::OStream::value(const Value &V) { + switch (V.kind()) { + case Value::Null: + valueBegin(); OS << "null"; - break; - case T_Boolean: - OS << (as<bool>() ? "true" : "false"); - break; - case T_Double: - OS << format("%.*g", std::numeric_limits<double>::max_digits10, - as<double>()); - break; - case T_Integer: - OS << as<int64_t>(); - break; - case T_StringRef: - quote(OS, as<StringRef>()); - break; - case T_String: - quote(OS, as<std::string>()); - break; - case T_Object: { - bool Comma = false; - OS << '{'; - I(Indent); - for (const auto *P : sortedElements(as<json::Object>())) { - if (Comma) - OS << ','; - Comma = true; - I(Newline); - quote(OS, P->first); - OS << ':'; - I(Space); - P->second.print(OS, I); - } - I(Outdent); - if (Comma) - I(Newline); - OS << '}'; - break; + return; + case Value::Boolean: + valueBegin(); + OS << (*V.getAsBoolean() ? "true" : "false"); + return; + case Value::Number: + valueBegin(); + if (V.Type == Value::T_Integer) + OS << *V.getAsInteger(); + else + OS << format("%.*g", std::numeric_limits<double>::max_digits10, + *V.getAsNumber()); + return; + case Value::String: + valueBegin(); + quote(OS, *V.getAsString()); + return; + case Value::Array: + return array([&] { + for (const Value &E : *V.getAsArray()) + value(E); + }); + case Value::Object: + return object([&] { + for (const Object::value_type *E : sortedElements(*V.getAsObject())) + attribute(E->first, E->second); + }); } - case T_Array: { - bool Comma = false; - OS << '['; - I(Indent); - for (const auto &E : as<json::Array>()) { - if (Comma) - OS << ','; - Comma = true; - I(Newline); - E.print(OS, I); - } - I(Outdent); - if (Comma) - I(Newline); - OS << ']'; - break; +} + +void llvm::json::OStream::valueBegin() { + assert(Stack.back().Ctx != Object && "Only attributes allowed here"); + if (Stack.back().HasValue) { + assert(Stack.back().Ctx != Singleton && "Only one value allowed here"); + OS << ','; + } + if (Stack.back().Ctx == Array) + newline(); + Stack.back().HasValue = true; +} + +void llvm::json::OStream::newline() { + if (IndentSize) { + OS.write('\n'); + OS.indent(Indent); } +} + +void llvm::json::OStream::arrayBegin() { + valueBegin(); + Stack.emplace_back(); + Stack.back().Ctx = Array; + Indent += IndentSize; + OS << '['; +} + +void llvm::json::OStream::arrayEnd() { + assert(Stack.back().Ctx == Array); + Indent -= IndentSize; + if (Stack.back().HasValue) + newline(); + OS << ']'; + Stack.pop_back(); + assert(!Stack.empty()); +} + +void llvm::json::OStream::objectBegin() { + valueBegin(); + Stack.emplace_back(); + Stack.back().Ctx = Object; + Indent += IndentSize; + OS << '{'; +} + +void llvm::json::OStream::objectEnd() { + assert(Stack.back().Ctx == Object); + Indent -= IndentSize; + if (Stack.back().HasValue) + newline(); + OS << '}'; + Stack.pop_back(); + assert(!Stack.empty()); +} + +void llvm::json::OStream::attributeBegin(llvm::StringRef Key) { + assert(Stack.back().Ctx == Object); + if (Stack.back().HasValue) + OS << ','; + newline(); + Stack.back().HasValue = true; + Stack.emplace_back(); + Stack.back().Ctx = Singleton; + if (LLVM_LIKELY(isUTF8(Key))) { + quote(OS, Key); + } else { + assert(false && "Invalid UTF-8 in attribute key"); + quote(OS, fixUTF8(Key)); } + OS.write(':'); + if (IndentSize) + OS.write(' '); +} + +void llvm::json::OStream::attributeEnd() { + assert(Stack.back().Ctx == Singleton); + assert(Stack.back().HasValue && "Attribute must have a value"); + Stack.pop_back(); + assert(Stack.back().Ctx == Object); } +} // namespace json +} // namespace llvm + void llvm::format_provider<llvm::json::Value>::format( const llvm::json::Value &E, raw_ostream &OS, StringRef Options) { - if (Options.empty()) { - OS << E; - return; - } unsigned IndentAmount = 0; - if (Options.getAsInteger(/*Radix=*/10, IndentAmount)) + if (!Options.empty() && Options.getAsInteger(/*Radix=*/10, IndentAmount)) llvm_unreachable("json::Value format options should be an integer"); - unsigned IndentLevel = 0; - E.print(OS, [&](IndenterAction A) { - switch (A) { - case Newline: - OS << '\n'; - OS.indent(IndentLevel); - break; - case Space: - OS << ' '; - break; - case Indent: - IndentLevel += IndentAmount; - break; - case Outdent: - IndentLevel -= IndentAmount; - break; - }; - }); + json::OStream(OS, IndentAmount).value(E); } -llvm::raw_ostream &llvm::json::operator<<(raw_ostream &OS, const Value &E) { - E.print(OS, [](IndenterAction A) { /*ignore*/ }); - return OS; -} diff --git a/contrib/llvm/lib/Support/JamCRC.cpp b/contrib/llvm/lib/Support/JamCRC.cpp index 17c55f565e08..e043a3c33c28 100644 --- a/contrib/llvm/lib/Support/JamCRC.cpp +++ b/contrib/llvm/lib/Support/JamCRC.cpp @@ -1,9 +1,8 @@ //===-- JamCRC.cpp - Cyclic Redundancy Check --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/KnownBits.cpp b/contrib/llvm/lib/Support/KnownBits.cpp index ac790ebed352..a6c591fca312 100644 --- a/contrib/llvm/lib/Support/KnownBits.cpp +++ b/contrib/llvm/lib/Support/KnownBits.cpp @@ -1,9 +1,8 @@ //===-- KnownBits.cpp - Stores known zeros/ones ---------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -16,18 +15,14 @@ using namespace llvm; -KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, - const KnownBits &LHS, KnownBits RHS) { - // Carry in a 1 for a subtract, rather than 0. - bool CarryIn = false; - if (!Add) { - // Sum = LHS + ~RHS + 1 - std::swap(RHS.Zero, RHS.One); - CarryIn = true; - } +static KnownBits computeForAddCarry( + const KnownBits &LHS, const KnownBits &RHS, + bool CarryZero, bool CarryOne) { + assert(!(CarryZero && CarryOne) && + "Carry can't be zero and one at the same time"); - APInt PossibleSumZero = ~LHS.Zero + ~RHS.Zero + CarryIn; - APInt PossibleSumOne = LHS.One + RHS.One + CarryIn; + APInt PossibleSumZero = ~LHS.Zero + ~RHS.Zero + !CarryZero; + APInt PossibleSumOne = LHS.One + RHS.One + CarryOne; // Compute known bits of the carry. APInt CarryKnownZero = ~(PossibleSumZero ^ LHS.Zero ^ RHS.Zero); @@ -46,9 +41,32 @@ KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, KnownBits KnownOut; KnownOut.Zero = ~std::move(PossibleSumZero) & Known; KnownOut.One = std::move(PossibleSumOne) & Known; + return KnownOut; +} + +KnownBits KnownBits::computeForAddCarry( + const KnownBits &LHS, const KnownBits &RHS, const KnownBits &Carry) { + assert(Carry.getBitWidth() == 1 && "Carry must be 1-bit"); + return ::computeForAddCarry( + LHS, RHS, Carry.Zero.getBoolValue(), Carry.One.getBoolValue()); +} + +KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, + const KnownBits &LHS, KnownBits RHS) { + KnownBits KnownOut; + if (Add) { + // Sum = LHS + RHS + 0 + KnownOut = ::computeForAddCarry( + LHS, RHS, /*CarryZero*/true, /*CarryOne*/false); + } else { + // Sum = LHS + ~RHS + 1 + std::swap(RHS.Zero, RHS.One); + KnownOut = ::computeForAddCarry( + LHS, RHS, /*CarryZero*/false, /*CarryOne*/true); + } // Are we still trying to solve for the sign bit? - if (!Known.isSignBitSet()) { + if (!KnownOut.isNegative() && !KnownOut.isNonNegative()) { if (NSW) { // Adding two non-negative numbers, or subtracting a negative number from // a non-negative one, can't wrap into negative. diff --git a/contrib/llvm/lib/Support/LEB128.cpp b/contrib/llvm/lib/Support/LEB128.cpp index 449626f2d451..d41b673e9c8a 100644 --- a/contrib/llvm/lib/Support/LEB128.cpp +++ b/contrib/llvm/lib/Support/LEB128.cpp @@ -1,9 +1,8 @@ //===- LEB128.cpp - LEB128 utility functions implementation -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/LineIterator.cpp b/contrib/llvm/lib/Support/LineIterator.cpp index 5baa1a37f385..164436a2c48e 100644 --- a/contrib/llvm/lib/Support/LineIterator.cpp +++ b/contrib/llvm/lib/Support/LineIterator.cpp @@ -1,9 +1,8 @@ //===- LineIterator.cpp - Implementation of line iteration ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp index c166230ba3a3..10181192afbd 100644 --- a/contrib/llvm/lib/Support/LockFileManager.cpp +++ b/contrib/llvm/lib/Support/LockFileManager.cpp @@ -1,9 +1,8 @@ //===--- LockFileManager.cpp - File-level Locking Utility------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/LowLevelType.cpp b/contrib/llvm/lib/Support/LowLevelType.cpp index cb2187405d6b..fe77cb3db413 100644 --- a/contrib/llvm/lib/Support/LowLevelType.cpp +++ b/contrib/llvm/lib/Support/LowLevelType.cpp @@ -1,9 +1,8 @@ //===-- llvm/Support/LowLevelType.cpp -------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -18,14 +17,14 @@ using namespace llvm; LLT::LLT(MVT VT) { if (VT.isVector()) { - init(/*isPointer=*/false, VT.getVectorNumElements() > 1, + init(/*IsPointer=*/false, VT.getVectorNumElements() > 1, VT.getVectorNumElements(), VT.getVectorElementType().getSizeInBits(), /*AddressSpace=*/0); } 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"); - init(/*isPointer=*/false, /*isVector=*/false, /*NumElements=*/0, + init(/*IsPointer=*/false, /*IsVector=*/false, /*NumElements=*/0, VT.getSizeInBits(), /*AddressSpace=*/0); } else { IsPointer = false; diff --git a/contrib/llvm/lib/Support/ManagedStatic.cpp b/contrib/llvm/lib/Support/ManagedStatic.cpp index 74f71a385027..28ceb1a70e42 100644 --- a/contrib/llvm/lib/Support/ManagedStatic.cpp +++ b/contrib/llvm/lib/Support/ManagedStatic.cpp @@ -1,9 +1,8 @@ //===-- ManagedStatic.cpp - Static Global wrapper -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/MathExtras.cpp b/contrib/llvm/lib/Support/MathExtras.cpp index ba0924540ceb..87c7101c424b 100644 --- a/contrib/llvm/lib/Support/MathExtras.cpp +++ b/contrib/llvm/lib/Support/MathExtras.cpp @@ -1,9 +1,8 @@ //===-- MathExtras.cpp - Implement the MathExtras header --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Memory.cpp b/contrib/llvm/lib/Support/Memory.cpp index c245eedd2c16..581484268cd8 100644 --- a/contrib/llvm/lib/Support/Memory.cpp +++ b/contrib/llvm/lib/Support/Memory.cpp @@ -1,9 +1,8 @@ //===- Memory.cpp - Memory Handling Support ---------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -16,6 +15,10 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/Valgrind.h" +#ifndef NDEBUG +#include "llvm/Support/raw_ostream.h" +#endif // ifndef NDEBUG + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Memory.inc" @@ -23,3 +26,28 @@ #ifdef _WIN32 #include "Windows/Memory.inc" #endif + +#ifndef NDEBUG + +namespace llvm { +namespace sys { + +raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF) { + assert((PF & ~(Memory::MF_READ | Memory::MF_WRITE | Memory::MF_EXEC)) == 0 && + "Unrecognized flags"); + + return OS << (PF & Memory::MF_READ ? 'R' : '-') + << (PF & Memory::MF_WRITE ? 'W' : '-') + << (PF & Memory::MF_EXEC ? 'X' : '-'); +} + +raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB) { + return OS << "[ " << MB.base() << " .. " + << (void *)((char *)MB.base() + MB.allocatedSize()) << " ] (" + << MB.allocatedSize() << " bytes)"; +} + +} // end namespace sys +} // end namespace llvm + +#endif // ifndef NDEBUG diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp index ef9159bac284..d0e5bb154c1a 100644 --- a/contrib/llvm/lib/Support/MemoryBuffer.cpp +++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp @@ -1,9 +1,8 @@ //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -183,7 +182,7 @@ class MemoryBufferMMapFile : public MB { } public: - MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, + MemoryBufferMMapFile(bool RequiresNullTerminator, sys::fs::file_t FD, uint64_t Len, uint64_t Offset, std::error_code &EC) : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { @@ -209,16 +208,16 @@ public: } static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> -getMemoryBufferForStream(int FD, const Twine &BufferName) { +getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) { const ssize_t ChunkSize = 4096*4; SmallString<ChunkSize> Buffer; - ssize_t ReadBytes; + size_t ReadBytes; // Read into Buffer until we hit EOF. do { Buffer.reserve(Buffer.size() + ChunkSize); - ReadBytes = sys::RetryAfterSignal(-1, ::read, FD, Buffer.end(), ChunkSize); - if (ReadBytes == -1) - return std::error_code(errno, std::generic_category()); + if (auto EC = sys::fs::readNativeFile( + FD, makeMutableArrayRef(Buffer.end(), ChunkSize), &ReadBytes)) + return EC; Buffer.set_size(Buffer.size() + ReadBytes); } while (ReadBytes != 0); @@ -235,7 +234,7 @@ MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, template <typename MB> static ErrorOr<std::unique_ptr<MB>> -getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, +getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, bool IsVolatile); @@ -243,15 +242,14 @@ template <typename MB> static ErrorOr<std::unique_ptr<MB>> getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { - int FD; - std::error_code EC = sys::fs::openFileForRead(Filename, FD, sys::fs::OF_None); - - if (EC) - return EC; - + Expected<sys::fs::file_t> FDOrErr = + sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); + if (!FDOrErr) + return errorToErrorCode(FDOrErr.takeError()); + sys::fs::file_t FD = *FDOrErr; auto Ret = getOpenFileImpl<MB>(FD, Filename, FileSize, MapSize, Offset, RequiresNullTerminator, IsVolatile); - close(FD); + sys::fs::closeFile(FD); return Ret; } @@ -305,7 +303,7 @@ WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) { return SB; } -static bool shouldUseMmap(int FD, +static bool shouldUseMmap(sys::fs::file_t FD, size_t FileSize, size_t MapSize, off_t Offset, @@ -363,12 +361,11 @@ static bool shouldUseMmap(int FD, static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize, uint64_t Offset) { - int FD; - std::error_code EC = sys::fs::openFileForReadWrite( - Filename, FD, sys::fs::CD_OpenExisting, sys::fs::OF_None); - - if (EC) - return EC; + Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForReadWrite( + Filename, sys::fs::CD_OpenExisting, sys::fs::OF_None); + if (!FDOrErr) + return errorToErrorCode(FDOrErr.takeError()); + sys::fs::file_t FD = *FDOrErr; // Default is to map the full file. if (MapSize == uint64_t(-1)) { @@ -392,6 +389,7 @@ getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize, MapSize = FileSize; } + std::error_code EC; std::unique_ptr<WriteThroughMemoryBuffer> Result( new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize, @@ -415,10 +413,10 @@ WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, template <typename MB> static ErrorOr<std::unique_ptr<MB>> -getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, +getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { - static int PageSize = sys::Process::getPageSize(); + static int PageSize = sys::Process::getPageSizeEstimate(); // Default is to map the full file. if (MapSize == uint64_t(-1)) { @@ -460,45 +458,20 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, return make_error_code(errc::not_enough_memory); } - char *BufPtr = Buf.get()->getBufferStart(); - - size_t BytesLeft = MapSize; -#ifndef HAVE_PREAD - if (lseek(FD, Offset, SEEK_SET) == -1) - return std::error_code(errno, std::generic_category()); -#endif - - while (BytesLeft) { -#ifdef HAVE_PREAD - ssize_t NumRead = sys::RetryAfterSignal(-1, ::pread, FD, BufPtr, BytesLeft, - MapSize - BytesLeft + Offset); -#else - ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, BufPtr, BytesLeft); -#endif - if (NumRead == -1) { - // Error while reading. - return std::error_code(errno, std::generic_category()); - } - if (NumRead == 0) { - memset(BufPtr, 0, BytesLeft); // zero-initialize rest of the buffer. - break; - } - BytesLeft -= NumRead; - BufPtr += NumRead; - } + sys::fs::readNativeFileSlice(FD, Buf->getBuffer(), Offset); return std::move(Buf); } ErrorOr<std::unique_ptr<MemoryBuffer>> -MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, +MemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) { return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, FileSize, 0, RequiresNullTerminator, IsVolatile); } ErrorOr<std::unique_ptr<MemoryBuffer>> -MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize, +MemoryBuffer::getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, int64_t Offset, bool IsVolatile) { assert(MapSize != uint64_t(-1)); return getOpenFileImpl<MemoryBuffer>(FD, Filename, -1, MapSize, Offset, false, @@ -512,18 +485,19 @@ ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { // fallback if it fails. sys::ChangeStdinToBinary(); - return getMemoryBufferForStream(0, "<stdin>"); + return getMemoryBufferForStream(sys::fs::getStdinHandle(), "<stdin>"); } ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFileAsStream(const Twine &Filename) { - int FD; - std::error_code EC = sys::fs::openFileForRead(Filename, FD, sys::fs::OF_None); - if (EC) - return EC; + Expected<sys::fs::file_t> FDOrErr = + sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); + if (!FDOrErr) + return errorToErrorCode(FDOrErr.takeError()); + sys::fs::file_t FD = *FDOrErr; ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = getMemoryBufferForStream(FD, Filename); - close(FD); + sys::fs::closeFile(FD); return Ret; } diff --git a/contrib/llvm/lib/Support/Mutex.cpp b/contrib/llvm/lib/Support/Mutex.cpp index 7138c7a4b984..69b7b8126ab1 100644 --- a/contrib/llvm/lib/Support/Mutex.cpp +++ b/contrib/llvm/lib/Support/Mutex.cpp @@ -1,9 +1,8 @@ //===- Mutex.cpp - Mutual Exclusion Lock ------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/NativeFormatting.cpp b/contrib/llvm/lib/Support/NativeFormatting.cpp index 85b4bfb81568..3731e0c56359 100644 --- a/contrib/llvm/lib/Support/NativeFormatting.cpp +++ b/contrib/llvm/lib/Support/NativeFormatting.cpp @@ -1,9 +1,8 @@ //===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/Optional.cpp b/contrib/llvm/lib/Support/Optional.cpp new file mode 100644 index 000000000000..2425739c845d --- /dev/null +++ b/contrib/llvm/lib/Support/Optional.cpp @@ -0,0 +1,14 @@ +//===- Optional.cpp - Optional values ---------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/raw_ostream.h" + +llvm::raw_ostream &llvm::operator<<(raw_ostream &OS, NoneType) { + return OS << "None"; +} diff --git a/contrib/llvm/lib/Support/Options.cpp b/contrib/llvm/lib/Support/Options.cpp index 71258450efa6..770b7381c20e 100644 --- a/contrib/llvm/lib/Support/Options.cpp +++ b/contrib/llvm/lib/Support/Options.cpp @@ -1,9 +1,8 @@ //===- llvm/Support/Options.cpp - Debug options support ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Parallel.cpp b/contrib/llvm/lib/Support/Parallel.cpp index 1844003b9d3d..621bccbf2a4c 100644 --- a/contrib/llvm/lib/Support/Parallel.cpp +++ b/contrib/llvm/lib/Support/Parallel.cpp @@ -1,9 +1,8 @@ //===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -18,7 +17,9 @@ #include <stack> #include <thread> -using namespace llvm; +namespace llvm { +namespace parallel { +namespace detail { namespace { @@ -119,11 +120,28 @@ Executor *Executor::getDefaultExecutor() { #endif } -void parallel::detail::TaskGroup::spawn(std::function<void()> F) { - L.inc(); - Executor::getDefaultExecutor()->add([&, F] { +static std::atomic<int> TaskGroupInstances; + +// Latch::sync() called by the dtor may cause one thread to block. If is a dead +// lock if all threads in the default executor are blocked. To prevent the dead +// lock, only allow the first TaskGroup to run tasks parallelly. In the scenario +// of nested parallel_for_each(), only the outermost one runs parallelly. +TaskGroup::TaskGroup() : Parallel(TaskGroupInstances++ == 0) {} +TaskGroup::~TaskGroup() { --TaskGroupInstances; } + +void TaskGroup::spawn(std::function<void()> F) { + if (Parallel) { + L.inc(); + Executor::getDefaultExecutor()->add([&, F] { + F(); + L.dec(); + }); + } else { F(); - L.dec(); - }); + } } + +} // namespace detail +} // namespace parallel +} // namespace llvm #endif // LLVM_ENABLE_THREADS diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp index 5ce2f50ebdaa..c49260125dba 100644 --- a/contrib/llvm/lib/Support/Path.cpp +++ b/contrib/llvm/lib/Support/Path.cpp @@ -1,9 +1,8 @@ //===-- Path.cpp - Implement OS Path Concept ------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -170,25 +169,6 @@ createUniqueEntity(const Twine &Model, int &ResultFD, SmallVectorImpl<char> &ResultPath, bool MakeAbsolute, unsigned Mode, FSEntity Type, sys::fs::OpenFlags Flags = sys::fs::OF_None) { - SmallString<128> ModelStorage; - Model.toVector(ModelStorage); - - if (MakeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - if (!sys::path::is_absolute(Twine(ModelStorage))) { - SmallString<128> TDir; - sys::path::system_temp_directory(true, TDir); - sys::path::append(TDir, Twine(ModelStorage)); - ModelStorage.swap(TDir); - } - } - - // From here on, DO NOT modify model. It may be needed if the randomly chosen - // path already exists. - ResultPath = ModelStorage; - // Null terminate. - ResultPath.push_back(0); - ResultPath.pop_back(); // Limit the number of attempts we make, so that we don't infinite loop. E.g. // "permission denied" could be for a specific file (so we retry with a @@ -196,13 +176,7 @@ createUniqueEntity(const Twine &Model, int &ResultFD, // Checking which is racy, so we try a number of times, then give up. std::error_code EC; for (int Retries = 128; Retries > 0; --Retries) { - // Replace '%' with random chars. - for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { - if (ModelStorage[i] == '%') - ResultPath[i] = - "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; - } - + sys::fs::createUniquePath(Model, ResultPath, MakeAbsolute); // Try to open + create the file. switch (Type) { case FS_File: { @@ -323,7 +297,8 @@ reverse_iterator rbegin(StringRef Path, Style style) { I.Path = Path; I.Position = Path.size(); I.S = style; - return ++I; + ++I; + return I; } reverse_iterator rend(StringRef Path) { @@ -763,6 +738,32 @@ std::error_code getUniqueID(const Twine Path, UniqueID &Result) { return std::error_code(); } +void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath, + bool MakeAbsolute) { + SmallString<128> ModelStorage; + Model.toVector(ModelStorage); + + if (MakeAbsolute) { + // Make model absolute by prepending a temp directory if it's not already. + if (!sys::path::is_absolute(Twine(ModelStorage))) { + SmallString<128> TDir; + sys::path::system_temp_directory(true, TDir); + sys::path::append(TDir, Twine(ModelStorage)); + ModelStorage.swap(TDir); + } + } + + ResultPath = ModelStorage; + ResultPath.push_back(0); + ResultPath.pop_back(); + + // Replace '%' with random chars. + for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { + if (ModelStorage[i] == '%') + ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; + } +} + std::error_code createUniqueFile(const Twine &Model, int &ResultFd, SmallVectorImpl<char> &ResultPath, unsigned Mode) { @@ -959,6 +960,7 @@ static std::error_code copy_file_internal(int ReadFD, int WriteFD) { return std::error_code(); } +#ifndef __APPLE__ std::error_code copy_file(const Twine &From, const Twine &To) { int ReadFD, WriteFD; if (std::error_code EC = openFileForRead(From, ReadFD, OF_None)) @@ -976,6 +978,7 @@ std::error_code copy_file(const Twine &From, const Twine &To) { return EC; } +#endif std::error_code copy_file(const Twine &From, int ToFD) { int ReadFD; @@ -1122,6 +1125,7 @@ TempFile &TempFile::operator=(TempFile &&Other) { TmpName = std::move(Other.TmpName); FD = Other.FD; Other.Done = true; + Other.FD = -1; return *this; } @@ -1129,26 +1133,27 @@ TempFile::~TempFile() { assert(Done); } Error TempFile::discard() { Done = true; - std::error_code RemoveEC; -// On windows closing will remove the file. -#ifndef _WIN32 - // Always try to close and remove. - if (!TmpName.empty()) { - RemoveEC = fs::remove(TmpName); - sys::DontRemoveFileOnSignal(TmpName); - } -#endif - - if (!RemoveEC) - TmpName = ""; - if (FD != -1 && close(FD) == -1) { std::error_code EC = std::error_code(errno, std::generic_category()); return errorCodeToError(EC); } FD = -1; +#ifdef _WIN32 + // On windows closing will remove the file. + TmpName = ""; + return Error::success(); +#else + // Always try to close and remove. + std::error_code RemoveEC; + if (!TmpName.empty()) { + RemoveEC = fs::remove(TmpName); + sys::DontRemoveFileOnSignal(TmpName); + if (!RemoveEC) + TmpName = ""; + } return errorCodeToError(RemoveEC); +#endif } Error TempFile::keep(const Twine &Name) { diff --git a/contrib/llvm/lib/Support/PluginLoader.cpp b/contrib/llvm/lib/Support/PluginLoader.cpp index 358137f08f5f..6fe195ffda7a 100644 --- a/contrib/llvm/lib/Support/PluginLoader.cpp +++ b/contrib/llvm/lib/Support/PluginLoader.cpp @@ -1,9 +1,8 @@ //===-- PluginLoader.cpp - Implement -load command line option ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp index 206de91ae239..aec00baec0e3 100644 --- a/contrib/llvm/lib/Support/PrettyStackTrace.cpp +++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp @@ -1,9 +1,8 @@ //===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -15,12 +14,14 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm-c/ErrorHandling.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" +#include <atomic> #include <cstdarg> #include <cstdio> #include <tuple> @@ -34,7 +35,7 @@ using namespace llvm; // If backtrace support is not enabled, compile out support for pretty stack // traces. This has the secondary effect of not requiring thread local storage // when backtrace support is disabled. -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES // We need a thread local pointer to manage the stack of our stack trace // objects, but we *really* cannot tolerate destructors running and do not want @@ -42,6 +43,22 @@ using namespace llvm; // thread-local variable. static LLVM_THREAD_LOCAL PrettyStackTraceEntry *PrettyStackTraceHead = nullptr; +// The use of 'volatile' here is to ensure that any particular thread always +// reloads the value of the counter. The 'std::atomic' allows us to specify that +// this variable is accessed in an unsychronized way (it's not actually +// synchronizing). This does technically mean that the value may not appear to +// be the same across threads running simultaneously on different CPUs, but in +// practice the worst that will happen is that we won't print a stack trace when +// we could have. +// +// This is initialized to 1 because 0 is used as a sentinel for "not enabled on +// the current thread". If the user happens to overflow an 'unsigned' with +// SIGINFO requests, it's possible that some threads will stop responding to it, +// but the program won't crash. +static volatile std::atomic<unsigned> GlobalSigInfoGenerationCounter = + ATOMIC_VAR_INIT(1); +static LLVM_THREAD_LOCAL unsigned ThreadLocalSigInfoGenerationCounter = 0; + namespace llvm { PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *Head) { PrettyStackTraceEntry *Prev = nullptr; @@ -57,8 +74,9 @@ static void PrintStack(raw_ostream &OS) { // to fail if we crashed due to stack overflow), we do an up-front pass to // reverse the stack, then print it, then reverse it again. unsigned ID = 0; - PrettyStackTraceEntry *ReversedStack = - llvm::ReverseStackTrace(PrettyStackTraceHead); + SaveAndRestore<PrettyStackTraceEntry *> SavedStack{PrettyStackTraceHead, + nullptr}; + PrettyStackTraceEntry *ReversedStack = ReverseStackTrace(SavedStack.get()); for (const PrettyStackTraceEntry *Entry = ReversedStack; Entry; Entry = Entry->getNextEntry()) { OS << ID++ << ".\t"; @@ -68,7 +86,10 @@ static void PrintStack(raw_ostream &OS) { llvm::ReverseStackTrace(ReversedStack); } -/// PrintCurStackTrace - Print the current stack trace to the specified stream. +/// Print the current stack trace to the specified stream. +/// +/// Marked NOINLINE so it can be called from debuggers. +LLVM_ATTRIBUTE_NOINLINE static void PrintCurStackTrace(raw_ostream &OS) { // Don't print an empty trace. if (!PrettyStackTraceHead) return; @@ -128,11 +149,24 @@ static void CrashHandler(void *) { #endif } -// defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES -#endif +static void printForSigInfoIfNeeded() { + unsigned CurrentSigInfoGeneration = + GlobalSigInfoGenerationCounter.load(std::memory_order_relaxed); + if (ThreadLocalSigInfoGenerationCounter == 0 || + ThreadLocalSigInfoGenerationCounter == CurrentSigInfoGeneration) { + return; + } + + PrintCurStackTrace(errs()); + ThreadLocalSigInfoGenerationCounter = CurrentSigInfoGeneration; +} + +#endif // ENABLE_BACKTRACES PrettyStackTraceEntry::PrettyStackTraceEntry() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES + // Handle SIGINFO first, because we haven't finished constructing yet. + printForSigInfoIfNeeded(); // Link ourselves. NextEntry = PrettyStackTraceHead; PrettyStackTraceHead = this; @@ -140,10 +174,12 @@ PrettyStackTraceEntry::PrettyStackTraceEntry() { } PrettyStackTraceEntry::~PrettyStackTraceEntry() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES assert(PrettyStackTraceHead == this && "Pretty stack trace entry destruction is out of order"); PrettyStackTraceHead = NextEntry; + // Handle SIGINFO first, because we already started destructing. + printForSigInfoIfNeeded(); #endif } @@ -175,7 +211,7 @@ void PrettyStackTraceProgram::print(raw_ostream &OS) const { OS << '\n'; } -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES static bool RegisterCrashPrinter() { sys::AddSignalHandler(CrashHandler, nullptr); return false; @@ -183,15 +219,37 @@ static bool RegisterCrashPrinter() { #endif void llvm::EnablePrettyStackTrace() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES // The first time this is called, we register the crash printer. static bool HandlerRegistered = RegisterCrashPrinter(); (void)HandlerRegistered; #endif } +void llvm::EnablePrettyStackTraceOnSigInfoForThisThread(bool ShouldEnable) { +#if ENABLE_BACKTRACES + if (!ShouldEnable) { + ThreadLocalSigInfoGenerationCounter = 0; + return; + } + + // The first time this is called, we register the SIGINFO handler. + static bool HandlerRegistered = []{ + sys::SetInfoSignalFunction([]{ + GlobalSigInfoGenerationCounter.fetch_add(1, std::memory_order_relaxed); + }); + return false; + }(); + (void)HandlerRegistered; + + // Next, enable it for the current thread. + ThreadLocalSigInfoGenerationCounter = + GlobalSigInfoGenerationCounter.load(std::memory_order_relaxed); +#endif +} + const void *llvm::SavePrettyStackState() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES return PrettyStackTraceHead; #else return nullptr; @@ -199,7 +257,7 @@ const void *llvm::SavePrettyStackState() { } void llvm::RestorePrettyStackState(const void *Top) { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES PrettyStackTraceHead = static_cast<PrettyStackTraceEntry *>(const_cast<void *>(Top)); #endif diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp index f32355aefbb7..5b6471008159 100644 --- a/contrib/llvm/lib/Support/Process.cpp +++ b/contrib/llvm/lib/Support/Process.cpp @@ -1,9 +1,8 @@ //===-- Process.cpp - Implement OS Process Concept --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Program.cpp b/contrib/llvm/lib/Support/Program.cpp index 63cdcdaabee9..0a9363c59fc6 100644 --- a/contrib/llvm/lib/Support/Program.cpp +++ b/contrib/llvm/lib/Support/Program.cpp @@ -1,9 +1,8 @@ //===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/RWMutex.cpp b/contrib/llvm/lib/Support/RWMutex.cpp index 8b6d74e49f31..7ce856b716c6 100644 --- a/contrib/llvm/lib/Support/RWMutex.cpp +++ b/contrib/llvm/lib/Support/RWMutex.cpp @@ -1,9 +1,8 @@ //===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/RandomNumberGenerator.cpp b/contrib/llvm/lib/Support/RandomNumberGenerator.cpp index df0d87fab021..09fad1979985 100644 --- a/contrib/llvm/lib/Support/RandomNumberGenerator.cpp +++ b/contrib/llvm/lib/Support/RandomNumberGenerator.cpp @@ -1,9 +1,8 @@ //===-- RandomNumberGenerator.cpp - Implement RNG class -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -27,13 +26,9 @@ using namespace llvm; #define DEBUG_TYPE "rng" -// Tracking BUG: 19665 -// http://llvm.org/bugs/show_bug.cgi?id=19665 -// -// Do not change to cl::opt<uint64_t> since this silently breaks argument parsing. -static cl::opt<unsigned long long> - Seed("rng-seed", cl::value_desc("seed"), cl::Hidden, - cl::desc("Seed for the random number generator"), cl::init(0)); +static cl::opt<uint64_t> Seed("rng-seed", cl::value_desc("seed"), cl::Hidden, + cl::desc("Seed for the random number generator"), + cl::init(0)); RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) { LLVM_DEBUG(if (Seed == 0) dbgs() diff --git a/contrib/llvm/lib/Support/Regex.cpp b/contrib/llvm/lib/Support/Regex.cpp index 48caab131526..4c1b07038024 100644 --- a/contrib/llvm/lib/Support/Regex.cpp +++ b/contrib/llvm/lib/Support/Regex.cpp @@ -1,9 +1,8 @@ //===-- Regex.cpp - Regular Expression matcher implementation -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/SHA1.cpp b/contrib/llvm/lib/Support/SHA1.cpp index 3007a78d5e22..47a5f07fbe7b 100644 --- a/contrib/llvm/lib/Support/SHA1.cpp +++ b/contrib/llvm/lib/Support/SHA1.cpp @@ -1,9 +1,8 @@ //====- SHA1.cpp - Private copy of the SHA1 implementation ---*- C++ -* ======// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/ScaledNumber.cpp b/contrib/llvm/lib/Support/ScaledNumber.cpp index 807c9fa521de..54d4cc33410b 100644 --- a/contrib/llvm/lib/Support/ScaledNumber.cpp +++ b/contrib/llvm/lib/Support/ScaledNumber.cpp @@ -1,9 +1,8 @@ //==- lib/Support/ScaledNumber.cpp - Support for scaled numbers -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Signals.cpp b/contrib/llvm/lib/Support/Signals.cpp index 333f492d4589..173a07f009d2 100644 --- a/contrib/llvm/lib/Support/Signals.cpp +++ b/contrib/llvm/lib/Support/Signals.cpp @@ -1,9 +1,8 @@ //===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -132,8 +131,8 @@ static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, // If we don't know argv0 or the address of main() at this point, try // to guess it anyway (it's possible on some platforms). std::string MainExecutableName = - Argv0.empty() ? sys::fs::getMainExecutable(nullptr, nullptr) - : (std::string)Argv0; + sys::fs::exists(Argv0) ? (std::string)Argv0 + : sys::fs::getMainExecutable(nullptr, nullptr); BumpPtrAllocator Allocator; StringSaver StrPool(Allocator); std::vector<const char *> Modules(Depth, nullptr); diff --git a/contrib/llvm/lib/Support/Signposts.cpp b/contrib/llvm/lib/Support/Signposts.cpp new file mode 100644 index 000000000000..d456f41d2fa6 --- /dev/null +++ b/contrib/llvm/lib/Support/Signposts.cpp @@ -0,0 +1,119 @@ +//===-- Signposts.cpp - Interval debug annotations ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Signposts.h" +#include "llvm/Support/Timer.h" + +#include "llvm/Config/config.h" +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +#include "llvm/ADT/DenseMap.h" +#include <os/signpost.h> +#endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS + +using namespace llvm; + +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +namespace { +os_log_t *LogCreator() { + os_log_t *X = new os_log_t; + *X = os_log_create("org.llvm.signposts", OS_LOG_CATEGORY_POINTS_OF_INTEREST); + return X; +} +void LogDeleter(os_log_t *X) { + os_release(*X); + delete X; +} +} // end anonymous namespace + +namespace llvm { +class SignpostEmitterImpl { + 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; + + LogTy &getLogger() const { return *SignpostLog; } + os_signpost_id_t getSignpostForTimer(const Timer *T) { + const auto &I = Signposts.find(T); + if (I != Signposts.end()) + return I->second; + + const auto &Inserted = Signposts.insert( + std::make_pair(T, os_signpost_id_make_with_pointer(getLogger(), T))); + return Inserted.first->second; + } + +public: + SignpostEmitterImpl() : SignpostLog(LogCreator(), LogDeleter), Signposts() {} + + bool isEnabled() const { return os_signpost_enabled(*SignpostLog); } + + void startTimerInterval(Timer *T) { + 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()); + } + } + + void endTimerInterval(Timer *T) { + 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()); + } + } +}; +} // end namespace llvm +#endif // if LLVM_SUPPORT_XCODE_SIGNPOSTS + +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +#define HAVE_ANY_SIGNPOST_IMPL 1 +#endif + +SignpostEmitter::SignpostEmitter() { +#if HAVE_ANY_SIGNPOST_IMPL + Impl = new SignpostEmitterImpl(); +#else // if HAVE_ANY_SIGNPOST_IMPL + Impl = nullptr; +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} + +SignpostEmitter::~SignpostEmitter() { +#if HAVE_ANY_SIGNPOST_IMPL + delete Impl; +#endif // if HAVE_ANY_SIGNPOST_IMPL +} + +bool SignpostEmitter::isEnabled() const { +#if HAVE_ANY_SIGNPOST_IMPL + return Impl->isEnabled(); +#else + return false; +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} + +void SignpostEmitter::startTimerInterval(Timer *T) { +#if HAVE_ANY_SIGNPOST_IMPL + if (Impl == nullptr) + return; + return Impl->startTimerInterval(T); +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} + +void SignpostEmitter::endTimerInterval(Timer *T) { +#if HAVE_ANY_SIGNPOST_IMPL + if (Impl == nullptr) + return; + Impl->endTimerInterval(T); +#endif // if !HAVE_ANY_SIGNPOST_IMPL +} diff --git a/contrib/llvm/lib/Support/SmallPtrSet.cpp b/contrib/llvm/lib/Support/SmallPtrSet.cpp index fed4a17d6635..f60464c8e756 100644 --- a/contrib/llvm/lib/Support/SmallPtrSet.cpp +++ b/contrib/llvm/lib/Support/SmallPtrSet.cpp @@ -1,9 +1,8 @@ //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/SmallVector.cpp b/contrib/llvm/lib/Support/SmallVector.cpp index 1070c6672edc..36f0a81f6b00 100644 --- a/contrib/llvm/lib/Support/SmallVector.cpp +++ b/contrib/llvm/lib/Support/SmallVector.cpp @@ -1,9 +1,8 @@ //===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm/lib/Support/SourceMgr.cpp index a55ad881d012..2a241f18c362 100644 --- a/contrib/llvm/lib/Support/SourceMgr.cpp +++ b/contrib/llvm/lib/Support/SourceMgr.cpp @@ -1,9 +1,8 @@ //===- SourceMgr.cpp - Manager for Simple Source Buffers & Diagnostics ----===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -96,14 +95,9 @@ unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const { assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max()); T PtrOffset = static_cast<T>(PtrDiff); - // std::lower_bound returns the first EOL offset that's not-less-than - // PtrOffset, meaning the EOL that _ends the line_ that PtrOffset is on - // (including if PtrOffset refers to the EOL itself). If there's no such - // EOL, returns end(). - auto EOL = std::lower_bound(Offsets->begin(), Offsets->end(), PtrOffset); - - // Lines count from 1, so add 1 to the distance from the 0th line. - return (1 + (EOL - Offsets->begin())); + // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get + // the line number. + return llvm::lower_bound(*Offsets, PtrOffset) - Offsets->begin() + 1; } SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other) diff --git a/contrib/llvm/lib/Support/SpecialCaseList.cpp b/contrib/llvm/lib/Support/SpecialCaseList.cpp index bf807e66e02c..96e09f9552bb 100644 --- a/contrib/llvm/lib/Support/SpecialCaseList.cpp +++ b/contrib/llvm/lib/Support/SpecialCaseList.cpp @@ -1,9 +1,8 @@ //===-- SpecialCaseList.cpp - special case list for sanitizers ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Statistic.cpp b/contrib/llvm/lib/Support/Statistic.cpp index d57300a75d1d..e4f0535d21aa 100644 --- a/contrib/llvm/lib/Support/Statistic.cpp +++ b/contrib/llvm/lib/Support/Statistic.cpp @@ -1,9 +1,8 @@ //===-- Statistic.cpp - Easy way to expose stats information --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -136,8 +135,7 @@ bool llvm::AreStatisticsEnabled() { } void StatisticInfo::sort() { - std::stable_sort(Stats.begin(), Stats.end(), - [](const Statistic *LHS, const Statistic *RHS) { + llvm::stable_sort(Stats, [](const Statistic *LHS, const Statistic *RHS) { if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType())) return Cmp < 0; diff --git a/contrib/llvm/lib/Support/StringExtras.cpp b/contrib/llvm/lib/Support/StringExtras.cpp index 386d74a47983..bf28b2be5657 100644 --- a/contrib/llvm/lib/Support/StringExtras.cpp +++ b/contrib/llvm/lib/Support/StringExtras.cpp @@ -1,9 +1,8 @@ //===-- StringExtras.cpp - Implement the StringExtras header --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/StringMap.cpp b/contrib/llvm/lib/Support/StringMap.cpp index c1f707ce50a5..6b5ea020dd46 100644 --- a/contrib/llvm/lib/Support/StringMap.cpp +++ b/contrib/llvm/lib/Support/StringMap.cpp @@ -1,9 +1,8 @@ //===--- StringMap.cpp - String Hash table map implementation -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/StringPool.cpp b/contrib/llvm/lib/Support/StringPool.cpp index c591857c415d..82351017b8cc 100644 --- a/contrib/llvm/lib/Support/StringPool.cpp +++ b/contrib/llvm/lib/Support/StringPool.cpp @@ -1,9 +1,8 @@ //===-- StringPool.cpp - Interned string pool -----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/StringRef.cpp b/contrib/llvm/lib/Support/StringRef.cpp index f0349260e22f..4bafc4ec7181 100644 --- a/contrib/llvm/lib/Support/StringRef.cpp +++ b/contrib/llvm/lib/Support/StringRef.cpp @@ -1,9 +1,8 @@ //===-- StringRef.cpp - Lightweight String References ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/StringSaver.cpp b/contrib/llvm/lib/Support/StringSaver.cpp index bf0ac8de9821..f7ccfb97ea79 100644 --- a/contrib/llvm/lib/Support/StringSaver.cpp +++ b/contrib/llvm/lib/Support/StringSaver.cpp @@ -1,9 +1,8 @@ //===-- StringSaver.cpp ---------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/SymbolRemappingReader.cpp b/contrib/llvm/lib/Support/SymbolRemappingReader.cpp index 264c890ce8f1..1caf0947216e 100644 --- a/contrib/llvm/lib/Support/SymbolRemappingReader.cpp +++ b/contrib/llvm/lib/Support/SymbolRemappingReader.cpp @@ -1,9 +1,8 @@ //===- SymbolRemappingReader.cpp - Read symbol remapping file -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/SystemUtils.cpp b/contrib/llvm/lib/Support/SystemUtils.cpp index 7fa6ae3f6199..47e0c72ec7c1 100644 --- a/contrib/llvm/lib/Support/SystemUtils.cpp +++ b/contrib/llvm/lib/Support/SystemUtils.cpp @@ -1,9 +1,8 @@ //===- SystemUtils.cpp - Utilities for low-level system tasks -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/TarWriter.cpp b/contrib/llvm/lib/Support/TarWriter.cpp index 5b4d554befe4..6136e9219767 100644 --- a/contrib/llvm/lib/Support/TarWriter.cpp +++ b/contrib/llvm/lib/Support/TarWriter.cpp @@ -1,9 +1,8 @@ //===-- TarWriter.cpp - Tar archive file creator --------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/TargetParser.cpp b/contrib/llvm/lib/Support/TargetParser.cpp index bdc0dc52c5e2..d213b9a8c6af 100644 --- a/contrib/llvm/lib/Support/TargetParser.cpp +++ b/contrib/llvm/lib/Support/TargetParser.cpp @@ -1,9 +1,8 @@ //===-- TargetParser - Parser for target features ---------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -63,7 +62,7 @@ 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[33] = { +constexpr GPUInfo AMDGCNGPUs[37] = { // Name Canonical Kind Features // Name {{"gfx600"}, {"gfx600"}, GK_GFX600, FEATURE_FAST_FMA_F32}, @@ -98,7 +97,11 @@ constexpr GPUInfo AMDGCNGPUs[33] = { {{"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}, + {{"gfx1011"}, {"gfx1011"}, GK_GFX1011, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, + {{"gfx1012"}, {"gfx1012"}, GK_GFX1012, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32}, }; const GPUInfo *getArchEntry(AMDGPU::GPUKind AK, ArrayRef<GPUInfo> Table) { @@ -170,30 +173,36 @@ void AMDGPU::fillValidArchListR600(SmallVectorImpl<StringRef> &Values) { } AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) { - if (GPU == "generic") - return {7, 0, 0}; - AMDGPU::GPUKind AK = parseArchAMDGCN(GPU); - if (AK == AMDGPU::GPUKind::GK_NONE) + if (AK == AMDGPU::GPUKind::GK_NONE) { + if (GPU == "generic-hsa") + return {7, 0, 0}; + if (GPU == "generic") + return {6, 0, 0}; return {0, 0, 0}; + } switch (AK) { - case GK_GFX600: return {6, 0, 0}; - case GK_GFX601: return {6, 0, 1}; - 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_GFX801: return {8, 0, 1}; - case GK_GFX802: return {8, 0, 2}; - case GK_GFX803: return {8, 0, 3}; - case GK_GFX810: return {8, 1, 0}; - case GK_GFX900: return {9, 0, 0}; - case GK_GFX902: return {9, 0, 2}; - case GK_GFX904: return {9, 0, 4}; - case GK_GFX906: return {9, 0, 6}; - case GK_GFX909: return {9, 0, 9}; - default: return {0, 0, 0}; + case GK_GFX600: return {6, 0, 0}; + case GK_GFX601: return {6, 0, 1}; + 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_GFX801: return {8, 0, 1}; + case GK_GFX802: return {8, 0, 2}; + case GK_GFX803: return {8, 0, 3}; + case GK_GFX810: return {8, 1, 0}; + case GK_GFX900: return {9, 0, 0}; + case GK_GFX902: return {9, 0, 2}; + case GK_GFX904: return {9, 0, 4}; + case GK_GFX906: return {9, 0, 6}; + case GK_GFX908: return {9, 0, 8}; + case GK_GFX909: return {9, 0, 9}; + case GK_GFX1010: return {10, 1, 0}; + case GK_GFX1011: return {10, 1, 1}; + case GK_GFX1012: return {10, 1, 2}; + default: return {0, 0, 0}; } } diff --git a/contrib/llvm/lib/Support/TargetRegistry.cpp b/contrib/llvm/lib/Support/TargetRegistry.cpp index bb63891cd713..1f9c3bbf8229 100644 --- a/contrib/llvm/lib/Support/TargetRegistry.cpp +++ b/contrib/llvm/lib/Support/TargetRegistry.cpp @@ -1,9 +1,8 @@ //===--- TargetRegistry.cpp - Target registration -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/ThreadLocal.cpp b/contrib/llvm/lib/Support/ThreadLocal.cpp index f6e4a652302c..44e6223cf17b 100644 --- a/contrib/llvm/lib/Support/ThreadLocal.cpp +++ b/contrib/llvm/lib/Support/ThreadLocal.cpp @@ -1,9 +1,8 @@ //===- ThreadLocal.cpp - Thread Local Data ----------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/ThreadPool.cpp b/contrib/llvm/lib/Support/ThreadPool.cpp index d0212ca13467..40982d777914 100644 --- a/contrib/llvm/lib/Support/ThreadPool.cpp +++ b/contrib/llvm/lib/Support/ThreadPool.cpp @@ -1,9 +1,8 @@ //==-- llvm/Support/ThreadPool.cpp - A ThreadPool implementation -*- C++ -*-==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Threading.cpp b/contrib/llvm/lib/Support/Threading.cpp index fcb1030e1ab4..e5899a60f4db 100644 --- a/contrib/llvm/lib/Support/Threading.cpp +++ b/contrib/llvm/lib/Support/Threading.cpp @@ -1,9 +1,8 @@ //===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/TimeProfiler.cpp b/contrib/llvm/lib/Support/TimeProfiler.cpp new file mode 100644 index 000000000000..bc2340815645 --- /dev/null +++ b/contrib/llvm/lib/Support/TimeProfiler.cpp @@ -0,0 +1,199 @@ +//===-- TimeProfiler.cpp - Hierarchical Time Profiler ---------------------===// +// +// 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 hierarchical time profiler. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TimeProfiler.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/JSON.h" +#include <cassert> +#include <chrono> +#include <string> +#include <vector> + +using namespace std::chrono; + +namespace llvm { + +static cl::opt<unsigned> TimeTraceGranularity( + "time-trace-granularity", + cl::desc( + "Minimum time granularity (in microseconds) traced by time profiler"), + cl::init(500)); + +TimeTraceProfiler *TimeTraceProfilerInstance = nullptr; + +typedef duration<steady_clock::rep, steady_clock::period> DurationType; +typedef std::pair<size_t, DurationType> CountAndDurationType; +typedef std::pair<std::string, CountAndDurationType> + NameAndCountAndDurationType; + +struct Entry { + time_point<steady_clock> Start; + DurationType Duration; + std::string Name; + std::string Detail; + + Entry(time_point<steady_clock> &&S, DurationType &&D, std::string &&N, + std::string &&Dt) + : Start(std::move(S)), Duration(std::move(D)), Name(std::move(N)), + Detail(std::move(Dt)){}; +}; + +struct TimeTraceProfiler { + TimeTraceProfiler() { + StartTime = steady_clock::now(); + } + + void begin(std::string Name, llvm::function_ref<std::string()> Detail) { + Stack.emplace_back(steady_clock::now(), DurationType{}, std::move(Name), + Detail()); + } + + void end() { + assert(!Stack.empty() && "Must call begin() first"); + auto &E = Stack.back(); + E.Duration = steady_clock::now() - E.Start; + + // Only include sections longer than TimeTraceGranularity msec. + if (duration_cast<microseconds>(E.Duration).count() > TimeTraceGranularity) + Entries.emplace_back(E); + + // Track total time taken by each "name", but only the topmost levels of + // them; e.g. if there's a template instantiation that instantiates other + // templates from within, we only want to add the topmost one. "topmost" + // happens to be the ones that don't have any currently open entries above + // itself. + if (std::find_if(++Stack.rbegin(), Stack.rend(), [&](const Entry &Val) { + return Val.Name == E.Name; + }) == Stack.rend()) { + auto &CountAndTotal = CountAndTotalPerName[E.Name]; + CountAndTotal.first++; + CountAndTotal.second += E.Duration; + } + + Stack.pop_back(); + } + + void Write(raw_pwrite_stream &OS) { + assert(Stack.empty() && + "All profiler sections should be ended when calling Write"); + json::OStream J(OS); + J.objectBegin(); + J.attributeBegin("traceEvents"); + J.arrayBegin(); + + // Emit all events for the main flame graph. + for (const auto &E : Entries) { + auto StartUs = duration_cast<microseconds>(E.Start - StartTime).count(); + auto DurUs = duration_cast<microseconds>(E.Duration).count(); + + J.object([&]{ + J.attribute("pid", 1); + J.attribute("tid", 0); + J.attribute("ph", "X"); + J.attribute("ts", StartUs); + J.attribute("dur", DurUs); + J.attribute("name", E.Name); + J.attributeObject("args", [&] { J.attribute("detail", E.Detail); }); + }); + } + + // Emit totals by section name as additional "thread" events, sorted from + // longest one. + int Tid = 1; + std::vector<NameAndCountAndDurationType> SortedTotals; + SortedTotals.reserve(CountAndTotalPerName.size()); + for (const auto &E : CountAndTotalPerName) + SortedTotals.emplace_back(E.getKey(), E.getValue()); + + llvm::sort(SortedTotals.begin(), SortedTotals.end(), + [](const NameAndCountAndDurationType &A, + const NameAndCountAndDurationType &B) { + return A.second.second > B.second.second; + }); + for (const auto &E : SortedTotals) { + auto DurUs = duration_cast<microseconds>(E.second.second).count(); + auto Count = CountAndTotalPerName[E.first].first; + + J.object([&]{ + J.attribute("pid", 1); + J.attribute("tid", Tid); + J.attribute("ph", "X"); + J.attribute("ts", 0); + J.attribute("dur", DurUs); + J.attribute("name", "Total " + E.first); + J.attributeObject("args", [&] { + J.attribute("count", int64_t(Count)); + J.attribute("avg ms", int64_t(DurUs / Count / 1000)); + }); + }); + + ++Tid; + } + + // Emit metadata event with process name. + J.object([&] { + J.attribute("cat", ""); + J.attribute("pid", 1); + J.attribute("tid", 0); + J.attribute("ts", 0); + J.attribute("ph", "M"); + J.attribute("name", "process_name"); + J.attributeObject("args", [&] { J.attribute("name", "clang"); }); + }); + + J.arrayEnd(); + J.attributeEnd(); + J.objectEnd(); + } + + SmallVector<Entry, 16> Stack; + SmallVector<Entry, 128> Entries; + StringMap<CountAndDurationType> CountAndTotalPerName; + time_point<steady_clock> StartTime; +}; + +void timeTraceProfilerInitialize() { + assert(TimeTraceProfilerInstance == nullptr && + "Profiler should not be initialized"); + TimeTraceProfilerInstance = new TimeTraceProfiler(); +} + +void timeTraceProfilerCleanup() { + delete TimeTraceProfilerInstance; + TimeTraceProfilerInstance = nullptr; +} + +void timeTraceProfilerWrite(raw_pwrite_stream &OS) { + assert(TimeTraceProfilerInstance != nullptr && + "Profiler object can't be null"); + TimeTraceProfilerInstance->Write(OS); +} + +void timeTraceProfilerBegin(StringRef Name, StringRef Detail) { + if (TimeTraceProfilerInstance != nullptr) + TimeTraceProfilerInstance->begin(Name, [&]() { return Detail; }); +} + +void timeTraceProfilerBegin(StringRef Name, + llvm::function_ref<std::string()> Detail) { + if (TimeTraceProfilerInstance != nullptr) + TimeTraceProfilerInstance->begin(Name, Detail); +} + +void timeTraceProfilerEnd() { + if (TimeTraceProfilerInstance != nullptr) + TimeTraceProfilerInstance->end(); +} + +} // namespace llvm diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp index 82f5810dd107..2a7ff1eaaf63 100644 --- a/contrib/llvm/lib/Support/Timer.cpp +++ b/contrib/llvm/lib/Support/Timer.cpp @@ -1,9 +1,8 @@ //===-- Timer.cpp - Interval Timing Support -------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -20,6 +19,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Signposts.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include <limits> @@ -40,6 +40,9 @@ static std::string &getLibSupportInfoOutputFilename() { static ManagedStatic<sys::SmartMutex<true> > TimerLock; +/// Allows llvm::Timer to emit signposts when supported. +static ManagedStatic<SignpostEmitter> Signposts; + namespace { static cl::opt<bool> TrackSpace("track-memory", cl::desc("Enable -time-passes memory " @@ -134,6 +137,7 @@ TimeRecord TimeRecord::getCurrentTime(bool Start) { void Timer::startTimer() { assert(!Running && "Cannot start a running timer"); Running = Triggered = true; + Signposts->startTimerInterval(this); StartTime = TimeRecord::getCurrentTime(true); } @@ -142,6 +146,7 @@ void Timer::stopTimer() { Running = false; Time += TimeRecord::getCurrentTime(false); Time -= StartTime; + Signposts->endTimerInterval(this); } void Timer::clear() { @@ -342,7 +347,7 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { TimersToPrint.clear(); } -void TimerGroup::prepareToPrintList() { +void TimerGroup::prepareToPrintList(bool ResetTime) { // See if any of our timers were started, if so add them to TimersToPrint. for (Timer *T = FirstTimer; T; T = T->Next) { if (!T->hasTriggered()) continue; @@ -352,15 +357,20 @@ void TimerGroup::prepareToPrintList() { TimersToPrint.emplace_back(T->Time, T->Name, T->Description); + if (ResetTime) + T->clear(); + if (WasRunning) T->startTimer(); } } -void TimerGroup::print(raw_ostream &OS) { - sys::SmartScopedLock<true> L(*TimerLock); - - prepareToPrintList(); +void TimerGroup::print(raw_ostream &OS, bool ResetAfterPrint) { + { + // After preparing the timers we can free the lock + sys::SmartScopedLock<true> L(*TimerLock); + prepareToPrintList(ResetAfterPrint); + } // If any timers were started, print the group. if (!TimersToPrint.empty()) @@ -400,7 +410,7 @@ void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R, const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) { sys::SmartScopedLock<true> L(*TimerLock); - prepareToPrintList(); + prepareToPrintList(false); for (const PrintRecord &R : TimersToPrint) { OS << delim; delim = ",\n"; diff --git a/contrib/llvm/lib/Support/ToolOutputFile.cpp b/contrib/llvm/lib/Support/ToolOutputFile.cpp index e12d9e824f7e..ed3a247f0115 100644 --- a/contrib/llvm/lib/Support/ToolOutputFile.cpp +++ b/contrib/llvm/lib/Support/ToolOutputFile.cpp @@ -1,9 +1,8 @@ //===--- ToolOutputFile.cpp - Implement the ToolOutputFile class --------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/TrigramIndex.cpp b/contrib/llvm/lib/Support/TrigramIndex.cpp index 721763c88525..94810b56db8e 100644 --- a/contrib/llvm/lib/Support/TrigramIndex.cpp +++ b/contrib/llvm/lib/Support/TrigramIndex.cpp @@ -1,9 +1,8 @@ //===-- TrigramIndex.cpp - a heuristic for SpecialCaseList ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp index 26d9327f6208..d419463e6a5e 100644 --- a/contrib/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -1,9 +1,8 @@ //===--- Triple.cpp - Target triple helper class --------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -23,6 +22,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case aarch64: return "aarch64"; case aarch64_be: return "aarch64_be"; + case aarch64_32: return "aarch64_32"; case arm: return "arm"; case armeb: return "armeb"; case arc: return "arc"; @@ -81,7 +81,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { return StringRef(); case aarch64: - case aarch64_be: return "aarch64"; + case aarch64_be: + case aarch64_32: return "aarch64"; case arc: return "arc"; @@ -209,6 +210,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { case HermitCore: return "hermit"; case Hurd: return "hurd"; case WASI: return "wasi"; + case Emscripten: return "emscripten"; } llvm_unreachable("Invalid OSType"); @@ -226,6 +228,8 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case CODE16: return "code16"; case EABI: return "eabi"; case EABIHF: return "eabihf"; + case ELFv1: return "elfv1"; + case ELFv2: return "elfv2"; case Android: return "android"; case Musl: return "musl"; case MuslEABI: return "musleabi"; @@ -235,6 +239,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case Cygnus: return "cygnus"; case CoreCLR: return "coreclr"; case Simulator: return "simulator"; + case MacABI: return "macabi"; } llvm_unreachable("Invalid EnvironmentType!"); @@ -260,8 +265,10 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { return StringSwitch<Triple::ArchType>(Name) .Case("aarch64", aarch64) .Case("aarch64_be", aarch64_be) + .Case("aarch64_32", aarch64_32) .Case("arc", arc) .Case("arm64", aarch64) // "arm64" is an alias for "aarch64" + .Case("arm64_32", aarch64_32) .Case("arm", arm) .Case("armeb", armeb) .Case("avr", avr) @@ -389,8 +396,10 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("xscaleeb", Triple::armeb) .Case("aarch64", Triple::aarch64) .Case("aarch64_be", Triple::aarch64_be) + .Case("aarch64_32", Triple::aarch64_32) .Case("arc", Triple::arc) .Case("arm64", Triple::aarch64) + .Case("arm64_32", Triple::aarch64_32) .Case("arm", Triple::arm) .Case("armeb", Triple::armeb) .Case("thumb", Triple::thumb) @@ -507,6 +516,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("hermit", Triple::HermitCore) .StartsWith("hurd", Triple::Hurd) .StartsWith("wasi", Triple::WASI) + .StartsWith("emscripten", Triple::Emscripten) .Default(Triple::UnknownOS); } @@ -514,6 +524,8 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { return StringSwitch<Triple::EnvironmentType>(EnvironmentName) .StartsWith("eabihf", Triple::EABIHF) .StartsWith("eabi", Triple::EABI) + .StartsWith("elfv1", Triple::ELFv1) + .StartsWith("elfv2", Triple::ELFv2) .StartsWith("gnuabin32", Triple::GNUABIN32) .StartsWith("gnuabi64", Triple::GNUABI64) .StartsWith("gnueabihf", Triple::GNUEABIHF) @@ -530,11 +542,15 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) { .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) { return StringSwitch<Triple::ObjectFormatType>(EnvironmentName) + // "xcoff" must come before "coff" because of the order-dependendent + // pattern matching. + .EndsWith("xcoff", Triple::XCOFF) .EndsWith("coff", Triple::COFF) .EndsWith("elf", Triple::ELF) .EndsWith("macho", Triple::MachO) @@ -611,6 +627,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { return Triple::ARMSubArch_v8m_baseline; case ARM::ArchKind::ARMV8MMainline: return Triple::ARMSubArch_v8m_mainline; + case ARM::ArchKind::ARMV8_1MMainline: + return Triple::ARMSubArch_v8_1m_mainline; default: return Triple::NoSubArch; } @@ -623,6 +641,7 @@ static StringRef getObjectFormatTypeName(Triple::ObjectFormatType Kind) { case Triple::ELF: return "elf"; case Triple::MachO: return "macho"; case Triple::Wasm: return "wasm"; + case Triple::XCOFF: return "xcoff"; } llvm_unreachable("unknown object format type"); } @@ -631,6 +650,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { switch (T.getArch()) { case Triple::UnknownArch: case Triple::aarch64: + case Triple::aarch64_32: case Triple::arm: case Triple::thumb: case Triple::x86: @@ -687,6 +707,8 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::ppc64: if (T.isOSDarwin()) return Triple::MachO; + else if (T.isOSAIX()) + return Triple::XCOFF; return Triple::ELF; case Triple::wasm32: @@ -1212,6 +1234,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::msp430: return 16; + case llvm::Triple::aarch64_32: case llvm::Triple::arc: case llvm::Triple::arm: case llvm::Triple::armeb: @@ -1292,6 +1315,7 @@ Triple Triple::get32BitArchVariant() const { T.setArch(UnknownArch); break; + case Triple::aarch64_32: case Triple::amdil: case Triple::hsail: case Triple::spir: @@ -1383,6 +1407,7 @@ Triple Triple::get64BitArchVariant() const { // Already 64-bit. break; + case Triple::aarch64_32: T.setArch(Triple::aarch64); break; case Triple::arm: T.setArch(Triple::aarch64); break; case Triple::armeb: T.setArch(Triple::aarch64_be); break; case Triple::le32: T.setArch(Triple::le64); break; @@ -1493,6 +1518,7 @@ Triple Triple::getLittleEndianArchVariant() const { bool Triple::isLittleEndian() const { switch (getArch()) { case Triple::aarch64: + case Triple::aarch64_32: case Triple::amdgcn: case Triple::amdil64: case Triple::amdil: diff --git a/contrib/llvm/lib/Support/Twine.cpp b/contrib/llvm/lib/Support/Twine.cpp index 4726c8ab7494..fbbcd8848f1c 100644 --- a/contrib/llvm/lib/Support/Twine.cpp +++ b/contrib/llvm/lib/Support/Twine.cpp @@ -1,9 +1,8 @@ //===-- Twine.cpp - Fast Temporary String Concatenation -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/Unicode.cpp b/contrib/llvm/lib/Support/Unicode.cpp index b719bd826dc1..4d195069682b 100644 --- a/contrib/llvm/lib/Support/Unicode.cpp +++ b/contrib/llvm/lib/Support/Unicode.cpp @@ -1,9 +1,8 @@ //===- llvm/Support/Unicode.cpp - Unicode character properties -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Unix/COM.inc b/contrib/llvm/lib/Support/Unix/COM.inc index 5b71de74ebf3..03a690ac3766 100644 --- a/contrib/llvm/lib/Support/Unix/COM.inc +++ b/contrib/llvm/lib/Support/Unix/COM.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Unix/COM.inc - Unix COM Implementation -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc b/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc index 029451f347e8..a2a379963de0 100644 --- a/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc @@ -1,9 +1,8 @@ //===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc index b65f84bf4444..17d78dc18be7 100644 --- a/contrib/llvm/lib/Support/Unix/Host.inc +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -50,6 +49,23 @@ static std::string updateTripleOSVersion(std::string TargetTripleString) { TargetTripleString += "-darwin"; TargetTripleString += getOSVersion(); } + // On AIX, the AIX version and release should be that of the current host + // unless if the version has already been specified. + if (Triple(LLVM_HOST_TRIPLE).getOS() == Triple::AIX) { + Triple TT(TargetTripleString); + if (TT.getOS() == Triple::AIX && !TT.getOSMajorVersion()) { + struct utsname name; + if (uname(&name) != -1) { + std::string NewOSName = Triple::getOSTypeName(Triple::AIX); + NewOSName += name.version; + NewOSName += '.'; + NewOSName += name.release; + NewOSName += ".0.0"; + TT.setOSName(NewOSName); + return TT.str(); + } + } + } return TargetTripleString; } diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index adbfff2f59a5..a0927da50e48 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -1,9 +1,8 @@ //===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -46,7 +45,7 @@ extern "C" void __clear_cache(void *, void*); namespace { int getPosixProtectionFlags(unsigned Flags) { - switch (Flags) { + switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { case llvm::sys::Memory::MF_READ: return PROT_READ; case llvm::sys::Memory::MF_WRITE: @@ -59,14 +58,13 @@ int getPosixProtectionFlags(unsigned Flags) { llvm::sys::Memory::MF_EXEC: return PROT_READ | PROT_WRITE | PROT_EXEC; case llvm::sys::Memory::MF_EXEC: -#if defined(__FreeBSD__) +#if (defined(__FreeBSD__) || defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) // On PowerPC, having an executable page that has no read permission // can have unintended consequences. The function InvalidateInstruction- // Cache uses instructions dcbf and icbi, both of which are treated by // the processor as loads. If the page has no read permissions, // executing these instructions will result in a segmentation fault. - // Somehow, this problem is not present on Linux, but it does happen - // on FreeBSD. return PROT_READ | PROT_EXEC; #else return PROT_EXEC; @@ -92,19 +90,24 @@ Memory::allocateMappedMemory(size_t NumBytes, if (NumBytes == 0) return MemoryBlock(); - static const size_t PageSize = Process::getPageSize(); - const size_t NumPages = (NumBytes+PageSize-1)/PageSize; - - int fd = -1; - - int MMFlags = MAP_PRIVATE | -#ifdef MAP_ANONYMOUS - MAP_ANONYMOUS + // On platforms that have it, we can use MAP_ANON to get a memory-mapped + // page without file backing, but we need a fallback of opening /dev/zero + // for strictly POSIX platforms instead. + int fd; +#if defined(MAP_ANON) + fd = -1; #else - MAP_ANON + fd = open("/dev/zero", O_RDWR); + if (fd == -1) { + EC = std::error_code(errno, std::generic_category()); + return MemoryBlock(); + } #endif - ; // Ends statement above + int MMFlags = MAP_PRIVATE; +#if defined(MAP_ANON) + MMFlags |= MAP_ANON; +#endif int Protect = getPosixProtectionFlags(PFlags); #if defined(__NetBSD__) && defined(PROT_MPROTECT) @@ -113,23 +116,39 @@ Memory::allocateMappedMemory(size_t NumBytes, // Use any near hint and the page size to set a page-aligned starting address uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + - NearBlock->size() : 0; + NearBlock->allocatedSize() : 0; + static const size_t PageSize = Process::getPageSizeEstimate(); + const size_t NumPages = (NumBytes+PageSize-1)/PageSize; + if (Start && Start % PageSize) Start += PageSize - Start % PageSize; - void *Addr = ::mmap(reinterpret_cast<void*>(Start), PageSize*NumPages, - Protect, MMFlags, fd, 0); + // FIXME: Handle huge page requests (MF_HUGE_HINT). + void *Addr = ::mmap(reinterpret_cast<void *>(Start), PageSize*NumPages, Protect, + MMFlags, fd, 0); if (Addr == MAP_FAILED) { - if (NearBlock) //Try again without a near hint + if (NearBlock) { //Try again without a near hint +#if !defined(MAP_ANON) + close(fd); +#endif return allocateMappedMemory(NumBytes, nullptr, PFlags, EC); + } EC = std::error_code(errno, std::generic_category()); +#if !defined(MAP_ANON) + close(fd); +#endif return MemoryBlock(); } +#if !defined(MAP_ANON) + close(fd); +#endif + MemoryBlock Result; Result.Address = Addr; - Result.Size = NumPages*PageSize; + Result.AllocatedSize = PageSize*NumPages; + Result.Flags = PFlags; // Rely on protectMappedMemory to invalidate instruction cache. if (PFlags & MF_EXEC) { @@ -143,22 +162,22 @@ Memory::allocateMappedMemory(size_t NumBytes, std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { - if (M.Address == nullptr || M.Size == 0) + if (M.Address == nullptr || M.AllocatedSize == 0) return std::error_code(); - if (0 != ::munmap(M.Address, M.Size)) + if (0 != ::munmap(M.Address, M.AllocatedSize)) return std::error_code(errno, std::generic_category()); M.Address = nullptr; - M.Size = 0; + M.AllocatedSize = 0; return std::error_code(); } std::error_code Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { - static const size_t PageSize = Process::getPageSize(); - if (M.Address == nullptr || M.Size == 0) + static const size_t PageSize = Process::getPageSizeEstimate(); + if (M.Address == nullptr || M.AllocatedSize == 0) return std::error_code(); if (!Flags) @@ -166,7 +185,7 @@ Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { int Protect = getPosixProtectionFlags(Flags); uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize); - uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, PageSize); + uintptr_t End = alignAddr((uint8_t *)M.Address + M.AllocatedSize, PageSize); bool InvalidateCache = (Flags & MF_EXEC); @@ -179,7 +198,7 @@ Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { if (Result != 0) return std::error_code(errno, std::generic_category()); - Memory::InvalidateInstructionCache(M.Address, M.Size); + Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); InvalidateCache = false; } #endif @@ -190,7 +209,7 @@ Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { return std::error_code(errno, std::generic_category()); if (InvalidateCache) - Memory::InvalidateInstructionCache(M.Address, M.Size); + Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); return std::error_code(); } diff --git a/contrib/llvm/lib/Support/Unix/Mutex.inc b/contrib/llvm/lib/Support/Unix/Mutex.inc index fe6b17041457..2c982b38d6ff 100644 --- a/contrib/llvm/lib/Support/Unix/Mutex.inc +++ b/contrib/llvm/lib/Support/Unix/Mutex.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index d7cc0d627d09..e80880c6b3cb 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -38,6 +37,7 @@ #ifdef __APPLE__ #include <mach-o/dyld.h> #include <sys/attr.h> +#include <copyfile.h> #elif defined(__DragonFly__) #include <sys/mount.h> #endif @@ -56,7 +56,7 @@ #include <sys/types.h> #if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \ - !defined(__linux__) && !defined(__FreeBSD_kernel__) + !defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(_AIX) #include <sys/statvfs.h> #define STATVFS statvfs #define FSTATVFS fstatvfs @@ -77,6 +77,14 @@ #endif #endif #include <sys/vfs.h> +#elif defined(_AIX) +#include <sys/statfs.h> + +// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to +// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide +// the typedef prior to including <sys/vmount.h> to work around this issue. +typedef uint_t uint; +#include <sys/vmount.h> #else #include <sys/mount.h> #endif @@ -108,7 +116,11 @@ test_dir(char ret[PATH_MAX], const char *dir, const char *bin) struct stat sb; char fullpath[PATH_MAX]; - snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin); + int chars = snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin); + // We cannot write PATH_MAX characters because the string will be terminated + // with a null character. Fail if truncation happened. + if (chars >= PATH_MAX) + return 1; if (!realpath(fullpath, ret)) return 1; if (stat(fullpath, &sb) != 0) @@ -120,8 +132,6 @@ test_dir(char ret[PATH_MAX], const char *dir, const char *bin) static char * getprogpath(char ret[PATH_MAX], const char *bin) { - char *pv, *s, *t; - /* First approach: absolute path. */ if (bin[0] == '/') { if (test_dir(ret, "/", bin) == 0) @@ -140,18 +150,21 @@ getprogpath(char ret[PATH_MAX], const char *bin) } /* Third approach: $PATH */ + char *pv; if ((pv = getenv("PATH")) == nullptr) return nullptr; - s = pv = strdup(pv); - if (!pv) + char *s = strdup(pv); + if (!s) return nullptr; - while ((t = strsep(&s, ":")) != nullptr) { + char *state; + for (char *t = strtok_r(s, ":", &state); t != nullptr; + t = strtok_r(nullptr, ":", &state)) { if (test_dir(ret, t, bin) == 0) { - free(pv); + free(s); return ret; } } - free(pv); + free(s); return nullptr; } #endif // __FreeBSD__ || __NetBSD__ || __FreeBSD_kernel__ @@ -173,8 +186,21 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__minix) || defined(__DragonFly__) || \ defined(__FreeBSD_kernel__) || defined(_AIX) + StringRef curproc("/proc/curproc/file"); char exe_path[PATH_MAX]; - + // /proc is not mounted by default under FreeBSD, but gives more accurate + // information than argv[0] when it is. + if (sys::fs::exists(curproc)) { + ssize_t len = readlink(curproc.str().c_str(), exe_path, sizeof(exe_path)); + if (len > 0) { + // Null terminate the string for realpath. readlink never null + // terminates its output. + len = std::min(len, ssize_t(sizeof(exe_path) - 1)); + exe_path[len] = '\0'; + return exe_path; + } + } + // If we don't have procfs mounted, fall back to argv[0] if (getprogpath(exe_path, argv0) != NULL) return exe_path; #elif defined(__linux__) || defined(__CYGWIN__) @@ -196,20 +222,20 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { // the program, and not the eventual binary file. Therefore, call realpath // so this behaves the same on all platforms. #if _POSIX_VERSION >= 200112 || defined(__GLIBC__) - char *real_path = realpath(exe_path, NULL); - std::string ret = std::string(real_path); - free(real_path); - return ret; + if (char *real_path = realpath(exe_path, NULL)) { + std::string ret = std::string(real_path); + free(real_path); + return ret; + } #else char real_path[MAXPATHLEN]; - realpath(exe_path, real_path); - return std::string(real_path); + if (realpath(exe_path, real_path)) + return std::string(real_path); #endif - } else { - // Fall back to the classical detection. - if (getprogpath(exe_path, argv0)) - return exe_path; } + // Fall back to the classical detection. + if (getprogpath(exe_path, argv0)) + return exe_path; #elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR) // Use dladdr to get executable path if available. Dl_info DLInfo; @@ -246,7 +272,7 @@ uint32_t file_status::getLinkCount() const { ErrorOr<space_info> disk_space(const Twine &Path) { struct STATVFS Vfs; - if (::STATVFS(Path.str().c_str(), &Vfs)) + if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs)) return std::error_code(errno, std::generic_category()); auto FrSize = STATVFS_F_FRSIZE(Vfs); space_info SpaceInfo; @@ -398,6 +424,9 @@ static bool is_local_impl(struct STATVFS &Vfs) { #elif defined(__Fuchsia__) // Fuchsia doesn't yet support remote filesystem mounts. return true; +#elif defined(__EMSCRIPTEN__) + // Emscripten doesn't currently support remote filesystem mounts. + return true; #elif defined(__HAIKU__) // Haiku doesn't expose this information. return false; @@ -406,6 +435,40 @@ static bool is_local_impl(struct STATVFS &Vfs) { StringRef fstype(Vfs.f_basetype); // NFS is the only non-local fstype?? return !fstype.equals("nfs"); +#elif defined(_AIX) + // Call mntctl; try more than twice in case of timing issues with a concurrent + // mount. + int Ret; + size_t BufSize = 2048u; + std::unique_ptr<char[]> Buf; + int Tries = 3; + while (Tries--) { + Buf = llvm::make_unique<char[]>(BufSize); + Ret = mntctl(MCTL_QUERY, BufSize, Buf.get()); + if (Ret != 0) + break; + BufSize = *reinterpret_cast<unsigned int *>(Buf.get()); + Buf.reset(); + } + + if (Ret == -1) + // There was an error; "remote" is the conservative answer. + return false; + + // Look for the correct vmount entry. + char *CurObjPtr = Buf.get(); + while (Ret--) { + struct vmount *Vp = reinterpret_cast<struct vmount *>(CurObjPtr); + static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid), + "fsid length mismatch"); + if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0) + return (Vp->vmt_flags & MNT_REMOTE) == 0; + + CurObjPtr += Vp->vmt_length; + } + + // vmount entry not found; "remote" is the conservative answer. + return false; #else return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL); #endif @@ -413,7 +476,7 @@ static bool is_local_impl(struct STATVFS &Vfs) { std::error_code is_local(const Twine &Path, bool &Result) { struct STATVFS Vfs; - if (::STATVFS(Path.str().c_str(), &Vfs)) + if (::STATVFS(const_cast<char *>(Path.str().c_str()), &Vfs)) return std::error_code(errno, std::generic_category()); Result = is_local_impl(Vfs); @@ -447,7 +510,12 @@ std::error_code resize_file(int FD, uint64_t Size) { // If we have posix_fallocate use it. Unlike ftruncate it always allocates // space, so we get an error if the disk is full. if (int Err = ::posix_fallocate(FD, 0, Size)) { - if (Err != EINVAL && Err != EOPNOTSUPP) +#ifdef _AIX + constexpr int NotSupportedError = ENOTSUP; +#else + constexpr int NotSupportedError = EOPNOTSUPP; +#endif + if (Err != EINVAL && Err != NotSupportedError) return std::error_code(Err, std::generic_category()); } #endif @@ -626,6 +694,14 @@ std::error_code status(int FD, file_status &Result) { return fillStatus(StatRet, Status, Result); } +unsigned getUmask() { + // Chose arbitary new mask and reset the umask to the old mask. + // umask(2) never fails so ignore the return of the second call. + unsigned Mask = ::umask(0); + (void) ::umask(Mask); + return Mask; +} + std::error_code setPermissions(const Twine &Path, perms Permissions) { SmallString<128> PathStorage; StringRef P = Path.toNullTerminatedStringRef(PathStorage); @@ -635,6 +711,12 @@ std::error_code setPermissions(const Twine &Path, perms Permissions) { return std::error_code(); } +std::error_code setPermissions(int FD, perms Permissions) { + if (::fchmod(FD, Permissions)) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, TimePoint<> ModificationTime) { #if defined(HAVE_FUTIMENS) @@ -722,7 +804,7 @@ const char *mapped_file_region::const_data() const { } int mapped_file_region::alignment() { - return Process::getPageSize(); + return Process::getPageSizeEstimate(); } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, @@ -910,9 +992,54 @@ Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, return ResultFD; } -void closeFile(file_t &F) { - ::close(F); +file_t getStdinHandle() { return 0; } +file_t getStdoutHandle() { return 1; } +file_t getStderrHandle() { return 2; } + +std::error_code readNativeFile(file_t FD, MutableArrayRef<char> Buf, + size_t *BytesRead) { + *BytesRead = sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Buf.size()); + if (ssize_t(*BytesRead) == -1) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + +std::error_code readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf, + size_t Offset) { + char *BufPtr = Buf.data(); + size_t BytesLeft = Buf.size(); + +#ifndef HAVE_PREAD + // If we don't have pread, seek to Offset. + if (lseek(FD, Offset, SEEK_SET) == -1) + return std::error_code(errno, std::generic_category()); +#endif + + while (BytesLeft) { +#ifdef HAVE_PREAD + ssize_t NumRead = sys::RetryAfterSignal(-1, ::pread, FD, BufPtr, BytesLeft, + Buf.size() - BytesLeft + Offset); +#else + ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, BufPtr, BytesLeft); +#endif + if (NumRead == -1) { + // Error while reading. + return std::error_code(errno, std::generic_category()); + } + if (NumRead == 0) { + memset(BufPtr, 0, BytesLeft); // zero-initialize rest of the buffer. + break; + } + BytesLeft -= NumRead; + BufPtr += NumRead; + } + return std::error_code(); +} + +std::error_code closeFile(file_t &F) { + file_t TmpF = F; F = kInvalidFile; + return Process::SafelyCloseFileDescriptor(TmpF); } template <typename T> @@ -1063,5 +1190,37 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { } // end namespace path +namespace fs { + +#ifdef __APPLE__ +/// This implementation tries to perform an APFS CoW clone of the file, +/// which can be much faster and uses less space. +/// Unfortunately fcopyfile(3) does not support COPYFILE_CLONE, so the +/// file descriptor variant of this function still uses the default +/// implementation. +std::error_code copy_file(const Twine &From, const Twine &To) { + uint32_t Flag = COPYFILE_DATA; +#if __has_builtin(__builtin_available) + if (__builtin_available(macos 10.12, *)) { + bool IsSymlink; + if (std::error_code Error = is_symlink_file(From, IsSymlink)) + return Error; + // COPYFILE_CLONE clones the symlink instead of following it + // and returns EEXISTS if the target file already exists. + if (!IsSymlink && !exists(To)) + Flag = COPYFILE_CLONE; + } +#endif + int Status = + copyfile(From.str().c_str(), To.str().c_str(), /* State */ NULL, Flag); + + if (Status == 0) + return std::error_code(); + return std::error_code(errno, std::generic_category()); +} +#endif // __APPLE__ + +} // end namespace fs + } // end namespace sys } // end namespace llvm diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index 3185f45a3a61..4115ee396582 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -1,9 +1,8 @@ //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -33,10 +32,7 @@ #if HAVE_SIGNAL_H #include <signal.h> #endif -// DragonFlyBSD, and OpenBSD have deprecated <malloc.h> for -// <stdlib.h> instead. Unix.h includes this for us already. -#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ - !defined(__OpenBSD__) +#if defined(HAVE_MALLINFO) #include <malloc.h> #endif #if defined(HAVE_MALLCTL) @@ -73,7 +69,7 @@ static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsage // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and // offset in mmap(3) should be aligned to the AllocationGranularity. -unsigned Process::getPageSize() { +Expected<unsigned> Process::getPageSize() { #if defined(HAVE_GETPAGESIZE) static const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) @@ -81,6 +77,9 @@ unsigned Process::getPageSize() { #else #error Cannot get the page size on this machine #endif + if (page_size == -1) + return errorCodeToError(std::error_code(errno, std::generic_category())); + return static_cast<unsigned>(page_size); } @@ -292,7 +291,8 @@ static unsigned getColumns(int FileID) { unsigned Columns = 0; -#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) +#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) \ + && !(defined(_XOPEN_SOURCE) || defined(_POSIX_C_SOURCE)) // Try to determine the width of the terminal. struct winsize ws; if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index d0abc3763e82..c4123a64046f 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -246,12 +245,16 @@ static bool Execute(ProcessInfo &PI, StringRef Program, Envp = const_cast<const char **>(*_NSGetEnviron()); #endif - // Explicitly initialized to prevent what appears to be a valgrind false - // positive. - pid_t PID = 0; - int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, - /*attrp*/ nullptr, const_cast<char **>(Argv), - const_cast<char **>(Envp)); + constexpr int maxRetries = 8; + int retries = 0; + pid_t PID; + int Err; + do { + PID = 0; // Make Valgrind happy. + Err = posix_spawn(&PID, Program.str().c_str(), FileActions, + /*attrp*/ nullptr, const_cast<char **>(Argv), + const_cast<char **>(Envp)); + } while (Err == EINTR && ++retries < maxRetries); if (FileActions) posix_spawn_file_actions_destroy(FileActions); diff --git a/contrib/llvm/lib/Support/Unix/RWMutex.inc b/contrib/llvm/lib/Support/Unix/RWMutex.inc index 85a104334a27..8b47dfa0f85c 100644 --- a/contrib/llvm/lib/Support/Unix/RWMutex.inc +++ b/contrib/llvm/lib/Support/Unix/RWMutex.inc @@ -1,9 +1,8 @@ //= llvm/Support/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index ad88d5e96906..634c16aa36c7 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -1,9 +1,8 @@ //===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -43,6 +42,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Program.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/UniqueLock.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -81,10 +81,13 @@ using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. +static RETSIGTYPE InfoSignalHandler(int Sig); // defined below. +using SignalHandlerFunctionType = void (*)(); /// The function to call if ctrl-c is pressed. -using InterruptFunctionType = void (*)(); -static std::atomic<InterruptFunctionType> InterruptFunction = +static std::atomic<SignalHandlerFunctionType> InterruptFunction = + ATOMIC_VAR_INIT(nullptr); +static std::atomic<SignalHandlerFunctionType> InfoSignalFunction = ATOMIC_VAR_INIT(nullptr); namespace { @@ -200,15 +203,15 @@ struct FilesToRemoveCleanup { static StringRef Argv0; -// Signals that represent requested termination. There's no bug or failure, or -// if there is, it's not our direct responsibility. For whatever reason, our -// continued execution is no longer desirable. +/// Signals that represent requested termination. There's no bug or failure, or +/// if there is, it's not our direct responsibility. For whatever reason, our +/// continued execution is no longer desirable. static const int IntSigs[] = { - SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 + SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR2 }; -// Signals that represent that we have a bug, and our prompt termination has -// been ordered. +/// Signals that represent that we have a bug, and our prompt termination has +/// been ordered. static const int KillSigs[] = { SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT #ifdef SIGSYS @@ -225,11 +228,24 @@ static const int KillSigs[] = { #endif }; +/// Signals that represent requests for status. +static const int InfoSigs[] = { + SIGUSR1 +#ifdef SIGINFO + , SIGINFO +#endif +}; + +static const size_t NumSigs = + array_lengthof(IntSigs) + array_lengthof(KillSigs) + + array_lengthof(InfoSigs); + + static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0); static struct { struct sigaction SA; int SigNo; -} RegisteredSignalInfo[array_lengthof(IntSigs) + array_lengthof(KillSigs)]; +} RegisteredSignalInfo[NumSigs]; #if defined(HAVE_SIGALTSTACK) // Hold onto both the old and new alternate signal stack so that it's not @@ -277,15 +293,24 @@ static void RegisterHandlers() { // Not signal-safe. // be able to reliably handle signals due to stack overflow. CreateSigAltStack(); - auto registerHandler = [&](int Signal) { + enum class SignalKind { IsKill, IsInfo }; + auto registerHandler = [&](int Signal, SignalKind Kind) { unsigned Index = NumRegisteredSignals.load(); assert(Index < array_lengthof(RegisteredSignalInfo) && "Out of space for signal handlers!"); struct sigaction NewHandler; - NewHandler.sa_handler = SignalHandler; - NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; + switch (Kind) { + case SignalKind::IsKill: + NewHandler.sa_handler = SignalHandler; + NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; + break; + case SignalKind::IsInfo: + NewHandler.sa_handler = InfoSignalHandler; + NewHandler.sa_flags = SA_ONSTACK; + break; + } sigemptyset(&NewHandler.sa_mask); // Install the new handler, save the old one in RegisteredSignalInfo. @@ -295,9 +320,11 @@ static void RegisterHandlers() { // Not signal-safe. }; for (auto S : IntSigs) - registerHandler(S); + registerHandler(S, SignalKind::IsKill); for (auto S : KillSigs) - registerHandler(S); + registerHandler(S, SignalKind::IsKill); + for (auto S : InfoSigs) + registerHandler(S, SignalKind::IsInfo); } static void UnregisterHandlers() { @@ -357,6 +384,12 @@ static RETSIGTYPE SignalHandler(int Sig) { #endif } +static RETSIGTYPE InfoSignalHandler(int Sig) { + SaveAndRestore<int> SaveErrnoDuringASignalHandler(errno); + if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction) + CurrentInfoFunction(); +} + void llvm::sys::RunInterruptHandlers() { RemoveFilesToRemove(); } @@ -366,6 +399,11 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) { RegisterHandlers(); } +void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { + InfoSignalFunction.exchange(Handler); + RegisterHandlers(); +} + // The public API bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { @@ -540,11 +578,8 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { else OS << d; free(d); - // FIXME: When we move to C++11, use %t length modifier. It's not in - // C++03 and causes gcc to issue warnings. Losing the upper 32 bits of - // the stack offset for a stack dump isn't likely to cause any problems. - OS << format(" + %u",(unsigned)((char*)StackTrace[i]- - (char*)dlinfo.dli_saddr)); + OS << format(" + %tu", (static_cast<const char*>(StackTrace[i])- + static_cast<const char*>(dlinfo.dli_saddr))); } OS << '\n'; } diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc index a6564f0fa281..a402ae980424 100644 --- a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc @@ -1,9 +1,8 @@ //=== llvm/Support/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Unix/Threading.inc b/contrib/llvm/lib/Support/Unix/Threading.inc index 92bec36d6a2d..ed9a96563055 100644 --- a/contrib/llvm/lib/Support/Unix/Threading.inc +++ b/contrib/llvm/lib/Support/Unix/Threading.inc @@ -1,9 +1,8 @@ //===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -218,3 +217,42 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { #endif #endif } + +SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { +#if defined(__linux__) && defined(SCHED_IDLE) + // Some *really* old glibcs are missing SCHED_IDLE. + // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html + // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html + sched_param priority; + // For each of the above policies, param->sched_priority must be 0. + priority.sched_priority = 0; + // SCHED_IDLE for running very low priority background jobs. + // SCHED_OTHER the standard round-robin time-sharing policy; + return !pthread_setschedparam( + pthread_self(), + Priority == ThreadPriority::Background ? SCHED_IDLE : SCHED_OTHER, + &priority) + ? SetThreadPriorityResult::SUCCESS + : SetThreadPriorityResult::FAILURE; +#elif defined(__APPLE__) + // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html + // When setting a thread into background state the scheduling priority is set + // to lowest value, disk and network IO are throttled. Network IO will be + // throttled for any sockets the thread opens after going into background + // state. Any previously opened sockets are not affected. + + // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getiopolicy_np.3.html + // I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O + // request occurs within a small time window (usually a fraction of a second) + // of another NORMAL I/O request, the thread that issues the THROTTLE I/O is + // forced to sleep for a certain interval. This slows down the thread that + // issues the THROTTLE I/O so that NORMAL I/Os can utilize most of the disk + // I/O bandwidth. + return !setpriority(PRIO_DARWIN_THREAD, 0, + Priority == ThreadPriority::Background ? PRIO_DARWIN_BG + : 0) + ? SetThreadPriorityResult::SUCCESS + : SetThreadPriorityResult::FAILURE; +#endif + return SetThreadPriorityResult::FAILURE; +} diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h index 0c5d4de556d5..86309b0567f5 100644 --- a/contrib/llvm/lib/Support/Unix/Unix.h +++ b/contrib/llvm/lib/Support/Unix/Unix.h @@ -1,9 +1,8 @@ //===- llvm/Support/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -19,7 +18,7 @@ //=== is guaranteed to work on all UNIX variants. //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Config/config.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/Errno.h" #include <algorithm> diff --git a/contrib/llvm/lib/Support/Unix/Watchdog.inc b/contrib/llvm/lib/Support/Unix/Watchdog.inc index f4253391d952..b363ef779560 100644 --- a/contrib/llvm/lib/Support/Unix/Watchdog.inc +++ b/contrib/llvm/lib/Support/Unix/Watchdog.inc @@ -1,9 +1,8 @@ //===--- Unix/Watchdog.inc - Unix Watchdog Implementation -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Valgrind.cpp b/contrib/llvm/lib/Support/Valgrind.cpp index 8d852a67c075..886cb6ba3311 100644 --- a/contrib/llvm/lib/Support/Valgrind.cpp +++ b/contrib/llvm/lib/Support/Valgrind.cpp @@ -1,9 +1,8 @@ //===-- Valgrind.cpp - Implement Valgrind communication ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/VersionTuple.cpp b/contrib/llvm/lib/Support/VersionTuple.cpp index 3f219bfbedfa..60b59424fbb4 100644 --- a/contrib/llvm/lib/Support/VersionTuple.cpp +++ b/contrib/llvm/lib/Support/VersionTuple.cpp @@ -1,9 +1,8 @@ //===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/VirtualFileSystem.cpp b/contrib/llvm/lib/Support/VirtualFileSystem.cpp index f2a8a1bb27af..5d3480e97148 100644 --- a/contrib/llvm/lib/Support/VirtualFileSystem.cpp +++ b/contrib/llvm/lib/Support/VirtualFileSystem.cpp @@ -1,9 +1,8 @@ //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -57,8 +56,10 @@ using namespace llvm; using namespace llvm::vfs; +using llvm::sys::fs::file_t; using llvm::sys::fs::file_status; using llvm::sys::fs::file_type; +using llvm::sys::fs::kInvalidFile; using llvm::sys::fs::perms; using llvm::sys::fs::UniqueID; @@ -67,19 +68,19 @@ Status::Status(const file_status &Status) User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()), Type(Status.type()), Perms(Status.permissions()) {} -Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime, +Status::Status(const Twine &Name, UniqueID UID, sys::TimePoint<> MTime, uint32_t User, uint32_t Group, uint64_t Size, file_type Type, perms Perms) - : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size), - Type(Type), Perms(Perms) {} + : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group), + Size(Size), Type(Type), Perms(Perms) {} -Status Status::copyWithNewName(const Status &In, StringRef NewName) { +Status Status::copyWithNewName(const Status &In, const Twine &NewName) { return Status(NewName, In.getUniqueID(), In.getLastModificationTime(), In.getUser(), In.getGroup(), In.getSize(), In.getType(), In.getPermissions()); } -Status Status::copyWithNewName(const file_status &In, StringRef NewName) { +Status Status::copyWithNewName(const file_status &In, const Twine &NewName) { return Status(NewName, In.getUniqueID(), In.getLastModificationTime(), In.getUser(), In.getGroup(), In.getSize(), In.type(), In.permissions()); @@ -171,15 +172,15 @@ namespace { class RealFile : public File { friend class RealFileSystem; - int FD; + file_t FD; Status S; std::string RealName; - RealFile(int FD, StringRef NewName, StringRef NewRealPathName) + RealFile(file_t FD, StringRef NewName, StringRef NewRealPathName) : FD(FD), S(NewName, {}, {}, {}, {}, {}, llvm::sys::fs::file_type::status_error, {}), RealName(NewRealPathName.str()) { - assert(FD >= 0 && "Invalid or inactive file descriptor"); + assert(FD != kInvalidFile && "Invalid or inactive file descriptor"); } public: @@ -199,7 +200,7 @@ public: RealFile::~RealFile() { close(); } ErrorOr<Status> RealFile::status() { - assert(FD != -1 && "cannot stat closed file"); + assert(FD != kInvalidFile && "cannot stat closed file"); if (!S.isStatusKnown()) { file_status RealStatus; if (std::error_code EC = sys::fs::status(FD, RealStatus)) @@ -216,22 +217,41 @@ ErrorOr<std::string> RealFile::getName() { ErrorOr<std::unique_ptr<MemoryBuffer>> RealFile::getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) { - assert(FD != -1 && "cannot get buffer for closed file"); + assert(FD != kInvalidFile && "cannot get buffer for closed file"); return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator, IsVolatile); } std::error_code RealFile::close() { - std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD); - FD = -1; + std::error_code EC = sys::fs::closeFile(FD); + FD = kInvalidFile; return EC; } namespace { -/// The file system according to your operating system. +/// A file system according to your operating system. +/// This may be linked to the process's working directory, or maintain its own. +/// +/// Currently, its own working directory is emulated by storing the path and +/// sending absolute paths to llvm::sys::fs:: functions. +/// A more principled approach would be to push this down a level, modelling +/// the working dir as an llvm::sys::fs::WorkingDir or similar. +/// This would enable the use of openat()-style functions on some platforms. class RealFileSystem : public FileSystem { public: + explicit RealFileSystem(bool LinkCWDToProcess) { + if (!LinkCWDToProcess) { + SmallString<128> PWD, RealPWD; + if (llvm::sys::fs::current_path(PWD)) + return; // Awful, but nothing to do here. + if (llvm::sys::fs::real_path(PWD, RealPWD)) + WD = {PWD, PWD}; + else + WD = {PWD, RealPWD}; + } + } + ErrorOr<Status> status(const Twine &Path) override; ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; @@ -243,72 +263,95 @@ public: SmallVectorImpl<char> &Output) const override; private: - mutable std::mutex CWDMutex; - mutable std::string CWDCache; + // If this FS has its own working dir, use it to make Path absolute. + // The returned twine is safe to use as long as both Storage and Path live. + Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const { + if (!WD) + return Path; + Path.toVector(Storage); + sys::fs::make_absolute(WD->Resolved, Storage); + return Storage; + } + + struct WorkingDirectory { + // The current working directory, without symlinks resolved. (echo $PWD). + SmallString<128> Specified; + // The current working directory, with links resolved. (readlink .). + SmallString<128> Resolved; + }; + Optional<WorkingDirectory> WD; }; } // namespace ErrorOr<Status> RealFileSystem::status(const Twine &Path) { + SmallString<256> Storage; sys::fs::file_status RealStatus; - if (std::error_code EC = sys::fs::status(Path, RealStatus)) + if (std::error_code EC = + sys::fs::status(adjustPath(Path, Storage), RealStatus)) return EC; - return Status::copyWithNewName(RealStatus, Path.str()); + return Status::copyWithNewName(RealStatus, Path); } ErrorOr<std::unique_ptr<File>> RealFileSystem::openFileForRead(const Twine &Name) { - int FD; - SmallString<256> RealName; - if (std::error_code EC = - sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName)) - return EC; - return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str())); + SmallString<256> RealName, Storage; + Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead( + adjustPath(Name, Storage), sys::fs::OF_None, &RealName); + if (!FDOrErr) + return errorToErrorCode(FDOrErr.takeError()); + return std::unique_ptr<File>( + new RealFile(*FDOrErr, Name.str(), RealName.str())); } llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const { - std::lock_guard<std::mutex> Lock(CWDMutex); - if (!CWDCache.empty()) - return CWDCache; - SmallString<256> Dir; + if (WD) + return WD->Specified.str(); + + SmallString<128> Dir; if (std::error_code EC = llvm::sys::fs::current_path(Dir)) return EC; - CWDCache = Dir.str(); - return CWDCache; + return Dir.str(); } std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) { - // FIXME: chdir is thread hostile; on the other hand, creating the same - // behavior as chdir is complex: chdir resolves the path once, thus - // guaranteeing that all subsequent relative path operations work - // on the same path the original chdir resulted in. This makes a - // difference for example on network filesystems, where symlinks might be - // switched during runtime of the tool. Fixing this depends on having a - // file system abstraction that allows openat() style interactions. - if (auto EC = llvm::sys::fs::set_current_path(Path)) - return EC; - - // Invalidate cache. - std::lock_guard<std::mutex> Lock(CWDMutex); - CWDCache.clear(); + if (!WD) + return llvm::sys::fs::set_current_path(Path); + + SmallString<128> Absolute, Resolved, Storage; + adjustPath(Path, Storage).toVector(Absolute); + bool IsDir; + if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir)) + return Err; + if (!IsDir) + return std::make_error_code(std::errc::not_a_directory); + if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved)) + return Err; + WD = {Absolute, Resolved}; return std::error_code(); } std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) { - return llvm::sys::fs::is_local(Path, Result); + SmallString<256> Storage; + return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result); } std::error_code RealFileSystem::getRealPath(const Twine &Path, SmallVectorImpl<char> &Output) const { - return llvm::sys::fs::real_path(Path, Output); + SmallString<256> Storage; + return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output); } IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { - static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem(); + static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true)); return FS; } +std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() { + return llvm::make_unique<RealFileSystem>(false); +} + namespace { class RealFSDirIter : public llvm::vfs::detail::DirIterImpl { @@ -334,7 +377,9 @@ public: directory_iterator RealFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { - return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC)); + SmallString<128> Storage; + return directory_iterator( + std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC)); } //===-----------------------------------------------------------------------===/ @@ -511,7 +556,7 @@ public: /// Return the \p Status for this node. \p RequestedName should be the name /// through which the caller referred to this node. It will override /// \p Status::Name in the return value, to mimic the behavior of \p RealFile. - Status getStatus(StringRef RequestedName) const { + Status getStatus(const Twine &RequestedName) const { return Status::copyWithNewName(Stat, RequestedName); } llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); } @@ -585,7 +630,7 @@ public: /// Return the \p Status for this node. \p RequestedName should be the name /// through which the caller referred to this node. It will override /// \p Status::Name in the return value, to mimic the behavior of \p RealFile. - Status getStatus(StringRef RequestedName) const { + Status getStatus(const Twine &RequestedName) const { return Status::copyWithNewName(Stat, RequestedName); } InMemoryNode *getChild(StringRef Name) { @@ -619,7 +664,7 @@ public: }; namespace { -Status getNodeStatus(const InMemoryNode *Node, StringRef RequestedName) { +Status getNodeStatus(const InMemoryNode *Node, const Twine &RequestedName) { if (auto Dir = dyn_cast<detail::InMemoryDirectory>(Node)) return Dir->getStatus(RequestedName); if (auto File = dyn_cast<detail::InMemoryFile>(Node)) @@ -817,7 +862,7 @@ bool InMemoryFileSystem::addHardLink(const Twine &FromPath, llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) { auto Node = lookupInMemoryNode(*this, Root.get(), Path); if (Node) - return detail::getNodeStatus(*Node, Path.str()); + return detail::getNodeStatus(*Node, Path); return Node.getError(); } @@ -1237,7 +1282,7 @@ class llvm::vfs::RedirectingFileSystemParser { EntryArrayContents; std::string ExternalContentsPath; std::string Name; - yaml::Node *NameValueNode; + yaml::Node *NameValueNode = nullptr; auto UseExternalName = RedirectingFileSystem::RedirectingFileEntry::NK_NotSet; RedirectingFileSystem::EntryKind Kind; @@ -1633,7 +1678,7 @@ static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames, Status ExternalStatus) { Status S = ExternalStatus; if (!UseExternalNames) - S = Status::copyWithNewName(S, Path.str()); + S = Status::copyWithNewName(S, Path); S.IsVFSMapped = true; return S; } @@ -1650,7 +1695,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, return S; } else { // directory auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(E); - return Status::copyWithNewName(DE->getStatus(), Path.str()); + return Status::copyWithNewName(DE->getStatus(), Path); } } diff --git a/contrib/llvm/lib/Support/Watchdog.cpp b/contrib/llvm/lib/Support/Watchdog.cpp index be55e3122e70..246f3dc7a0ca 100644 --- a/contrib/llvm/lib/Support/Watchdog.cpp +++ b/contrib/llvm/lib/Support/Watchdog.cpp @@ -1,9 +1,8 @@ //===---- Watchdog.cpp - Implement Watchdog ---------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/COM.inc b/contrib/llvm/lib/Support/Windows/COM.inc index 54f3ecf28ec2..002182bc3939 100644 --- a/contrib/llvm/lib/Support/Windows/COM.inc +++ b/contrib/llvm/lib/Support/Windows/COM.inc @@ -1,9 +1,8 @@ //==- llvm/Support/Windows/COM.inc - Windows COM Implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc index 1d47f0848a6d..71b206c4cf9e 100644 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -1,9 +1,8 @@ //===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc index 58c4dc5d678f..21b947f26df3 100644 --- a/contrib/llvm/lib/Support/Windows/Host.inc +++ b/contrib/llvm/lib/Support/Windows/Host.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Win32/Host.inc ------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm/lib/Support/Windows/Memory.inc index 318e65aaa9ee..a67f9c7d0f35 100644 --- a/contrib/llvm/lib/Support/Windows/Memory.inc +++ b/contrib/llvm/lib/Support/Windows/Memory.inc @@ -1,9 +1,8 @@ //===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,7 +22,7 @@ namespace { DWORD getWindowsProtectionFlags(unsigned Flags) { - switch (Flags) { + switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { // Contrary to what you might expect, the Windows page protection flags // are not a bitwise combination of RWX values case llvm::sys::Memory::MF_READ: @@ -48,6 +47,9 @@ DWORD getWindowsProtectionFlags(unsigned Flags) { return PAGE_NOACCESS; } +// While we'd be happy to allocate single pages, the Windows allocation +// granularity may be larger than a single page (in practice, it is 64K) +// so mapping less than that will create an unreachable fragment of memory. size_t getAllocationGranularity() { SYSTEM_INFO Info; ::GetSystemInfo(&Info); @@ -57,6 +59,38 @@ size_t getAllocationGranularity() { return Info.dwAllocationGranularity; } +// Large/huge memory pages need explicit process permissions in order to be +// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 +// Also large pages need to be manually enabled on your OS. If all this is +// sucessfull, we return the minimal large memory page size. +static size_t enableProcessLargePages() { + HANDLE Token = 0; + size_t LargePageMin = GetLargePageMinimum(); + if (LargePageMin) + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &Token); + if (!Token) + return 0; + LUID Luid; + if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { + CloseHandle(Token); + return 0; + } + TOKEN_PRIVILEGES TP{}; + TP.PrivilegeCount = 1; + TP.Privileges[0].Luid = Luid; + TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { + CloseHandle(Token); + return 0; + } + DWORD E = GetLastError(); + CloseHandle(Token); + if (E == ERROR_SUCCESS) + return LargePageMin; + return 0; +} + } // namespace namespace llvm { @@ -75,22 +109,23 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, if (NumBytes == 0) return MemoryBlock(); - // While we'd be happy to allocate single pages, the Windows allocation - // granularity may be larger than a single page (in practice, it is 64K) - // so mapping less than that will create an unreachable fragment of memory. - // Avoid using one-time initialization of static locals here, since they - // aren't thread safe with MSVC. - static volatile size_t GranularityCached; - size_t Granularity = GranularityCached; - if (Granularity == 0) { - Granularity = getAllocationGranularity(); - GranularityCached = Granularity; + static size_t DefaultGranularity = getAllocationGranularity(); + static size_t LargePageGranularity = enableProcessLargePages(); + + DWORD AllocType = MEM_RESERVE | MEM_COMMIT; + bool HugePages = false; + size_t Granularity = DefaultGranularity; + + if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { + AllocType |= MEM_LARGE_PAGES; + HugePages = true; + Granularity = LargePageGranularity; } - const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; + size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + - NearBlock->size() + NearBlock->allocatedSize() : 0; // If the requested address is not aligned to the allocation granularity, @@ -100,13 +135,13 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, DWORD Protect = getWindowsProtectionFlags(Flags); - void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start), - NumBlocks*Granularity, - MEM_RESERVE | MEM_COMMIT, Protect); + size_t AllocSize = NumBlocks * Granularity; + void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), + AllocSize, AllocType, Protect); if (PA == NULL) { - if (NearBlock) { - // Try again without the NearBlock hint - return allocateMappedMemory(NumBytes, NULL, Flags, EC); + if (NearBlock || HugePages) { + // Try again without the NearBlock hint and without large memory pages + return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); } EC = mapWindowsError(::GetLastError()); return MemoryBlock(); @@ -114,40 +149,41 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, MemoryBlock Result; Result.Address = PA; - Result.Size = NumBlocks*Granularity; + Result.AllocatedSize = AllocSize; + Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(Result.Address, Result.Size); + Memory::InvalidateInstructionCache(Result.Address, AllocSize); return Result; } std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { - if (M.Address == 0 || M.Size == 0) + if (M.Address == 0 || M.AllocatedSize == 0) return std::error_code(); if (!VirtualFree(M.Address, 0, MEM_RELEASE)) return mapWindowsError(::GetLastError()); M.Address = 0; - M.Size = 0; + M.AllocatedSize = 0; return std::error_code(); } std::error_code Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { - if (M.Address == 0 || M.Size == 0) + if (M.Address == 0 || M.AllocatedSize == 0) return std::error_code(); DWORD Protect = getWindowsProtectionFlags(Flags); DWORD OldFlags; - if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags)) + if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) return mapWindowsError(::GetLastError()); if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(M.Address, M.Size); + Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); return std::error_code(); } diff --git a/contrib/llvm/lib/Support/Windows/Mutex.inc b/contrib/llvm/lib/Support/Windows/Mutex.inc index 0af145ec9a4e..b55b14febf2c 100644 --- a/contrib/llvm/lib/Support/Windows/Mutex.inc +++ b/contrib/llvm/lib/Support/Windows/Mutex.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc index d34aa763124c..5704930aeecc 100644 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -735,6 +734,14 @@ std::error_code status(int FD, file_status &Result) { return getStatus(FileHandle, Result); } +std::error_code status(file_t FileHandle, file_status &Result) { + return getStatus(FileHandle, Result); +} + +unsigned getUmask() { + return 0; +} + std::error_code setPermissions(const Twine &Path, perms Permissions) { SmallVector<wchar_t, 128> PathUTF16; if (std::error_code EC = widenPath(Path, PathUTF16)) @@ -766,6 +773,11 @@ std::error_code setPermissions(const Twine &Path, perms Permissions) { return std::error_code(); } +std::error_code setPermissions(int FD, perms Permissions) { + // FIXME Not implemented. + return std::make_error_code(std::errc::not_supported); +} + std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, TimePoint<> ModificationTime) { FILETIME AccessFT = toFILETIME(AccessTime); @@ -776,10 +788,9 @@ std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, return std::error_code(); } -std::error_code mapped_file_region::init(int FD, uint64_t Offset, - mapmode Mode) { +std::error_code mapped_file_region::init(sys::fs::file_t OrigFileHandle, + uint64_t Offset, mapmode Mode) { this->Mode = Mode; - HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); if (OrigFileHandle == INVALID_HANDLE_VALUE) return make_error_code(errc::bad_file_descriptor); @@ -846,8 +857,9 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, return std::error_code(); } -mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, - uint64_t offset, std::error_code &ec) +mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode, + size_t length, uint64_t offset, + std::error_code &ec) : Size(length), Mapping() { ec = init(fd, offset, mode); if (ec) @@ -1197,9 +1209,73 @@ Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, return Result; } -void closeFile(file_t &F) { - ::CloseHandle(F); +file_t convertFDToNativeFile(int FD) { + return reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); +} + +file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); } +file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } +file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); } + +std::error_code readNativeFileImpl(file_t FileHandle, char *BufPtr, size_t BytesToRead, + size_t *BytesRead, OVERLAPPED *Overlap) { + // ReadFile can only read 2GB at a time. The caller should check the number of + // bytes and read in a loop until termination. + DWORD BytesToRead32 = + std::min(size_t(std::numeric_limits<DWORD>::max()), BytesToRead); + DWORD BytesRead32 = 0; + bool Success = + ::ReadFile(FileHandle, BufPtr, BytesToRead32, &BytesRead32, Overlap); + *BytesRead = BytesRead32; + if (!Success) { + DWORD Err = ::GetLastError(); + // Pipe EOF is not an error. + if (Err == ERROR_BROKEN_PIPE) + return std::error_code(); + return mapWindowsError(Err); + } + return std::error_code(); +} + +std::error_code readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf, + size_t *BytesRead) { + return readNativeFileImpl(FileHandle, Buf.data(), Buf.size(), BytesRead, + /*Overlap=*/nullptr); +} + +std::error_code readNativeFileSlice(file_t FileHandle, + MutableArrayRef<char> Buf, size_t Offset) { + char *BufPtr = Buf.data(); + size_t BytesLeft = Buf.size(); + + while (BytesLeft) { + uint64_t CurOff = Buf.size() - BytesLeft + Offset; + OVERLAPPED Overlapped = {}; + Overlapped.Offset = uint32_t(CurOff); + Overlapped.OffsetHigh = uint32_t(uint64_t(CurOff) >> 32); + + size_t BytesRead = 0; + if (auto EC = readNativeFileImpl(FileHandle, BufPtr, BytesLeft, &BytesRead, + &Overlapped)) + return EC; + + // Once we reach EOF, zero the remaining bytes in the buffer. + if (BytesRead == 0) { + memset(BufPtr, 0, BytesLeft); + break; + } + BytesLeft -= BytesRead; + BufPtr += BytesRead; + } + return std::error_code(); +} + +std::error_code closeFile(file_t &F) { + file_t TmpF = F; F = kInvalidFile; + if (!::CloseHandle(TmpF)) + return mapWindowsError(::GetLastError()); + return std::error_code(); } std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc index 2b2d79231434..4b91f9f7fc66 100644 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -1,9 +1,8 @@ //===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -57,7 +56,7 @@ static unsigned computePageSize() { return static_cast<unsigned>(info.dwPageSize); } -unsigned Process::getPageSize() { +Expected<unsigned> Process::getPageSize() { static unsigned Ret = computePageSize(); return Ret; } diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc index c037956603f2..0f54e59ee55b 100644 --- a/contrib/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm/lib/Support/Windows/Program.inc @@ -1,9 +1,8 @@ //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc index 5eb9351eee52..8df9bc394160 100644 --- a/contrib/llvm/lib/Support/Windows/RWMutex.inc +++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc @@ -1,9 +1,8 @@ //= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index 41eb5e593aa5..6a820ef22b1e 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -1,9 +1,8 @@ //===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -557,6 +556,10 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) { LeaveCriticalSection(&CriticalSection); } +void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { + // Unimplemented. +} + /// Add a function to be called when a signal is delivered to the process. The /// handler can have a cookie passed to it to identify what instance of the diff --git a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc index 8be1c3ecfbb9..1e0ed955e9ab 100644 --- a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc @@ -1,9 +1,8 @@ //= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/Threading.inc b/contrib/llvm/lib/Support/Windows/Threading.inc index 0bd92f66c6b8..96649472cc90 100644 --- a/contrib/llvm/lib/Support/Windows/Threading.inc +++ b/contrib/llvm/lib/Support/Windows/Threading.inc @@ -1,9 +1,8 @@ //===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -107,3 +106,19 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { // value. Name.clear(); } + +SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { + // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority + // Begin background processing mode. The system lowers the resource scheduling + // priorities of the thread so that it can perform background work without + // significantly affecting activity in the foreground. + // End background processing mode. The system restores the resource scheduling + // priorities of the thread as they were before the thread entered background + // processing mode. + return SetThreadPriority(GetCurrentThread(), + Priority == ThreadPriority::Background + ? THREAD_MODE_BACKGROUND_BEGIN + : THREAD_MODE_BACKGROUND_END) + ? SetThreadPriorityResult::SUCCESS + : SetThreadPriorityResult::FAILURE; +} diff --git a/contrib/llvm/lib/Support/Windows/Watchdog.inc b/contrib/llvm/lib/Support/Windows/Watchdog.inc index fab2bdf2a941..a362c999de76 100644 --- a/contrib/llvm/lib/Support/Windows/Watchdog.inc +++ b/contrib/llvm/lib/Support/Windows/Watchdog.inc @@ -1,9 +1,8 @@ //===--- Windows/Watchdog.inc - Windows Watchdog Implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm/lib/Support/Windows/WindowsSupport.h index 979cc5d01390..fed9b2f462ef 100644 --- a/contrib/llvm/lib/Support/Windows/WindowsSupport.h +++ b/contrib/llvm/lib/Support/Windows/WindowsSupport.h @@ -1,9 +1,8 @@ //===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/WithColor.cpp b/contrib/llvm/lib/Support/WithColor.cpp index cf4c10956f21..345dd9cf3949 100644 --- a/contrib/llvm/lib/Support/WithColor.cpp +++ b/contrib/llvm/lib/Support/WithColor.cpp @@ -1,9 +1,8 @@ //===- WithColor.cpp ------------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp index 9ef1410b99a5..9b2fe9c4418a 100644 --- a/contrib/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm/lib/Support/YAMLParser.cpp @@ -1,9 +1,8 @@ //===- YAMLParser.cpp - Simple YAML parser --------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp index b9bbee7883c6..09eb36943de9 100644 --- a/contrib/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm/lib/Support/YAMLTraits.cpp @@ -1,9 +1,8 @@ //===- lib/Support/YAMLTraits.cpp -----------------------------------------===// // -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -114,6 +113,11 @@ const Node *Input::getCurrentNode() const { } bool Input::mapTag(StringRef Tag, bool Default) { + // CurrentNode can be null if setCurrentDocument() was unable to + // parse the document because it was invalid or empty. + if (!CurrentNode) + return false; + std::string foundTag = CurrentNode->_node->getVerbatimTag(); if (foundTag.empty()) { // If no tag found and 'Tag' is the default, say it was found. @@ -442,7 +446,8 @@ bool Output::outputting() { void Output::beginMapping() { StateStack.push_back(inMapFirstKey); - NeedsNewLine = true; + PaddingBeforeContainer = Padding; + Padding = "\n"; } bool Output::mapTag(StringRef Tag, bool Use) { @@ -470,7 +475,7 @@ bool Output::mapTag(StringRef Tag, bool Use) { } // Tags inside maps in sequences should act as keys in the map from a // formatting perspective, so we always want a newline in a sequence. - NeedsNewLine = true; + Padding = "\n"; } } return Use; @@ -478,8 +483,12 @@ bool Output::mapTag(StringRef Tag, bool Use) { void Output::endMapping() { // If we did not map anything, we should explicitly emit an empty map - if (StateStack.back() == inMapFirstKey) + if (StateStack.back() == inMapFirstKey) { + Padding = PaddingBeforeContainer; + newLineCheck(); output("{}"); + Padding = "\n"; + } StateStack.pop_back(); } @@ -544,14 +553,19 @@ void Output::endDocuments() { unsigned Output::beginSequence() { StateStack.push_back(inSeqFirstElement); - NeedsNewLine = true; + PaddingBeforeContainer = Padding; + Padding = "\n"; return 0; } void Output::endSequence() { // If we did not emit anything, we should explicitly emit an empty sequence - if (StateStack.back() == inSeqFirstElement) + if (StateStack.back() == inSeqFirstElement) { + Padding = PaddingBeforeContainer; + newLineCheck(); output("[]"); + Padding = "\n"; + } StateStack.pop_back(); } @@ -661,11 +675,6 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) { return; } - unsigned i = 0; - unsigned j = 0; - unsigned End = S.size(); - const char *Base = S.data(); - const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\""; output(Quote); // Starting quote. @@ -673,11 +682,16 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) { // present, and will be escaped using a variety of unicode-scalar and special short-form // escapes. This is handled in yaml::escape. if (MustQuote == QuotingType::Double) { - output(yaml::escape(Base, /* EscapePrintable= */ false)); + output(yaml::escape(S, /* EscapePrintable= */ false)); outputUpToEndOfLine(Quote); return; } + unsigned i = 0; + unsigned j = 0; + unsigned End = S.size(); + const char *Base = S.data(); + // When using single-quoted strings, any single quote ' must be doubled to be escaped. while (j < End) { if (S[j] == '\'') { // Escape quotes. @@ -742,7 +756,7 @@ void Output::outputUpToEndOfLine(StringRef s) { output(s); if (StateStack.empty() || (!inFlowSeqAnyElement(StateStack.back()) && !inFlowMapAnyKey(StateStack.back()))) - NeedsNewLine = true; + Padding = "\n"; } void Output::outputNewLine() { @@ -755,11 +769,13 @@ void Output::outputNewLine() { // void Output::newLineCheck() { - if (!NeedsNewLine) + if (Padding != "\n") { + output(Padding); + Padding = {}; return; - NeedsNewLine = false; - + } outputNewLine(); + Padding = {}; if (StateStack.size() == 0) return; @@ -793,9 +809,9 @@ void Output::paddedKey(StringRef key) { output(":"); const char *spaces = " "; if (key.size() < strlen(spaces)) - output(&spaces[key.size()]); + Padding = &spaces[key.size()]; else - output(" "); + Padding = " "; } void Output::flowKey(StringRef Key) { diff --git a/contrib/llvm/lib/Support/Z3Solver.cpp b/contrib/llvm/lib/Support/Z3Solver.cpp new file mode 100644 index 000000000000..f1a6fdf87cf2 --- /dev/null +++ b/contrib/llvm/lib/Support/Z3Solver.cpp @@ -0,0 +1,900 @@ +//== Z3Solver.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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" +#include "llvm/Support/SMTAPI.h" +#include <set> + +using namespace llvm; + +#if LLVM_WITH_Z3 + +#include <z3.h> + +namespace { + +/// Configuration class for Z3 +class Z3Config { + friend class Z3Context; + + Z3_config Config; + +public: + Z3Config() : Config(Z3_mk_config()) { + // Enable model finding + Z3_set_param_value(Config, "model", "true"); + // Disable proof generation + Z3_set_param_value(Config, "proof", "false"); + // Set timeout to 15000ms = 15s + Z3_set_param_value(Config, "timeout", "15000"); + } + + ~Z3Config() { Z3_del_config(Config); } +}; // end class Z3Config + +// Function used to report errors +void Z3ErrorHandler(Z3_context Context, Z3_error_code Error) { + llvm::report_fatal_error("Z3 error: " + + llvm::Twine(Z3_get_error_msg(Context, Error))); +} + +/// Wrapper for Z3 context +class Z3Context { +public: + Z3_context Context; + + Z3Context() { + Context = Z3_mk_context_rc(Z3Config().Config); + // The error function is set here because the context is the first object + // created by the backend + Z3_set_error_handler(Context, Z3ErrorHandler); + } + + virtual ~Z3Context() { + Z3_del_context(Context); + Context = nullptr; + } +}; // end class Z3Context + +/// Wrapper for Z3 Sort +class Z3Sort : public SMTSort { + friend class Z3Solver; + + Z3Context &Context; + + Z3_sort Sort; + +public: + /// Default constructor, mainly used by make_shared + Z3Sort(Z3Context &C, Z3_sort ZS) : Context(C), Sort(ZS) { + Z3_inc_ref(Context.Context, reinterpret_cast<Z3_ast>(Sort)); + } + + /// Override implicit copy constructor for correct reference counting. + Z3Sort(const Z3Sort &Other) : Context(Other.Context), Sort(Other.Sort) { + Z3_inc_ref(Context.Context, reinterpret_cast<Z3_ast>(Sort)); + } + + /// Override implicit copy assignment constructor for correct reference + /// counting. + Z3Sort &operator=(const Z3Sort &Other) { + Z3_inc_ref(Context.Context, reinterpret_cast<Z3_ast>(Other.Sort)); + Z3_dec_ref(Context.Context, reinterpret_cast<Z3_ast>(Sort)); + Sort = Other.Sort; + return *this; + } + + Z3Sort(Z3Sort &&Other) = delete; + Z3Sort &operator=(Z3Sort &&Other) = delete; + + ~Z3Sort() { + if (Sort) + Z3_dec_ref(Context.Context, reinterpret_cast<Z3_ast>(Sort)); + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddInteger( + Z3_get_ast_id(Context.Context, reinterpret_cast<Z3_ast>(Sort))); + } + + bool isBitvectorSortImpl() const override { + return (Z3_get_sort_kind(Context.Context, Sort) == Z3_BV_SORT); + } + + bool isFloatSortImpl() const override { + return (Z3_get_sort_kind(Context.Context, Sort) == Z3_FLOATING_POINT_SORT); + } + + bool isBooleanSortImpl() const override { + return (Z3_get_sort_kind(Context.Context, Sort) == Z3_BOOL_SORT); + } + + unsigned getBitvectorSortSizeImpl() const override { + return Z3_get_bv_sort_size(Context.Context, Sort); + } + + unsigned getFloatSortSizeImpl() const override { + return Z3_fpa_get_ebits(Context.Context, Sort) + + Z3_fpa_get_sbits(Context.Context, Sort); + } + + bool equal_to(SMTSort const &Other) const override { + return Z3_is_eq_sort(Context.Context, Sort, + static_cast<const Z3Sort &>(Other).Sort); + } + + void print(raw_ostream &OS) const override { + OS << Z3_sort_to_string(Context.Context, Sort); + } +}; // end class Z3Sort + +static const Z3Sort &toZ3Sort(const SMTSort &S) { + return static_cast<const Z3Sort &>(S); +} + +class Z3Expr : public SMTExpr { + friend class Z3Solver; + + Z3Context &Context; + + Z3_ast AST; + +public: + Z3Expr(Z3Context &C, Z3_ast ZA) : SMTExpr(), Context(C), AST(ZA) { + Z3_inc_ref(Context.Context, AST); + } + + /// Override implicit copy constructor for correct reference counting. + Z3Expr(const Z3Expr &Copy) : SMTExpr(), Context(Copy.Context), AST(Copy.AST) { + Z3_inc_ref(Context.Context, AST); + } + + /// Override implicit copy assignment constructor for correct reference + /// counting. + Z3Expr &operator=(const Z3Expr &Other) { + Z3_inc_ref(Context.Context, Other.AST); + Z3_dec_ref(Context.Context, AST); + AST = Other.AST; + return *this; + } + + Z3Expr(Z3Expr &&Other) = delete; + Z3Expr &operator=(Z3Expr &&Other) = delete; + + ~Z3Expr() { + if (AST) + Z3_dec_ref(Context.Context, AST); + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddInteger(Z3_get_ast_id(Context.Context, AST)); + } + + /// Comparison of AST equality, not model equivalence. + bool equal_to(SMTExpr const &Other) const override { + assert(Z3_is_eq_sort(Context.Context, Z3_get_sort(Context.Context, AST), + Z3_get_sort(Context.Context, + static_cast<const Z3Expr &>(Other).AST)) && + "AST's must have the same sort"); + return Z3_is_eq_ast(Context.Context, AST, + static_cast<const Z3Expr &>(Other).AST); + } + + void print(raw_ostream &OS) const override { + OS << Z3_ast_to_string(Context.Context, AST); + } +}; // end class Z3Expr + +static const Z3Expr &toZ3Expr(const SMTExpr &E) { + return static_cast<const Z3Expr &>(E); +} + +class Z3Model { + friend class Z3Solver; + + Z3Context &Context; + + Z3_model Model; + +public: + Z3Model(Z3Context &C, Z3_model ZM) : Context(C), Model(ZM) { + Z3_model_inc_ref(Context.Context, Model); + } + + Z3Model(const Z3Model &Other) = delete; + Z3Model(Z3Model &&Other) = delete; + Z3Model &operator=(Z3Model &Other) = delete; + Z3Model &operator=(Z3Model &&Other) = delete; + + ~Z3Model() { + if (Model) + Z3_model_dec_ref(Context.Context, Model); + } + + void print(raw_ostream &OS) const { + OS << Z3_model_to_string(Context.Context, Model); + } + + LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); } +}; // end class Z3Model + +/// Get the corresponding IEEE floating-point type for a given bitwidth. +static const llvm::fltSemantics &getFloatSemantics(unsigned BitWidth) { + switch (BitWidth) { + default: + llvm_unreachable("Unsupported floating-point semantics!"); + break; + case 16: + return llvm::APFloat::IEEEhalf(); + case 32: + return llvm::APFloat::IEEEsingle(); + case 64: + return llvm::APFloat::IEEEdouble(); + case 128: + return llvm::APFloat::IEEEquad(); + } +} + +// Determine whether two float semantics are equivalent +static bool areEquivalent(const llvm::fltSemantics &LHS, + const llvm::fltSemantics &RHS) { + return (llvm::APFloat::semanticsPrecision(LHS) == + llvm::APFloat::semanticsPrecision(RHS)) && + (llvm::APFloat::semanticsMinExponent(LHS) == + llvm::APFloat::semanticsMinExponent(RHS)) && + (llvm::APFloat::semanticsMaxExponent(LHS) == + llvm::APFloat::semanticsMaxExponent(RHS)) && + (llvm::APFloat::semanticsSizeInBits(LHS) == + llvm::APFloat::semanticsSizeInBits(RHS)); +} + +class Z3Solver : public SMTSolver { + friend class Z3ConstraintManager; + + Z3Context Context; + + Z3_solver Solver; + + // Cache Sorts + std::set<Z3Sort> CachedSorts; + + // Cache Exprs + std::set<Z3Expr> CachedExprs; + +public: + Z3Solver() : Solver(Z3_mk_simple_solver(Context.Context)) { + Z3_solver_inc_ref(Context.Context, Solver); + } + + Z3Solver(const Z3Solver &Other) = delete; + Z3Solver(Z3Solver &&Other) = delete; + Z3Solver &operator=(Z3Solver &Other) = delete; + Z3Solver &operator=(Z3Solver &&Other) = delete; + + ~Z3Solver() { + if (Solver) + Z3_solver_dec_ref(Context.Context, Solver); + } + + void addConstraint(const SMTExprRef &Exp) const override { + Z3_solver_assert(Context.Context, Solver, toZ3Expr(*Exp).AST); + } + + // Given an SMTSort, adds/retrives it from the cache and returns + // an SMTSortRef to the SMTSort in the cache + SMTSortRef newSortRef(const SMTSort &Sort) { + auto It = CachedSorts.insert(toZ3Sort(Sort)); + return &(*It.first); + } + + // Given an SMTExpr, adds/retrives it from the cache and returns + // an SMTExprRef to the SMTExpr in the cache + SMTExprRef newExprRef(const SMTExpr &Exp) { + auto It = CachedExprs.insert(toZ3Expr(Exp)); + return &(*It.first); + } + + SMTSortRef getBoolSort() override { + return newSortRef(Z3Sort(Context, Z3_mk_bool_sort(Context.Context))); + } + + SMTSortRef getBitvectorSort(unsigned BitWidth) override { + return newSortRef( + Z3Sort(Context, Z3_mk_bv_sort(Context.Context, BitWidth))); + } + + SMTSortRef getSort(const SMTExprRef &Exp) override { + return newSortRef( + Z3Sort(Context, Z3_get_sort(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTSortRef getFloat16Sort() override { + return newSortRef(Z3Sort(Context, Z3_mk_fpa_sort_16(Context.Context))); + } + + SMTSortRef getFloat32Sort() override { + return newSortRef(Z3Sort(Context, Z3_mk_fpa_sort_32(Context.Context))); + } + + SMTSortRef getFloat64Sort() override { + return newSortRef(Z3Sort(Context, Z3_mk_fpa_sort_64(Context.Context))); + } + + SMTSortRef getFloat128Sort() override { + return newSortRef(Z3Sort(Context, Z3_mk_fpa_sort_128(Context.Context))); + } + + SMTExprRef mkBVNeg(const SMTExprRef &Exp) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvneg(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkBVNot(const SMTExprRef &Exp) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvnot(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkNot(const SMTExprRef &Exp) override { + return newExprRef( + Z3Expr(Context, Z3_mk_not(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkBVAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvadd(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSub(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvsub(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVMul(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvmul(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSRem(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvsrem(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVURem(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvurem(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvsdiv(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVUDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvudiv(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVShl(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvshl(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVAshr(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvashr(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVLshr(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvlshr(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVXor(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvxor(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVOr(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvor(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvand(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVUlt(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvult(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSlt(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvslt(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVUgt(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvugt(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSgt(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvsgt(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVUle(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvule(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSle(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvsle(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVUge(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvuge(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVSge(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_bvsge(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + Z3_ast Args[2] = {toZ3Expr(*LHS).AST, toZ3Expr(*RHS).AST}; + return newExprRef(Z3Expr(Context, Z3_mk_and(Context.Context, 2, Args))); + } + + SMTExprRef mkOr(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + Z3_ast Args[2] = {toZ3Expr(*LHS).AST, toZ3Expr(*RHS).AST}; + return newExprRef(Z3Expr(Context, Z3_mk_or(Context.Context, 2, Args))); + } + + SMTExprRef mkEqual(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_eq(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPNeg(const SMTExprRef &Exp) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_neg(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkFPIsInfinite(const SMTExprRef &Exp) override { + return newExprRef(Z3Expr( + Context, Z3_mk_fpa_is_infinite(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkFPIsNaN(const SMTExprRef &Exp) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_is_nan(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkFPIsNormal(const SMTExprRef &Exp) override { + return newExprRef(Z3Expr( + Context, Z3_mk_fpa_is_normal(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkFPIsZero(const SMTExprRef &Exp) override { + return newExprRef(Z3Expr( + Context, Z3_mk_fpa_is_zero(Context.Context, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkFPMul(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef( + Z3Expr(Context, + Z3_mk_fpa_mul(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, toZ3Expr(*RoundingMode).AST))); + } + + SMTExprRef mkFPDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef( + Z3Expr(Context, + Z3_mk_fpa_div(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, toZ3Expr(*RoundingMode).AST))); + } + + SMTExprRef mkFPRem(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_rem(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef( + Z3Expr(Context, + Z3_mk_fpa_add(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, toZ3Expr(*RoundingMode).AST))); + } + + SMTExprRef mkFPSub(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef( + Z3Expr(Context, + Z3_mk_fpa_sub(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, toZ3Expr(*RoundingMode).AST))); + } + + SMTExprRef mkFPLt(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_lt(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPGt(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_gt(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPLe(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_leq(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPGe(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_geq(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPEqual(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_fpa_eq(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkIte(const SMTExprRef &Cond, const SMTExprRef &T, + const SMTExprRef &F) override { + return newExprRef( + Z3Expr(Context, Z3_mk_ite(Context.Context, toZ3Expr(*Cond).AST, + toZ3Expr(*T).AST, toZ3Expr(*F).AST))); + } + + SMTExprRef mkBVSignExt(unsigned i, const SMTExprRef &Exp) override { + return newExprRef(Z3Expr( + Context, Z3_mk_sign_ext(Context.Context, i, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkBVZeroExt(unsigned i, const SMTExprRef &Exp) override { + return newExprRef(Z3Expr( + Context, Z3_mk_zero_ext(Context.Context, i, toZ3Expr(*Exp).AST))); + } + + SMTExprRef mkBVExtract(unsigned High, unsigned Low, + const SMTExprRef &Exp) override { + return newExprRef(Z3Expr(Context, Z3_mk_extract(Context.Context, High, Low, + toZ3Expr(*Exp).AST))); + } + + /// Creates a predicate that checks for overflow in a bitvector addition + /// operation + SMTExprRef mkBVAddNoOverflow(const SMTExprRef &LHS, const SMTExprRef &RHS, + bool isSigned) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvadd_no_overflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, isSigned))); + } + + /// Creates a predicate that checks for underflow in a signed bitvector + /// addition operation + SMTExprRef mkBVAddNoUnderflow(const SMTExprRef &LHS, + const SMTExprRef &RHS) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvadd_no_underflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + /// Creates a predicate that checks for overflow in a signed bitvector + /// subtraction operation + SMTExprRef mkBVSubNoOverflow(const SMTExprRef &LHS, + const SMTExprRef &RHS) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvsub_no_overflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + /// Creates a predicate that checks for underflow in a bitvector subtraction + /// operation + SMTExprRef mkBVSubNoUnderflow(const SMTExprRef &LHS, const SMTExprRef &RHS, + bool isSigned) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvsub_no_underflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, isSigned))); + } + + /// Creates a predicate that checks for overflow in a signed bitvector + /// division/modulus operation + SMTExprRef mkBVSDivNoOverflow(const SMTExprRef &LHS, + const SMTExprRef &RHS) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvsdiv_no_overflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + /// Creates a predicate that checks for overflow in a bitvector negation + /// operation + SMTExprRef mkBVNegNoOverflow(const SMTExprRef &Exp) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvneg_no_overflow(Context.Context, toZ3Expr(*Exp).AST))); + } + + /// Creates a predicate that checks for overflow in a bitvector multiplication + /// operation + SMTExprRef mkBVMulNoOverflow(const SMTExprRef &LHS, const SMTExprRef &RHS, + bool isSigned) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvmul_no_overflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST, isSigned))); + } + + /// Creates a predicate that checks for underflow in a signed bitvector + /// multiplication operation + SMTExprRef mkBVMulNoUnderflow(const SMTExprRef &LHS, + const SMTExprRef &RHS) override { + return newExprRef(Z3Expr( + Context, Z3_mk_bvmul_no_underflow(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkBVConcat(const SMTExprRef &LHS, const SMTExprRef &RHS) override { + return newExprRef( + Z3Expr(Context, Z3_mk_concat(Context.Context, toZ3Expr(*LHS).AST, + toZ3Expr(*RHS).AST))); + } + + SMTExprRef mkFPtoFP(const SMTExprRef &From, const SMTSortRef &To) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef(Z3Expr( + Context, + Z3_mk_fpa_to_fp_float(Context.Context, toZ3Expr(*RoundingMode).AST, + toZ3Expr(*From).AST, toZ3Sort(*To).Sort))); + } + + SMTExprRef mkSBVtoFP(const SMTExprRef &From, const SMTSortRef &To) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef(Z3Expr( + Context, + Z3_mk_fpa_to_fp_signed(Context.Context, toZ3Expr(*RoundingMode).AST, + toZ3Expr(*From).AST, toZ3Sort(*To).Sort))); + } + + SMTExprRef mkUBVtoFP(const SMTExprRef &From, const SMTSortRef &To) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef(Z3Expr( + Context, + Z3_mk_fpa_to_fp_unsigned(Context.Context, toZ3Expr(*RoundingMode).AST, + toZ3Expr(*From).AST, toZ3Sort(*To).Sort))); + } + + SMTExprRef mkFPtoSBV(const SMTExprRef &From, unsigned ToWidth) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef(Z3Expr( + Context, Z3_mk_fpa_to_sbv(Context.Context, toZ3Expr(*RoundingMode).AST, + toZ3Expr(*From).AST, ToWidth))); + } + + SMTExprRef mkFPtoUBV(const SMTExprRef &From, unsigned ToWidth) override { + SMTExprRef RoundingMode = getFloatRoundingMode(); + return newExprRef(Z3Expr( + Context, Z3_mk_fpa_to_ubv(Context.Context, toZ3Expr(*RoundingMode).AST, + toZ3Expr(*From).AST, ToWidth))); + } + + SMTExprRef mkBoolean(const bool b) override { + return newExprRef(Z3Expr(Context, b ? Z3_mk_true(Context.Context) + : Z3_mk_false(Context.Context))); + } + + SMTExprRef mkBitvector(const llvm::APSInt Int, unsigned BitWidth) override { + const SMTSortRef Sort = getBitvectorSort(BitWidth); + return newExprRef( + Z3Expr(Context, Z3_mk_numeral(Context.Context, Int.toString(10).c_str(), + toZ3Sort(*Sort).Sort))); + } + + SMTExprRef mkFloat(const llvm::APFloat Float) override { + SMTSortRef Sort = + getFloatSort(llvm::APFloat::semanticsSizeInBits(Float.getSemantics())); + + llvm::APSInt Int = llvm::APSInt(Float.bitcastToAPInt(), false); + SMTExprRef Z3Int = mkBitvector(Int, Int.getBitWidth()); + return newExprRef(Z3Expr( + Context, Z3_mk_fpa_to_fp_bv(Context.Context, toZ3Expr(*Z3Int).AST, + toZ3Sort(*Sort).Sort))); + } + + SMTExprRef mkSymbol(const char *Name, SMTSortRef Sort) override { + return newExprRef( + Z3Expr(Context, Z3_mk_const(Context.Context, + Z3_mk_string_symbol(Context.Context, Name), + toZ3Sort(*Sort).Sort))); + } + + llvm::APSInt getBitvector(const SMTExprRef &Exp, unsigned BitWidth, + bool isUnsigned) override { + return llvm::APSInt( + llvm::APInt(BitWidth, + Z3_get_numeral_string(Context.Context, toZ3Expr(*Exp).AST), + 10), + isUnsigned); + } + + bool getBoolean(const SMTExprRef &Exp) override { + return Z3_get_bool_value(Context.Context, toZ3Expr(*Exp).AST) == Z3_L_TRUE; + } + + SMTExprRef getFloatRoundingMode() override { + // TODO: Don't assume nearest ties to even rounding mode + return newExprRef(Z3Expr(Context, Z3_mk_fpa_rne(Context.Context))); + } + + bool toAPFloat(const SMTSortRef &Sort, const SMTExprRef &AST, + llvm::APFloat &Float, bool useSemantics) { + assert(Sort->isFloatSort() && "Unsupported sort to floating-point!"); + + llvm::APSInt Int(Sort->getFloatSortSize(), true); + const llvm::fltSemantics &Semantics = + getFloatSemantics(Sort->getFloatSortSize()); + SMTSortRef BVSort = getBitvectorSort(Sort->getFloatSortSize()); + if (!toAPSInt(BVSort, AST, Int, true)) { + return false; + } + + if (useSemantics && !areEquivalent(Float.getSemantics(), Semantics)) { + assert(false && "Floating-point types don't match!"); + return false; + } + + Float = llvm::APFloat(Semantics, Int); + return true; + } + + bool toAPSInt(const SMTSortRef &Sort, const SMTExprRef &AST, + llvm::APSInt &Int, bool useSemantics) { + if (Sort->isBitvectorSort()) { + if (useSemantics && Int.getBitWidth() != Sort->getBitvectorSortSize()) { + assert(false && "Bitvector types don't match!"); + return false; + } + + // FIXME: This function is also used to retrieve floating-point values, + // which can be 16, 32, 64 or 128 bits long. Bitvectors can be anything + // between 1 and 64 bits long, which is the reason we have this weird + // guard. In the future, we need proper calls in the backend to retrieve + // floating-points and its special values (NaN, +/-infinity, +/-zero), + // then we can drop this weird condition. + if (Sort->getBitvectorSortSize() <= 64 || + Sort->getBitvectorSortSize() == 128) { + Int = getBitvector(AST, Int.getBitWidth(), Int.isUnsigned()); + return true; + } + + assert(false && "Bitwidth not supported!"); + return false; + } + + if (Sort->isBooleanSort()) { + if (useSemantics && Int.getBitWidth() < 1) { + assert(false && "Boolean type doesn't match!"); + return false; + } + + Int = llvm::APSInt(llvm::APInt(Int.getBitWidth(), getBoolean(AST)), + Int.isUnsigned()); + return true; + } + + llvm_unreachable("Unsupported sort to integer!"); + } + + bool getInterpretation(const SMTExprRef &Exp, llvm::APSInt &Int) override { + Z3Model Model(Context, Z3_solver_get_model(Context.Context, Solver)); + Z3_func_decl Func = Z3_get_app_decl( + Context.Context, Z3_to_app(Context.Context, toZ3Expr(*Exp).AST)); + if (Z3_model_has_interp(Context.Context, Model.Model, Func) != Z3_L_TRUE) + return false; + + SMTExprRef Assign = newExprRef( + Z3Expr(Context, + Z3_model_get_const_interp(Context.Context, Model.Model, Func))); + SMTSortRef Sort = getSort(Assign); + return toAPSInt(Sort, Assign, Int, true); + } + + bool getInterpretation(const SMTExprRef &Exp, llvm::APFloat &Float) override { + Z3Model Model(Context, Z3_solver_get_model(Context.Context, Solver)); + Z3_func_decl Func = Z3_get_app_decl( + Context.Context, Z3_to_app(Context.Context, toZ3Expr(*Exp).AST)); + if (Z3_model_has_interp(Context.Context, Model.Model, Func) != Z3_L_TRUE) + return false; + + SMTExprRef Assign = newExprRef( + Z3Expr(Context, + Z3_model_get_const_interp(Context.Context, Model.Model, Func))); + SMTSortRef Sort = getSort(Assign); + return toAPFloat(Sort, Assign, Float, true); + } + + Optional<bool> check() const override { + Z3_lbool res = Z3_solver_check(Context.Context, Solver); + if (res == Z3_L_TRUE) + return true; + + if (res == Z3_L_FALSE) + return false; + + return Optional<bool>(); + } + + void push() override { return Z3_solver_push(Context.Context, Solver); } + + void pop(unsigned NumStates = 1) override { + assert(Z3_solver_get_num_scopes(Context.Context, Solver) >= NumStates); + return Z3_solver_pop(Context.Context, Solver, NumStates); + } + + bool isFPSupported() override { return true; } + + /// Reset the solver and remove all constraints. + void reset() override { Z3_solver_reset(Context.Context, Solver); } + + void print(raw_ostream &OS) const override { + OS << Z3_solver_to_string(Context.Context, Solver); + } +}; // end class Z3Solver + +} // end anonymous namespace + +#endif + +llvm::SMTSolverRef llvm::CreateZ3Solver() { +#if LLVM_WITH_Z3 + return llvm::make_unique<Z3Solver>(); +#else + llvm::report_fatal_error("LLVM was not compiled with Z3 support, rebuild " + "with -DLLVM_ENABLE_Z3_SOLVER=ON", + false); + return nullptr; +#endif +} + +LLVM_DUMP_METHOD void SMTSort::dump() const { print(llvm::errs()); } +LLVM_DUMP_METHOD void SMTExpr::dump() const { print(llvm::errs()); } +LLVM_DUMP_METHOD void SMTSolver::dump() const { print(llvm::errs()); } diff --git a/contrib/llvm/lib/Support/circular_raw_ostream.cpp b/contrib/llvm/lib/Support/circular_raw_ostream.cpp index e768f17cd00d..acd230704ff8 100644 --- a/contrib/llvm/lib/Support/circular_raw_ostream.cpp +++ b/contrib/llvm/lib/Support/circular_raw_ostream.cpp @@ -1,9 +1,8 @@ //===- circular_raw_ostream.cpp - Implement circular_raw_ostream ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/raw_os_ostream.cpp b/contrib/llvm/lib/Support/raw_os_ostream.cpp index 44f2325d7f8a..81f0d739696e 100644 --- a/contrib/llvm/lib/Support/raw_os_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_os_ostream.cpp @@ -1,9 +1,8 @@ //===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp index 21dde7ff914a..2baccaa0cbd7 100644 --- a/contrib/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -1,9 +1,8 @@ //===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -613,7 +612,7 @@ raw_fd_ostream::~raw_fd_ostream() { // destructing raw_ostream objects which may have errors. if (has_error()) report_fatal_error("IO failure on output stream: " + error().message(), - /*GenCrashDiag=*/false); + /*gen_crash_diag=*/false); } #if defined(_WIN32) |