summaryrefslogtreecommitdiff
path: root/llvm/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r--llvm/lib/Support/AArch64TargetParser.cpp10
-rw-r--r--llvm/lib/Support/AMDGPUMetadata.cpp6
-rw-r--r--llvm/lib/Support/APFloat.cpp446
-rw-r--r--llvm/lib/Support/APInt.cpp25
-rw-r--r--llvm/lib/Support/APSInt.cpp9
-rw-r--r--llvm/lib/Support/ARMAttributeParser.cpp848
-rw-r--r--llvm/lib/Support/ARMBuildAttrs.cpp140
-rw-r--r--llvm/lib/Support/ARMTargetParser.cpp42
-rw-r--r--llvm/lib/Support/BranchProbability.cpp2
-rw-r--r--llvm/lib/Support/CRC.cpp12
-rw-r--r--llvm/lib/Support/CachePruning.cpp2
-rw-r--r--llvm/lib/Support/CodeGenCoverage.cpp17
-rw-r--r--llvm/lib/Support/CommandLine.cpp170
-rw-r--r--llvm/lib/Support/Compression.cpp8
-rw-r--r--llvm/lib/Support/ConvertUTFWrapper.cpp2
-rw-r--r--llvm/lib/Support/CrashRecoveryContext.cpp91
-rw-r--r--llvm/lib/Support/DataExtractor.cpp164
-rw-r--r--llvm/lib/Support/Debug.cpp2
-rw-r--r--llvm/lib/Support/DebugCounter.cpp8
-rw-r--r--llvm/lib/Support/ELFAttributeParser.cpp233
-rw-r--r--llvm/lib/Support/ELFAttributes.cpp34
-rw-r--r--llvm/lib/Support/ErrorHandling.cpp3
-rw-r--r--llvm/lib/Support/ExtensibleRTTI.cpp13
-rw-r--r--llvm/lib/Support/FileCheck.cpp928
-rw-r--r--llvm/lib/Support/FileCheckImpl.h349
-rw-r--r--llvm/lib/Support/FileCollector.cpp67
-rw-r--r--llvm/lib/Support/FileOutputBuffer.cpp6
-rw-r--r--llvm/lib/Support/FileUtilities.cpp10
-rw-r--r--llvm/lib/Support/FoldingSet.cpp51
-rw-r--r--llvm/lib/Support/FormatVariadic.cpp5
-rw-r--r--llvm/lib/Support/FormattedStream.cpp66
-rw-r--r--llvm/lib/Support/GraphWriter.cpp31
-rw-r--r--llvm/lib/Support/Host.cpp552
-rw-r--r--llvm/lib/Support/InitLLVM.cpp2
-rw-r--r--llvm/lib/Support/IntEqClasses.cpp1
-rw-r--r--llvm/lib/Support/IntervalMap.cpp1
-rw-r--r--llvm/lib/Support/ItaniumManglingCanonicalizer.cpp11
-rw-r--r--llvm/lib/Support/KnownBits.cpp26
-rw-r--r--llvm/lib/Support/LockFileManager.cpp80
-rw-r--r--llvm/lib/Support/MD5.cpp1
-rw-r--r--llvm/lib/Support/MemAlloc.cpp34
-rw-r--r--llvm/lib/Support/MemoryBuffer.cpp18
-rw-r--r--llvm/lib/Support/NativeFormatting.cpp5
-rw-r--r--llvm/lib/Support/OptimizedStructLayout.cpp449
-rw-r--r--llvm/lib/Support/Parallel.cpp27
-rw-r--r--llvm/lib/Support/Path.cpp154
-rw-r--r--llvm/lib/Support/PrettyStackTrace.cpp15
-rw-r--r--llvm/lib/Support/Process.cpp12
-rw-r--r--llvm/lib/Support/Program.cpp27
-rw-r--r--llvm/lib/Support/RISCVAttributeParser.cpp67
-rw-r--r--llvm/lib/Support/RISCVAttributes.cpp25
-rw-r--r--llvm/lib/Support/RandomNumberGenerator.cpp2
-rw-r--r--llvm/lib/Support/Regex.cpp8
-rw-r--r--llvm/lib/Support/SHA1.cpp11
-rw-r--r--llvm/lib/Support/Signals.cpp2
-rw-r--r--llvm/lib/Support/SmallVector.cpp47
-rw-r--r--llvm/lib/Support/SourceMgr.cpp254
-rw-r--r--llvm/lib/Support/SpecialCaseList.cpp6
-rw-r--r--llvm/lib/Support/Statistic.cpp2
-rw-r--r--llvm/lib/Support/StringExtras.cpp45
-rw-r--r--llvm/lib/Support/StringMap.cpp52
-rw-r--r--llvm/lib/Support/StringPool.cpp34
-rw-r--r--llvm/lib/Support/StringRef.cpp16
-rw-r--r--llvm/lib/Support/SuffixTree.cpp210
-rw-r--r--llvm/lib/Support/SystemUtils.cpp13
-rw-r--r--llvm/lib/Support/TarWriter.cpp15
-rw-r--r--llvm/lib/Support/TargetParser.cpp10
-rw-r--r--llvm/lib/Support/ThreadPool.cpp46
-rw-r--r--llvm/lib/Support/Threading.cpp67
-rw-r--r--llvm/lib/Support/TimeProfiler.cpp214
-rw-r--r--llvm/lib/Support/Timer.cpp7
-rw-r--r--llvm/lib/Support/ToolOutputFile.cpp28
-rw-r--r--llvm/lib/Support/TrigramIndex.cpp1
-rw-r--r--llvm/lib/Support/Triple.cpp92
-rw-r--r--llvm/lib/Support/Unix/Host.inc2
-rw-r--r--llvm/lib/Support/Unix/Memory.inc1
-rw-r--r--llvm/lib/Support/Unix/Path.inc111
-rw-r--r--llvm/lib/Support/Unix/Process.inc26
-rw-r--r--llvm/lib/Support/Unix/Program.inc87
-rw-r--r--llvm/lib/Support/Unix/Threading.inc35
-rw-r--r--llvm/lib/Support/Unix/Unix.h4
-rw-r--r--llvm/lib/Support/VersionTuple.cpp3
-rw-r--r--llvm/lib/Support/VirtualFileSystem.cpp146
-rw-r--r--llvm/lib/Support/Windows/DynamicLibrary.inc2
-rw-r--r--llvm/lib/Support/Windows/Host.inc2
-rw-r--r--llvm/lib/Support/Windows/Memory.inc2
-rw-r--r--llvm/lib/Support/Windows/Path.inc117
-rw-r--r--llvm/lib/Support/Windows/Process.inc48
-rw-r--r--llvm/lib/Support/Windows/Program.inc30
-rw-r--r--llvm/lib/Support/Windows/Signals.inc28
-rw-r--r--llvm/lib/Support/Windows/ThreadLocal.inc2
-rw-r--r--llvm/lib/Support/Windows/Threading.inc176
-rw-r--r--llvm/lib/Support/Windows/WindowsSupport.h243
-rw-r--r--llvm/lib/Support/WithColor.cpp48
-rw-r--r--llvm/lib/Support/X86TargetParser.cpp595
-rw-r--r--llvm/lib/Support/YAMLParser.cpp24
-rw-r--r--llvm/lib/Support/YAMLTraits.cpp8
-rw-r--r--llvm/lib/Support/Z3Solver.cpp40
-rw-r--r--llvm/lib/Support/raw_ostream.cpp194
99 files changed, 5830 insertions, 2633 deletions
diff --git a/llvm/lib/Support/AArch64TargetParser.cpp b/llvm/lib/Support/AArch64TargetParser.cpp
index b5cd4af0eb3de..a6de44605675a 100644
--- a/llvm/lib/Support/AArch64TargetParser.cpp
+++ b/llvm/lib/Support/AArch64TargetParser.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/AArch64TargetParser.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
#include <cctype>
using namespace llvm;
@@ -116,6 +116,8 @@ bool AArch64::getArchFeatures(AArch64::ArchKind AK,
Features.push_back("+v8.4a");
if (AK == ArchKind::ARMV8_5A)
Features.push_back("+v8.5a");
+ if (AK == AArch64::ArchKind::ARMV8_6A)
+ Features.push_back("+v8.6a");
return AK != ArchKind::INVALID;
}
@@ -191,7 +193,7 @@ AArch64::ArchKind AArch64::parseArch(StringRef Arch) {
return ArchKind::INVALID;
StringRef Syn = ARM::getArchSynonym(Arch);
- for (const auto A : AArch64ARCHNames) {
+ for (const auto &A : AArch64ARCHNames) {
if (A.getName().endswith(Syn))
return A.ID;
}
@@ -199,7 +201,7 @@ AArch64::ArchKind AArch64::parseArch(StringRef Arch) {
}
AArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) {
- for (const auto A : AArch64ARCHExtNames) {
+ for (const auto &A : AArch64ARCHExtNames) {
if (ArchExt == A.getName())
return static_cast<ArchExtKind>(A.ID);
}
@@ -207,7 +209,7 @@ AArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) {
}
AArch64::ArchKind AArch64::parseCPUArch(StringRef CPU) {
- for (const auto C : AArch64CPUNames) {
+ for (const auto &C : AArch64CPUNames) {
if (CPU == C.getName())
return C.ArchID;
}
diff --git a/llvm/lib/Support/AMDGPUMetadata.cpp b/llvm/lib/Support/AMDGPUMetadata.cpp
index 4ea197a973894..bfa1fe86cd3ed 100644
--- a/llvm/lib/Support/AMDGPUMetadata.cpp
+++ b/llvm/lib/Support/AMDGPUMetadata.cpp
@@ -111,7 +111,11 @@ struct MappingTraits<Kernel::Arg::Metadata> {
YIO.mapRequired(Kernel::Arg::Key::Size, MD.mSize);
YIO.mapRequired(Kernel::Arg::Key::Align, MD.mAlign);
YIO.mapRequired(Kernel::Arg::Key::ValueKind, MD.mValueKind);
- YIO.mapRequired(Kernel::Arg::Key::ValueType, MD.mValueType);
+
+ // Removed. Accepted for parsing compatibility, but not emitted.
+ Optional<ValueType> Unused;
+ YIO.mapOptional(Kernel::Arg::Key::ValueType, Unused);
+
YIO.mapOptional(Kernel::Arg::Key::PointeeAlign, MD.mPointeeAlign,
uint32_t(0));
YIO.mapOptional(Kernel::Arg::Key::AddrSpaceQual, MD.mAddrSpaceQual,
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 050c37baefb87..569cac790af99 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -69,6 +69,7 @@ namespace llvm {
};
static const fltSemantics semIEEEhalf = {15, -14, 11, 16};
+ static const fltSemantics semBFloat = {127, -126, 8, 16};
static const fltSemantics semIEEEsingle = {127, -126, 24, 32};
static const fltSemantics semIEEEdouble = {1023, -1022, 53, 64};
static const fltSemantics semIEEEquad = {16383, -16382, 113, 128};
@@ -117,6 +118,8 @@ namespace llvm {
switch (S) {
case S_IEEEhalf:
return IEEEhalf();
+ case S_BFloat:
+ return BFloat();
case S_IEEEsingle:
return IEEEsingle();
case S_IEEEdouble:
@@ -135,6 +138,8 @@ namespace llvm {
APFloatBase::SemanticsToEnum(const llvm::fltSemantics &Sem) {
if (&Sem == &llvm::APFloat::IEEEhalf())
return S_IEEEhalf;
+ else if (&Sem == &llvm::APFloat::BFloat())
+ return S_BFloat;
else if (&Sem == &llvm::APFloat::IEEEsingle())
return S_IEEEsingle;
else if (&Sem == &llvm::APFloat::IEEEdouble())
@@ -152,6 +157,9 @@ namespace llvm {
const fltSemantics &APFloatBase::IEEEhalf() {
return semIEEEhalf;
}
+ const fltSemantics &APFloatBase::BFloat() {
+ return semBFloat;
+ }
const fltSemantics &APFloatBase::IEEEsingle() {
return semIEEEsingle;
}
@@ -171,6 +179,12 @@ namespace llvm {
return semPPCDoubleDouble;
}
+ constexpr RoundingMode APFloatBase::rmNearestTiesToEven;
+ constexpr RoundingMode APFloatBase::rmTowardPositive;
+ constexpr RoundingMode APFloatBase::rmTowardNegative;
+ constexpr RoundingMode APFloatBase::rmTowardZero;
+ constexpr RoundingMode APFloatBase::rmNearestTiesToAway;
+
/* A tight upper bound on number of parts required to hold the value
pow(5, power) is
@@ -1323,6 +1337,9 @@ bool IEEEFloat::roundAwayFromZero(roundingMode rounding_mode,
case rmTowardNegative:
return sign;
+
+ default:
+ break;
}
llvm_unreachable("Invalid rounding mode found");
}
@@ -1439,25 +1456,26 @@ IEEEFloat::opStatus IEEEFloat::addOrSubtractSpecials(const IEEEFloat &rhs,
default:
llvm_unreachable(nullptr);
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
+ assign(rhs);
+ LLVM_FALLTHROUGH;
case PackCategoriesIntoKey(fcNaN, fcZero):
case PackCategoriesIntoKey(fcNaN, fcNormal):
case PackCategoriesIntoKey(fcNaN, fcInfinity):
case PackCategoriesIntoKey(fcNaN, fcNaN):
+ if (isSignaling()) {
+ makeQuiet();
+ return opInvalidOp;
+ }
+ return rhs.isSignaling() ? opInvalidOp : opOK;
+
case PackCategoriesIntoKey(fcNormal, fcZero):
case PackCategoriesIntoKey(fcInfinity, fcNormal):
case PackCategoriesIntoKey(fcInfinity, fcZero):
return opOK;
- case PackCategoriesIntoKey(fcZero, fcNaN):
- case PackCategoriesIntoKey(fcNormal, fcNaN):
- case PackCategoriesIntoKey(fcInfinity, fcNaN):
- // We need to be sure to flip the sign here for subtraction because we
- // don't have a separate negate operation so -NaN becomes 0 - NaN here.
- sign = rhs.sign ^ subtract;
- category = fcNaN;
- copySignificand(rhs);
- return opOK;
-
case PackCategoriesIntoKey(fcNormal, fcInfinity):
case PackCategoriesIntoKey(fcZero, fcInfinity):
category = fcInfinity;
@@ -1562,20 +1580,22 @@ IEEEFloat::opStatus IEEEFloat::multiplySpecials(const IEEEFloat &rhs) {
default:
llvm_unreachable(nullptr);
- case PackCategoriesIntoKey(fcNaN, fcZero):
- case PackCategoriesIntoKey(fcNaN, fcNormal):
- case PackCategoriesIntoKey(fcNaN, fcInfinity):
- case PackCategoriesIntoKey(fcNaN, fcNaN):
- sign = false;
- return opOK;
-
case PackCategoriesIntoKey(fcZero, fcNaN):
case PackCategoriesIntoKey(fcNormal, fcNaN):
case PackCategoriesIntoKey(fcInfinity, fcNaN):
+ assign(rhs);
sign = false;
- category = fcNaN;
- copySignificand(rhs);
- return opOK;
+ LLVM_FALLTHROUGH;
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ sign ^= rhs.sign; // restore the original sign
+ if (isSignaling()) {
+ makeQuiet();
+ return opInvalidOp;
+ }
+ return rhs.isSignaling() ? opInvalidOp : opOK;
case PackCategoriesIntoKey(fcNormal, fcInfinity):
case PackCategoriesIntoKey(fcInfinity, fcNormal):
@@ -1607,15 +1627,20 @@ IEEEFloat::opStatus IEEEFloat::divideSpecials(const IEEEFloat &rhs) {
case PackCategoriesIntoKey(fcZero, fcNaN):
case PackCategoriesIntoKey(fcNormal, fcNaN):
case PackCategoriesIntoKey(fcInfinity, fcNaN):
- category = fcNaN;
- copySignificand(rhs);
+ assign(rhs);
+ sign = false;
LLVM_FALLTHROUGH;
case PackCategoriesIntoKey(fcNaN, fcZero):
case PackCategoriesIntoKey(fcNaN, fcNormal):
case PackCategoriesIntoKey(fcNaN, fcInfinity):
case PackCategoriesIntoKey(fcNaN, fcNaN):
- sign = false;
- LLVM_FALLTHROUGH;
+ sign ^= rhs.sign; // restore the original sign
+ if (isSignaling()) {
+ makeQuiet();
+ return opInvalidOp;
+ }
+ return rhs.isSignaling() ? opInvalidOp : opOK;
+
case PackCategoriesIntoKey(fcInfinity, fcZero):
case PackCategoriesIntoKey(fcInfinity, fcNormal):
case PackCategoriesIntoKey(fcZero, fcInfinity):
@@ -1645,21 +1670,62 @@ IEEEFloat::opStatus IEEEFloat::modSpecials(const IEEEFloat &rhs) {
default:
llvm_unreachable(nullptr);
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
+ assign(rhs);
+ LLVM_FALLTHROUGH;
case PackCategoriesIntoKey(fcNaN, fcZero):
case PackCategoriesIntoKey(fcNaN, fcNormal):
case PackCategoriesIntoKey(fcNaN, fcInfinity):
case PackCategoriesIntoKey(fcNaN, fcNaN):
+ if (isSignaling()) {
+ makeQuiet();
+ return opInvalidOp;
+ }
+ return rhs.isSignaling() ? opInvalidOp : opOK;
+
case PackCategoriesIntoKey(fcZero, fcInfinity):
case PackCategoriesIntoKey(fcZero, fcNormal):
case PackCategoriesIntoKey(fcNormal, fcInfinity):
return opOK;
+ case PackCategoriesIntoKey(fcNormal, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcNormal):
+ case PackCategoriesIntoKey(fcInfinity, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcZero):
+ makeNaN();
+ return opInvalidOp;
+
+ case PackCategoriesIntoKey(fcNormal, fcNormal):
+ return opOK;
+ }
+}
+
+IEEEFloat::opStatus IEEEFloat::remainderSpecials(const IEEEFloat &rhs) {
+ switch (PackCategoriesIntoKey(category, rhs.category)) {
+ default:
+ llvm_unreachable(nullptr);
+
case PackCategoriesIntoKey(fcZero, fcNaN):
case PackCategoriesIntoKey(fcNormal, fcNaN):
case PackCategoriesIntoKey(fcInfinity, fcNaN):
- sign = false;
- category = fcNaN;
- copySignificand(rhs);
+ assign(rhs);
+ LLVM_FALLTHROUGH;
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ if (isSignaling()) {
+ makeQuiet();
+ return opInvalidOp;
+ }
+ return rhs.isSignaling() ? opInvalidOp : opOK;
+
+ case PackCategoriesIntoKey(fcZero, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcInfinity):
return opOK;
case PackCategoriesIntoKey(fcNormal, fcZero):
@@ -1671,7 +1737,7 @@ IEEEFloat::opStatus IEEEFloat::modSpecials(const IEEEFloat &rhs) {
return opInvalidOp;
case PackCategoriesIntoKey(fcNormal, fcNormal):
- return opOK;
+ return opDivByZero; // fake status, indicating this is not a special case
}
}
@@ -1759,40 +1825,108 @@ IEEEFloat::opStatus IEEEFloat::divide(const IEEEFloat &rhs,
return fs;
}
-/* Normalized remainder. This is not currently correct in all cases. */
+/* Normalized remainder. */
IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) {
opStatus fs;
- IEEEFloat V = *this;
unsigned int origSign = sign;
- fs = V.divide(rhs, rmNearestTiesToEven);
- if (fs == opDivByZero)
+ // First handle the special cases.
+ fs = remainderSpecials(rhs);
+ if (fs != opDivByZero)
return fs;
- int parts = partCount();
- integerPart *x = new integerPart[parts];
- bool ignored;
- fs = V.convertToInteger(makeMutableArrayRef(x, parts),
- parts * integerPartWidth, true, rmNearestTiesToEven,
- &ignored);
- if (fs == opInvalidOp) {
- delete[] x;
- return fs;
+ fs = opOK;
+
+ // Make sure the current value is less than twice the denom. If the addition
+ // did not succeed (an overflow has happened), which means that the finite
+ // value we currently posses must be less than twice the denom (as we are
+ // using the same semantics).
+ IEEEFloat P2 = rhs;
+ if (P2.add(rhs, rmNearestTiesToEven) == opOK) {
+ fs = mod(P2);
+ assert(fs == opOK);
}
- fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true,
- rmNearestTiesToEven);
- assert(fs==opOK); // should always work
+ // Lets work with absolute numbers.
+ IEEEFloat P = rhs;
+ P.sign = false;
+ sign = false;
- fs = V.multiply(rhs, rmNearestTiesToEven);
- assert(fs==opOK || fs==opInexact); // should not overflow or underflow
+ //
+ // To calculate the remainder we use the following scheme.
+ //
+ // The remainder is defained as follows:
+ //
+ // remainder = numer - rquot * denom = x - r * p
+ //
+ // Where r is the result of: x/p, rounded toward the nearest integral value
+ // (with halfway cases rounded toward the even number).
+ //
+ // Currently, (after x mod 2p):
+ // r is the number of 2p's present inside x, which is inherently, an even
+ // number of p's.
+ //
+ // We may split the remaining calculation into 4 options:
+ // - if x < 0.5p then we round to the nearest number with is 0, and are done.
+ // - if x == 0.5p then we round to the nearest even number which is 0, and we
+ // are done as well.
+ // - if 0.5p < x < p then we round to nearest number which is 1, and we have
+ // to subtract 1p at least once.
+ // - if x >= p then we must subtract p at least once, as x must be a
+ // remainder.
+ //
+ // By now, we were done, or we added 1 to r, which in turn, now an odd number.
+ //
+ // We can now split the remaining calculation to the following 3 options:
+ // - if x < 0.5p then we round to the nearest number with is 0, and are done.
+ // - if x == 0.5p then we round to the nearest even number. As r is odd, we
+ // must round up to the next even number. so we must subtract p once more.
+ // - if x > 0.5p (and inherently x < p) then we must round r up to the next
+ // integral, and subtract p once more.
+ //
- fs = subtract(V, rmNearestTiesToEven);
- assert(fs==opOK || fs==opInexact); // likewise
+ // Extend the semantics to prevent an overflow/underflow or inexact result.
+ bool losesInfo;
+ fltSemantics extendedSemantics = *semantics;
+ extendedSemantics.maxExponent++;
+ extendedSemantics.minExponent--;
+ extendedSemantics.precision += 2;
+
+ IEEEFloat VEx = *this;
+ fs = VEx.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo);
+ assert(fs == opOK && !losesInfo);
+ IEEEFloat PEx = P;
+ fs = PEx.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo);
+ assert(fs == opOK && !losesInfo);
+
+ // It is simpler to work with 2x instead of 0.5p, and we do not need to lose
+ // any fraction.
+ fs = VEx.add(VEx, rmNearestTiesToEven);
+ assert(fs == opOK);
+
+ if (VEx.compare(PEx) == cmpGreaterThan) {
+ fs = subtract(P, rmNearestTiesToEven);
+ assert(fs == opOK);
+
+ // Make VEx = this.add(this), but because we have different semantics, we do
+ // not want to `convert` again, so we just subtract PEx twice (which equals
+ // to the desired value).
+ fs = VEx.subtract(PEx, rmNearestTiesToEven);
+ assert(fs == opOK);
+ fs = VEx.subtract(PEx, rmNearestTiesToEven);
+ assert(fs == opOK);
+
+ cmpResult result = VEx.compare(PEx);
+ if (result == cmpGreaterThan || result == cmpEqual) {
+ fs = subtract(P, rmNearestTiesToEven);
+ assert(fs == opOK);
+ }
+ }
if (isZero())
sign = origSign; // IEEE754 requires this
- delete[] x;
+ else
+ sign ^= origSign;
return fs;
}
@@ -1860,14 +1994,59 @@ IEEEFloat::opStatus IEEEFloat::fusedMultiplyAdd(const IEEEFloat &multiplicand,
return fs;
}
-/* Rounding-mode corrrect round to integral value. */
+/* Rounding-mode correct round to integral value. */
IEEEFloat::opStatus IEEEFloat::roundToIntegral(roundingMode rounding_mode) {
opStatus fs;
+ if (isInfinity())
+ // [IEEE Std 754-2008 6.1]:
+ // The behavior of infinity in floating-point arithmetic is derived from the
+ // limiting cases of real arithmetic with operands of arbitrarily
+ // large magnitude, when such a limit exists.
+ // ...
+ // Operations on infinite operands are usually exact and therefore signal no
+ // exceptions ...
+ return opOK;
+
+ if (isNaN()) {
+ if (isSignaling()) {
+ // [IEEE Std 754-2008 6.2]:
+ // Under default exception handling, any operation signaling an invalid
+ // operation exception and for which a floating-point result is to be
+ // delivered shall deliver a quiet NaN.
+ makeQuiet();
+ // [IEEE Std 754-2008 6.2]:
+ // Signaling NaNs shall be reserved operands that, under default exception
+ // handling, signal the invalid operation exception(see 7.2) for every
+ // general-computational and signaling-computational operation except for
+ // the conversions described in 5.12.
+ return opInvalidOp;
+ } else {
+ // [IEEE Std 754-2008 6.2]:
+ // For an operation with quiet NaN inputs, other than maximum and minimum
+ // operations, if a floating-point result is to be delivered the result
+ // shall be a quiet NaN which should be one of the input NaNs.
+ // ...
+ // Every general-computational and quiet-computational operation involving
+ // one or more input NaNs, none of them signaling, shall signal no
+ // exception, except fusedMultiplyAdd might signal the invalid operation
+ // exception(see 7.2).
+ return opOK;
+ }
+ }
+
+ if (isZero()) {
+ // [IEEE Std 754-2008 6.3]:
+ // ... the sign of the result of conversions, the quantize operation, the
+ // roundToIntegral operations, and the roundToIntegralExact(see 5.3.1) is
+ // the sign of the first or only operand.
+ return opOK;
+ }
+
// If the exponent is large enough, we know that this value is already
// integral, and the arithmetic below would potentially cause it to saturate
// to +/-Inf. Bail out early instead.
- if (isFiniteNonZero() && exponent+1 >= (int)semanticsPrecision(*semantics))
+ if (exponent+1 >= (int)semanticsPrecision(*semantics))
return opOK;
// The algorithm here is quite simple: we add 2^(p-1), where p is the
@@ -1881,19 +2060,18 @@ IEEEFloat::opStatus IEEEFloat::roundToIntegral(roundingMode rounding_mode) {
IEEEFloat MagicConstant(*semantics);
fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
rmNearestTiesToEven);
+ assert(fs == opOK);
MagicConstant.sign = sign;
- if (fs != opOK)
- return fs;
-
- // Preserve the input sign so that we can handle 0.0/-0.0 cases correctly.
+ // Preserve the input sign so that we can handle the case of zero result
+ // correctly.
bool inputSign = isNegative();
fs = add(MagicConstant, rounding_mode);
- if (fs != opOK && fs != opInexact)
- return fs;
- fs = subtract(MagicConstant, rounding_mode);
+ // Current value and 'MagicConstant' are both integers, so the result of the
+ // subtraction is always exact according to Sterbenz' lemma.
+ subtract(MagicConstant, rounding_mode);
// Restore the input sign.
if (inputSign != isNegative())
@@ -2621,24 +2799,70 @@ IEEEFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) {
}
bool IEEEFloat::convertFromStringSpecials(StringRef str) {
+ const size_t MIN_NAME_SIZE = 3;
+
+ if (str.size() < MIN_NAME_SIZE)
+ return false;
+
if (str.equals("inf") || str.equals("INFINITY") || str.equals("+Inf")) {
makeInf(false);
return true;
}
- if (str.equals("-inf") || str.equals("-INFINITY") || str.equals("-Inf")) {
- makeInf(true);
- return true;
+ bool IsNegative = str.front() == '-';
+ if (IsNegative) {
+ str = str.drop_front();
+ if (str.size() < MIN_NAME_SIZE)
+ return false;
+
+ if (str.equals("inf") || str.equals("INFINITY") || str.equals("Inf")) {
+ makeInf(true);
+ return true;
+ }
}
- if (str.equals("nan") || str.equals("NaN")) {
- makeNaN(false, false);
- return true;
+ // If we have a 's' (or 'S') prefix, then this is a Signaling NaN.
+ bool IsSignaling = str.front() == 's' || str.front() == 'S';
+ if (IsSignaling) {
+ str = str.drop_front();
+ if (str.size() < MIN_NAME_SIZE)
+ return false;
}
- if (str.equals("-nan") || str.equals("-NaN")) {
- makeNaN(false, true);
- return true;
+ if (str.startswith("nan") || str.startswith("NaN")) {
+ str = str.drop_front(3);
+
+ // A NaN without payload.
+ if (str.empty()) {
+ makeNaN(IsSignaling, IsNegative);
+ return true;
+ }
+
+ // Allow the payload to be inside parentheses.
+ if (str.front() == '(') {
+ // Parentheses should be balanced (and not empty).
+ if (str.size() <= 2 || str.back() != ')')
+ return false;
+
+ str = str.slice(1, str.size() - 1);
+ }
+
+ // Determine the payload number's radix.
+ unsigned Radix = 10;
+ if (str[0] == '0') {
+ if (str.size() > 1 && tolower(str[1]) == 'x') {
+ str = str.drop_front(2);
+ Radix = 16;
+ } else
+ Radix = 8;
+ }
+
+ // Parse the payload and make the NaN.
+ APInt Payload;
+ if (!str.getAsInteger(Radix, Payload)) {
+ makeNaN(IsSignaling, IsNegative, &Payload);
+ return true;
+ }
}
return false;
@@ -3039,6 +3263,33 @@ APInt IEEEFloat::convertFloatAPFloatToAPInt() const {
(mysignificand & 0x7fffff)));
}
+APInt IEEEFloat::convertBFloatAPFloatToAPInt() const {
+ assert(semantics == (const llvm::fltSemantics *)&semBFloat);
+ assert(partCount() == 1);
+
+ uint32_t myexponent, mysignificand;
+
+ if (isFiniteNonZero()) {
+ myexponent = exponent + 127; // bias
+ mysignificand = (uint32_t)*significandParts();
+ if (myexponent == 1 && !(mysignificand & 0x80))
+ myexponent = 0; // denormal
+ } else if (category == fcZero) {
+ myexponent = 0;
+ mysignificand = 0;
+ } else if (category == fcInfinity) {
+ myexponent = 0xff;
+ mysignificand = 0;
+ } else {
+ assert(category == fcNaN && "Unknown category!");
+ myexponent = 0xff;
+ mysignificand = (uint32_t)*significandParts();
+ }
+
+ return APInt(16, (((sign & 1) << 15) | ((myexponent & 0xff) << 7) |
+ (mysignificand & 0x7f)));
+}
+
APInt IEEEFloat::convertHalfAPFloatToAPInt() const {
assert(semantics == (const llvm::fltSemantics*)&semIEEEhalf);
assert(partCount()==1);
@@ -3074,6 +3325,9 @@ APInt IEEEFloat::bitcastToAPInt() const {
if (semantics == (const llvm::fltSemantics*)&semIEEEhalf)
return convertHalfAPFloatToAPInt();
+ if (semantics == (const llvm::fltSemantics *)&semBFloat)
+ return convertBFloatAPFloatToAPInt();
+
if (semantics == (const llvm::fltSemantics*)&semIEEEsingle)
return convertFloatAPFloatToAPInt();
@@ -3270,6 +3524,37 @@ void IEEEFloat::initFromFloatAPInt(const APInt &api) {
}
}
+void IEEEFloat::initFromBFloatAPInt(const APInt &api) {
+ assert(api.getBitWidth() == 16);
+ uint32_t i = (uint32_t)*api.getRawData();
+ uint32_t myexponent = (i >> 7) & 0xff;
+ uint32_t mysignificand = i & 0x7f;
+
+ initialize(&semBFloat);
+ assert(partCount() == 1);
+
+ sign = i >> 15;
+ if (myexponent == 0 && mysignificand == 0) {
+ // exponent, significand meaningless
+ category = fcZero;
+ } else if (myexponent == 0xff && mysignificand == 0) {
+ // exponent, significand meaningless
+ category = fcInfinity;
+ } else if (myexponent == 0xff && mysignificand != 0) {
+ // sign, exponent, significand meaningless
+ category = fcNaN;
+ *significandParts() = mysignificand;
+ } else {
+ category = fcNormal;
+ exponent = myexponent - 127; // bias
+ *significandParts() = mysignificand;
+ if (myexponent == 0) // denormal
+ exponent = -126;
+ else
+ *significandParts() |= 0x80; // integer bit
+ }
+}
+
void IEEEFloat::initFromHalfAPInt(const APInt &api) {
assert(api.getBitWidth()==16);
uint32_t i = (uint32_t)*api.getRawData();
@@ -3308,6 +3593,8 @@ void IEEEFloat::initFromHalfAPInt(const APInt &api) {
void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) {
if (Sem == &semIEEEhalf)
return initFromHalfAPInt(api);
+ if (Sem == &semBFloat)
+ return initFromBFloatAPInt(api);
if (Sem == &semIEEEsingle)
return initFromFloatAPInt(api);
if (Sem == &semIEEEdouble)
@@ -4425,7 +4712,7 @@ bool DoubleAPFloat::isDenormal() const {
return getCategory() == fcNormal &&
(Floats[0].isDenormal() || Floats[1].isDenormal() ||
// (double)(Hi + Lo) == Hi defines a normal number.
- Floats[0].compare(Floats[0] + Floats[1]) != cmpEqual);
+ Floats[0] != Floats[0] + Floats[1]);
}
bool DoubleAPFloat::isSmallest() const {
@@ -4547,26 +4834,9 @@ APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,
llvm_unreachable("Unexpected semantics");
}
-APFloat APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) {
- if (isIEEE) {
- switch (BitWidth) {
- case 16:
- return APFloat(semIEEEhalf, APInt::getAllOnesValue(BitWidth));
- case 32:
- return APFloat(semIEEEsingle, APInt::getAllOnesValue(BitWidth));
- case 64:
- return APFloat(semIEEEdouble, APInt::getAllOnesValue(BitWidth));
- case 80:
- return APFloat(semX87DoubleExtended, APInt::getAllOnesValue(BitWidth));
- case 128:
- return APFloat(semIEEEquad, APInt::getAllOnesValue(BitWidth));
- default:
- llvm_unreachable("Unknown floating bit width");
- }
- } else {
- assert(BitWidth == 128);
- return APFloat(semPPCDoubleDouble, APInt::getAllOnesValue(BitWidth));
- }
+APFloat APFloat::getAllOnesValue(const fltSemantics &Semantics,
+ unsigned BitWidth) {
+ return APFloat(Semantics, APInt::getAllOnesValue(BitWidth));
}
void APFloat::print(raw_ostream &OS) const {
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 9b9cd70078b3d..9a6f93feaa29f 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -548,9 +548,11 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) {
hash_code llvm::hash_value(const APInt &Arg) {
if (Arg.isSingleWord())
- return hash_combine(Arg.U.VAL);
+ return hash_combine(Arg.BitWidth, Arg.U.VAL);
- return hash_combine_range(Arg.U.pVal, Arg.U.pVal + Arg.getNumWords());
+ return hash_combine(
+ Arg.BitWidth,
+ hash_combine_range(Arg.U.pVal, Arg.U.pVal + Arg.getNumWords()));
}
bool APInt::isSplat(unsigned SplatSizeInBits) const {
@@ -670,20 +672,16 @@ bool APInt::isSubsetOfSlowCase(const APInt &RHS) const {
}
APInt APInt::byteSwap() const {
- assert(BitWidth >= 16 && BitWidth % 16 == 0 && "Cannot byteswap!");
+ assert(BitWidth >= 16 && BitWidth % 8 == 0 && "Cannot byteswap!");
if (BitWidth == 16)
return APInt(BitWidth, ByteSwap_16(uint16_t(U.VAL)));
if (BitWidth == 32)
return APInt(BitWidth, ByteSwap_32(unsigned(U.VAL)));
- if (BitWidth == 48) {
- unsigned Tmp1 = unsigned(U.VAL >> 16);
- Tmp1 = ByteSwap_32(Tmp1);
- uint16_t Tmp2 = uint16_t(U.VAL);
- Tmp2 = ByteSwap_16(Tmp2);
- return APInt(BitWidth, (uint64_t(Tmp2) << 32) | Tmp1);
+ if (BitWidth <= 64) {
+ uint64_t Tmp1 = ByteSwap_64(U.VAL);
+ Tmp1 >>= (64 - BitWidth);
+ return APInt(BitWidth, Tmp1);
}
- if (BitWidth == 64)
- return APInt(BitWidth, ByteSwap_64(U.VAL));
APInt Result(getNumWords() * APINT_BITS_PER_WORD, 0);
for (unsigned I = 0, N = getNumWords(); I != N; ++I)
@@ -2283,7 +2281,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix,
std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const {
SmallString<40> S;
toString(S, Radix, Signed, /* formatAsCLiteral = */false);
- return S.str();
+ return std::string(S.str());
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
@@ -3088,7 +3086,8 @@ void llvm::StoreIntToMemory(const APInt &IntVal, uint8_t *Dst,
/// 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) {
+void llvm::LoadIntFromMemory(APInt &IntVal, const 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()));
diff --git a/llvm/lib/Support/APSInt.cpp b/llvm/lib/Support/APSInt.cpp
index 7c48880f96eac..b65b6824eaf8e 100644
--- a/llvm/lib/Support/APSInt.cpp
+++ b/llvm/lib/Support/APSInt.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/StringRef.h"
+#include <cassert>
using namespace llvm;
@@ -25,14 +26,14 @@ APSInt::APSInt(StringRef Str) {
APInt Tmp(NumBits, Str, /*radix=*/10);
if (Str[0] == '-') {
unsigned MinBits = Tmp.getMinSignedBits();
- if (MinBits > 0 && MinBits < NumBits)
- Tmp = Tmp.trunc(MinBits);
+ if (MinBits < NumBits)
+ Tmp = Tmp.trunc(std::max<unsigned>(1, MinBits));
*this = APSInt(Tmp, /*isUnsigned=*/false);
return;
}
unsigned ActiveBits = Tmp.getActiveBits();
- if (ActiveBits > 0 && ActiveBits < NumBits)
- Tmp = Tmp.trunc(ActiveBits);
+ if (ActiveBits < NumBits)
+ Tmp = Tmp.trunc(std::max<unsigned>(1, ActiveBits));
*this = APSInt(Tmp, /*isUnsigned=*/true);
}
diff --git a/llvm/lib/Support/ARMAttributeParser.cpp b/llvm/lib/Support/ARMAttributeParser.cpp
index 8a89f4c45fb95..17ad38d226143 100644
--- a/llvm/lib/Support/ARMAttributeParser.cpp
+++ b/llvm/lib/Support/ARMAttributeParser.cpp
@@ -1,4 +1,4 @@
-//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===//
+//===- ARMAttributeParser.cpp - ARM Attribute Information Printer ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -9,719 +9,365 @@
#include "llvm/Support/ARMAttributeParser.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/ScopedPrinter.h"
using namespace llvm;
using namespace llvm::ARMBuildAttrs;
-
-static const EnumEntry<unsigned> TagNames[] = {
- { "Tag_File", ARMBuildAttrs::File },
- { "Tag_Section", ARMBuildAttrs::Section },
- { "Tag_Symbol", ARMBuildAttrs::Symbol },
-};
-
-namespace llvm {
-#define ATTRIBUTE_HANDLER(Attr_) \
- { ARMBuildAttrs::Attr_, &ARMAttributeParser::Attr_ }
-
-const ARMAttributeParser::DisplayHandler
-ARMAttributeParser::DisplayRoutines[] = {
- { ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::StringAttribute, },
- { ARMBuildAttrs::CPU_name, &ARMAttributeParser::StringAttribute },
- ATTRIBUTE_HANDLER(CPU_arch),
- ATTRIBUTE_HANDLER(CPU_arch_profile),
- ATTRIBUTE_HANDLER(ARM_ISA_use),
- ATTRIBUTE_HANDLER(THUMB_ISA_use),
- 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),
- ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
- ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
- ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
- ATTRIBUTE_HANDLER(ABI_FP_rounding),
- ATTRIBUTE_HANDLER(ABI_FP_denormal),
- ATTRIBUTE_HANDLER(ABI_FP_exceptions),
- ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
- ATTRIBUTE_HANDLER(ABI_FP_number_model),
- ATTRIBUTE_HANDLER(ABI_align_needed),
- ATTRIBUTE_HANDLER(ABI_align_preserved),
- ATTRIBUTE_HANDLER(ABI_enum_size),
- ATTRIBUTE_HANDLER(ABI_HardFP_use),
- ATTRIBUTE_HANDLER(ABI_VFP_args),
- ATTRIBUTE_HANDLER(ABI_WMMX_args),
- ATTRIBUTE_HANDLER(ABI_optimization_goals),
- ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
- ATTRIBUTE_HANDLER(compatibility),
- ATTRIBUTE_HANDLER(CPU_unaligned_access),
- ATTRIBUTE_HANDLER(FP_HP_extension),
- ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
- ATTRIBUTE_HANDLER(MPextension_use),
- ATTRIBUTE_HANDLER(DIV_use),
- ATTRIBUTE_HANDLER(DSP_extension),
- ATTRIBUTE_HANDLER(T2EE_use),
- ATTRIBUTE_HANDLER(Virtualization_use),
- ATTRIBUTE_HANDLER(nodefaults)
+#define ATTRIBUTE_HANDLER(attr) \
+ { ARMBuildAttrs::attr, &ARMAttributeParser::attr }
+
+const ARMAttributeParser::DisplayHandler ARMAttributeParser::displayRoutines[] =
+ {
+ {ARMBuildAttrs::CPU_raw_name, &ARMAttributeParser::stringAttribute},
+ {ARMBuildAttrs::CPU_name, &ARMAttributeParser::stringAttribute},
+ ATTRIBUTE_HANDLER(CPU_arch),
+ ATTRIBUTE_HANDLER(CPU_arch_profile),
+ ATTRIBUTE_HANDLER(ARM_ISA_use),
+ ATTRIBUTE_HANDLER(THUMB_ISA_use),
+ 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),
+ ATTRIBUTE_HANDLER(ABI_PCS_RO_data),
+ ATTRIBUTE_HANDLER(ABI_PCS_GOT_use),
+ ATTRIBUTE_HANDLER(ABI_PCS_wchar_t),
+ ATTRIBUTE_HANDLER(ABI_FP_rounding),
+ ATTRIBUTE_HANDLER(ABI_FP_denormal),
+ ATTRIBUTE_HANDLER(ABI_FP_exceptions),
+ ATTRIBUTE_HANDLER(ABI_FP_user_exceptions),
+ ATTRIBUTE_HANDLER(ABI_FP_number_model),
+ ATTRIBUTE_HANDLER(ABI_align_needed),
+ ATTRIBUTE_HANDLER(ABI_align_preserved),
+ ATTRIBUTE_HANDLER(ABI_enum_size),
+ ATTRIBUTE_HANDLER(ABI_HardFP_use),
+ ATTRIBUTE_HANDLER(ABI_VFP_args),
+ ATTRIBUTE_HANDLER(ABI_WMMX_args),
+ ATTRIBUTE_HANDLER(ABI_optimization_goals),
+ ATTRIBUTE_HANDLER(ABI_FP_optimization_goals),
+ ATTRIBUTE_HANDLER(compatibility),
+ ATTRIBUTE_HANDLER(CPU_unaligned_access),
+ ATTRIBUTE_HANDLER(FP_HP_extension),
+ ATTRIBUTE_HANDLER(ABI_FP_16bit_format),
+ ATTRIBUTE_HANDLER(MPextension_use),
+ ATTRIBUTE_HANDLER(DIV_use),
+ ATTRIBUTE_HANDLER(DSP_extension),
+ ATTRIBUTE_HANDLER(T2EE_use),
+ ATTRIBUTE_HANDLER(Virtualization_use),
+ ATTRIBUTE_HANDLER(nodefaults),
};
#undef ATTRIBUTE_HANDLER
-uint64_t ARMAttributeParser::ParseInteger(const uint8_t *Data,
- uint32_t &Offset) {
- unsigned DecodeLength;
- uint64_t Value = decodeULEB128(Data + Offset, &DecodeLength);
- Offset += DecodeLength;
- return Value;
-}
-
-StringRef ARMAttributeParser::ParseString(const uint8_t *Data,
- uint32_t &Offset) {
- const char *String = reinterpret_cast<const char*>(Data + Offset);
- size_t Length = std::strlen(String);
- Offset = Offset + Length + 1;
- return StringRef(String, Length);
-}
-
-void ARMAttributeParser::IntegerAttribute(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
-
- uint64_t Value = ParseInteger(Data, Offset);
- Attributes.insert(std::make_pair(Tag, Value));
-
- if (SW)
- SW->printNumber(ARMBuildAttrs::AttrTypeAsString(Tag), Value);
-}
-
-void ARMAttributeParser::StringAttribute(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag, /*TagPrefix*/false);
- StringRef ValueDesc = ParseString(Data, Offset);
-
- if (SW) {
- DictScope AS(*SW, "Attribute");
- SW->printNumber("Tag", Tag);
- if (!TagName.empty())
- SW->printString("TagName", TagName);
- SW->printString("Value", ValueDesc);
+Error ARMAttributeParser::stringAttribute(AttrType tag) {
+ StringRef tagName =
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*TagPrefix=*/false);
+ StringRef desc = de.getCStrRef(cursor);
+
+ if (sw) {
+ DictScope scope(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ sw->printString("Value", desc);
}
+ return Error::success();
}
-void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value,
- StringRef ValueDesc) {
- Attributes.insert(std::make_pair(Tag, Value));
-
- if (SW) {
- StringRef TagName = ARMBuildAttrs::AttrTypeAsString(Tag,
- /*TagPrefix*/false);
- DictScope AS(*SW, "Attribute");
- SW->printNumber("Tag", Tag);
- SW->printNumber("Value", Value);
- if (!TagName.empty())
- SW->printString("TagName", TagName);
- if (!ValueDesc.empty())
- SW->printString("Description", ValueDesc);
- }
-}
-
-void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
+Error ARMAttributeParser::CPU_arch(AttrType tag) {
+ static const char *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", nullptr,
"ARM v8-M Baseline", "ARM v8-M Mainline", nullptr, nullptr, nullptr,
"ARM v8.1-M Mainline"
};
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+ return parseStringAttribute("CPU_arch", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Encoded = ParseInteger(Data, Offset);
+Error ARMAttributeParser::CPU_arch_profile(AttrType tag) {
+ uint64_t value = de.getULEB128(cursor);
- StringRef Profile;
- switch (Encoded) {
- default: Profile = "Unknown"; break;
- case 'A': Profile = "Application"; break;
- case 'R': Profile = "Real-time"; break;
- case 'M': Profile = "Microcontroller"; break;
- case 'S': Profile = "Classic"; break;
- case 0: Profile = "None"; break;
+ StringRef profile;
+ switch (value) {
+ default: profile = "Unknown"; break;
+ case 'A': profile = "Application"; break;
+ case 'R': profile = "Real-time"; break;
+ case 'M': profile = "Microcontroller"; break;
+ case 'S': profile = "Classic"; break;
+ case 0: profile = "None"; break;
}
- PrintAttribute(Tag, Encoded, Profile);
+ printAttribute(tag, value, profile);
+ return Error::success();
}
-void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ARM_ISA_use(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Permitted"};
+ return parseStringAttribute("ARM_ISA_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::THUMB_ISA_use(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Thumb-1", "Thumb-2"};
+ return parseStringAttribute("THUMB_ISA_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4",
- "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::FP_arch(AttrType tag) {
+ static const char *strings[] = {
+ "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16",
+ "VFPv4", "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16"};
+ return parseStringAttribute("FP_arch", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::WMMX_arch(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "WMMXv1", "WMMXv2"};
+ return parseStringAttribute("WMMX_arch", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::Advanced_SIMD_arch(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "NEONv1", "NEONv2+FMA",
+ "ARMv8-a NEON", "ARMv8.1-a NEON"};
+ return parseStringAttribute("Advanced_SIMD_arch", tag, makeArrayRef(strings));
}
-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);
+Error ARMAttributeParser::MVE_arch(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "MVE integer",
+ "MVE integer and float"};
+ return parseStringAttribute("MVE_arch", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
+Error ARMAttributeParser::PCS_config(AttrType tag) {
+ static const char *strings[] = {
"None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004",
- "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+ "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)"};
+ return parseStringAttribute("PCS_config", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_PCS_R9_use(AttrType tag) {
+ static const char *strings[] = {"v6", "Static Base", "TLS", "Unused"};
+ return parseStringAttribute("ABI_PCS_R9_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Absolute", "PC-relative", "SB-relative", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_PCS_RW_data(AttrType tag) {
+ static const char *strings[] = {"Absolute", "PC-relative", "SB-relative",
+ "Not Permitted"};
+ return parseStringAttribute("ABI_PCS_RW_data", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Absolute", "PC-relative", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_PCS_RO_data(AttrType tag) {
+ static const char *strings[] = {"Absolute", "PC-relative", "Not Permitted"};
+ return parseStringAttribute("ABI_PCS_RO_data", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Direct", "GOT-Indirect"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_PCS_GOT_use(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Direct", "GOT-Indirect"};
+ return parseStringAttribute("ABI_PCS_GOT_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_PCS_wchar_t(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Unknown", "2-byte",
+ "Unknown", "4-byte"};
+ return parseStringAttribute("ABI_PCS_wchar_t", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "IEEE-754", "Runtime" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_FP_rounding(AttrType tag) {
+ static const char *strings[] = {"IEEE-754", "Runtime"};
+ return parseStringAttribute("ABI_FP_rounding", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Unsupported", "IEEE-754", "Sign Only"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_FP_denormal(AttrType tag) {
+ static const char *strings[] = {"Unsupported", "IEEE-754", "Sign Only"};
+ return parseStringAttribute("ABI_FP_denormal", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_FP_exceptions(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "IEEE-754"};
+ return parseStringAttribute("ABI_FP_exceptions", tag, makeArrayRef(strings));
}
-
-void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_FP_user_exceptions(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "IEEE-754"};
+ return parseStringAttribute("ABI_FP_user_exceptions", tag,
+ makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Finite Only", "RTABI", "IEEE-754"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_FP_number_model(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Finite Only", "RTABI",
+ "IEEE-754"};
+ return parseStringAttribute("ABI_FP_number_model", tag,
+ makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved"
- };
+Error ARMAttributeParser::ABI_align_needed(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "8-byte alignment",
+ "4-byte alignment", "Reserved"};
- uint64_t Value = ParseInteger(Data, Offset);
+ uint64_t value = de.getULEB128(cursor);
- std::string Description;
- if (Value < array_lengthof(Strings))
- Description = std::string(Strings[Value]);
- else if (Value <= 12)
- Description = std::string("8-byte alignment, ") + utostr(1ULL << Value)
- + std::string("-byte extended alignment");
+ std::string description;
+ if (value < array_lengthof(strings))
+ description = strings[value];
+ else if (value <= 12)
+ description = "8-byte alignment, " + utostr(1ULL << value) +
+ "-byte extended alignment";
else
- Description = "Invalid";
+ description = "Invalid";
- PrintAttribute(Tag, Value, Description);
+ printAttribute(tag, value, description);
+ return Error::success();
}
-void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Required", "8-byte data alignment", "8-byte data and code alignment",
- "Reserved"
- };
+Error ARMAttributeParser::ABI_align_preserved(AttrType tag) {
+ static const char *strings[] = {"Not Required", "8-byte data alignment",
+ "8-byte data and code alignment", "Reserved"};
- uint64_t Value = ParseInteger(Data, Offset);
+ uint64_t value = de.getULEB128(cursor);
- std::string Description;
- if (Value < array_lengthof(Strings))
- Description = std::string(Strings[Value]);
- else if (Value <= 12)
- Description = std::string("8-byte stack alignment, ") +
- utostr(1ULL << Value) + std::string("-byte data alignment");
+ std::string description;
+ if (value < array_lengthof(strings))
+ description = std::string(strings[value]);
+ else if (value <= 12)
+ description = std::string("8-byte stack alignment, ") +
+ utostr(1ULL << value) + std::string("-byte data alignment");
else
- Description = "Invalid";
+ description = "Invalid";
- PrintAttribute(Tag, Value, Description);
+ printAttribute(tag, value, description);
+ return Error::success();
}
-void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "Packed", "Int32", "External Int32"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_enum_size(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Packed", "Int32",
+ "External Int32"};
+ return parseStringAttribute("ABI_enum_size", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_HardFP_use(AttrType tag) {
+ static const char *strings[] = {"Tag_FP_arch", "Single-Precision", "Reserved",
+ "Tag_FP_arch (deprecated)"};
+ return parseStringAttribute("ABI_HardFP_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "AAPCS", "AAPCS VFP", "Custom", "Not Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_VFP_args(AttrType tag) {
+ static const char *strings[] = {"AAPCS", "AAPCS VFP", "Custom",
+ "Not Permitted"};
+ return parseStringAttribute("ABI_VFP_args", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_WMMX_args(AttrType tag) {
+ static const char *strings[] = {"AAPCS", "iWMMX", "Custom"};
+ return parseStringAttribute("ABI_WMMX_args", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_optimization_goals(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
+Error ARMAttributeParser::ABI_optimization_goals(AttrType tag) {
+ static const char *strings[] = {
"None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging",
"Best Debugging"
};
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag,
- const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy",
- "Best Accuracy"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
-}
-
-void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Integer = ParseInteger(Data, Offset);
- StringRef String = ParseString(Data, Offset);
-
- if (SW) {
- DictScope AS(*SW, "Attribute");
- SW->printNumber("Tag", Tag);
- SW->startLine() << "Value: " << Integer << ", " << String << '\n';
- SW->printString("TagName", AttrTypeAsString(Tag, /*TagPrefix*/false));
- switch (Integer) {
+ return parseStringAttribute("ABI_optimization_goals", tag,
+ makeArrayRef(strings));
+}
+
+Error ARMAttributeParser::ABI_FP_optimization_goals(AttrType tag) {
+ static const char *strings[] = {
+ "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size",
+ "Accuracy", "Best Accuracy"};
+ return parseStringAttribute("ABI_FP_optimization_goals", tag,
+ makeArrayRef(strings));
+}
+
+Error ARMAttributeParser::compatibility(AttrType tag) {
+ uint64_t integer = de.getULEB128(cursor);
+ StringRef string = de.getCStrRef(cursor);
+
+ if (sw) {
+ DictScope scope(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ sw->startLine() << "Value: " << integer << ", " << string << '\n';
+ sw->printString("TagName",
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap,
+ /*hasTagPrefix=*/false));
+ switch (integer) {
case 0:
- SW->printString("Description", StringRef("No Specific Requirements"));
+ sw->printString("Description", StringRef("No Specific Requirements"));
break;
case 1:
- SW->printString("Description", StringRef("AEABI Conformant"));
+ sw->printString("Description", StringRef("AEABI Conformant"));
break;
default:
- SW->printString("Description", StringRef("AEABI Non-Conformant"));
+ sw->printString("Description", StringRef("AEABI Non-Conformant"));
break;
}
}
+ return Error::success();
}
-void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "v6-style" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::CPU_unaligned_access(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "v6-style"};
+ return parseStringAttribute("CPU_unaligned_access", tag,
+ makeArrayRef(strings));
}
-void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "If Available", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::FP_HP_extension(AttrType tag) {
+ static const char *strings[] = {"If Available", "Permitted"};
+ return parseStringAttribute("FP_HP_extension", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::ABI_FP_16bit_format(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "IEEE-754", "VFPv3"};
+ return parseStringAttribute("ABI_FP_16bit_format", tag,
+ makeArrayRef(strings));
}
-void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::MPextension_use(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Permitted"};
+ return parseStringAttribute("MPextension_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "If Available", "Not Permitted", "Permitted"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::DIV_use(AttrType tag) {
+ static const char *strings[] = {"If Available", "Not Permitted", "Permitted"};
+ return parseStringAttribute("DIV_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::DSP_extension(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::DSP_extension(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Permitted"};
+ return parseStringAttribute("DSP_extension", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = { "Not Permitted", "Permitted" };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::T2EE_use(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "Permitted"};
+ return parseStringAttribute("T2EE_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- static const char *const Strings[] = {
- "Not Permitted", "TrustZone", "Virtualization Extensions",
- "TrustZone + Virtualization Extensions"
- };
-
- uint64_t Value = ParseInteger(Data, Offset);
- StringRef ValueDesc =
- (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr;
- PrintAttribute(Tag, Value, ValueDesc);
+Error ARMAttributeParser::Virtualization_use(AttrType tag) {
+ static const char *strings[] = {"Not Permitted", "TrustZone",
+ "Virtualization Extensions",
+ "TrustZone + Virtualization Extensions"};
+ return parseStringAttribute("Virtualization_use", tag, makeArrayRef(strings));
}
-void ARMAttributeParser::nodefaults(AttrType Tag, const uint8_t *Data,
- uint32_t &Offset) {
- uint64_t Value = ParseInteger(Data, Offset);
- PrintAttribute(Tag, Value, "Unspecified Tags UNDEFINED");
-}
-
-void ARMAttributeParser::ParseIndexList(const uint8_t *Data, uint32_t &Offset,
- SmallVectorImpl<uint8_t> &IndexList) {
- for (;;) {
- unsigned DecodeLength;
- uint64_t Value = decodeULEB128(Data + Offset, &DecodeLength);
- Offset += DecodeLength;
- if (Value == 0)
- break;
- IndexList.push_back(Value);
- }
+Error ARMAttributeParser::nodefaults(AttrType tag) {
+ uint64_t value = de.getULEB128(cursor);
+ printAttribute(tag, value, "Unspecified Tags UNDEFINED");
+ return Error::success();
}
-void ARMAttributeParser::ParseAttributeList(const uint8_t *Data,
- uint32_t &Offset, uint32_t Length) {
- while (Offset < Length) {
- unsigned DecodeLength;
- uint64_t Tag = decodeULEB128(Data + Offset, &DecodeLength);
- Offset += DecodeLength;
-
- bool Handled = false;
- for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines);
- AHI != AHE && !Handled; ++AHI) {
- if (uint64_t(DisplayRoutines[AHI].Attribute) == Tag) {
- (this->*DisplayRoutines[AHI].Routine)(ARMBuildAttrs::AttrType(Tag),
- Data, Offset);
- Handled = true;
- break;
- }
- }
- if (!Handled) {
- if (Tag < 32) {
- errs() << "unhandled AEABI Tag " << Tag
- << " (" << ARMBuildAttrs::AttrTypeAsString(Tag) << ")\n";
- continue;
- }
-
- if (Tag % 2 == 0)
- IntegerAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
- else
- StringAttribute(ARMBuildAttrs::AttrType(Tag), Data, Offset);
- }
- }
-}
-
-void ARMAttributeParser::ParseSubsection(const uint8_t *Data, uint32_t Length) {
- uint32_t Offset = sizeof(uint32_t); /* SectionLength */
-
- const char *VendorName = reinterpret_cast<const char*>(Data + Offset);
- size_t VendorNameLength = std::strlen(VendorName);
- Offset = Offset + VendorNameLength + 1;
-
- if (SW) {
- SW->printNumber("SectionLength", Length);
- SW->printString("Vendor", StringRef(VendorName, VendorNameLength));
- }
-
- if (StringRef(VendorName, VendorNameLength).lower() != "aeabi") {
- return;
- }
-
- while (Offset < Length) {
- /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
- uint8_t Tag = Data[Offset];
- Offset = Offset + sizeof(Tag);
-
- uint32_t Size =
- *reinterpret_cast<const support::ulittle32_t*>(Data + Offset);
- Offset = Offset + sizeof(Size);
-
- if (SW) {
- SW->printEnum("Tag", Tag, makeArrayRef(TagNames));
- SW->printNumber("Size", Size);
- }
-
- if (Size > Length) {
- errs() << "subsection length greater than section length\n";
- return;
- }
-
- StringRef ScopeName, IndexName;
- SmallVector<uint8_t, 8> Indicies;
- switch (Tag) {
- case ARMBuildAttrs::File:
- ScopeName = "FileAttributes";
+Error ARMAttributeParser::handler(uint64_t tag, bool &handled) {
+ handled = false;
+ for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines); AHI != AHE;
+ ++AHI) {
+ if (uint64_t(displayRoutines[AHI].attribute) == tag) {
+ if (Error e =
+ (this->*displayRoutines[AHI].routine)(static_cast<AttrType>(tag)))
+ return e;
+ handled = true;
break;
- case ARMBuildAttrs::Section:
- ScopeName = "SectionAttributes";
- IndexName = "Sections";
- ParseIndexList(Data, Offset, Indicies);
- break;
- case ARMBuildAttrs::Symbol:
- ScopeName = "SymbolAttributes";
- IndexName = "Symbols";
- ParseIndexList(Data, Offset, Indicies);
- break;
- default:
- errs() << "unrecognised tag: 0x" << Twine::utohexstr(Tag) << '\n';
- return;
- }
-
- if (SW) {
- DictScope ASS(*SW, ScopeName);
- if (!Indicies.empty())
- SW->printList(IndexName, Indicies);
- ParseAttributeList(Data, Offset, Length);
- } else {
- ParseAttributeList(Data, Offset, Length);
}
}
-}
-
-void ARMAttributeParser::Parse(ArrayRef<uint8_t> Section, bool isLittle) {
- uint64_t Offset = 1;
- unsigned SectionNumber = 0;
-
- while (Offset < Section.size()) {
- uint32_t SectionLength = isLittle ?
- support::endian::read32le(Section.data() + Offset) :
- support::endian::read32be(Section.data() + Offset);
-
- if (SW) {
- SW->startLine() << "Section " << ++SectionNumber << " {\n";
- 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;
-
- if (SW) {
- SW->unindent();
- SW->startLine() << "}\n";
- }
- }
-}
+ return Error::success();
}
diff --git a/llvm/lib/Support/ARMBuildAttrs.cpp b/llvm/lib/Support/ARMBuildAttrs.cpp
index d0c4fb792cb8c..5aaf0a4e7c62e 100644
--- a/llvm/lib/Support/ARMBuildAttrs.cpp
+++ b/llvm/lib/Support/ARMBuildAttrs.cpp
@@ -6,97 +6,63 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ARMBuildAttributes.h"
using namespace llvm;
-namespace {
-const struct {
- ARMBuildAttrs::AttrType Attr;
- StringRef TagName;
-} ARMAttributeTags[] = {
- { ARMBuildAttrs::File, "Tag_File" },
- { ARMBuildAttrs::Section, "Tag_Section" },
- { ARMBuildAttrs::Symbol, "Tag_Symbol" },
- { ARMBuildAttrs::CPU_raw_name, "Tag_CPU_raw_name" },
- { ARMBuildAttrs::CPU_name, "Tag_CPU_name" },
- { ARMBuildAttrs::CPU_arch, "Tag_CPU_arch" },
- { ARMBuildAttrs::CPU_arch_profile, "Tag_CPU_arch_profile" },
- { ARMBuildAttrs::ARM_ISA_use, "Tag_ARM_ISA_use" },
- { ARMBuildAttrs::THUMB_ISA_use, "Tag_THUMB_ISA_use" },
- { 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" },
- { ARMBuildAttrs::ABI_PCS_RO_data, "Tag_ABI_PCS_RO_data" },
- { ARMBuildAttrs::ABI_PCS_GOT_use, "Tag_ABI_PCS_GOT_use" },
- { ARMBuildAttrs::ABI_PCS_wchar_t, "Tag_ABI_PCS_wchar_t" },
- { ARMBuildAttrs::ABI_FP_rounding, "Tag_ABI_FP_rounding" },
- { ARMBuildAttrs::ABI_FP_denormal, "Tag_ABI_FP_denormal" },
- { ARMBuildAttrs::ABI_FP_exceptions, "Tag_ABI_FP_exceptions" },
- { ARMBuildAttrs::ABI_FP_user_exceptions, "Tag_ABI_FP_user_exceptions" },
- { ARMBuildAttrs::ABI_FP_number_model, "Tag_ABI_FP_number_model" },
- { ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align_needed" },
- { ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align_preserved" },
- { ARMBuildAttrs::ABI_enum_size, "Tag_ABI_enum_size" },
- { ARMBuildAttrs::ABI_HardFP_use, "Tag_ABI_HardFP_use" },
- { ARMBuildAttrs::ABI_VFP_args, "Tag_ABI_VFP_args" },
- { ARMBuildAttrs::ABI_WMMX_args, "Tag_ABI_WMMX_args" },
- { ARMBuildAttrs::ABI_optimization_goals, "Tag_ABI_optimization_goals" },
- { ARMBuildAttrs::ABI_FP_optimization_goals, "Tag_ABI_FP_optimization_goals" },
- { ARMBuildAttrs::compatibility, "Tag_compatibility" },
- { ARMBuildAttrs::CPU_unaligned_access, "Tag_CPU_unaligned_access" },
- { ARMBuildAttrs::FP_HP_extension, "Tag_FP_HP_extension" },
- { ARMBuildAttrs::ABI_FP_16bit_format, "Tag_ABI_FP_16bit_format" },
- { ARMBuildAttrs::MPextension_use, "Tag_MPextension_use" },
- { ARMBuildAttrs::DIV_use, "Tag_DIV_use" },
- { ARMBuildAttrs::DSP_extension, "Tag_DSP_extension" },
- { ARMBuildAttrs::nodefaults, "Tag_nodefaults" },
- { ARMBuildAttrs::also_compatible_with, "Tag_also_compatible_with" },
- { ARMBuildAttrs::T2EE_use, "Tag_T2EE_use" },
- { ARMBuildAttrs::conformance, "Tag_conformance" },
- { ARMBuildAttrs::Virtualization_use, "Tag_Virtualization_use" },
+static const TagNameItem tagData[] = {
+ {ARMBuildAttrs::File, "Tag_File"},
+ {ARMBuildAttrs::Section, "Tag_Section"},
+ {ARMBuildAttrs::Symbol, "Tag_Symbol"},
+ {ARMBuildAttrs::CPU_raw_name, "Tag_CPU_raw_name"},
+ {ARMBuildAttrs::CPU_name, "Tag_CPU_name"},
+ {ARMBuildAttrs::CPU_arch, "Tag_CPU_arch"},
+ {ARMBuildAttrs::CPU_arch_profile, "Tag_CPU_arch_profile"},
+ {ARMBuildAttrs::ARM_ISA_use, "Tag_ARM_ISA_use"},
+ {ARMBuildAttrs::THUMB_ISA_use, "Tag_THUMB_ISA_use"},
+ {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"},
+ {ARMBuildAttrs::ABI_PCS_RO_data, "Tag_ABI_PCS_RO_data"},
+ {ARMBuildAttrs::ABI_PCS_GOT_use, "Tag_ABI_PCS_GOT_use"},
+ {ARMBuildAttrs::ABI_PCS_wchar_t, "Tag_ABI_PCS_wchar_t"},
+ {ARMBuildAttrs::ABI_FP_rounding, "Tag_ABI_FP_rounding"},
+ {ARMBuildAttrs::ABI_FP_denormal, "Tag_ABI_FP_denormal"},
+ {ARMBuildAttrs::ABI_FP_exceptions, "Tag_ABI_FP_exceptions"},
+ {ARMBuildAttrs::ABI_FP_user_exceptions, "Tag_ABI_FP_user_exceptions"},
+ {ARMBuildAttrs::ABI_FP_number_model, "Tag_ABI_FP_number_model"},
+ {ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align_needed"},
+ {ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align_preserved"},
+ {ARMBuildAttrs::ABI_enum_size, "Tag_ABI_enum_size"},
+ {ARMBuildAttrs::ABI_HardFP_use, "Tag_ABI_HardFP_use"},
+ {ARMBuildAttrs::ABI_VFP_args, "Tag_ABI_VFP_args"},
+ {ARMBuildAttrs::ABI_WMMX_args, "Tag_ABI_WMMX_args"},
+ {ARMBuildAttrs::ABI_optimization_goals, "Tag_ABI_optimization_goals"},
+ {ARMBuildAttrs::ABI_FP_optimization_goals, "Tag_ABI_FP_optimization_goals"},
+ {ARMBuildAttrs::compatibility, "Tag_compatibility"},
+ {ARMBuildAttrs::CPU_unaligned_access, "Tag_CPU_unaligned_access"},
+ {ARMBuildAttrs::FP_HP_extension, "Tag_FP_HP_extension"},
+ {ARMBuildAttrs::ABI_FP_16bit_format, "Tag_ABI_FP_16bit_format"},
+ {ARMBuildAttrs::MPextension_use, "Tag_MPextension_use"},
+ {ARMBuildAttrs::DIV_use, "Tag_DIV_use"},
+ {ARMBuildAttrs::DSP_extension, "Tag_DSP_extension"},
+ {ARMBuildAttrs::nodefaults, "Tag_nodefaults"},
+ {ARMBuildAttrs::also_compatible_with, "Tag_also_compatible_with"},
+ {ARMBuildAttrs::T2EE_use, "Tag_T2EE_use"},
+ {ARMBuildAttrs::conformance, "Tag_conformance"},
+ {ARMBuildAttrs::Virtualization_use, "Tag_Virtualization_use"},
- // Legacy Names
- { ARMBuildAttrs::FP_arch, "Tag_VFP_arch" },
- { ARMBuildAttrs::FP_HP_extension, "Tag_VFP_HP_extension" },
- { ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align8_needed" },
- { ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align8_preserved" },
+ // Legacy Names
+ {ARMBuildAttrs::FP_arch, "Tag_VFP_arch"},
+ {ARMBuildAttrs::FP_HP_extension, "Tag_VFP_HP_extension"},
+ {ARMBuildAttrs::ABI_align_needed, "Tag_ABI_align8_needed"},
+ {ARMBuildAttrs::ABI_align_preserved, "Tag_ABI_align8_preserved"},
};
-}
-
-namespace llvm {
-namespace ARMBuildAttrs {
-StringRef AttrTypeAsString(unsigned Attr, bool HasTagPrefix) {
- return AttrTypeAsString(static_cast<AttrType>(Attr), HasTagPrefix);
-}
-
-StringRef AttrTypeAsString(AttrType Attr, bool HasTagPrefix) {
- for (unsigned TI = 0, TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
- TI != TE; ++TI)
- if (ARMAttributeTags[TI].Attr == Attr) {
- auto TagName = ARMAttributeTags[TI].TagName;
- return HasTagPrefix ? TagName : TagName.drop_front(4);
- }
- return "";
-}
-
-int AttrTypeFromString(StringRef Tag) {
- bool HasTagPrefix = Tag.startswith("Tag_");
- for (unsigned TI = 0,
- TE = sizeof(ARMAttributeTags) / sizeof(*ARMAttributeTags);
- TI != TE; ++TI) {
- auto TagName = ARMAttributeTags[TI].TagName;
- if (TagName.drop_front(HasTagPrefix ? 0 : 4) == Tag) {
- return ARMAttributeTags[TI].Attr;
- }
- }
- return -1;
-}
-}
-}
+const TagNameMap llvm::ARMBuildAttrs::ARMAttributeTags(tagData,
+ sizeof(tagData) /
+ sizeof(TagNameItem));
diff --git a/llvm/lib/Support/ARMTargetParser.cpp b/llvm/lib/Support/ARMTargetParser.cpp
index f2c22fd93c8b8..56a91f7dc7876 100644
--- a/llvm/lib/Support/ARMTargetParser.cpp
+++ b/llvm/lib/Support/ARMTargetParser.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/ARMTargetParser.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
#include <cctype>
using namespace llvm;
@@ -27,7 +28,7 @@ static StringRef getHWDivSynonym(StringRef HWDiv) {
ARM::ArchKind ARM::parseArch(StringRef Arch) {
Arch = getCanonicalArchName(Arch);
StringRef Syn = getArchSynonym(Arch);
- for (const auto A : ARCHNames) {
+ for (const auto &A : ARCHNames) {
if (A.getName().endswith(Syn))
return A.ID;
}
@@ -74,6 +75,7 @@ unsigned ARM::parseArchVersion(StringRef Arch) {
case ArchKind::ARMV8_3A:
case ArchKind::ARMV8_4A:
case ArchKind::ARMV8_5A:
+ case ArchKind::ARMV8_6A:
case ArchKind::ARMV8R:
case ArchKind::ARMV8MBaseline:
case ArchKind::ARMV8MMainline:
@@ -108,6 +110,7 @@ ARM::ProfileKind ARM::parseArchProfile(StringRef Arch) {
case ArchKind::ARMV8_3A:
case ArchKind::ARMV8_4A:
case ArchKind::ARMV8_5A:
+ case ArchKind::ARMV8_6A:
return ProfileKind::A;
case ArchKind::ARMV2:
case ArchKind::ARMV2A:
@@ -150,6 +153,7 @@ StringRef ARM::getArchSynonym(StringRef Arch) {
.Case("v8.3a", "v8.3-a")
.Case("v8.4a", "v8.4-a")
.Case("v8.5a", "v8.5-a")
+ .Case("v8.6a", "v8.6-a")
.Case("v8r", "v8-r")
.Case("v8m.base", "v8-m.base")
.Case("v8m.main", "v8-m.main")
@@ -367,11 +371,11 @@ unsigned ARM::getDefaultFPU(StringRef CPU, ARM::ArchKind AK) {
.Default(ARM::FK_INVALID);
}
-unsigned ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
+uint64_t ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
if (CPU == "generic")
return ARM::ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
- return StringSwitch<unsigned>(CPU)
+ return StringSwitch<uint64_t>(CPU)
#define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
.Case(NAME, \
ARCHNames[static_cast<unsigned>(ArchKind::ID)].ArchBaseExtensions | \
@@ -380,7 +384,7 @@ unsigned ARM::getDefaultExtensions(StringRef CPU, ARM::ArchKind AK) {
.Default(ARM::AEK_INVALID);
}
-bool ARM::getHWDivFeatures(unsigned HWDivKind,
+bool ARM::getHWDivFeatures(uint64_t HWDivKind,
std::vector<StringRef> &Features) {
if (HWDivKind == AEK_INVALID)
@@ -399,7 +403,7 @@ bool ARM::getHWDivFeatures(unsigned HWDivKind,
return true;
}
-bool ARM::getExtensionFeatures(unsigned Extensions,
+bool ARM::getExtensionFeatures(uint64_t Extensions,
std::vector<StringRef> &Features) {
if (Extensions == AEK_INVALID)
@@ -431,7 +435,7 @@ unsigned ARM::getArchAttr(ARM::ArchKind AK) {
return ARCHNames[static_cast<unsigned>(AK)].ArchAttr;
}
-StringRef ARM::getArchExtName(unsigned ArchExtKind) {
+StringRef ARM::getArchExtName(uint64_t ArchExtKind) {
for (const auto AE : ARCHExtNames) {
if (ArchExtKind == AE.ID)
return AE.getName();
@@ -486,29 +490,25 @@ static unsigned findDoublePrecisionFPU(unsigned InputFPUKind) {
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);
+ uint64_t ID = parseArchExt(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 (Negated) {
+ if ((AE.ID & ID) == ID && AE.NegFeature)
+ Features.push_back(AE.NegFeature);
+ } else {
+ if ((AE.ID & ID) == AE.ID && AE.Feature)
+ Features.push_back(AE.Feature);
+ }
}
if (CPU == "")
@@ -532,7 +532,7 @@ bool ARM::appendArchExtFeatures(
return StartingNumFeatures != Features.size();
}
-StringRef ARM::getHWDivName(unsigned HWDivKind) {
+StringRef ARM::getHWDivName(uint64_t HWDivKind) {
for (const auto D : HWDivNames) {
if (HWDivKind == D.ID)
return D.getName();
@@ -555,7 +555,7 @@ StringRef ARM::getDefaultCPU(StringRef Arch) {
return "generic";
}
-unsigned ARM::parseHWDiv(StringRef HWDiv) {
+uint64_t ARM::parseHWDiv(StringRef HWDiv) {
StringRef Syn = getHWDivSynonym(HWDiv);
for (const auto D : HWDivNames) {
if (Syn == D.getName())
@@ -564,7 +564,7 @@ unsigned ARM::parseHWDiv(StringRef HWDiv) {
return AEK_INVALID;
}
-unsigned ARM::parseArchExt(StringRef ArchExt) {
+uint64_t ARM::parseArchExt(StringRef ArchExt) {
for (const auto A : ARCHExtNames) {
if (ArchExt == A.getName())
return A.ID;
diff --git a/llvm/lib/Support/BranchProbability.cpp b/llvm/lib/Support/BranchProbability.cpp
index 195e2d58d8e19..60d5478a90529 100644
--- a/llvm/lib/Support/BranchProbability.cpp
+++ b/llvm/lib/Support/BranchProbability.cpp
@@ -19,7 +19,7 @@
using namespace llvm;
-const uint32_t BranchProbability::D;
+constexpr uint32_t BranchProbability::D;
raw_ostream &BranchProbability::print(raw_ostream &OS) const {
if (isUnknown())
diff --git a/llvm/lib/Support/CRC.cpp b/llvm/lib/Support/CRC.cpp
index a3dba1a3aa10a..7ff09debe3b7c 100644
--- a/llvm/lib/Support/CRC.cpp
+++ b/llvm/lib/Support/CRC.cpp
@@ -25,7 +25,7 @@
using namespace llvm;
-#if !LLVM_ENABLE_ZLIB
+#if LLVM_ENABLE_ZLIB == 0 || !HAVE_ZLIB_H
static const uint32_t CRCTable[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
@@ -85,7 +85,15 @@ uint32_t llvm::crc32(uint32_t CRC, ArrayRef<uint8_t> Data) {
#include <zlib.h>
uint32_t llvm::crc32(uint32_t CRC, ArrayRef<uint8_t> Data) {
- return ::crc32(CRC, (const Bytef *)Data.data(), Data.size());
+ // Zlib's crc32() only takes a 32-bit length, so we have to iterate for larger
+ // sizes. One could use crc32_z() instead, but that's a recent (2017) addition
+ // and may not be available on all systems.
+ do {
+ ArrayRef<uint8_t> Slice = Data.take_front(UINT32_MAX);
+ CRC = ::crc32(CRC, (const Bytef *)Slice.data(), (uInt)Slice.size());
+ Data = Data.drop_front(Slice.size());
+ } while (Data.size() > 0);
+ return CRC;
}
#endif
diff --git a/llvm/lib/Support/CachePruning.cpp b/llvm/lib/Support/CachePruning.cpp
index 7a2f6c53435ad..7663644db558c 100644
--- a/llvm/lib/Support/CachePruning.cpp
+++ b/llvm/lib/Support/CachePruning.cpp
@@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/CachePruning.h"
-
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
diff --git a/llvm/lib/Support/CodeGenCoverage.cpp b/llvm/lib/Support/CodeGenCoverage.cpp
index 2db4193ce3825..93f386b6e23dc 100644
--- a/llvm/lib/Support/CodeGenCoverage.cpp
+++ b/llvm/lib/Support/CodeGenCoverage.cpp
@@ -11,20 +11,14 @@
#include "llvm/Support/CodeGenCoverage.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/ToolOutputFile.h"
-#if LLVM_ON_UNIX
-#include <unistd.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#endif
-
using namespace llvm;
static sys::SmartMutex<true> OutputMutex;
@@ -89,14 +83,7 @@ bool CodeGenCoverage::emit(StringRef CoveragePrefix,
// We can handle locking within a process easily enough but we don't want to
// manage it between multiple processes. Use the process ID to ensure no
// more than one process is ever writing to the same file at the same time.
- std::string Pid =
-#if LLVM_ON_UNIX
- llvm::to_string(::getpid());
-#elif defined(_WIN32)
- llvm::to_string(::GetCurrentProcessId());
-#else
- "";
-#endif
+ std::string Pid = llvm::to_string(sys::Process::getProcessId());
std::string CoverageFilename = (CoveragePrefix + Pid).str();
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index cb73380ba3830..12ef0d511b147 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -592,6 +592,10 @@ static Option *LookupNearestOption(StringRef Arg,
ie = OptionsMap.end();
it != ie; ++it) {
Option *O = it->second;
+ // Do not suggest really hidden options (not shown in any help).
+ if (O->getOptionHiddenFlag() == ReallyHidden)
+ continue;
+
SmallVector<StringRef, 16> OptionNames;
O->getExtraOptionNames(OptionNames);
if (O->hasArgStr())
@@ -606,7 +610,7 @@ static Option *LookupNearestOption(StringRef Arg,
Best = O;
BestDistance = Distance;
if (RHS.empty() || !PermitValue)
- NearestString = Name;
+ NearestString = std::string(Name);
else
NearestString = (Twine(Name) + "=" + RHS).str();
}
@@ -919,91 +923,118 @@ static size_t parseBackslash(StringRef Src, size_t I, SmallString<128> &Token) {
return I - 1;
}
-void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver,
- SmallVectorImpl<const char *> &NewArgv,
- bool MarkEOLs) {
+// Windows treats whitespace, double quotes, and backslashes specially.
+static bool isWindowsSpecialChar(char C) {
+ return isWhitespaceOrNull(C) || C == '\\' || C == '\"';
+}
+
+// Windows tokenization implementation. The implementation is designed to be
+// inlined and specialized for the two user entry points.
+static inline void
+tokenizeWindowsCommandLineImpl(StringRef Src, StringSaver &Saver,
+ function_ref<void(StringRef)> AddToken,
+ bool AlwaysCopy, function_ref<void()> MarkEOL) {
SmallString<128> Token;
- // This is a small state machine to consume characters until it reaches the
- // end of the source string.
+ // Try to do as much work inside the state machine as possible.
enum { INIT, UNQUOTED, QUOTED } State = INIT;
- for (size_t I = 0, E = Src.size(); I != E; ++I) {
- char C = Src[I];
-
- // INIT state indicates that the current input index is at the start of
- // the string or between tokens.
- if (State == INIT) {
- if (isWhitespaceOrNull(C)) {
- // Mark the end of lines in response files
- if (MarkEOLs && C == '\n')
- NewArgv.push_back(nullptr);
- continue;
+ for (size_t I = 0, E = Src.size(); I < E; ++I) {
+ switch (State) {
+ case INIT: {
+ assert(Token.empty() && "token should be empty in initial state");
+ // Eat whitespace before a token.
+ while (I < E && isWhitespaceOrNull(Src[I])) {
+ if (Src[I] == '\n')
+ MarkEOL();
+ ++I;
}
- if (C == '"') {
+ // Stop if this was trailing whitespace.
+ if (I >= E)
+ break;
+ size_t Start = I;
+ while (I < E && !isWindowsSpecialChar(Src[I]))
+ ++I;
+ StringRef NormalChars = Src.slice(Start, I);
+ if (I >= E || isWhitespaceOrNull(Src[I])) {
+ if (I < E && Src[I] == '\n')
+ MarkEOL();
+ // No special characters: slice out the substring and start the next
+ // token. Copy the string if the caller asks us to.
+ AddToken(AlwaysCopy ? Saver.save(NormalChars) : NormalChars);
+ } else if (Src[I] == '\"') {
+ Token += NormalChars;
State = QUOTED;
- continue;
- }
- if (C == '\\') {
+ } else if (Src[I] == '\\') {
+ Token += NormalChars;
I = parseBackslash(Src, I, Token);
State = UNQUOTED;
- continue;
+ } else {
+ llvm_unreachable("unexpected special character");
}
- Token.push_back(C);
- State = UNQUOTED;
- continue;
+ break;
}
- // UNQUOTED state means that it's reading a token not quoted by double
- // quotes.
- if (State == UNQUOTED) {
- // Whitespace means the end of the token.
- if (isWhitespaceOrNull(C)) {
- NewArgv.push_back(Saver.save(StringRef(Token)).data());
+ case UNQUOTED:
+ if (isWhitespaceOrNull(Src[I])) {
+ // Whitespace means the end of the token. If we are in this state, the
+ // token must have contained a special character, so we must copy the
+ // token.
+ AddToken(Saver.save(Token.str()));
Token.clear();
+ if (Src[I] == '\n')
+ MarkEOL();
State = INIT;
- // Mark the end of lines in response files
- if (MarkEOLs && C == '\n')
- NewArgv.push_back(nullptr);
- continue;
- }
- if (C == '"') {
+ } else if (Src[I] == '\"') {
State = QUOTED;
- continue;
- }
- if (C == '\\') {
+ } else if (Src[I] == '\\') {
I = parseBackslash(Src, I, Token);
- continue;
+ } else {
+ Token.push_back(Src[I]);
}
- Token.push_back(C);
- continue;
- }
+ break;
- // QUOTED state means that it's reading a token quoted by double quotes.
- if (State == QUOTED) {
- if (C == '"') {
+ case QUOTED:
+ if (Src[I] == '\"') {
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;
+ ++I;
+ } else {
+ // Otherwise, end the quoted portion and return to the unquoted state.
+ State = UNQUOTED;
}
- State = UNQUOTED;
- continue;
- }
- if (C == '\\') {
+ } else if (Src[I] == '\\') {
I = parseBackslash(Src, I, Token);
- continue;
+ } else {
+ Token.push_back(Src[I]);
}
- Token.push_back(C);
+ break;
}
}
- // Append the last token after hitting EOF with no whitespace.
- if (!Token.empty())
- NewArgv.push_back(Saver.save(StringRef(Token)).data());
- // Mark the end of response files
- if (MarkEOLs)
- NewArgv.push_back(nullptr);
+
+ if (State == UNQUOTED)
+ AddToken(Saver.save(Token.str()));
+}
+
+void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs) {
+ auto AddToken = [&](StringRef Tok) { NewArgv.push_back(Tok.data()); };
+ auto OnEOL = [&]() {
+ if (MarkEOLs)
+ NewArgv.push_back(nullptr);
+ };
+ tokenizeWindowsCommandLineImpl(Src, Saver, AddToken,
+ /*AlwaysCopy=*/true, OnEOL);
+}
+
+void cl::TokenizeWindowsCommandLineNoCopy(StringRef Src, StringSaver &Saver,
+ SmallVectorImpl<StringRef> &NewArgv) {
+ auto AddToken = [&](StringRef Tok) { NewArgv.push_back(Tok); };
+ auto OnEOL = []() {};
+ tokenizeWindowsCommandLineImpl(Src, Saver, AddToken, /*AlwaysCopy=*/false,
+ OnEOL);
}
void cl::tokenizeConfigFile(StringRef Source, StringSaver &Saver,
@@ -1324,7 +1355,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
argc = static_cast<int>(newArgv.size());
// Copy the program name into ProgName, making sure not to overflow it.
- ProgramName = sys::path::filename(StringRef(argv[0]));
+ ProgramName = std::string(sys::path::filename(StringRef(argv[0])));
ProgramOverview = Overview;
bool IgnoreErrors = Errs;
@@ -1581,9 +1612,9 @@ bool CommandLineParser::ParseCommandLineOptions(int argc,
} else {
assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size());
unsigned ValNo = 0;
- for (size_t j = 1, e = PositionalOpts.size(); j != e; ++j)
- if (RequiresValue(PositionalOpts[j])) {
- ErrorParsing |= ProvidePositionalOption(PositionalOpts[j],
+ for (size_t J = 0, E = PositionalOpts.size(); J != E; ++J)
+ if (RequiresValue(PositionalOpts[J])) {
+ ErrorParsing |= ProvidePositionalOption(PositionalOpts[J],
PositionalVals[ValNo].first,
PositionalVals[ValNo].second);
ValNo++;
@@ -1751,9 +1782,10 @@ void basic_parser_impl::printOptionInfo(const Option &O,
if (!ValName.empty()) {
if (O.getMiscFlags() & PositionalEatsArgs) {
outs() << " <" << getValueStr(O, ValName) << ">...";
- } else {
+ } else if (O.getValueExpectedFlag() == ValueOptional)
+ outs() << "[=<" << getValueStr(O, ValName) << ">]";
+ else
outs() << "=<" << getValueStr(O, ValName) << '>';
- }
}
Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
@@ -2482,7 +2514,7 @@ public:
OS << " with assertions";
#endif
#if LLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO
- std::string CPU = sys::getHostCPUName();
+ std::string CPU = std::string(sys::getHostCPUName());
if (CPU == "generic")
CPU = "(unknown)";
OS << ".\n"
@@ -2505,7 +2537,7 @@ public:
// information.
if (ExtraVersionPrinters != nullptr) {
outs() << '\n';
- for (auto I : *ExtraVersionPrinters)
+ for (const auto &I : *ExtraVersionPrinters)
I(outs());
}
diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp
index 4165a2740cd03..27d92f0e0aec2 100644
--- a/llvm/lib/Support/Compression.cpp
+++ b/llvm/lib/Support/Compression.cpp
@@ -17,13 +17,13 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
-#if LLVM_ENABLE_ZLIB
+#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H
#include <zlib.h>
#endif
using namespace llvm;
-#if LLVM_ENABLE_ZLIB
+#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ
static Error createError(StringRef Err) {
return make_error<StringError>(Err, inconvertibleErrorCode());
}
@@ -74,10 +74,10 @@ Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
Error zlib::uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize) {
- UncompressedBuffer.resize(UncompressedSize);
+ UncompressedBuffer.reserve(UncompressedSize);
Error E =
uncompress(InputBuffer, UncompressedBuffer.data(), UncompressedSize);
- UncompressedBuffer.resize(UncompressedSize);
+ UncompressedBuffer.set_size(UncompressedSize);
return E;
}
diff --git a/llvm/lib/Support/ConvertUTFWrapper.cpp b/llvm/lib/Support/ConvertUTFWrapper.cpp
index eb4ead6b46b45..6ec567882ea6b 100644
--- a/llvm/lib/Support/ConvertUTFWrapper.cpp
+++ b/llvm/lib/Support/ConvertUTFWrapper.cpp
@@ -102,7 +102,7 @@ bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) {
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I)
- ByteSwapped[I] = llvm::sys::SwapByteOrder_16(ByteSwapped[I]);
+ ByteSwapped[I] = llvm::ByteSwap_16(ByteSwapped[I]);
Src = &ByteSwapped[0];
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
}
diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp
index b9031f52375c3..ec7d7d641dce5 100644
--- a/llvm/lib/Support/CrashRecoveryContext.cpp
+++ b/llvm/lib/Support/CrashRecoveryContext.cpp
@@ -14,9 +14,6 @@
#include "llvm/Support/ThreadLocal.h"
#include <mutex>
#include <setjmp.h>
-#ifdef _WIN32
-#include <excpt.h> // for GetExceptionInformation
-#endif
#if LLVM_ON_UNIX
#include <sysexits.h> // EX_IOERR
#endif
@@ -41,11 +38,11 @@ struct CrashRecoveryContextImpl {
::jmp_buf JumpBuffer;
volatile unsigned Failed : 1;
unsigned SwitchedThread : 1;
+ unsigned ValidJumpBuffer : 1;
public:
- CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
- Failed(false),
- SwitchedThread(false) {
+ CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept
+ : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) {
Next = CurrentContext->get();
CurrentContext->set(this);
}
@@ -80,10 +77,13 @@ public:
CRC->RetCode = RetCode;
// Jump back to the RunSafely we were called under.
- longjmp(JumpBuffer, 1);
+ if (ValidJumpBuffer)
+ longjmp(JumpBuffer, 1);
+
+ // Otherwise let the caller decide of the outcome of the crash. Currently
+ // this occurs when using SEH on Windows with MSVC or clang-cl.
}
};
-
}
static ManagedStatic<std::mutex> gCrashRecoveryContextMutex;
@@ -175,6 +175,9 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
}
#if defined(_MSC_VER)
+
+#include <windows.h> // for GetExceptionInformation
+
// If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way
// better than VEH. Vectored exception handling catches all exceptions happening
// on the thread with installed exception handlers, so it can interfere with
@@ -188,30 +191,45 @@ static void uninstallExceptionOrSignalHandlers() {}
// We need this function because the call to GetExceptionInformation() can only
// occur inside the __except evaluation block
-static int ExceptionFilter(bool DumpStackAndCleanup,
- _EXCEPTION_POINTERS *Except) {
- if (DumpStackAndCleanup)
- sys::CleanupOnSignal((uintptr_t)Except);
- return EXCEPTION_EXECUTE_HANDLER;
-}
+static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
+ // Lookup the current thread local recovery object.
+ const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
-static bool InvokeFunctionCall(function_ref<void()> Fn,
- bool DumpStackAndCleanup, int &RetCode) {
- __try {
- Fn();
- } __except (ExceptionFilter(DumpStackAndCleanup, GetExceptionInformation())) {
- RetCode = GetExceptionCode();
- return false;
+ if (!CRCI) {
+ // Something has gone horribly wrong, so let's just tell everyone
+ // to keep searching
+ CrashRecoveryContext::Disable();
+ return EXCEPTION_CONTINUE_SEARCH;
}
- return true;
+
+ int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
+ if ((RetCode & 0xF0000000) == 0xE0000000)
+ RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
+
+ // Handle the crash
+ const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
+ RetCode, reinterpret_cast<uintptr_t>(Except));
+
+ return EXCEPTION_EXECUTE_HANDLER;
}
+#if defined(__clang__) && defined(_M_IX86)
+// Work around PR44697.
+__attribute__((optnone))
+#endif
bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
if (!gCrashRecoveryEnabled) {
Fn();
return true;
}
- return InvokeFunctionCall(Fn, DumpStackAndCleanupOnFailure, RetCode);
+ assert(!Impl && "Crash recovery context already initialized!");
+ Impl = new CrashRecoveryContextImpl(this);
+ __try {
+ Fn();
+ } __except (ExceptionFilter(GetExceptionInformation())) {
+ return false;
+ }
+ return true;
}
#else // !_MSC_VER
@@ -236,7 +254,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
// XP, so if support for older versions of Windows is required,
// it will have to be added.
-#include "Windows/WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
@@ -264,10 +282,13 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
// TODO: We can capture the stack backtrace here and store it on the
// implementation if we so choose.
+ int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
+ if ((RetCode & 0xF0000000) == 0xE0000000)
+ RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit
+
// Handle the crash
const_cast<CrashRecoveryContextImpl *>(CRCI)->HandleCrash(
- (int)ExceptionInfo->ExceptionRecord->ExceptionCode,
- reinterpret_cast<uintptr_t>(ExceptionInfo));
+ RetCode, reinterpret_cast<uintptr_t>(ExceptionInfo));
// Note that we don't actually get here because HandleCrash calls
// longjmp, which means the HandleCrash function never returns.
@@ -388,6 +409,7 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this);
Impl = CRCI;
+ CRCI->ValidJumpBuffer = true;
if (setjmp(CRCI->JumpBuffer) != 0) {
return false;
}
@@ -399,12 +421,19 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) {
#endif // !_MSC_VER
-void CrashRecoveryContext::HandleCrash() {
- CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
+LLVM_ATTRIBUTE_NORETURN
+void CrashRecoveryContext::HandleExit(int RetCode) {
+#if defined(_WIN32)
+ // SEH and VEH
+ ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL);
+#else
+ // On Unix we don't need to raise an exception, we go directly to
+ // HandleCrash(), then longjmp will unwind the stack for us.
+ CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
assert(CRCI && "Crash recovery context never initialized!");
- // As per convention, -2 indicates a crash or timeout as opposed to failure to
- // execute (see llvm/include/llvm/Support/Program.h)
- CRCI->HandleCrash(-2, 0);
+ CRCI->HandleCrash(RetCode, 0 /*no sig num*/);
+#endif
+ llvm_unreachable("Most likely setjmp wasn't called!");
}
// FIXME: Portability.
diff --git a/llvm/lib/Support/DataExtractor.cpp b/llvm/lib/Support/DataExtractor.cpp
index a98297cdb35f2..133d674275e8c 100644
--- a/llvm/lib/Support/DataExtractor.cpp
+++ b/llvm/lib/Support/DataExtractor.cpp
@@ -15,29 +15,40 @@
using namespace llvm;
-static void unexpectedEndReached(Error *E) {
- if (E)
- *E = createStringError(errc::illegal_byte_sequence,
- "unexpected end of data");
+bool DataExtractor::prepareRead(uint64_t Offset, uint64_t Size,
+ Error *E) const {
+ if (isValidOffsetForDataOfSize(Offset, Size))
+ return true;
+ if (E) {
+ if (Offset <= Data.size())
+ *E = createStringError(
+ errc::illegal_byte_sequence,
+ "unexpected end of data at offset 0x%zx while reading [0x%" PRIx64
+ ", 0x%" PRIx64 ")",
+ Data.size(), Offset, Offset + Size);
+ else
+ *E = createStringError(errc::invalid_argument,
+ "offset 0x%" PRIx64
+ " is beyond the end of data at 0x%zx",
+ Offset, Data.size());
+ }
+ return false;
}
static bool isError(Error *E) { return E && *E; }
template <typename T>
-static T getU(uint64_t *offset_ptr, const DataExtractor *de,
- bool isLittleEndian, const char *Data, llvm::Error *Err) {
+T DataExtractor::getU(uint64_t *offset_ptr, Error *Err) const {
ErrorAsOutParameter ErrAsOut(Err);
T val = 0;
if (isError(Err))
return val;
uint64_t offset = *offset_ptr;
- if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) {
- unexpectedEndReached(Err);
+ if (!prepareRead(offset, sizeof(T), Err))
return val;
- }
- std::memcpy(&val, &Data[offset], sizeof(val));
- if (sys::IsLittleEndianHost != isLittleEndian)
+ std::memcpy(&val, &Data.data()[offset], sizeof(val));
+ if (sys::IsLittleEndianHost != IsLittleEndian)
sys::swapByteOrder(val);
// Advance the offset
@@ -46,22 +57,19 @@ static T getU(uint64_t *offset_ptr, const DataExtractor *de,
}
template <typename T>
-static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
- const DataExtractor *de, bool isLittleEndian, const char *Data,
- llvm::Error *Err) {
+T *DataExtractor::getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
+ Error *Err) const {
ErrorAsOutParameter ErrAsOut(Err);
if (isError(Err))
return nullptr;
uint64_t offset = *offset_ptr;
- if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) {
- unexpectedEndReached(Err);
+ if (!prepareRead(offset, sizeof(*dst) * count, Err))
return nullptr;
- }
for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
++value_ptr, offset += sizeof(*dst))
- *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data, Err);
+ *value_ptr = getU<T>(offset_ptr, Err);
// Advance the offset
*offset_ptr = offset;
// Return a non-NULL pointer to the converted data as an indicator of
@@ -70,55 +78,49 @@ static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
}
uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
- return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+ return getU<uint8_t>(offset_ptr, Err);
}
-uint8_t *
-DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const {
- return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data(), nullptr);
+uint8_t *DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst,
+ uint32_t count) const {
+ return getUs<uint8_t>(offset_ptr, dst, count, nullptr);
}
uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
- return getUs<uint8_t>(&C.Offset, Dst, Count, this, IsLittleEndian,
- Data.data(), &C.Err);
+ return getUs<uint8_t>(&C.Offset, Dst, Count, &C.Err);
}
uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
- return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+ return getU<uint16_t>(offset_ptr, Err);
}
uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
uint32_t count) const {
- return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data(), nullptr);
+ return getUs<uint16_t>(offset_ptr, dst, count, nullptr);
}
-uint32_t DataExtractor::getU24(uint64_t *offset_ptr) const {
- uint24_t ExtractedVal =
- getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data(), nullptr);
+uint32_t DataExtractor::getU24(uint64_t *OffsetPtr, Error *Err) const {
+ uint24_t ExtractedVal = getU<uint24_t>(OffsetPtr, Err);
// The 3 bytes are in the correct byte order for the host.
return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
}
uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
- return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+ return getU<uint32_t>(offset_ptr, Err);
}
uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
uint32_t count) const {
- return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data(), nullptr);
+ return getUs<uint32_t>(offset_ptr, dst, count, nullptr);
}
uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
- return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
+ return getU<uint64_t>(offset_ptr, Err);
}
uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
uint32_t count) const {
- return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
- Data.data(), nullptr);
+ return getUs<uint64_t>(offset_ptr, dst, count, nullptr);
}
uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
@@ -151,59 +153,77 @@ DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
llvm_unreachable("getSigned unhandled case!");
}
-const char *DataExtractor::getCStr(uint64_t *offset_ptr) const {
- uint64_t offset = *offset_ptr;
- StringRef::size_type pos = Data.find('\0', offset);
- if (pos != StringRef::npos) {
- *offset_ptr = pos + 1;
- return Data.data() + offset;
- }
- return nullptr;
-}
+StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const {
+ ErrorAsOutParameter ErrAsOut(Err);
+ if (isError(Err))
+ return StringRef();
-StringRef DataExtractor::getCStrRef(uint64_t *offset_ptr) const {
- uint64_t Start = *offset_ptr;
+ uint64_t Start = *OffsetPtr;
StringRef::size_type Pos = Data.find('\0', Start);
if (Pos != StringRef::npos) {
- *offset_ptr = Pos + 1;
+ *OffsetPtr = Pos + 1;
return StringRef(Data.data() + Start, Pos - Start);
}
+ if (Err)
+ *Err = createStringError(errc::illegal_byte_sequence,
+ "no null terminated string at offset 0x%" PRIx64,
+ Start);
return StringRef();
}
-uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr,
- llvm::Error *Err) const {
- assert(*offset_ptr <= Data.size());
+StringRef DataExtractor::getFixedLengthString(uint64_t *OffsetPtr,
+ uint64_t Length,
+ StringRef TrimChars) const {
+ StringRef Bytes(getBytes(OffsetPtr, Length));
+ return Bytes.trim(TrimChars);
+}
+
+StringRef DataExtractor::getBytes(uint64_t *OffsetPtr, uint64_t Length,
+ Error *Err) const {
ErrorAsOutParameter ErrAsOut(Err);
if (isError(Err))
- return 0;
+ return StringRef();
+
+ if (!prepareRead(*OffsetPtr, Length, Err))
+ return StringRef();
+
+ StringRef Result = Data.substr(*OffsetPtr, Length);
+ *OffsetPtr += Length;
+ return Result;
+}
+
+template <typename T>
+static T getLEB128(StringRef Data, uint64_t *OffsetPtr, Error *Err,
+ T (&Decoder)(const uint8_t *p, unsigned *n,
+ const uint8_t *end, const char **error)) {
+ ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(Data);
+ assert(*OffsetPtr <= Bytes.size());
+ ErrorAsOutParameter ErrAsOut(Err);
+ if (isError(Err))
+ return T();
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);
+ T result =
+ Decoder(Bytes.data() + *OffsetPtr, &bytes_read, Bytes.end(), &error);
if (error) {
if (Err)
- *Err = createStringError(errc::illegal_byte_sequence, error);
- return 0;
+ *Err = createStringError(errc::illegal_byte_sequence,
+ "unable to decode LEB128 at offset 0x%8.8" PRIx64
+ ": %s",
+ *OffsetPtr, error);
+ return T();
}
- *offset_ptr += bytes_read;
+ *OffsetPtr += bytes_read;
return result;
}
-int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const {
- assert(*offset_ptr <= Data.size());
+uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {
+ return getLEB128(Data, offset_ptr, Err, decodeULEB128);
+}
- 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;
- *offset_ptr += bytes_read;
- return result;
+int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {
+ return getLEB128(Data, offset_ptr, Err, decodeSLEB128);
}
void DataExtractor::skip(Cursor &C, uint64_t Length) const {
@@ -211,8 +231,6 @@ void DataExtractor::skip(Cursor &C, uint64_t Length) const {
if (isError(&C.Err))
return;
- if (isValidOffsetForDataOfSize(C.Offset, Length))
+ if (prepareRead(C.Offset, Length, &C.Err))
C.Offset += Length;
- else
- unexpectedEndReached(&C.Err);
}
diff --git a/llvm/lib/Support/Debug.cpp b/llvm/lib/Support/Debug.cpp
index 737cd576ed80f..73b25d55237b0 100644
--- a/llvm/lib/Support/Debug.cpp
+++ b/llvm/lib/Support/Debug.cpp
@@ -105,7 +105,7 @@ struct DebugOnlyOpt {
SmallVector<StringRef,8> dbgTypes;
StringRef(Val).split(dbgTypes, ',', -1, false);
for (auto dbgType : dbgTypes)
- CurrentDebugType->push_back(dbgType);
+ CurrentDebugType->push_back(std::string(dbgType));
}
};
diff --git a/llvm/lib/Support/DebugCounter.cpp b/llvm/lib/Support/DebugCounter.cpp
index 1e3ec300964ca..8c579f395282e 100644
--- a/llvm/lib/Support/DebugCounter.cpp
+++ b/llvm/lib/Support/DebugCounter.cpp
@@ -31,7 +31,7 @@ private:
// width, so we do the same.
Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6);
const auto &CounterInstance = DebugCounter::instance();
- for (auto Name : CounterInstance) {
+ for (const auto &Name : CounterInstance) {
const auto Info =
CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name));
size_t NumSpaces = GlobalWidth - Info.first.size() - 8;
@@ -85,7 +85,7 @@ void DebugCounter::push_back(const std::string &Val) {
// add it to the counter values.
if (CounterPair.first.endswith("-skip")) {
auto CounterName = CounterPair.first.drop_back(5);
- unsigned CounterID = getCounterId(CounterName);
+ unsigned CounterID = getCounterId(std::string(CounterName));
if (!CounterID) {
errs() << "DebugCounter Error: " << CounterName
<< " is not a registered counter\n";
@@ -98,7 +98,7 @@ void DebugCounter::push_back(const std::string &Val) {
Counter.IsSet = true;
} else if (CounterPair.first.endswith("-count")) {
auto CounterName = CounterPair.first.drop_back(6);
- unsigned CounterID = getCounterId(CounterName);
+ unsigned CounterID = getCounterId(std::string(CounterName));
if (!CounterID) {
errs() << "DebugCounter Error: " << CounterName
<< " is not a registered counter\n";
@@ -123,7 +123,7 @@ void DebugCounter::print(raw_ostream &OS) const {
auto &Us = instance();
OS << "Counters and values:\n";
for (auto &CounterName : CounterNames) {
- unsigned CounterID = getCounterId(CounterName);
+ unsigned CounterID = getCounterId(std::string(CounterName));
OS << left_justify(RegisteredCounters[CounterID], 32) << ": {"
<< Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip
<< "," << Us.Counters[CounterID].StopAfter << "}\n";
diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttributeParser.cpp
new file mode 100644
index 0000000000000..df955cdf5d30a
--- /dev/null
+++ b/llvm/lib/Support/ELFAttributeParser.cpp
@@ -0,0 +1,233 @@
+//===--- ELFAttributeParser.cpp - ELF Attribute Parser --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::ELFAttrs;
+
+static const EnumEntry<unsigned> tagNames[] = {
+ {"Tag_File", ELFAttrs::File},
+ {"Tag_Section", ELFAttrs::Section},
+ {"Tag_Symbol", ELFAttrs::Symbol},
+};
+
+Error ELFAttributeParser::parseStringAttribute(const char *name, unsigned tag,
+ ArrayRef<const char *> strings) {
+ uint64_t value = de.getULEB128(cursor);
+ if (value >= strings.size()) {
+ printAttribute(tag, value, "");
+ return createStringError(errc::invalid_argument,
+ "unknown " + Twine(name) +
+ " value: " + Twine(value));
+ }
+ printAttribute(tag, value, strings[value]);
+ return Error::success();
+}
+
+Error ELFAttributeParser::integerAttribute(unsigned tag) {
+ StringRef tagName =
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
+ uint64_t value = de.getULEB128(cursor);
+ attributes.insert(std::make_pair(tag, value));
+
+ if (sw) {
+ DictScope scope(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ sw->printNumber("Value", value);
+ }
+ return Error::success();
+}
+
+Error ELFAttributeParser::stringAttribute(unsigned tag) {
+ StringRef tagName =
+ ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);
+ StringRef desc = de.getCStrRef(cursor);
+ attributesStr.insert(std::make_pair(tag, desc));
+
+ if (sw) {
+ DictScope scope(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ sw->printString("Value", desc);
+ }
+ return Error::success();
+}
+
+void ELFAttributeParser::printAttribute(unsigned tag, unsigned value,
+ StringRef valueDesc) {
+ attributes.insert(std::make_pair(tag, value));
+
+ if (sw) {
+ StringRef tagName = ELFAttrs::attrTypeAsString(tag, tagToStringMap,
+ /*hasTagPrefix=*/false);
+ DictScope as(*sw, "Attribute");
+ sw->printNumber("Tag", tag);
+ sw->printNumber("Value", value);
+ if (!tagName.empty())
+ sw->printString("TagName", tagName);
+ if (!valueDesc.empty())
+ sw->printString("Description", valueDesc);
+ }
+}
+
+void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {
+ for (;;) {
+ uint64_t value = de.getULEB128(cursor);
+ if (!cursor || !value)
+ break;
+ indexList.push_back(value);
+ }
+}
+
+Error ELFAttributeParser::parseAttributeList(uint32_t length) {
+ uint64_t pos;
+ uint64_t end = cursor.tell() + length;
+ while ((pos = cursor.tell()) < end) {
+ uint64_t tag = de.getULEB128(cursor);
+ bool handled;
+ if (Error e = handler(tag, handled))
+ return e;
+
+ if (!handled) {
+ if (tag < 32) {
+ return createStringError(errc::invalid_argument,
+ "invalid tag 0x" + Twine::utohexstr(tag) +
+ " at offset 0x" + Twine::utohexstr(pos));
+ }
+
+ if (tag % 2 == 0) {
+ if (Error e = integerAttribute(tag))
+ return e;
+ } else {
+ if (Error e = stringAttribute(tag))
+ return e;
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error ELFAttributeParser::parseSubsection(uint32_t length) {
+ uint64_t end = cursor.tell() - sizeof(length) + length;
+ StringRef vendorName = de.getCStrRef(cursor);
+ if (sw) {
+ sw->printNumber("SectionLength", length);
+ sw->printString("Vendor", vendorName);
+ }
+
+ // Ignore unrecognized vendor-name.
+ if (vendorName.lower() != vendor)
+ return createStringError(errc::invalid_argument,
+ "unrecognized vendor-name: " + vendorName);
+
+ while (cursor.tell() < end) {
+ /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size
+ uint8_t tag = de.getU8(cursor);
+ uint32_t size = de.getU32(cursor);
+ if (!cursor)
+ return cursor.takeError();
+
+ if (sw) {
+ sw->printEnum("Tag", tag, makeArrayRef(tagNames));
+ sw->printNumber("Size", size);
+ }
+ if (size < 5)
+ return createStringError(errc::invalid_argument,
+ "invalid attribute size " + Twine(size) +
+ " at offset 0x" +
+ Twine::utohexstr(cursor.tell() - 5));
+
+ StringRef scopeName, indexName;
+ SmallVector<uint8_t, 8> indicies;
+ switch (tag) {
+ case ELFAttrs::File:
+ scopeName = "FileAttributes";
+ break;
+ case ELFAttrs::Section:
+ scopeName = "SectionAttributes";
+ indexName = "Sections";
+ parseIndexList(indicies);
+ break;
+ case ELFAttrs::Symbol:
+ scopeName = "SymbolAttributes";
+ indexName = "Symbols";
+ parseIndexList(indicies);
+ break;
+ default:
+ return createStringError(errc::invalid_argument,
+ "unrecognized tag 0x" + Twine::utohexstr(tag) +
+ " at offset 0x" +
+ Twine::utohexstr(cursor.tell() - 5));
+ }
+
+ if (sw) {
+ DictScope scope(*sw, scopeName);
+ if (!indicies.empty())
+ sw->printList(indexName, indicies);
+ if (Error e = parseAttributeList(size - 5))
+ return e;
+ } else if (Error e = parseAttributeList(size - 5))
+ return e;
+ }
+ return Error::success();
+}
+
+Error ELFAttributeParser::parse(ArrayRef<uint8_t> section,
+ support::endianness endian) {
+ unsigned sectionNumber = 0;
+ de = DataExtractor(section, endian == support::little, 0);
+
+ // For early returns, we have more specific errors, consume the Error in
+ // cursor.
+ struct ClearCursorError {
+ DataExtractor::Cursor &cursor;
+ ~ClearCursorError() { consumeError(cursor.takeError()); }
+ } clear{cursor};
+
+ // Unrecognized format-version.
+ uint8_t formatVersion = de.getU8(cursor);
+ if (formatVersion != 'A')
+ return createStringError(errc::invalid_argument,
+ "unrecognized format-version: 0x" +
+ utohexstr(formatVersion));
+
+ while (!de.eof(cursor)) {
+ uint32_t sectionLength = de.getU32(cursor);
+ if (!cursor)
+ return cursor.takeError();
+
+ if (sw) {
+ sw->startLine() << "Section " << ++sectionNumber << " {\n";
+ sw->indent();
+ }
+
+ if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())
+ return createStringError(errc::invalid_argument,
+ "invalid section length " +
+ Twine(sectionLength) + " at offset 0x" +
+ utohexstr(cursor.tell() - 4));
+
+ if (Error e = parseSubsection(sectionLength))
+ return e;
+ if (sw) {
+ sw->unindent();
+ sw->startLine() << "}\n";
+ }
+ }
+
+ return cursor.takeError();
+}
diff --git a/llvm/lib/Support/ELFAttributes.cpp b/llvm/lib/Support/ELFAttributes.cpp
new file mode 100644
index 0000000000000..5be38825d6c6f
--- /dev/null
+++ b/llvm/lib/Support/ELFAttributes.cpp
@@ -0,0 +1,34 @@
+//===-- ELFAttributes.cpp - ELF Attributes --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ELFAttributes.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace llvm;
+
+StringRef ELFAttrs::attrTypeAsString(unsigned attr, TagNameMap tagNameMap,
+ bool hasTagPrefix) {
+ auto tagNameIt = find_if(
+ tagNameMap, [attr](const TagNameItem item) { return item.attr == attr; });
+ if (tagNameIt == tagNameMap.end())
+ return "";
+ StringRef tagName = tagNameIt->tagName;
+ return hasTagPrefix ? tagName : tagName.drop_front(4);
+}
+
+Optional<unsigned> ELFAttrs::attrTypeFromString(StringRef tag,
+ TagNameMap tagNameMap) {
+ bool hasTagPrefix = tag.startswith("Tag_");
+ auto tagNameIt =
+ find_if(tagNameMap, [tag, hasTagPrefix](const TagNameItem item) {
+ return item.tagName.drop_front(hasTagPrefix ? 0 : 4) == tag;
+ });
+ if (tagNameIt == tagNameMap.end())
+ return None;
+ return tagNameIt->attr;
+}
diff --git a/llvm/lib/Support/ErrorHandling.cpp b/llvm/lib/Support/ErrorHandling.cpp
index 0f13f7a536f1d..f70a6921a41a4 100644
--- a/llvm/lib/Support/ErrorHandling.cpp
+++ b/llvm/lib/Support/ErrorHandling.cpp
@@ -19,6 +19,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/WindowsError.h"
@@ -122,7 +123,7 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
// files registered with RemoveFileOnSignal.
sys::RunInterruptHandlers();
- exit(1);
+ abort();
}
void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler,
diff --git a/llvm/lib/Support/ExtensibleRTTI.cpp b/llvm/lib/Support/ExtensibleRTTI.cpp
new file mode 100644
index 0000000000000..1c98d1bb8febc
--- /dev/null
+++ b/llvm/lib/Support/ExtensibleRTTI.cpp
@@ -0,0 +1,13 @@
+//===----- lib/Support/ExtensibleRTTI.cpp - ExtensibleRTTI utilities ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ExtensibleRTTI.h"
+
+void llvm::RTTIRoot::anchor() {}
+char llvm::RTTIRoot::ID = 0;
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index 2261ecc236c25..d0e79c675bcbd 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -17,6 +17,7 @@
#include "FileCheckImpl.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/CheckedArithmetic.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstdint>
#include <list>
@@ -25,17 +26,301 @@
using namespace llvm;
-Expected<uint64_t> NumericVariableUse::eval() const {
- Optional<uint64_t> Value = Variable->getValue();
+StringRef ExpressionFormat::toString() const {
+ switch (Value) {
+ case Kind::NoFormat:
+ return StringRef("<none>");
+ case Kind::Unsigned:
+ return StringRef("%u");
+ case Kind::Signed:
+ return StringRef("%d");
+ case Kind::HexUpper:
+ return StringRef("%X");
+ case Kind::HexLower:
+ return StringRef("%x");
+ }
+ llvm_unreachable("unknown expression format");
+}
+
+Expected<StringRef> ExpressionFormat::getWildcardRegex() const {
+ switch (Value) {
+ case Kind::Unsigned:
+ return StringRef("[0-9]+");
+ case Kind::Signed:
+ return StringRef("-?[0-9]+");
+ case Kind::HexUpper:
+ return StringRef("[0-9A-F]+");
+ case Kind::HexLower:
+ return StringRef("[0-9a-f]+");
+ default:
+ return createStringError(std::errc::invalid_argument,
+ "trying to match value with invalid format");
+ }
+}
+
+Expected<std::string>
+ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const {
+ if (Value == Kind::Signed) {
+ Expected<int64_t> SignedValue = IntegerValue.getSignedValue();
+ if (!SignedValue)
+ return SignedValue.takeError();
+ return itostr(*SignedValue);
+ }
+
+ Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue();
+ if (!UnsignedValue)
+ return UnsignedValue.takeError();
+ switch (Value) {
+ case Kind::Unsigned:
+ return utostr(*UnsignedValue);
+ case Kind::HexUpper:
+ return utohexstr(*UnsignedValue, /*LowerCase=*/false);
+ case Kind::HexLower:
+ return utohexstr(*UnsignedValue, /*LowerCase=*/true);
+ default:
+ return createStringError(std::errc::invalid_argument,
+ "trying to match value with invalid format");
+ }
+}
+
+Expected<ExpressionValue>
+ExpressionFormat::valueFromStringRepr(StringRef StrVal,
+ const SourceMgr &SM) const {
+ bool ValueIsSigned = Value == Kind::Signed;
+ StringRef OverflowErrorStr = "unable to represent numeric value";
+ if (ValueIsSigned) {
+ int64_t SignedValue;
+
+ if (StrVal.getAsInteger(10, SignedValue))
+ return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr);
+
+ return ExpressionValue(SignedValue);
+ }
+
+ bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower;
+ uint64_t UnsignedValue;
+ if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue))
+ return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr);
+
+ return ExpressionValue(UnsignedValue);
+}
+
+static int64_t getAsSigned(uint64_t UnsignedValue) {
+ // Use memcpy to reinterpret the bitpattern in Value since casting to
+ // signed is implementation-defined if the unsigned value is too big to be
+ // represented in the signed type and using an union violates type aliasing
+ // rules.
+ int64_t SignedValue;
+ memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue));
+ return SignedValue;
+}
+
+Expected<int64_t> ExpressionValue::getSignedValue() const {
+ if (Negative)
+ return getAsSigned(Value);
+
+ if (Value > (uint64_t)std::numeric_limits<int64_t>::max())
+ return make_error<OverflowError>();
+
+ // Value is in the representable range of int64_t so we can use cast.
+ return static_cast<int64_t>(Value);
+}
+
+Expected<uint64_t> ExpressionValue::getUnsignedValue() const {
+ if (Negative)
+ return make_error<OverflowError>();
+
+ return Value;
+}
+
+ExpressionValue ExpressionValue::getAbsolute() const {
+ if (!Negative)
+ return *this;
+
+ int64_t SignedValue = getAsSigned(Value);
+ int64_t MaxInt64 = std::numeric_limits<int64_t>::max();
+ // Absolute value can be represented as int64_t.
+ if (SignedValue >= -MaxInt64)
+ return ExpressionValue(-getAsSigned(Value));
+
+ // -X == -(max int64_t + Rem), negate each component independently.
+ SignedValue += MaxInt64;
+ uint64_t RemainingValueAbsolute = -SignedValue;
+ return ExpressionValue(MaxInt64 + RemainingValueAbsolute);
+}
+
+Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand,
+ const ExpressionValue &RightOperand) {
+ if (LeftOperand.isNegative() && RightOperand.isNegative()) {
+ int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
+ int64_t RightValue = cantFail(RightOperand.getSignedValue());
+ Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue);
+ if (!Result)
+ return make_error<OverflowError>();
+
+ return ExpressionValue(*Result);
+ }
+
+ // (-A) + B == B - A.
+ if (LeftOperand.isNegative())
+ return RightOperand - LeftOperand.getAbsolute();
+
+ // A + (-B) == A - B.
+ if (RightOperand.isNegative())
+ return LeftOperand - RightOperand.getAbsolute();
+
+ // Both values are positive at this point.
+ uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+ uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+ Optional<uint64_t> Result =
+ checkedAddUnsigned<uint64_t>(LeftValue, RightValue);
+ if (!Result)
+ return make_error<OverflowError>();
+
+ return ExpressionValue(*Result);
+}
+
+Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand,
+ const ExpressionValue &RightOperand) {
+ // Result will be negative and thus might underflow.
+ if (LeftOperand.isNegative() && !RightOperand.isNegative()) {
+ int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
+ uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+ // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement.
+ if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max())
+ return make_error<OverflowError>();
+ Optional<int64_t> Result =
+ checkedSub(LeftValue, static_cast<int64_t>(RightValue));
+ if (!Result)
+ return make_error<OverflowError>();
+
+ return ExpressionValue(*Result);
+ }
+
+ // (-A) - (-B) == B - A.
+ if (LeftOperand.isNegative())
+ return RightOperand.getAbsolute() - LeftOperand.getAbsolute();
+
+ // A - (-B) == A + B.
+ if (RightOperand.isNegative())
+ return LeftOperand + RightOperand.getAbsolute();
+
+ // Both values are positive at this point.
+ uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+ uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+ if (LeftValue >= RightValue)
+ return ExpressionValue(LeftValue - RightValue);
+ else {
+ uint64_t AbsoluteDifference = RightValue - LeftValue;
+ uint64_t MaxInt64 = std::numeric_limits<int64_t>::max();
+ // Value might underflow.
+ if (AbsoluteDifference > MaxInt64) {
+ AbsoluteDifference -= MaxInt64;
+ int64_t Result = -MaxInt64;
+ int64_t MinInt64 = std::numeric_limits<int64_t>::min();
+ // Underflow, tested by:
+ // abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t))
+ if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result)))
+ return make_error<OverflowError>();
+ Result -= static_cast<int64_t>(AbsoluteDifference);
+ return ExpressionValue(Result);
+ }
+
+ return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference));
+ }
+}
+
+Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand,
+ const ExpressionValue &RightOperand) {
+ // -A * -B == A * B
+ if (LeftOperand.isNegative() && RightOperand.isNegative())
+ return LeftOperand.getAbsolute() * RightOperand.getAbsolute();
+
+ // A * -B == -B * A
+ if (RightOperand.isNegative())
+ return RightOperand * LeftOperand;
+
+ assert(!RightOperand.isNegative() && "Unexpected negative operand!");
+
+ // Result will be negative and can underflow.
+ if (LeftOperand.isNegative()) {
+ auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute();
+ if (!Result)
+ return Result;
+
+ return ExpressionValue(0) - *Result;
+ }
+
+ // Result will be positive and can overflow.
+ uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+ uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+ Optional<uint64_t> Result =
+ checkedMulUnsigned<uint64_t>(LeftValue, RightValue);
+ if (!Result)
+ return make_error<OverflowError>();
+
+ return ExpressionValue(*Result);
+}
+
+Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand,
+ const ExpressionValue &RightOperand) {
+ // -A / -B == A / B
+ if (LeftOperand.isNegative() && RightOperand.isNegative())
+ return LeftOperand.getAbsolute() / RightOperand.getAbsolute();
+
+ // Check for divide by zero.
+ if (RightOperand == ExpressionValue(0))
+ return make_error<OverflowError>();
+
+ // Result will be negative and can underflow.
+ if (LeftOperand.isNegative() || RightOperand.isNegative())
+ return ExpressionValue(0) -
+ cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute());
+
+ uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+ uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+ return ExpressionValue(LeftValue / RightValue);
+}
+
+Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand,
+ const ExpressionValue &RightOperand) {
+ if (LeftOperand.isNegative() && RightOperand.isNegative()) {
+ int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
+ int64_t RightValue = cantFail(RightOperand.getSignedValue());
+ return ExpressionValue(std::max(LeftValue, RightValue));
+ }
+
+ if (!LeftOperand.isNegative() && !RightOperand.isNegative()) {
+ uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+ uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+ return ExpressionValue(std::max(LeftValue, RightValue));
+ }
+
+ if (LeftOperand.isNegative())
+ return RightOperand;
+
+ return LeftOperand;
+}
+
+Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand,
+ const ExpressionValue &RightOperand) {
+ if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand)
+ return RightOperand;
+
+ return LeftOperand;
+}
+
+Expected<ExpressionValue> NumericVariableUse::eval() const {
+ Optional<ExpressionValue> Value = Variable->getValue();
if (Value)
return *Value;
- return make_error<UndefVarError>(Name);
+ return make_error<UndefVarError>(getExpressionStr());
}
-Expected<uint64_t> BinaryOperation::eval() const {
- Expected<uint64_t> LeftOp = LeftOperand->eval();
- Expected<uint64_t> RightOp = RightOperand->eval();
+Expected<ExpressionValue> BinaryOperation::eval() const {
+ Expected<ExpressionValue> LeftOp = LeftOperand->eval();
+ Expected<ExpressionValue> RightOp = RightOperand->eval();
// Bubble up any error (e.g. undefined variables) in the recursive
// evaluation.
@@ -51,11 +336,42 @@ Expected<uint64_t> BinaryOperation::eval() const {
return EvalBinop(*LeftOp, *RightOp);
}
+Expected<ExpressionFormat>
+BinaryOperation::getImplicitFormat(const SourceMgr &SM) const {
+ Expected<ExpressionFormat> LeftFormat = LeftOperand->getImplicitFormat(SM);
+ Expected<ExpressionFormat> RightFormat = RightOperand->getImplicitFormat(SM);
+ if (!LeftFormat || !RightFormat) {
+ Error Err = Error::success();
+ if (!LeftFormat)
+ Err = joinErrors(std::move(Err), LeftFormat.takeError());
+ if (!RightFormat)
+ Err = joinErrors(std::move(Err), RightFormat.takeError());
+ return std::move(Err);
+ }
+
+ if (*LeftFormat != ExpressionFormat::Kind::NoFormat &&
+ *RightFormat != ExpressionFormat::Kind::NoFormat &&
+ *LeftFormat != *RightFormat)
+ return ErrorDiagnostic::get(
+ SM, getExpressionStr(),
+ "implicit format conflict between '" + LeftOperand->getExpressionStr() +
+ "' (" + LeftFormat->toString() + ") and '" +
+ RightOperand->getExpressionStr() + "' (" + RightFormat->toString() +
+ "), need an explicit format specifier");
+
+ return *LeftFormat != ExpressionFormat::Kind::NoFormat ? *LeftFormat
+ : *RightFormat;
+}
+
Expected<std::string> NumericSubstitution::getResult() const {
- Expected<uint64_t> EvaluatedValue = ExpressionASTPointer->eval();
+ assert(ExpressionPointer->getAST() != nullptr &&
+ "Substituting empty expression");
+ Expected<ExpressionValue> EvaluatedValue =
+ ExpressionPointer->getAST()->eval();
if (!EvaluatedValue)
return EvaluatedValue.takeError();
- return utostr(*EvaluatedValue);
+ ExpressionFormat Format = ExpressionPointer->getFormat();
+ return Format.getMatchingString(*EvaluatedValue);
}
Expected<std::string> StringSubstitution::getResult() const {
@@ -66,30 +382,27 @@ Expected<std::string> StringSubstitution::getResult() const {
return Regex::escape(*VarVal);
}
-bool Pattern::isValidVarNameStart(char C) { return C == '_' || isalpha(C); }
+bool Pattern::isValidVarNameStart(char C) { return C == '_' || isAlpha(C); }
Expected<Pattern::VariableProperties>
Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
if (Str.empty())
return ErrorDiagnostic::get(SM, Str, "empty variable name");
- bool ParsedOneChar = false;
- unsigned I = 0;
+ size_t 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 ErrorDiagnostic::get(SM, Str, "invalid variable name");
+ if (!isValidVarNameStart(Str[I++]))
+ return ErrorDiagnostic::get(SM, Str, "invalid variable name");
+ for (size_t E = Str.size(); I != E; ++I)
// Variable names are composed of alphanumeric characters and underscores.
- if (Str[I] != '_' && !isalnum(Str[I]))
+ if (Str[I] != '_' && !isAlnum(Str[I]))
break;
- ParsedOneChar = true;
- }
StringRef Name = Str.take_front(I);
Str = Str.substr(I);
@@ -107,13 +420,15 @@ static char popFront(StringRef &S) {
return C;
}
+char OverflowError::ID = 0;
char UndefVarError::ID = 0;
char ErrorDiagnostic::ID = 0;
char NotFoundError::ID = 0;
Expected<NumericVariable *> Pattern::parseNumericVariableDefinition(
StringRef &Expr, FileCheckPatternContext *Context,
- Optional<size_t> LineNumber, const SourceMgr &SM) {
+ Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat,
+ const SourceMgr &SM) {
Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
if (!ParseVarResult)
return ParseVarResult.takeError();
@@ -137,10 +452,14 @@ Expected<NumericVariable *> Pattern::parseNumericVariableDefinition(
NumericVariable *DefinedNumericVariable;
auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
- if (VarTableIter != Context->GlobalNumericVariableTable.end())
+ if (VarTableIter != Context->GlobalNumericVariableTable.end()) {
DefinedNumericVariable = VarTableIter->second;
- else
- DefinedNumericVariable = Context->makeNumericVariable(Name, LineNumber);
+ if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat)
+ return ErrorDiagnostic::get(
+ SM, Expr, "format different from previous variable definition");
+ } else
+ DefinedNumericVariable =
+ Context->makeNumericVariable(Name, ImplicitFormat, LineNumber);
return DefinedNumericVariable;
}
@@ -165,7 +484,8 @@ Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse(
if (VarTableIter != Context->GlobalNumericVariableTable.end())
NumericVariable = VarTableIter->second;
else {
- NumericVariable = Context->makeNumericVariable(Name);
+ NumericVariable = Context->makeNumericVariable(
+ Name, ExpressionFormat(ExpressionFormat::Kind::Unsigned));
Context->GlobalNumericVariableTable[Name] = NumericVariable;
}
@@ -180,16 +500,36 @@ Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse(
}
Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
- StringRef &Expr, AllowedOperand AO, Optional<size_t> LineNumber,
- FileCheckPatternContext *Context, const SourceMgr &SM) {
+ StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint,
+ Optional<size_t> LineNumber, FileCheckPatternContext *Context,
+ const SourceMgr &SM) {
+ if (Expr.startswith("(")) {
+ if (AO != AllowedOperand::Any)
+ return ErrorDiagnostic::get(
+ SM, Expr, "parenthesized expression not permitted here");
+ return parseParenExpr(Expr, LineNumber, Context, SM);
+ }
+
if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
// Try to parse as a numeric variable use.
Expected<Pattern::VariableProperties> ParseVarResult =
parseVariable(Expr, SM);
- if (ParseVarResult)
+ if (ParseVarResult) {
+ // Try to parse a function call.
+ if (Expr.ltrim(SpaceChars).startswith("(")) {
+ if (AO != AllowedOperand::Any)
+ return ErrorDiagnostic::get(SM, ParseVarResult->Name,
+ "unexpected function call");
+
+ return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context,
+ SM);
+ }
+
return parseNumericVariableUse(ParseVarResult->Name,
ParseVarResult->IsPseudo, LineNumber,
Context, SM);
+ }
+
if (AO == AllowedOperand::LineVar)
return ParseVarResult.takeError();
// Ignore the error and retry parsing as a literal.
@@ -197,41 +537,79 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
}
// Otherwise, parse it as a literal.
- uint64_t LiteralValue;
- if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
- return std::make_unique<ExpressionLiteral>(LiteralValue);
-
- return ErrorDiagnostic::get(SM, Expr,
- "invalid operand format '" + Expr + "'");
+ int64_t SignedLiteralValue;
+ uint64_t UnsignedLiteralValue;
+ StringRef SaveExpr = Expr;
+ // Accept both signed and unsigned literal, default to signed literal.
+ if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0,
+ UnsignedLiteralValue))
+ return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
+ UnsignedLiteralValue);
+ Expr = SaveExpr;
+ if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue))
+ return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
+ SignedLiteralValue);
+
+ return ErrorDiagnostic::get(
+ SM, Expr,
+ Twine("invalid ") +
+ (MaybeInvalidConstraint ? "matching constraint or " : "") +
+ "operand format");
}
-static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
- return LeftOp + RightOp;
-}
+Expected<std::unique_ptr<ExpressionAST>>
+Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM) {
+ Expr = Expr.ltrim(SpaceChars);
+ assert(Expr.startswith("("));
+
+ // Parse right operand.
+ Expr.consume_front("(");
+ Expr = Expr.ltrim(SpaceChars);
+ if (Expr.empty())
+ return ErrorDiagnostic::get(SM, Expr, "missing operand in expression");
-static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
- return LeftOp - RightOp;
+ // Note: parseNumericOperand handles nested opening parentheses.
+ Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand(
+ Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
+ Context, SM);
+ Expr = Expr.ltrim(SpaceChars);
+ while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) {
+ StringRef OrigExpr = Expr;
+ SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false,
+ LineNumber, Context, SM);
+ Expr = Expr.ltrim(SpaceChars);
+ }
+ if (!SubExprResult)
+ return SubExprResult;
+
+ if (!Expr.consume_front(")")) {
+ return ErrorDiagnostic::get(SM, Expr,
+ "missing ')' at end of nested expression");
+ }
+ return SubExprResult;
}
Expected<std::unique_ptr<ExpressionAST>>
-Pattern::parseBinop(StringRef &Expr, std::unique_ptr<ExpressionAST> LeftOp,
+Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr,
+ std::unique_ptr<ExpressionAST> LeftOp,
bool IsLegacyLineExpr, Optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM) {
- Expr = Expr.ltrim(SpaceChars);
- if (Expr.empty())
+ RemainingExpr = RemainingExpr.ltrim(SpaceChars);
+ if (RemainingExpr.empty())
return std::move(LeftOp);
// Check if this is a supported operation and select a function to perform
// it.
- SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
- char Operator = popFront(Expr);
+ SMLoc OpLoc = SMLoc::getFromPointer(RemainingExpr.data());
+ char Operator = popFront(RemainingExpr);
binop_eval_t EvalBinop;
switch (Operator) {
case '+':
- EvalBinop = add;
+ EvalBinop = operator+;
break;
case '-':
- EvalBinop = sub;
+ EvalBinop = operator-;
break;
default:
return ErrorDiagnostic::get(
@@ -239,29 +617,145 @@ Pattern::parseBinop(StringRef &Expr, std::unique_ptr<ExpressionAST> LeftOp,
}
// Parse right operand.
- Expr = Expr.ltrim(SpaceChars);
- if (Expr.empty())
- return ErrorDiagnostic::get(SM, Expr, "missing operand in expression");
+ RemainingExpr = RemainingExpr.ltrim(SpaceChars);
+ if (RemainingExpr.empty())
+ return ErrorDiagnostic::get(SM, RemainingExpr,
+ "missing operand in expression");
// The second operand in a legacy @LINE expression is always a literal.
AllowedOperand AO =
- IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
+ IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any;
Expected<std::unique_ptr<ExpressionAST>> RightOpResult =
- parseNumericOperand(Expr, AO, LineNumber, Context, SM);
+ parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false,
+ LineNumber, Context, SM);
if (!RightOpResult)
return RightOpResult;
- Expr = Expr.ltrim(SpaceChars);
- return std::make_unique<BinaryOperation>(EvalBinop, std::move(LeftOp),
+ Expr = Expr.drop_back(RemainingExpr.size());
+ return std::make_unique<BinaryOperation>(Expr, EvalBinop, std::move(LeftOp),
std::move(*RightOpResult));
}
-Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericSubstitutionBlock(
+Expected<std::unique_ptr<ExpressionAST>>
+Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
+ Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM) {
+ Expr = Expr.ltrim(SpaceChars);
+ assert(Expr.startswith("("));
+
+ auto OptFunc = StringSwitch<Optional<binop_eval_t>>(FuncName)
+ .Case("add", operator+)
+ .Case("div", operator/)
+ .Case("max", max)
+ .Case("min", min)
+ .Case("mul", operator*)
+ .Case("sub", operator-)
+ .Default(None);
+
+ if (!OptFunc)
+ return ErrorDiagnostic::get(
+ SM, FuncName, Twine("call to undefined function '") + FuncName + "'");
+
+ Expr.consume_front("(");
+ Expr = Expr.ltrim(SpaceChars);
+
+ // Parse call arguments, which are comma separated.
+ SmallVector<std::unique_ptr<ExpressionAST>, 4> Args;
+ while (!Expr.empty() && !Expr.startswith(")")) {
+ if (Expr.startswith(","))
+ return ErrorDiagnostic::get(SM, Expr, "missing argument");
+
+ // Parse the argument, which is an arbitary expression.
+ StringRef OuterBinOpExpr = Expr;
+ Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand(
+ Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
+ Context, SM);
+ while (Arg && !Expr.empty()) {
+ Expr = Expr.ltrim(SpaceChars);
+ // Have we reached an argument terminator?
+ if (Expr.startswith(",") || Expr.startswith(")"))
+ break;
+
+ // Arg = Arg <op> <expr>
+ Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber,
+ Context, SM);
+ }
+
+ // Prefer an expression error over a generic invalid argument message.
+ if (!Arg)
+ return Arg.takeError();
+ Args.push_back(std::move(*Arg));
+
+ // Have we parsed all available arguments?
+ Expr = Expr.ltrim(SpaceChars);
+ if (!Expr.consume_front(","))
+ break;
+
+ Expr = Expr.ltrim(SpaceChars);
+ if (Expr.startswith(")"))
+ return ErrorDiagnostic::get(SM, Expr, "missing argument");
+ }
+
+ if (!Expr.consume_front(")"))
+ return ErrorDiagnostic::get(SM, Expr,
+ "missing ')' at end of call expression");
+
+ const unsigned NumArgs = Args.size();
+ if (NumArgs == 2)
+ return std::make_unique<BinaryOperation>(Expr, *OptFunc, std::move(Args[0]),
+ std::move(Args[1]));
+
+ // TODO: Support more than binop_eval_t.
+ return ErrorDiagnostic::get(SM, FuncName,
+ Twine("function '") + FuncName +
+ Twine("' takes 2 arguments but ") +
+ Twine(NumArgs) + " given");
+}
+
+Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock(
StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable,
bool IsLegacyLineExpr, Optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM) {
std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr;
StringRef DefExpr = StringRef();
DefinedNumericVariable = None;
+ ExpressionFormat ExplicitFormat = ExpressionFormat();
+
+ // Parse format specifier (NOTE: ',' is also an argument seperator).
+ size_t FormatSpecEnd = Expr.find(',');
+ size_t FunctionStart = Expr.find('(');
+ if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) {
+ Expr = Expr.ltrim(SpaceChars);
+ if (!Expr.consume_front("%"))
+ return ErrorDiagnostic::get(
+ SM, Expr, "invalid matching format specification in expression");
+
+ // Check for unknown matching format specifier and set matching format in
+ // class instance representing this expression.
+ SMLoc fmtloc = SMLoc::getFromPointer(Expr.data());
+ switch (popFront(Expr)) {
+ case 'u':
+ ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::Unsigned);
+ break;
+ case 'd':
+ ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::Signed);
+ break;
+ case 'x':
+ ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower);
+ break;
+ case 'X':
+ ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexUpper);
+ break;
+ default:
+ return ErrorDiagnostic::get(SM, fmtloc,
+ "invalid format specifier in expression");
+ }
+
+ Expr = Expr.ltrim(SpaceChars);
+ if (!Expr.consume_front(","))
+ return ErrorDiagnostic::get(
+ SM, Expr, "invalid matching format specification in expression");
+ }
+
// Save variable definition expression if any.
size_t DefEnd = Expr.find(':');
if (DefEnd != StringRef::npos) {
@@ -269,18 +763,30 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericSubstitutionBlock(
Expr = Expr.substr(DefEnd + 1);
}
+ // Parse matching constraint.
+ Expr = Expr.ltrim(SpaceChars);
+ bool HasParsedValidConstraint = false;
+ if (Expr.consume_front("=="))
+ HasParsedValidConstraint = true;
+
// Parse the expression itself.
Expr = Expr.ltrim(SpaceChars);
- if (!Expr.empty()) {
+ if (Expr.empty()) {
+ if (HasParsedValidConstraint)
+ return ErrorDiagnostic::get(
+ SM, Expr, "empty numeric expression should not have a constraint");
+ } else {
+ Expr = Expr.rtrim(SpaceChars);
+ StringRef OuterBinOpExpr = Expr;
// The first operand in a legacy @LINE expression is always the @LINE
// pseudo variable.
AllowedOperand AO =
IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
- Expected<std::unique_ptr<ExpressionAST>> ParseResult =
- parseNumericOperand(Expr, AO, LineNumber, Context, SM);
+ Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand(
+ Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM);
while (ParseResult && !Expr.empty()) {
- ParseResult = parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr,
- LineNumber, Context, SM);
+ ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult),
+ IsLegacyLineExpr, LineNumber, Context, SM);
// Legacy @LINE expressions only allow 2 operands.
if (ParseResult && IsLegacyLineExpr && !Expr.empty())
return ErrorDiagnostic::get(
@@ -288,22 +794,42 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericSubstitutionBlock(
"unexpected characters at end of expression '" + Expr + "'");
}
if (!ParseResult)
- return ParseResult;
+ return ParseResult.takeError();
ExpressionASTPointer = std::move(*ParseResult);
}
+ // Select format of the expression, i.e. (i) its explicit format, if any,
+ // otherwise (ii) its implicit format, if any, otherwise (iii) the default
+ // format (unsigned). Error out in case of conflicting implicit format
+ // without explicit format.
+ ExpressionFormat Format;
+ if (ExplicitFormat)
+ Format = ExplicitFormat;
+ else if (ExpressionASTPointer) {
+ Expected<ExpressionFormat> ImplicitFormat =
+ ExpressionASTPointer->getImplicitFormat(SM);
+ if (!ImplicitFormat)
+ return ImplicitFormat.takeError();
+ Format = *ImplicitFormat;
+ }
+ if (!Format)
+ Format = ExpressionFormat(ExpressionFormat::Kind::Unsigned);
+
+ std::unique_ptr<Expression> ExpressionPointer =
+ std::make_unique<Expression>(std::move(ExpressionASTPointer), Format);
+
// Parse the numeric variable definition.
if (DefEnd != StringRef::npos) {
DefExpr = DefExpr.ltrim(SpaceChars);
- Expected<NumericVariable *> ParseResult =
- parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
+ Expected<NumericVariable *> ParseResult = parseNumericVariableDefinition(
+ DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM);
if (!ParseResult)
return ParseResult.takeError();
DefinedNumericVariable = *ParseResult;
}
- return std::move(ExpressionASTPointer);
+ return std::move(ExpressionPointer);
}
bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
@@ -476,10 +1002,10 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
}
// Parse numeric substitution block.
- std::unique_ptr<ExpressionAST> ExpressionASTPointer;
+ std::unique_ptr<Expression> ExpressionPointer;
Optional<NumericVariable *> DefinedNumericVariable;
if (IsNumBlock) {
- Expected<std::unique_ptr<ExpressionAST>> ParseResult =
+ Expected<std::unique_ptr<Expression>> ParseResult =
parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
IsLegacyLineExpr, LineNumber, Context,
SM);
@@ -487,16 +1013,18 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
logAllUnhandledErrors(ParseResult.takeError(), errs());
return true;
}
- ExpressionASTPointer = std::move(*ParseResult);
- SubstNeeded = ExpressionASTPointer != nullptr;
+ ExpressionPointer = std::move(*ParseResult);
+ SubstNeeded = ExpressionPointer->getAST() != nullptr;
if (DefinedNumericVariable) {
IsDefinition = true;
DefName = (*DefinedNumericVariable)->getName();
}
if (SubstNeeded)
SubstStr = MatchStr;
- else
- MatchRegexp = "[0-9]+";
+ else {
+ ExpressionFormat Format = ExpressionPointer->getFormat();
+ MatchRegexp = cantFail(Format.getWildcardRegex());
+ }
}
// Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
@@ -554,8 +1082,7 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
Substitution *Substitution =
IsNumBlock
? Context->makeNumericSubstitution(
- SubstStr, std::move(ExpressionASTPointer),
- SubstInsertIdx)
+ SubstStr, std::move(ExpressionPointer), SubstInsertIdx)
: Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
Substitutions.push_back(Substitution);
}
@@ -626,7 +1153,7 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
if (!Substitutions.empty()) {
TmpStr = RegExStr;
if (LineNumber)
- Context->LineVariable->setValue(*LineNumber);
+ Context->LineVariable->setValue(ExpressionValue(*LineNumber));
size_t InsertOffset = 0;
// Substitute all string variables and expressions whose values are only
@@ -635,8 +1162,18 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
for (const auto &Substitution : Substitutions) {
// Substitute and check for failure (e.g. use of undefined variable).
Expected<std::string> Value = Substitution->getResult();
- if (!Value)
- return Value.takeError();
+ if (!Value) {
+ // Convert to an ErrorDiagnostic to get location information. This is
+ // done here rather than PrintNoMatch since now we know which
+ // substitution block caused the overflow.
+ Error Err =
+ handleErrors(Value.takeError(), [&](const OverflowError &E) {
+ return ErrorDiagnostic::get(SM, Substitution->getFromString(),
+ "unable to substitute variable or "
+ "numeric expression: overflow error");
+ });
+ return std::move(Err);
+ }
// Plop it into the regex at the adjusted offset.
TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
@@ -676,11 +1213,12 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
NumericVariableMatch.DefinedNumericVariable;
StringRef MatchedValue = MatchInfo[CaptureParenGroup];
- uint64_t Val;
- if (MatchedValue.getAsInteger(10, Val))
- return ErrorDiagnostic::get(SM, MatchedValue,
- "Unable to represent numeric value");
- DefinedNumericVariable->setValue(Val);
+ ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat();
+ Expected<ExpressionValue> Value =
+ Format.valueFromStringRepr(MatchedValue, SM);
+ if (!Value)
+ return Value.takeError();
+ DefinedNumericVariable->setValue(*Value);
}
// Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
@@ -721,17 +1259,20 @@ void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
// variables it uses.
if (!MatchedValue) {
bool UndefSeen = false;
- handleAllErrors(MatchedValue.takeError(), [](const NotFoundError &E) {},
- // Handled in PrintNoMatch().
- [](const ErrorDiagnostic &E) {},
- [&](const UndefVarError &E) {
- if (!UndefSeen) {
- OS << "uses undefined variable(s):";
- UndefSeen = true;
- }
- OS << " ";
- E.log(OS);
- });
+ handleAllErrors(
+ MatchedValue.takeError(), [](const NotFoundError &E) {},
+ // Handled in PrintNoMatch().
+ [](const ErrorDiagnostic &E) {},
+ // Handled in match().
+ [](const OverflowError &E) {},
+ [&](const UndefVarError &E) {
+ if (!UndefSeen) {
+ OS << "uses undefined variable(s):";
+ UndefSeen = true;
+ }
+ OS << " ";
+ E.log(OS);
+ });
} else {
// Substitution succeeded. Print substituted value.
OS << "with \"";
@@ -837,10 +1378,10 @@ FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
}
Substitution *FileCheckPatternContext::makeNumericSubstitution(
- StringRef ExpressionStr,
- std::unique_ptr<ExpressionAST> ExpressionASTPointer, size_t InsertIdx) {
+ StringRef ExpressionStr, std::unique_ptr<Expression> Expression,
+ size_t InsertIdx) {
Substitutions.push_back(std::make_unique<NumericSubstitution>(
- this, ExpressionStr, std::move(ExpressionASTPointer), InsertIdx));
+ this, ExpressionStr, std::move(Expression), InsertIdx));
return Substitutions.back().get();
}
@@ -915,20 +1456,17 @@ FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
const Check::FileCheckType &CheckTy,
SMLoc CheckLoc, MatchType MatchTy,
SMRange InputRange)
- : CheckTy(CheckTy), MatchTy(MatchTy) {
+ : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy) {
auto Start = SM.getLineAndColumn(InputRange.Start);
auto End = SM.getLineAndColumn(InputRange.End);
InputStartLine = Start.first;
InputStartCol = Start.second;
InputEndLine = End.first;
InputEndCol = End.second;
- Start = SM.getLineAndColumn(CheckLoc);
- CheckLine = Start.first;
- CheckCol = Start.second;
}
static bool IsPartOfWord(char c) {
- return (isalnum(c) || c == '-' || c == '_');
+ return (isAlnum(c) || c == '-' || c == '_');
}
Check::FileCheckType &Check::FileCheckType::setCount(int C) {
@@ -946,7 +1484,7 @@ std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
case Check::CheckPlain:
if (Count > 1)
return Prefix.str() + "-COUNT";
- return Prefix;
+ return std::string(Prefix);
case Check::CheckNext:
return Prefix.str() + "-NEXT";
case Check::CheckSame:
@@ -959,6 +1497,8 @@ std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
return Prefix.str() + "-LABEL";
case Check::CheckEmpty:
return Prefix.str() + "-EMPTY";
+ case Check::CheckComment:
+ return std::string(Prefix);
case Check::CheckEOF:
return "implicit EOF";
case Check::CheckBadNot:
@@ -970,13 +1510,24 @@ std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
}
static std::pair<Check::FileCheckType, StringRef>
-FindCheckType(StringRef Buffer, StringRef Prefix) {
+FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) {
if (Buffer.size() <= Prefix.size())
return {Check::CheckNone, StringRef()};
char NextChar = Buffer[Prefix.size()];
StringRef Rest = Buffer.drop_front(Prefix.size() + 1);
+
+ // Check for comment.
+ if (Req.CommentPrefixes.end() != std::find(Req.CommentPrefixes.begin(),
+ Req.CommentPrefixes.end(),
+ Prefix)) {
+ if (NextChar == ':')
+ return {Check::CheckComment, Rest};
+ // Ignore a comment prefix if it has a suffix like "-NOT".
+ return {Check::CheckNone, StringRef()};
+ }
+
// Verify that the : is present after the prefix.
if (NextChar == ':')
return {Check::CheckPlain, Rest};
@@ -1055,8 +1606,9 @@ static size_t SkipWord(StringRef Str, size_t Loc) {
/// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
/// is unspecified.
static std::pair<StringRef, StringRef>
-FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
- unsigned &LineNumber, Check::FileCheckType &CheckTy) {
+FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE,
+ StringRef &Buffer, unsigned &LineNumber,
+ Check::FileCheckType &CheckTy) {
SmallVector<StringRef, 2> Matches;
while (!Buffer.empty()) {
@@ -1084,7 +1636,7 @@ FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
// Now extract the type.
StringRef AfterSuffix;
- std::tie(CheckTy, AfterSuffix) = FindCheckType(Buffer, Prefix);
+ std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix);
// If we've found a valid check type for this prefix, we're done.
if (CheckTy != Check::CheckNone)
@@ -1104,7 +1656,8 @@ FindFirstMatchingPrefix(Regex &PrefixRE, StringRef &Buffer,
void FileCheckPatternContext::createLineVariable() {
assert(!LineVariable && "@LINE pseudo numeric variable already created");
StringRef LineName = "@LINE";
- LineVariable = makeNumericVariable(LineName);
+ LineVariable = makeNumericVariable(
+ LineName, ExpressionFormat(ExpressionFormat::Kind::Unsigned));
GlobalNumericVariableTable[LineName] = LineVariable;
}
@@ -1114,8 +1667,12 @@ FileCheck::FileCheck(FileCheckRequest Req)
FileCheck::~FileCheck() = default;
-bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
- Regex &PrefixRE) {
+bool FileCheck::readCheckFile(
+ SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
+ std::pair<unsigned, unsigned> *ImpPatBufferIDRange) {
+ if (ImpPatBufferIDRange)
+ ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0;
+
Error DefineError =
PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);
if (DefineError) {
@@ -1126,17 +1683,27 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
PatternContext->createLineVariable();
std::vector<Pattern> ImplicitNegativeChecks;
- for (const auto &PatternString : Req.ImplicitCheckNot) {
+ for (StringRef PatternString : Req.ImplicitCheckNot) {
// Create a buffer with fake command line content in order to display the
// command line option responsible for the specific implicit CHECK-NOT.
std::string Prefix = "-implicit-check-not='";
std::string Suffix = "'";
std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(
- Prefix + PatternString + Suffix, "command line");
+ (Prefix + PatternString + Suffix).str(), "command line");
StringRef PatternInBuffer =
CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
- SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
+ unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
+ if (ImpPatBufferIDRange) {
+ if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) {
+ ImpPatBufferIDRange->first = BufferID;
+ ImpPatBufferIDRange->second = BufferID + 1;
+ } else {
+ assert(BufferID == ImpPatBufferIDRange->second &&
+ "expected consecutive source buffer IDs");
+ ++ImpPatBufferIDRange->second;
+ }
+ }
ImplicitNegativeChecks.push_back(
Pattern(Check::CheckNot, PatternContext.get()));
@@ -1150,6 +1717,7 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
// found.
unsigned LineNumber = 1;
+ bool FoundUsedCheckPrefix = false;
while (1) {
Check::FileCheckType CheckTy;
@@ -1157,9 +1725,12 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
StringRef UsedPrefix;
StringRef AfterSuffix;
std::tie(UsedPrefix, AfterSuffix) =
- FindFirstMatchingPrefix(PrefixRE, Buffer, LineNumber, CheckTy);
+ FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy);
if (UsedPrefix.empty())
break;
+ if (CheckTy != Check::CheckComment)
+ FoundUsedCheckPrefix = true;
+
assert(UsedPrefix.data() == Buffer.data() &&
"Failed to move Buffer's start forward, or pointed prefix outside "
"of the buffer!");
@@ -1201,9 +1772,17 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
// Remember the location of the start of the pattern, for diagnostics.
SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
+ // Extract the pattern from the buffer.
+ StringRef PatternBuffer = Buffer.substr(0, EOL);
+ Buffer = Buffer.substr(EOL);
+
+ // If this is a comment, we're done.
+ if (CheckTy == Check::CheckComment)
+ continue;
+
// Parse the pattern.
Pattern P(CheckTy, PatternContext.get(), LineNumber);
- if (P.parsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, Req))
+ if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req))
return true;
// Verify that CHECK-LABEL lines do not define or use variables
@@ -1215,8 +1794,6 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
return true;
}
- Buffer = Buffer.substr(EOL);
-
// Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
CheckTy == Check::CheckEmpty) &&
@@ -1243,31 +1820,30 @@ bool FileCheck::readCheckFile(SourceMgr &SM, StringRef Buffer,
DagNotMatches = ImplicitNegativeChecks;
}
- // 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(
- Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),
- *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
- std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
- }
-
- if (CheckStrings->empty()) {
+ // When there are no used prefixes we report an error except in the case that
+ // no prefix is specified explicitly but -implicit-check-not is specified.
+ if (!FoundUsedCheckPrefix &&
+ (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) {
errs() << "error: no check strings found with prefix"
<< (Req.CheckPrefixes.size() > 1 ? "es " : " ");
- auto I = Req.CheckPrefixes.begin();
- auto E = Req.CheckPrefixes.end();
- if (I != E) {
- errs() << "\'" << *I << ":'";
- ++I;
+ for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) {
+ if (I != 0)
+ errs() << ", ";
+ errs() << "\'" << Req.CheckPrefixes[I] << ":'";
}
- for (; I != E; ++I)
- errs() << ", \'" << *I << ":'";
-
errs() << '\n';
return true;
}
+ // Add an EOF pattern for any trailing --implicit-check-not/CHECK-DAG/-NOTs,
+ // and use the first prefix as a filler for the error message.
+ if (!DagNotMatches.empty()) {
+ CheckStrings->emplace_back(
+ Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),
+ *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
+ std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
+ }
+
return false;
}
@@ -1706,43 +2282,74 @@ size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
return StartPos;
}
-// A check prefix must contain only alphanumeric, hyphens and underscores.
-static bool ValidateCheckPrefix(StringRef CheckPrefix) {
- static const Regex Validator("^[a-zA-Z0-9_-]*$");
- return Validator.match(CheckPrefix);
-}
-
-bool FileCheck::ValidateCheckPrefixes() {
- StringSet<> PrefixSet;
-
- for (StringRef Prefix : Req.CheckPrefixes) {
- // Reject empty prefixes.
- if (Prefix == "")
+static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes,
+ ArrayRef<StringRef> SuppliedPrefixes) {
+ for (StringRef Prefix : SuppliedPrefixes) {
+ if (Prefix.empty()) {
+ errs() << "error: supplied " << Kind << " prefix must not be the empty "
+ << "string\n";
return false;
-
- if (!PrefixSet.insert(Prefix).second)
+ }
+ static const Regex Validator("^[a-zA-Z0-9_-]*$");
+ if (!Validator.match(Prefix)) {
+ errs() << "error: supplied " << Kind << " prefix must start with a "
+ << "letter and contain only alphanumeric characters, hyphens, and "
+ << "underscores: '" << Prefix << "'\n";
return false;
-
- if (!ValidateCheckPrefix(Prefix))
+ }
+ if (!UniquePrefixes.insert(Prefix).second) {
+ errs() << "error: supplied " << Kind << " prefix must be unique among "
+ << "check and comment prefixes: '" << Prefix << "'\n";
return false;
+ }
}
+ return true;
+}
+
+static const char *DefaultCheckPrefixes[] = {"CHECK"};
+static const char *DefaultCommentPrefixes[] = {"COM", "RUN"};
+bool FileCheck::ValidateCheckPrefixes() {
+ StringSet<> UniquePrefixes;
+ // Add default prefixes to catch user-supplied duplicates of them below.
+ if (Req.CheckPrefixes.empty()) {
+ for (const char *Prefix : DefaultCheckPrefixes)
+ UniquePrefixes.insert(Prefix);
+ }
+ if (Req.CommentPrefixes.empty()) {
+ for (const char *Prefix : DefaultCommentPrefixes)
+ UniquePrefixes.insert(Prefix);
+ }
+ // Do not validate the default prefixes, or diagnostics about duplicates might
+ // incorrectly indicate that they were supplied by the user.
+ if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes))
+ return false;
+ if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes))
+ return false;
return true;
}
Regex FileCheck::buildCheckPrefixRegex() {
- // 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())
- Req.CheckPrefixes.push_back("CHECK");
+ if (Req.CheckPrefixes.empty()) {
+ for (const char *Prefix : DefaultCheckPrefixes)
+ Req.CheckPrefixes.push_back(Prefix);
+ Req.IsDefaultCheckPrefix = true;
+ }
+ if (Req.CommentPrefixes.empty()) {
+ for (const char *Prefix : DefaultCommentPrefixes)
+ Req.CommentPrefixes.push_back(Prefix);
+ }
- // We already validated the contents of CheckPrefixes so just concatenate
- // them as alternatives.
+ // We already validated the contents of CheckPrefixes and CommentPrefixes so
+ // just concatenate them as alternatives.
SmallString<32> PrefixRegexStr;
- for (StringRef Prefix : Req.CheckPrefixes) {
- if (Prefix != Req.CheckPrefixes.front())
+ for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) {
+ if (I != 0)
PrefixRegexStr.push_back('|');
-
+ PrefixRegexStr.append(Req.CheckPrefixes[I]);
+ }
+ for (StringRef Prefix : Req.CommentPrefixes) {
+ PrefixRegexStr.push_back('|');
PrefixRegexStr.append(Prefix);
}
@@ -1750,7 +2357,7 @@ Regex FileCheck::buildCheckPrefixRegex() {
}
Error FileCheckPatternContext::defineCmdlineVariables(
- std::vector<std::string> &CmdlineDefines, SourceMgr &SM) {
+ ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) {
assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
"Overriding defined variable with command-line variable definitions");
@@ -1777,7 +2384,7 @@ Error FileCheckPatternContext::defineCmdlineVariables(
// format as in the input file to be able to reuse
// parseNumericSubstitutionBlock.
CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
- std::string SubstitutionStr = CmdlineDef;
+ std::string SubstitutionStr = std::string(CmdlineDef);
SubstitutionStr[EqIdx] = ':';
CmdlineDefsIndices.push_back(
std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
@@ -1815,20 +2422,19 @@ Error FileCheckPatternContext::defineCmdlineVariables(
// to create the necessary class instance.
StringRef CmdlineDefExpr = CmdlineDef.substr(1);
Optional<NumericVariable *> DefinedNumericVariable;
- Expected<std::unique_ptr<ExpressionAST>> ExpressionASTResult =
+ Expected<std::unique_ptr<Expression>> ExpressionResult =
Pattern::parseNumericSubstitutionBlock(
CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);
- if (!ExpressionASTResult) {
- Errs = joinErrors(std::move(Errs), ExpressionASTResult.takeError());
+ if (!ExpressionResult) {
+ Errs = joinErrors(std::move(Errs), ExpressionResult.takeError());
continue;
}
- std::unique_ptr<ExpressionAST> ExpressionASTPointer =
- std::move(*ExpressionASTResult);
+ std::unique_ptr<Expression> Expression = std::move(*ExpressionResult);
// Now evaluate the expression whose value this variable should be set
// to, since the expression of a command-line variable definition should
// only use variables defined earlier on the command-line. If not, this
// is an error and we report it.
- Expected<uint64_t> Value = ExpressionASTPointer->eval();
+ Expected<ExpressionValue> Value = Expression->getAST()->eval();
if (!Value) {
Errs = joinErrors(std::move(Errs), Value.takeError());
continue;
diff --git a/llvm/lib/Support/FileCheckImpl.h b/llvm/lib/Support/FileCheckImpl.h
index dc07d22aefd83..6ca67ec2964c2 100644
--- a/llvm/lib/Support/FileCheckImpl.h
+++ b/llvm/lib/Support/FileCheckImpl.h
@@ -15,6 +15,7 @@
#ifndef LLVM_LIB_SUPPORT_FILECHECKIMPL_H
#define LLVM_LIB_SUPPORT_FILECHECKIMPL_H
+#include "llvm/Support/FileCheck.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -30,28 +31,175 @@ namespace llvm {
// Numeric substitution handling code.
//===----------------------------------------------------------------------===//
+class ExpressionValue;
+
+/// Type representing the format an expression value should be textualized into
+/// for matching. Used to represent both explicit format specifiers as well as
+/// implicit format from using numeric variables.
+struct ExpressionFormat {
+ enum class Kind {
+ /// Denote absence of format. Used for implicit format of literals and
+ /// empty expressions.
+ NoFormat,
+ /// Value is an unsigned integer and should be printed as a decimal number.
+ Unsigned,
+ /// Value is a signed integer and should be printed as a decimal number.
+ Signed,
+ /// Value should be printed as an uppercase hex number.
+ HexUpper,
+ /// Value should be printed as a lowercase hex number.
+ HexLower
+ };
+
+private:
+ Kind Value;
+
+public:
+ /// Evaluates a format to true if it can be used in a match.
+ explicit operator bool() const { return Value != Kind::NoFormat; }
+
+ /// Define format equality: formats are equal if neither is NoFormat and
+ /// their kinds are the same.
+ bool operator==(const ExpressionFormat &Other) const {
+ return Value != Kind::NoFormat && Value == Other.Value;
+ }
+
+ bool operator!=(const ExpressionFormat &Other) const {
+ return !(*this == Other);
+ }
+
+ bool operator==(Kind OtherValue) const { return Value == OtherValue; }
+
+ bool operator!=(Kind OtherValue) const { return !(*this == OtherValue); }
+
+ /// \returns the format specifier corresponding to this format as a string.
+ StringRef toString() const;
+
+ ExpressionFormat() : Value(Kind::NoFormat){};
+ explicit ExpressionFormat(Kind Value) : Value(Value){};
+
+ /// \returns a wildcard regular expression StringRef that matches any value
+ /// in the format represented by this instance, or an error if the format is
+ /// NoFormat.
+ Expected<StringRef> getWildcardRegex() const;
+
+ /// \returns the string representation of \p Value in the format represented
+ /// by this instance, or an error if conversion to this format failed or the
+ /// format is NoFormat.
+ Expected<std::string> getMatchingString(ExpressionValue Value) const;
+
+ /// \returns the value corresponding to string representation \p StrVal
+ /// according to the matching format represented by this instance or an error
+ /// with diagnostic against \p SM if \p StrVal does not correspond to a valid
+ /// and representable value.
+ Expected<ExpressionValue> valueFromStringRepr(StringRef StrVal,
+ const SourceMgr &SM) const;
+};
+
+/// Class to represent an overflow error that might result when manipulating a
+/// value.
+class OverflowError : public ErrorInfo<OverflowError> {
+public:
+ static char ID;
+
+ std::error_code convertToErrorCode() const override {
+ return std::make_error_code(std::errc::value_too_large);
+ }
+
+ void log(raw_ostream &OS) const override { OS << "overflow error"; }
+};
+
+/// Class representing a numeric value.
+class ExpressionValue {
+private:
+ uint64_t Value;
+ bool Negative;
+
+public:
+ template <class T>
+ explicit ExpressionValue(T Val) : Value(Val), Negative(Val < 0) {}
+
+ bool operator==(const ExpressionValue &Other) const {
+ return Value == Other.Value && isNegative() == Other.isNegative();
+ }
+
+ bool operator!=(const ExpressionValue &Other) const {
+ return !(*this == Other);
+ }
+
+ /// Returns true if value is signed and negative, false otherwise.
+ bool isNegative() const {
+ assert((Value != 0 || !Negative) && "Unexpected negative zero!");
+ return Negative;
+ }
+
+ /// \returns the value as a signed integer or an error if the value is out of
+ /// range.
+ Expected<int64_t> getSignedValue() const;
+
+ /// \returns the value as an unsigned integer or an error if the value is out
+ /// of range.
+ Expected<uint64_t> getUnsignedValue() const;
+
+ /// \returns an unsigned ExpressionValue instance whose value is the absolute
+ /// value to this object's value.
+ ExpressionValue getAbsolute() const;
+};
+
+/// Performs operation and \returns its result or an error in case of failure,
+/// such as if an overflow occurs.
+Expected<ExpressionValue> operator+(const ExpressionValue &Lhs,
+ const ExpressionValue &Rhs);
+Expected<ExpressionValue> operator-(const ExpressionValue &Lhs,
+ const ExpressionValue &Rhs);
+Expected<ExpressionValue> operator*(const ExpressionValue &Lhs,
+ const ExpressionValue &Rhs);
+Expected<ExpressionValue> operator/(const ExpressionValue &Lhs,
+ const ExpressionValue &Rhs);
+Expected<ExpressionValue> max(const ExpressionValue &Lhs,
+ const ExpressionValue &Rhs);
+Expected<ExpressionValue> min(const ExpressionValue &Lhs,
+ const ExpressionValue &Rhs);
+
/// Base class representing the AST of a given expression.
class ExpressionAST {
+private:
+ StringRef ExpressionStr;
+
public:
+ ExpressionAST(StringRef ExpressionStr) : ExpressionStr(ExpressionStr) {}
+
virtual ~ExpressionAST() = default;
+ StringRef getExpressionStr() const { return ExpressionStr; }
+
/// Evaluates and \returns the value of the expression represented by this
/// AST or an error if evaluation fails.
- virtual Expected<uint64_t> eval() const = 0;
+ virtual Expected<ExpressionValue> eval() const = 0;
+
+ /// \returns either the implicit format of this AST, a diagnostic against
+ /// \p SM if implicit formats of the AST's components conflict, or NoFormat
+ /// if the AST has no implicit format (e.g. AST is made up of a single
+ /// literal).
+ virtual Expected<ExpressionFormat>
+ getImplicitFormat(const SourceMgr &SM) const {
+ return ExpressionFormat();
+ }
};
/// Class representing an unsigned literal in the AST of an expression.
class ExpressionLiteral : public ExpressionAST {
private:
/// Actual value of the literal.
- uint64_t Value;
+ ExpressionValue Value;
public:
- /// Constructs a literal with the specified value.
- ExpressionLiteral(uint64_t Val) : Value(Val) {}
+ template <class T>
+ explicit ExpressionLiteral(StringRef ExpressionStr, T Val)
+ : ExpressionAST(ExpressionStr), Value(Val) {}
/// \returns the literal's value.
- Expected<uint64_t> eval() const override { return Value; }
+ Expected<ExpressionValue> eval() const override { return Value; }
};
/// Class to represent an undefined variable error, which quotes that
@@ -78,14 +226,40 @@ public:
}
};
+/// Class representing an expression and its matching format.
+class Expression {
+private:
+ /// Pointer to AST of the expression.
+ std::unique_ptr<ExpressionAST> AST;
+
+ /// Format to use (e.g. hex upper case letters) when matching the value.
+ ExpressionFormat Format;
+
+public:
+ /// Generic constructor for an expression represented by the given \p AST and
+ /// whose matching format is \p Format.
+ Expression(std::unique_ptr<ExpressionAST> AST, ExpressionFormat Format)
+ : AST(std::move(AST)), Format(Format) {}
+
+ /// \returns pointer to AST of the expression. Pointer is guaranteed to be
+ /// valid as long as this object is.
+ ExpressionAST *getAST() const { return AST.get(); }
+
+ ExpressionFormat getFormat() const { return Format; }
+};
+
/// Class representing a numeric variable and its associated current value.
class NumericVariable {
private:
/// Name of the numeric variable.
StringRef Name;
+ /// Format to use for expressions using this variable without an explicit
+ /// format.
+ ExpressionFormat ImplicitFormat;
+
/// Value of numeric variable, if defined, or None otherwise.
- Optional<uint64_t> Value;
+ Optional<ExpressionValue> Value;
/// Line number where this variable is defined, or None if defined before
/// input is parsed. Used to determine whether a variable is defined on the
@@ -93,20 +267,25 @@ private:
Optional<size_t> DefLineNumber;
public:
- /// Constructor for a variable \p Name defined at line \p DefLineNumber or
- /// defined before input is parsed if \p DefLineNumber is None.
- explicit NumericVariable(StringRef Name,
+ /// Constructor for a variable \p Name with implicit format \p ImplicitFormat
+ /// defined at line \p DefLineNumber or defined before input is parsed if
+ /// \p DefLineNumber is None.
+ explicit NumericVariable(StringRef Name, ExpressionFormat ImplicitFormat,
Optional<size_t> DefLineNumber = None)
- : Name(Name), DefLineNumber(DefLineNumber) {}
+ : Name(Name), ImplicitFormat(ImplicitFormat),
+ DefLineNumber(DefLineNumber) {}
/// \returns name of this numeric variable.
StringRef getName() const { return Name; }
+ /// \returns implicit format of this numeric variable.
+ ExpressionFormat getImplicitFormat() const { return ImplicitFormat; }
+
/// \returns this variable's value.
- Optional<uint64_t> getValue() const { return Value; }
+ Optional<ExpressionValue> getValue() const { return Value; }
/// Sets value of this numeric variable to \p NewValue.
- void setValue(uint64_t NewValue) { Value = NewValue; }
+ void setValue(ExpressionValue NewValue) { Value = NewValue; }
/// Clears value of this numeric variable, regardless of whether it is
/// currently defined or not.
@@ -121,22 +300,25 @@ public:
/// expression.
class NumericVariableUse : public ExpressionAST {
private:
- /// Name of the numeric variable.
- StringRef Name;
-
/// Pointer to the class instance for the variable this use is about.
NumericVariable *Variable;
public:
NumericVariableUse(StringRef Name, NumericVariable *Variable)
- : Name(Name), Variable(Variable) {}
-
+ : ExpressionAST(Name), Variable(Variable) {}
/// \returns the value of the variable referenced by this instance.
- Expected<uint64_t> eval() const override;
+ Expected<ExpressionValue> eval() const override;
+
+ /// \returns implicit format of this numeric variable.
+ Expected<ExpressionFormat>
+ getImplicitFormat(const SourceMgr &SM) const override {
+ return Variable->getImplicitFormat();
+ }
};
/// Type of functions evaluating a given binary operation.
-using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
+using binop_eval_t = Expected<ExpressionValue> (*)(const ExpressionValue &,
+ const ExpressionValue &);
/// Class representing a single binary operation in the AST of an expression.
class BinaryOperation : public ExpressionAST {
@@ -151,9 +333,10 @@ private:
binop_eval_t EvalBinop;
public:
- BinaryOperation(binop_eval_t EvalBinop, std::unique_ptr<ExpressionAST> LeftOp,
+ BinaryOperation(StringRef ExpressionStr, binop_eval_t EvalBinop,
+ std::unique_ptr<ExpressionAST> LeftOp,
std::unique_ptr<ExpressionAST> RightOp)
- : EvalBinop(EvalBinop) {
+ : ExpressionAST(ExpressionStr), EvalBinop(EvalBinop) {
LeftOperand = std::move(LeftOp);
RightOperand = std::move(RightOp);
}
@@ -162,7 +345,14 @@ public:
/// using EvalBinop on the result of recursively evaluating the operands.
/// \returns the expression value or an error if an undefined numeric
/// variable is used in one of the operands.
- Expected<uint64_t> eval() const override;
+ Expected<ExpressionValue> eval() const override;
+
+ /// \returns the implicit format of this AST, if any, a diagnostic against
+ /// \p SM if the implicit formats of the AST's components conflict, or no
+ /// format if the AST has no implicit format (e.g. AST is made of a single
+ /// literal).
+ Expected<ExpressionFormat>
+ getImplicitFormat(const SourceMgr &SM) const override;
};
class FileCheckPatternContext;
@@ -218,14 +408,14 @@ class NumericSubstitution : public Substitution {
private:
/// Pointer to the class representing the expression whose value is to be
/// substituted.
- std::unique_ptr<ExpressionAST> ExpressionASTPointer;
+ std::unique_ptr<Expression> ExpressionPointer;
public:
- NumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,
- std::unique_ptr<ExpressionAST> ExprAST, size_t InsertIdx)
- : Substitution(Context, Expr, InsertIdx) {
- ExpressionASTPointer = std::move(ExprAST);
- }
+ NumericSubstitution(FileCheckPatternContext *Context, StringRef ExpressionStr,
+ std::unique_ptr<Expression> ExpressionPointer,
+ size_t InsertIdx)
+ : Substitution(Context, ExpressionStr, InsertIdx),
+ ExpressionPointer(std::move(ExpressionPointer)) {}
/// \returns a string containing the result of evaluating the expression in
/// this substitution, or an error if evaluation failed.
@@ -236,8 +426,6 @@ public:
// Pattern handling code.
//===----------------------------------------------------------------------===//
-struct FileCheckDiag;
-
/// Class holding the Pattern global state, shared by all patterns: tables
/// holding values of variables and whether they are defined or not at any
/// given time in the matching process.
@@ -270,6 +458,10 @@ private:
/// automatically free them once they are guaranteed to no longer be used.
std::vector<std::unique_ptr<NumericVariable>> NumericVariables;
+ /// Vector holding pointers to all parsed expressions. Used to automatically
+ /// free the expressions once they are guaranteed to no longer be used.
+ std::vector<std::unique_ptr<Expression>> Expressions;
+
/// Vector holding pointers to all substitutions. Used to automatically free
/// them once they are guaranteed to no longer be used.
std::vector<std::unique_ptr<Substitution>> Substitutions;
@@ -283,7 +475,7 @@ public:
/// command line, passed as a vector of [#]VAR=VAL strings in
/// \p CmdlineDefines. \returns an error list containing diagnostics against
/// \p SM for all definition parsing failures, if any, or Success otherwise.
- Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
+ Error defineCmdlineVariables(ArrayRef<StringRef> CmdlineDefines,
SourceMgr &SM);
/// Create @LINE pseudo variable. Value is set when pattern are being
@@ -307,10 +499,9 @@ private:
/// Makes a new numeric substitution and registers it for destruction when
/// the context is destroyed.
- Substitution *
- makeNumericSubstitution(StringRef ExpressionStr,
- std::unique_ptr<ExpressionAST> ExpressionAST,
- size_t InsertIdx);
+ Substitution *makeNumericSubstitution(StringRef ExpressionStr,
+ std::unique_ptr<Expression> Expression,
+ size_t InsertIdx);
};
/// Class to represent an error holding a diagnostic with location information
@@ -388,12 +579,12 @@ class Pattern {
std::map<StringRef, unsigned> VariableDefs;
/// Structure representing the definition of a numeric variable in a pattern.
- /// It holds the pointer to the class representing the numeric variable whose
- /// value is being defined and the number of the parenthesis group in
- /// RegExStr to capture that value.
+ /// It holds the pointer to the class instance holding the value and matching
+ /// format of the numeric variable whose value is being defined and the
+ /// number of the parenthesis group in RegExStr to capture that value.
struct NumericVariableMatch {
- /// Pointer to class representing the numeric variable whose value is being
- /// defined.
+ /// Pointer to class instance holding the value and matching format of the
+ /// numeric variable being defined.
NumericVariable *DefinedNumericVariable;
/// Number of the parenthesis group in RegExStr that captures the value of
@@ -457,12 +648,12 @@ public:
/// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE
/// expression and \p Context points to the class instance holding the live
/// string and numeric variables. \returns a pointer to the class instance
- /// representing the AST of the expression whose value must be substitued, or
- /// an error holding a diagnostic against \p SM if parsing fails. If
- /// substitution was successful, sets \p DefinedNumericVariable to point to
- /// the class representing the numeric variable defined in this numeric
- /// substitution block, or None if this block does not define any variable.
- static Expected<std::unique_ptr<ExpressionAST>> parseNumericSubstitutionBlock(
+ /// representing the expression whose value must be substitued, or an error
+ /// holding a diagnostic against \p SM if parsing fails. If substitution was
+ /// successful, sets \p DefinedNumericVariable to point to the class
+ /// representing the numeric variable defined in this numeric substitution
+ /// block, or None if this block does not define any variable.
+ static Expected<std::unique_ptr<Expression>> parseNumericSubstitutionBlock(
StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable,
bool IsLegacyLineExpr, Optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM);
@@ -526,7 +717,8 @@ private:
/// should defining such a variable be invalid.
static Expected<NumericVariable *> parseNumericVariableDefinition(
StringRef &Expr, FileCheckPatternContext *Context,
- Optional<size_t> LineNumber, const SourceMgr &SM);
+ Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat,
+ const SourceMgr &SM);
/// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use
/// at line \p LineNumber, or before input is parsed if \p LineNumber is
/// None. Parameter \p Context points to the class instance holding the live
@@ -536,29 +728,56 @@ private:
static Expected<std::unique_ptr<NumericVariableUse>> parseNumericVariableUse(
StringRef Name, bool IsPseudo, Optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM);
- enum class AllowedOperand { LineVar, Literal, Any };
+ enum class AllowedOperand { LineVar, LegacyLiteral, Any };
/// Parses \p Expr for use of a numeric operand at line \p LineNumber, or
- /// before input is parsed if \p LineNumber is None. Accepts both literal
- /// values and numeric variables, depending on the value of \p AO. Parameter
- /// \p Context points to the class instance holding the live string and
- /// numeric variables. \returns the class representing that operand in the
- /// AST of the expression or an error holding a diagnostic against \p SM
- /// otherwise.
+ /// before input is parsed if \p LineNumber is None. Accepts literal values,
+ /// numeric variables and function calls, depending on the value of \p AO.
+ /// \p MaybeInvalidConstraint indicates whether the text being parsed could
+ /// be an invalid constraint. \p Context points to the class instance holding
+ /// the live string and numeric variables. \returns the class representing
+ /// that operand in the AST of the expression or an error holding a
+ /// diagnostic against \p SM otherwise. If \p Expr starts with a "(" this
+ /// function will attempt to parse a parenthesized expression.
static Expected<std::unique_ptr<ExpressionAST>>
- parseNumericOperand(StringRef &Expr, AllowedOperand AO,
+ parseNumericOperand(StringRef &Expr, AllowedOperand AO, bool ConstraintParsed,
Optional<size_t> LineNumber,
FileCheckPatternContext *Context, const SourceMgr &SM);
- /// Parses \p Expr for a binary operation at line \p LineNumber, or before
- /// input is parsed if \p LineNumber is None. The left operand of this binary
- /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether
- /// we are parsing a legacy @LINE expression. Parameter \p Context points to
- /// the class instance holding the live string and numeric variables.
- /// \returns the class representing the binary operation in the AST of the
- /// expression, or an error holding a diagnostic against \p SM otherwise.
+ /// Parses and updates \p RemainingExpr for a binary operation at line
+ /// \p LineNumber, or before input is parsed if \p LineNumber is None. The
+ /// left operand of this binary operation is given in \p LeftOp and \p Expr
+ /// holds the string for the full expression, including the left operand.
+ /// Parameter \p IsLegacyLineExpr indicates whether we are parsing a legacy
+ /// @LINE expression. Parameter \p Context points to the class instance
+ /// holding the live string and numeric variables. \returns the class
+ /// representing the binary operation in the AST of the expression, or an
+ /// error holding a diagnostic against \p SM otherwise.
+ static Expected<std::unique_ptr<ExpressionAST>>
+ parseBinop(StringRef Expr, StringRef &RemainingExpr,
+ std::unique_ptr<ExpressionAST> LeftOp, bool IsLegacyLineExpr,
+ Optional<size_t> LineNumber, FileCheckPatternContext *Context,
+ const SourceMgr &SM);
+
+ /// Parses a parenthesized expression inside \p Expr at line \p LineNumber, or
+ /// before input is parsed if \p LineNumber is None. \p Expr must start with
+ /// a '('. Accepts both literal values and numeric variables. Parameter \p
+ /// Context points to the class instance holding the live string and numeric
+ /// variables. \returns the class representing that operand in the AST of the
+ /// expression or an error holding a diagnostic against \p SM otherwise.
+ static Expected<std::unique_ptr<ExpressionAST>>
+ parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber,
+ FileCheckPatternContext *Context, const SourceMgr &SM);
+
+ /// Parses \p Expr for an argument list belonging to a call to function \p
+ /// FuncName at line \p LineNumber, or before input is parsed if \p LineNumber
+ /// is None. Parameter \p FuncLoc is the source location used for diagnostics.
+ /// Parameter \p Context points to the class instance holding the live string
+ /// and numeric variables. \returns the class representing that call in the
+ /// AST of the expression or an error holding a diagnostic against \p SM
+ /// otherwise.
static Expected<std::unique_ptr<ExpressionAST>>
- parseBinop(StringRef &Expr, std::unique_ptr<ExpressionAST> LeftOp,
- bool IsLegacyLineExpr, Optional<size_t> LineNumber,
- FileCheckPatternContext *Context, const SourceMgr &SM);
+ parseCallExpr(StringRef &Expr, StringRef FuncName,
+ Optional<size_t> LineNumber, FileCheckPatternContext *Context,
+ const SourceMgr &SM);
};
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Support/FileCollector.cpp b/llvm/lib/Support/FileCollector.cpp
index 47fca64137223..59755556a5a3a 100644
--- a/llvm/lib/Support/FileCollector.cpp
+++ b/llvm/lib/Support/FileCollector.cpp
@@ -8,6 +8,7 @@
#include "llvm/Support/FileCollector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -34,7 +35,6 @@ static bool isCaseSensitivePath(StringRef Path) {
FileCollector::FileCollector(std::string Root, std::string OverlayRoot)
: Root(std::move(Root)), OverlayRoot(std::move(OverlayRoot)) {
- sys::fs::create_directories(this->Root, true);
}
bool FileCollector::getRealPath(StringRef SrcPath,
@@ -51,7 +51,7 @@ bool FileCollector::getRealPath(StringRef SrcPath,
auto EC = sys::fs::real_path(Directory, RealPath);
if (EC)
return false;
- SymlinkMap[Directory] = RealPath.str();
+ SymlinkMap[Directory] = std::string(RealPath.str());
} else {
RealPath = DirWithSymlink->second;
}
@@ -61,13 +61,19 @@ bool FileCollector::getRealPath(StringRef SrcPath,
return true;
}
-void FileCollector::addFile(const Twine &file) {
+void FileCollector::addFile(const Twine &File) {
std::lock_guard<std::mutex> lock(Mutex);
- std::string FileStr = file.str();
+ std::string FileStr = File.str();
if (markAsSeen(FileStr))
addFileImpl(FileStr);
}
+void FileCollector::addDirectory(const Twine &Dir) {
+ assert(sys::fs::is_directory(Dir));
+ std::error_code EC;
+ addDirectoryImpl(Dir, vfs::getRealFileSystem(), EC);
+}
+
void FileCollector::addFileImpl(StringRef SrcPath) {
// We need an absolute src path to append to the root.
SmallString<256> AbsoluteSrc = SrcPath;
@@ -101,6 +107,27 @@ void FileCollector::addFileImpl(StringRef SrcPath) {
addFileToMapping(VirtualPath, DstPath);
}
+llvm::vfs::directory_iterator
+FileCollector::addDirectoryImpl(const llvm::Twine &Dir,
+ IntrusiveRefCntPtr<vfs::FileSystem> FS,
+ std::error_code &EC) {
+ auto It = FS->dir_begin(Dir, EC);
+ if (EC)
+ return It;
+ addFile(Dir);
+ for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {
+ if (It->type() == sys::fs::file_type::regular_file ||
+ It->type() == sys::fs::file_type::directory_file ||
+ It->type() == sys::fs::file_type::symlink_file) {
+ addFile(It->path());
+ }
+ }
+ if (EC)
+ return It;
+ // Return a new iterator.
+ return FS->dir_begin(Dir, EC);
+}
+
/// Set the access and modification time for the given file from the given
/// status object.
static std::error_code
@@ -123,6 +150,13 @@ copyAccessAndModificationTime(StringRef Filename,
}
std::error_code FileCollector::copyFiles(bool StopOnError) {
+ auto Err = sys::fs::create_directories(Root, /*IgnoreExisting=*/true);
+ if (Err) {
+ return Err;
+ }
+
+ std::lock_guard<std::mutex> lock(Mutex);
+
for (auto &entry : VFSWriter.getMappings()) {
// Create directory tree.
if (std::error_code EC =
@@ -171,7 +205,7 @@ std::error_code FileCollector::copyFiles(bool StopOnError) {
return {};
}
-std::error_code FileCollector::writeMapping(StringRef mapping_file) {
+std::error_code FileCollector::writeMapping(StringRef MappingFile) {
std::lock_guard<std::mutex> lock(Mutex);
VFSWriter.setOverlayDir(OverlayRoot);
@@ -179,7 +213,7 @@ std::error_code FileCollector::writeMapping(StringRef mapping_file) {
VFSWriter.setUseExternalNames(false);
std::error_code EC;
- raw_fd_ostream os(mapping_file, EC, sys::fs::OF_Text);
+ raw_fd_ostream os(MappingFile, EC, sys::fs::OF_Text);
if (EC)
return EC;
@@ -188,7 +222,7 @@ std::error_code FileCollector::writeMapping(StringRef mapping_file) {
return {};
}
-namespace {
+namespace llvm {
class FileCollectorFileSystem : public vfs::FileSystem {
public:
@@ -213,22 +247,7 @@ public:
llvm::vfs::directory_iterator dir_begin(const llvm::Twine &Dir,
std::error_code &EC) override {
- auto It = FS->dir_begin(Dir, EC);
- if (EC)
- return It;
- // Collect everything that's listed in case the user needs it.
- Collector->addFile(Dir);
- for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {
- if (It->type() == sys::fs::file_type::regular_file ||
- It->type() == sys::fs::file_type::directory_file ||
- It->type() == sys::fs::file_type::symlink_file) {
- Collector->addFile(It->path());
- }
- }
- if (EC)
- return It;
- // Return a new iterator.
- return FS->dir_begin(Dir, EC);
+ return Collector->addDirectoryImpl(Dir, FS, EC);
}
std::error_code getRealPath(const Twine &Path,
@@ -259,7 +278,7 @@ private:
std::shared_ptr<FileCollector> Collector;
};
-} // end anonymous namespace
+} // namespace llvm
IntrusiveRefCntPtr<vfs::FileSystem>
FileCollector::createCollectorVFS(IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
diff --git a/llvm/lib/Support/FileOutputBuffer.cpp b/llvm/lib/Support/FileOutputBuffer.cpp
index 0a5306f684d4e..3342682270dcd 100644
--- a/llvm/lib/Support/FileOutputBuffer.cpp
+++ b/llvm/lib/Support/FileOutputBuffer.cpp
@@ -12,8 +12,8 @@
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
#include <system_error>
@@ -172,6 +172,10 @@ FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
if (Flags & F_executable)
Mode |= fs::all_exe;
+ // If Size is zero, don't use mmap which will fail with EINVAL.
+ if (Size == 0)
+ return createInMemoryBuffer(Path, Size, Mode);
+
fs::file_status Stat;
fs::status(Path, Stat);
diff --git a/llvm/lib/Support/FileUtilities.cpp b/llvm/lib/Support/FileUtilities.cpp
index d11fbb54dc0d8..e4a86bb69de4d 100644
--- a/llvm/lib/Support/FileUtilities.cpp
+++ b/llvm/lib/Support/FileUtilities.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/FileUtilities.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -92,9 +93,9 @@ static bool CompareNumbers(const char *&F1P, const char *&F2P,
// If one of the positions is at a space and the other isn't, chomp up 'til
// the end of the space.
- while (isspace(static_cast<unsigned char>(*F1P)) && F1P != F1End)
+ while (isSpace(static_cast<unsigned char>(*F1P)) && F1P != F1End)
++F1P;
- while (isspace(static_cast<unsigned char>(*F2P)) && F2P != F2End)
+ while (isSpace(static_cast<unsigned char>(*F2P)) && F2P != F2End)
++F2P;
// If we stop on numbers, compare their difference.
@@ -318,9 +319,8 @@ llvm::Error llvm::writeFileAtomically(
atomic_write_error::output_stream_error);
}
- if (const std::error_code Error =
- sys::fs::rename(/*from=*/GeneratedUniqPath.c_str(),
- /*to=*/FinalPath.str().c_str())) {
+ if (sys::fs::rename(/*from=*/GeneratedUniqPath.c_str(),
+ /*to=*/FinalPath.str().c_str())) {
return llvm::make_error<AtomicFileWriteError>(
atomic_write_error::failed_to_rename_temp_file);
}
diff --git a/llvm/lib/Support/FoldingSet.cpp b/llvm/lib/Support/FoldingSet.cpp
index ce6f196e1060f..e3d7168305af5 100644
--- a/llvm/lib/Support/FoldingSet.cpp
+++ b/llvm/lib/Support/FoldingSet.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
@@ -85,6 +86,10 @@ void FoldingSetNodeID::AddInteger(unsigned long long I) {
void FoldingSetNodeID::AddString(StringRef String) {
unsigned Size = String.size();
+
+ unsigned NumInserts = 1 + divideCeil(Size, 4);
+ Bits.reserve(Bits.size() + NumInserts);
+
Bits.push_back(Size);
if (!Size) return;
@@ -223,8 +228,6 @@ static void **AllocateBuckets(unsigned NumBuckets) {
//===----------------------------------------------------------------------===//
// FoldingSetBase Implementation
-void FoldingSetBase::anchor() {}
-
FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) {
assert(5 < Log2InitSize && Log2InitSize < 32 &&
"Initial hash table size out of range");
@@ -266,8 +269,10 @@ void FoldingSetBase::clear() {
NumNodes = 0;
}
-void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) {
- assert((NewBucketCount > NumBuckets) && "Can't shrink a folding set with GrowBucketCount");
+void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount,
+ const FoldingSetInfo &Info) {
+ assert((NewBucketCount > NumBuckets) &&
+ "Can't shrink a folding set with GrowBucketCount");
assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!");
void **OldBuckets = Buckets;
unsigned OldNumBuckets = NumBuckets;
@@ -290,8 +295,9 @@ void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) {
// Insert the node into the new bucket, after recomputing the hash.
InsertNode(NodeInBucket,
- GetBucketFor(ComputeNodeHash(NodeInBucket, TempID),
- Buckets, NumBuckets));
+ GetBucketFor(Info.ComputeNodeHash(this, NodeInBucket, TempID),
+ Buckets, NumBuckets),
+ Info);
TempID.clear();
}
}
@@ -301,25 +307,24 @@ void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) {
/// GrowHashTable - Double the size of the hash table and rehash everything.
///
-void FoldingSetBase::GrowHashTable() {
- GrowBucketCount(NumBuckets * 2);
+void FoldingSetBase::GrowHashTable(const FoldingSetInfo &Info) {
+ GrowBucketCount(NumBuckets * 2, Info);
}
-void FoldingSetBase::reserve(unsigned EltCount) {
+void FoldingSetBase::reserve(unsigned EltCount, const FoldingSetInfo &Info) {
// This will give us somewhere between EltCount / 2 and
// EltCount buckets. This puts us in the load factor
// range of 1.0 - 2.0.
if(EltCount < capacity())
return;
- GrowBucketCount(PowerOf2Floor(EltCount));
+ GrowBucketCount(PowerOf2Floor(EltCount), Info);
}
/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
/// return it. If not, return the insertion token that will make insertion
/// faster.
-FoldingSetBase::Node *
-FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID,
- void *&InsertPos) {
+FoldingSetBase::Node *FoldingSetBase::FindNodeOrInsertPos(
+ const FoldingSetNodeID &ID, void *&InsertPos, const FoldingSetInfo &Info) {
unsigned IDHash = ID.ComputeHash();
void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets);
void *Probe = *Bucket;
@@ -328,7 +333,7 @@ FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID,
FoldingSetNodeID TempID;
while (Node *NodeInBucket = GetNextPtr(Probe)) {
- if (NodeEquals(NodeInBucket, ID, IDHash, TempID))
+ if (Info.NodeEquals(this, NodeInBucket, ID, IDHash, TempID))
return NodeInBucket;
TempID.clear();
@@ -343,13 +348,15 @@ FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID,
/// InsertNode - Insert the specified node into the folding set, knowing that it
/// is not already in the map. InsertPos must be obtained from
/// FindNodeOrInsertPos.
-void FoldingSetBase::InsertNode(Node *N, void *InsertPos) {
+void FoldingSetBase::InsertNode(Node *N, void *InsertPos,
+ const FoldingSetInfo &Info) {
assert(!N->getNextInBucket());
// Do we need to grow the hashtable?
if (NumNodes+1 > capacity()) {
- GrowHashTable();
+ GrowHashTable(Info);
FoldingSetNodeID TempID;
- InsertPos = GetBucketFor(ComputeNodeHash(N, TempID), Buckets, NumBuckets);
+ InsertPos = GetBucketFor(Info.ComputeNodeHash(this, N, TempID), Buckets,
+ NumBuckets);
}
++NumNodes;
@@ -413,13 +420,15 @@ bool FoldingSetBase::RemoveNode(Node *N) {
/// GetOrInsertNode - If there is an existing simple Node exactly
/// equal to the specified node, return it. Otherwise, insert 'N' and it
/// instead.
-FoldingSetBase::Node *FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N) {
+FoldingSetBase::Node *
+FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N,
+ const FoldingSetInfo &Info) {
FoldingSetNodeID ID;
- GetNodeProfile(N, ID);
+ Info.GetNodeProfile(this, N, ID);
void *IP;
- if (Node *E = FindNodeOrInsertPos(ID, IP))
+ if (Node *E = FindNodeOrInsertPos(ID, IP, Info))
return E;
- InsertNode(N, IP);
+ InsertNode(N, IP, Info);
return N;
}
diff --git a/llvm/lib/Support/FormatVariadic.cpp b/llvm/lib/Support/FormatVariadic.cpp
index f9e89f69b528c..632e879e540dd 100644
--- a/llvm/lib/Support/FormatVariadic.cpp
+++ b/llvm/lib/Support/FormatVariadic.cpp
@@ -6,6 +6,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/FormatVariadic.h"
+#include <cassert>
using namespace llvm;
@@ -140,9 +141,9 @@ formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) {
return std::make_pair(ReplacementItem{Fmt}, StringRef());
}
-std::vector<ReplacementItem>
+SmallVector<ReplacementItem, 2>
formatv_object_base::parseFormatString(StringRef Fmt) {
- std::vector<ReplacementItem> Replacements;
+ SmallVector<ReplacementItem, 2> Replacements;
ReplacementItem I;
while (!Fmt.empty()) {
std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt);
diff --git a/llvm/lib/Support/FormattedStream.cpp b/llvm/lib/Support/FormattedStream.cpp
index 4eb747038bb9e..5716afc187e48 100644
--- a/llvm/lib/Support/FormattedStream.cpp
+++ b/llvm/lib/Support/FormattedStream.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Unicode.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -19,16 +21,22 @@ using namespace llvm;
/// UpdatePosition - Examine the given char sequence and figure out which
/// column we end up in after output, and how many line breaks are contained.
-///
-static void UpdatePosition(std::pair<unsigned, unsigned> &Position, const char *Ptr, size_t Size) {
+/// This assumes that the input string is well-formed UTF-8, and takes into
+/// account Unicode characters which render as multiple columns wide.
+void formatted_raw_ostream::UpdatePosition(const char *Ptr, size_t Size) {
unsigned &Column = Position.first;
unsigned &Line = Position.second;
- // Keep track of the current column and line by scanning the string for
- // special characters
- for (const char *End = Ptr + Size; Ptr != End; ++Ptr) {
- ++Column;
- switch (*Ptr) {
+ auto ProcessUTF8CodePoint = [&Line, &Column](StringRef CP) {
+ int Width = sys::unicode::columnWidthUTF8(CP);
+ if (Width != sys::unicode::ErrorNonPrintableCharacter)
+ Column += Width;
+
+ // The only special whitespace characters we care about are single-byte.
+ if (CP.size() > 1)
+ return;
+
+ switch (CP[0]) {
case '\n':
Line += 1;
LLVM_FALLTHROUGH;
@@ -40,6 +48,46 @@ static void UpdatePosition(std::pair<unsigned, unsigned> &Position, const char *
Column += (8 - (Column & 0x7)) & 0x7;
break;
}
+ };
+
+ // If we have a partial UTF-8 sequence from the previous buffer, check that
+ // first.
+ if (PartialUTF8Char.size()) {
+ size_t BytesFromBuffer =
+ getNumBytesForUTF8(PartialUTF8Char[0]) - PartialUTF8Char.size();
+ if (Size < BytesFromBuffer) {
+ // If we still don't have enough bytes for a complete code point, just
+ // append what we have.
+ PartialUTF8Char.append(StringRef(Ptr, Size));
+ return;
+ } else {
+ // The first few bytes from the buffer will complete the code point.
+ // Concatenate them and process their effect on the line and column
+ // numbers.
+ PartialUTF8Char.append(StringRef(Ptr, BytesFromBuffer));
+ ProcessUTF8CodePoint(PartialUTF8Char);
+ PartialUTF8Char.clear();
+ Ptr += BytesFromBuffer;
+ Size -= BytesFromBuffer;
+ }
+ }
+
+ // Now scan the rest of the buffer.
+ unsigned NumBytes;
+ for (const char *End = Ptr + Size; Ptr < End; Ptr += NumBytes) {
+ NumBytes = getNumBytesForUTF8(*Ptr);
+
+ // The buffer might end part way through a UTF-8 code unit sequence for a
+ // Unicode scalar value if it got flushed. If this happens, we can't know
+ // the display width until we see the rest of the code point. Stash the
+ // bytes we do have, so that we can reconstruct the whole code point later,
+ // even if the buffer is being flushed.
+ if ((unsigned)(End - Ptr) < NumBytes) {
+ PartialUTF8Char = StringRef(Ptr, End - Ptr);
+ return;
+ }
+
+ ProcessUTF8CodePoint(StringRef(Ptr, NumBytes));
}
}
@@ -52,9 +100,9 @@ void formatted_raw_ostream::ComputePosition(const char *Ptr, size_t Size) {
if (Ptr <= Scanned && Scanned <= Ptr + Size)
// Scan all characters added since our last scan to determine the new
// column.
- UpdatePosition(Position, Scanned, Size - (Scanned - Ptr));
+ UpdatePosition(Scanned, Size - (Scanned - Ptr));
else
- UpdatePosition(Position, Ptr, Size);
+ UpdatePosition(Ptr, Size);
// Update the scanning pointer.
Scanned = Ptr + Size;
diff --git a/llvm/lib/Support/GraphWriter.cpp b/llvm/lib/Support/GraphWriter.cpp
index c689a81925d4c..d8aae92603231 100644
--- a/llvm/lib/Support/GraphWriter.cpp
+++ b/llvm/lib/Support/GraphWriter.cpp
@@ -76,17 +76,42 @@ StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
return Colors[ColorNumber % NumColors];
}
+static std::string replaceIllegalFilenameChars(std::string Filename,
+ const char ReplacementChar) {
+#ifdef _WIN32
+ std::string IllegalChars = "\\/:?\"<>|";
+#else
+ std::string IllegalChars = "/";
+#endif
+
+ for (char IllegalChar : IllegalChars) {
+ std::replace(Filename.begin(), Filename.end(), IllegalChar,
+ ReplacementChar);
+ }
+
+ return Filename;
+}
+
std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
FD = -1;
SmallString<128> Filename;
- std::error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename);
+
+ // Windows can't always handle long paths, so limit the length of the name.
+ std::string N = Name.str();
+ N = N.substr(0, std::min<std::size_t>(N.size(), 140));
+
+ // Replace illegal characters in graph Filename with '_' if needed
+ std::string CleansedName = replaceIllegalFilenameChars(N, '_');
+
+ std::error_code EC =
+ sys::fs::createTemporaryFile(CleansedName, "dot", FD, Filename);
if (EC) {
errs() << "Error: " << EC.message() << "\n";
return "";
}
errs() << "Writing '" << Filename << "'... ";
- return Filename.str();
+ return std::string(Filename.str());
}
// Execute the graph viewer. Return true if there were errors.
@@ -147,7 +172,7 @@ static const char *getProgramName(GraphProgram::Name program) {
bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
GraphProgram::Name program) {
- std::string Filename = FilenameRef;
+ std::string Filename = std::string(FilenameRef);
std::string ErrMsg;
std::string ViewerPath;
GraphSession S;
diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp
index ef38c1c09413a..658c1ee74cfec 100644
--- a/llvm/lib/Support/Host.cpp
+++ b/llvm/lib/Support/Host.cpp
@@ -11,9 +11,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Host.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -21,6 +21,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/X86TargetParser.h"
#include "llvm/Support/raw_ostream.h"
#include <assert.h>
#include <string.h>
@@ -28,6 +29,7 @@
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Host.inc"
+#include <sched.h>
#endif
#ifdef _WIN32
#include "Windows/Host.inc"
@@ -140,6 +142,7 @@ StringRef sys::detail::getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent) {
.Case("POWER8E", "pwr8")
.Case("POWER8NVL", "pwr8")
.Case("POWER9", "pwr9")
+ .Case("POWER10", "pwr10")
// FIXME: If we get a simulator or machine with the capabilities of
// mcpu=future, we should revisit this and add the name reported by the
// simulator/machine.
@@ -178,6 +181,8 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
// The CPU part is a 3 digit hexadecimal number with a 0x prefix. The
// values correspond to the "Part number" in the CP15/c0 register. The
// contents are specified in the various processor manuals.
+ // This corresponds to the Main ID Register in Technical Reference Manuals.
+ // and is used in programs like sys-utils
return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
.Case("0x926", "arm926ej-s")
.Case("0xb02", "mpcore")
@@ -190,6 +195,8 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
.Case("0xc20", "cortex-m0")
.Case("0xc23", "cortex-m3")
.Case("0xc24", "cortex-m4")
+ .Case("0xd22", "cortex-m55")
+ .Case("0xd02", "cortex-a34")
.Case("0xd04", "cortex-a35")
.Case("0xd03", "cortex-a53")
.Case("0xd07", "cortex-a57")
@@ -197,6 +204,10 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
.Case("0xd09", "cortex-a73")
.Case("0xd0a", "cortex-a75")
.Case("0xd0b", "cortex-a76")
+ .Case("0xd0d", "cortex-a77")
+ .Case("0xd41", "cortex-a78")
+ .Case("0xd44", "cortex-x1")
+ .Case("0xd0c", "neoverse-n1")
.Default("generic");
}
@@ -215,6 +226,26 @@ StringRef sys::detail::getHostCPUNameForARM(StringRef ProcCpuinfoContent) {
}
}
+ if (Implementer == "0x46") { // Fujitsu Ltd.
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
+ if (Lines[I].startswith("CPU part")) {
+ return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
+ .Case("0x001", "a64fx")
+ .Default("generic");
+ }
+ }
+ }
+
+ if (Implementer == "0x4e") { // NVIDIA Corporation
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
+ if (Lines[I].startswith("CPU part")) {
+ return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :"))
+ .Case("0x004", "carmel")
+ .Default("generic");
+ }
+ }
+ }
+
if (Implementer == "0x48") // HiSilicon Technologies, Inc.
// Look for the CPU part line.
for (unsigned I = 0, E = Lines.size(); I != E; ++I)
@@ -552,58 +583,32 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
}
}
-static void
+static StringRef
getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
- unsigned Brand_id, unsigned Features,
- unsigned Features2, unsigned Features3,
+ const unsigned *Features,
unsigned *Type, unsigned *Subtype) {
- if (Brand_id != 0)
- return;
+ auto testFeature = [&](unsigned F) {
+ return (Features[F / 32] & (1U << (F % 32))) != 0;
+ };
+
+ StringRef CPU;
+
switch (Family) {
case 3:
- *Type = X86::INTEL_i386;
+ CPU = "i386";
break;
case 4:
- *Type = X86::INTEL_i486;
+ CPU = "i486";
break;
case 5:
- if (Features & (1 << X86::FEATURE_MMX)) {
- *Type = X86::INTEL_PENTIUM_MMX;
+ if (testFeature(X86::FEATURE_MMX)) {
+ CPU = "pentium-mmx";
break;
}
- *Type = X86::INTEL_PENTIUM;
+ CPU = "pentium";
break;
case 6:
switch (Model) {
- case 0x01: // Pentium Pro processor
- *Type = X86::INTEL_PENTIUM_PRO;
- break;
- case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor,
- // model 03
- case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor,
- // model 05, and Intel Celeron processor, model 05
- case 0x06: // Celeron processor, model 06
- *Type = X86::INTEL_PENTIUM_II;
- break;
- case 0x07: // Pentium III processor, model 07, and Pentium III Xeon
- // processor, model 07
- case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor,
- // model 08, and Celeron processor, model 08
- case 0x0a: // Pentium III Xeon processor, model 0Ah
- case 0x0b: // Pentium III processor, model 0Bh
- *Type = X86::INTEL_PENTIUM_III;
- break;
- case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09.
- case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model
- // 0Dh. All processors are manufactured using the 90 nm process.
- case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579
- // Integrated Processor with Intel QuickAssist Technology
- *Type = X86::INTEL_PENTIUM_M;
- break;
- case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model
- // 0Eh. All processors are manufactured using the 65 nm process.
- *Type = X86::INTEL_CORE_DUO;
- break; // yonah
case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
// processor, Intel Core 2 Quad processor, Intel Core 2 Quad
// mobile processor, Intel Core 2 Extreme processor, Intel
@@ -611,8 +616,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
// 0Fh. All processors are manufactured using the 65 nm process.
case 0x16: // Intel Celeron processor model 16h. All processors are
// manufactured using the 65 nm process
- *Type = X86::INTEL_CORE2; // "core2"
- *Subtype = X86::INTEL_CORE2_65;
+ CPU = "core2";
+ *Type = X86::INTEL_CORE2;
break;
case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
// 17h. All processors are manufactured using the 45 nm process.
@@ -620,34 +625,38 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
// 45nm: Penryn , Wolfdale, Yorkfield (XE)
case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
// the 45 nm process.
- *Type = X86::INTEL_CORE2; // "penryn"
- *Subtype = X86::INTEL_CORE2_45;
+ CPU = "penryn";
+ *Type = X86::INTEL_CORE2;
break;
case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
// processors are manufactured using the 45 nm process.
case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz.
// As found in a Summer 2010 model iMac.
case 0x1f:
- case 0x2e: // Nehalem EX
- *Type = X86::INTEL_COREI7; // "nehalem"
+ case 0x2e: // Nehalem EX
+ CPU = "nehalem";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_NEHALEM;
break;
case 0x25: // Intel Core i7, laptop version.
case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
// processors are manufactured using the 32 nm process.
case 0x2f: // Westmere EX
- *Type = X86::INTEL_COREI7; // "westmere"
+ CPU = "westmere";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_WESTMERE;
break;
case 0x2a: // Intel Core i7 processor. All processors are manufactured
// using the 32 nm process.
case 0x2d:
- *Type = X86::INTEL_COREI7; //"sandybridge"
+ CPU = "sandybridge";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_SANDYBRIDGE;
break;
case 0x3a:
- case 0x3e: // Ivy Bridge EP
- *Type = X86::INTEL_COREI7; // "ivybridge"
+ case 0x3e: // Ivy Bridge EP
+ CPU = "ivybridge";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_IVYBRIDGE;
break;
@@ -656,7 +665,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
case 0x3f:
case 0x45:
case 0x46:
- *Type = X86::INTEL_COREI7; // "haswell"
+ CPU = "haswell";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_HASWELL;
break;
@@ -665,7 +675,8 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
case 0x47:
case 0x4f:
case 0x56:
- *Type = X86::INTEL_COREI7; // "broadwell"
+ CPU = "broadwell";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_BROADWELL;
break;
@@ -674,39 +685,49 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
case 0x5e: // Skylake desktop
case 0x8e: // Kaby Lake mobile
case 0x9e: // Kaby Lake desktop
- *Type = X86::INTEL_COREI7; // "skylake"
+ case 0xa5: // Comet Lake-H/S
+ case 0xa6: // Comet Lake-U
+ CPU = "skylake";
+ *Type = X86::INTEL_COREI7;
*Subtype = X86::INTEL_COREI7_SKYLAKE;
break;
// Skylake Xeon:
case 0x55:
*Type = X86::INTEL_COREI7;
- if (Features2 & (1 << (X86::FEATURE_AVX512BF16 - 32)))
- *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"
+ if (testFeature(X86::FEATURE_AVX512BF16)) {
+ CPU = "cooperlake";
+ *Subtype = X86::INTEL_COREI7_COOPERLAKE;
+ } else if (testFeature(X86::FEATURE_AVX512VNNI)) {
+ CPU = "cascadelake";
+ *Subtype = X86::INTEL_COREI7_CASCADELAKE;
+ } else {
+ CPU = "skylake-avx512";
+ *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512;
+ }
break;
// Cannonlake:
case 0x66:
+ CPU = "cannonlake";
*Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_CANNONLAKE; // "cannonlake"
+ *Subtype = X86::INTEL_COREI7_CANNONLAKE;
break;
// Icelake:
case 0x7d:
case 0x7e:
+ CPU = "icelake-client";
*Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT; // "icelake-client"
+ *Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT;
break;
// Icelake Xeon:
case 0x6a:
case 0x6c:
+ CPU = "icelake-server";
*Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_ICELAKE_SERVER; // "icelake-server"
+ *Subtype = X86::INTEL_COREI7_ICELAKE_SERVER;
break;
case 0x1c: // Most 45 nm Intel Atom processors
@@ -714,8 +735,9 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
case 0x27: // 32 nm Atom Medfield
case 0x35: // 32 nm Atom Midview
case 0x36: // 32 nm Atom Midview
+ CPU = "bonnell";
*Type = X86::INTEL_BONNELL;
- break; // "bonnell"
+ break;
// Atom Silvermont codes from the Intel software optimization guide.
case 0x37:
@@ -724,14 +746,17 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
case 0x5a:
case 0x5d:
case 0x4c: // really airmont
+ CPU = "silvermont";
*Type = X86::INTEL_SILVERMONT;
- break; // "silvermont"
+ break;
// Goldmont:
case 0x5c: // Apollo Lake
case 0x5f: // Denverton
+ CPU = "goldmont";
*Type = X86::INTEL_GOLDMONT;
- break; // "goldmont"
+ break;
case 0x7a:
+ CPU = "goldmont-plus";
*Type = X86::INTEL_GOLDMONT_PLUS;
break;
case 0x86:
@@ -739,189 +764,140 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
break;
case 0x57:
- *Type = X86::INTEL_KNL; // knl
+ CPU = "tremont";
+ *Type = X86::INTEL_KNL;
break;
case 0x85:
- *Type = X86::INTEL_KNM; // knm
+ CPU = "knm";
+ *Type = X86::INTEL_KNM;
break;
default: // Unknown family 6 CPU, try to guess.
- // TODO detect tigerlake host
- if (Features3 & (1 << (X86::FEATURE_AVX512VP2INTERSECT - 64))) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_TIGERLAKE;
- break;
- }
-
- if (Features & (1 << X86::FEATURE_AVX512VBMI2)) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_ICELAKE_CLIENT;
- break;
- }
-
- if (Features & (1 << X86::FEATURE_AVX512VBMI)) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_CANNONLAKE;
- break;
- }
-
- if (Features2 & (1 << (X86::FEATURE_AVX512BF16 - 32))) {
- *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;
- break;
+ // Don't both with Type/Subtype here, they aren't used by the caller.
+ // They're used above to keep the code in sync with compiler-rt.
+ // TODO detect tigerlake host from model
+ if (testFeature(X86::FEATURE_AVX512VP2INTERSECT)) {
+ CPU = "tigerlake";
+ } else if (testFeature(X86::FEATURE_AVX512VBMI2)) {
+ CPU = "icelake-client";
+ } else if (testFeature(X86::FEATURE_AVX512VBMI)) {
+ CPU = "cannonlake";
+ } else if (testFeature(X86::FEATURE_AVX512BF16)) {
+ CPU = "cooperlake";
+ } else if (testFeature(X86::FEATURE_AVX512VNNI)) {
+ CPU = "cascadelake";
+ } else if (testFeature(X86::FEATURE_AVX512VL)) {
+ CPU = "skylake-avx512";
+ } else if (testFeature(X86::FEATURE_AVX512ER)) {
+ CPU = "knl";
+ } else if (testFeature(X86::FEATURE_CLFLUSHOPT)) {
+ if (testFeature(X86::FEATURE_SHA))
+ CPU = "goldmont";
+ else
+ CPU = "skylake";
+ } else if (testFeature(X86::FEATURE_ADX)) {
+ CPU = "broadwell";
+ } else if (testFeature(X86::FEATURE_AVX2)) {
+ CPU = "haswell";
+ } else if (testFeature(X86::FEATURE_AVX)) {
+ CPU = "sandybridge";
+ } else if (testFeature(X86::FEATURE_SSE4_2)) {
+ if (testFeature(X86::FEATURE_MOVBE))
+ CPU = "silvermont";
+ else
+ CPU = "nehalem";
+ } else if (testFeature(X86::FEATURE_SSE4_1)) {
+ CPU = "penryn";
+ } else if (testFeature(X86::FEATURE_SSSE3)) {
+ if (testFeature(X86::FEATURE_MOVBE))
+ CPU = "bonnell";
+ else
+ CPU = "core2";
+ } else if (testFeature(X86::FEATURE_64BIT)) {
+ CPU = "core2";
+ } else if (testFeature(X86::FEATURE_SSE3)) {
+ CPU = "yonah";
+ } else if (testFeature(X86::FEATURE_SSE2)) {
+ CPU = "pentium-m";
+ } else if (testFeature(X86::FEATURE_SSE)) {
+ CPU = "pentium3";
+ } else if (testFeature(X86::FEATURE_MMX)) {
+ CPU = "pentium2";
+ } else {
+ CPU = "pentiumpro";
}
-
- if (Features & (1 << X86::FEATURE_AVX512VL)) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_SKYLAKE_AVX512;
- break;
- }
-
- if (Features & (1 << X86::FEATURE_AVX512ER)) {
- *Type = X86::INTEL_KNL; // knl
- break;
- }
-
- if (Features3 & (1 << (X86::FEATURE_CLFLUSHOPT - 64))) {
- if (Features3 & (1 << (X86::FEATURE_SHA - 64))) {
- *Type = X86::INTEL_GOLDMONT;
- } else {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_SKYLAKE;
- }
- break;
- }
- if (Features3 & (1 << (X86::FEATURE_ADX - 64))) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_BROADWELL;
- break;
- }
- if (Features & (1 << X86::FEATURE_AVX2)) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_HASWELL;
- break;
- }
- if (Features & (1 << X86::FEATURE_AVX)) {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_SANDYBRIDGE;
- break;
- }
- if (Features & (1 << X86::FEATURE_SSE4_2)) {
- if (Features3 & (1 << (X86::FEATURE_MOVBE - 64))) {
- *Type = X86::INTEL_SILVERMONT;
- } else {
- *Type = X86::INTEL_COREI7;
- *Subtype = X86::INTEL_COREI7_NEHALEM;
- }
- break;
- }
- if (Features & (1 << X86::FEATURE_SSE4_1)) {
- *Type = X86::INTEL_CORE2; // "penryn"
- *Subtype = X86::INTEL_CORE2_45;
- break;
- }
- if (Features & (1 << X86::FEATURE_SSSE3)) {
- if (Features3 & (1 << (X86::FEATURE_MOVBE - 64))) {
- *Type = X86::INTEL_BONNELL; // "bonnell"
- } else {
- *Type = X86::INTEL_CORE2; // "core2"
- *Subtype = X86::INTEL_CORE2_65;
- }
- break;
- }
- if (Features3 & (1 << (X86::FEATURE_EM64T - 64))) {
- *Type = X86::INTEL_CORE2; // "core2"
- *Subtype = X86::INTEL_CORE2_65;
- break;
- }
- if (Features & (1 << X86::FEATURE_SSE3)) {
- *Type = X86::INTEL_CORE_DUO;
- break;
- }
- if (Features & (1 << X86::FEATURE_SSE2)) {
- *Type = X86::INTEL_PENTIUM_M;
- break;
- }
- if (Features & (1 << X86::FEATURE_SSE)) {
- *Type = X86::INTEL_PENTIUM_III;
- break;
- }
- if (Features & (1 << X86::FEATURE_MMX)) {
- *Type = X86::INTEL_PENTIUM_II;
- break;
- }
- *Type = X86::INTEL_PENTIUM_PRO;
break;
}
break;
case 15: {
- if (Features3 & (1 << (X86::FEATURE_EM64T - 64))) {
- *Type = X86::INTEL_NOCONA;
+ if (testFeature(X86::FEATURE_64BIT)) {
+ CPU = "nocona";
break;
}
- if (Features & (1 << X86::FEATURE_SSE3)) {
- *Type = X86::INTEL_PRESCOTT;
+ if (testFeature(X86::FEATURE_SSE3)) {
+ CPU = "prescott";
break;
}
- *Type = X86::INTEL_PENTIUM_IV;
+ CPU = "pentium4";
break;
}
default:
- break; /*"generic"*/
+ break; // Unknown.
}
+
+ return CPU;
}
-static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
- unsigned Features, unsigned *Type,
- unsigned *Subtype) {
- // FIXME: this poorly matches the generated SubtargetFeatureKV table. There
- // appears to be no way to generate the wide variety of AMD-specific targets
- // from the information returned from CPUID.
+static StringRef
+getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
+ const unsigned *Features,
+ unsigned *Type, unsigned *Subtype) {
+ auto testFeature = [&](unsigned F) {
+ return (Features[F / 32] & (1U << (F % 32))) != 0;
+ };
+
+ StringRef CPU;
+
switch (Family) {
case 4:
- *Type = X86::AMD_i486;
+ CPU = "i486";
break;
case 5:
- *Type = X86::AMDPENTIUM;
+ CPU = "pentium";
switch (Model) {
case 6:
case 7:
- *Subtype = X86::AMDPENTIUM_K6;
- break; // "k6"
+ CPU = "k6";
+ break;
case 8:
- *Subtype = X86::AMDPENTIUM_K62;
- break; // "k6-2"
+ CPU = "k6-2";
+ break;
case 9:
case 13:
- *Subtype = X86::AMDPENTIUM_K63;
- break; // "k6-3"
+ CPU = "k6-3";
+ break;
case 10:
- *Subtype = X86::AMDPENTIUM_GEODE;
- break; // "geode"
+ CPU = "geode";
+ break;
}
break;
case 6:
- if (Features & (1 << X86::FEATURE_SSE)) {
- *Type = X86::AMD_ATHLON_XP;
- break; // "athlon-xp"
+ if (testFeature(X86::FEATURE_SSE)) {
+ CPU = "athlon-xp";
+ break;
}
- *Type = X86::AMD_ATHLON;
- break; // "athlon"
+ CPU = "athlon";
+ break;
case 15:
- if (Features & (1 << X86::FEATURE_SSE3)) {
- *Type = X86::AMD_K8SSE3;
- break; // "k8-sse3"
+ if (testFeature(X86::FEATURE_SSE3)) {
+ CPU = "k8-sse3";
+ break;
}
- *Type = X86::AMD_K8;
- break; // "k8"
+ CPU = "k8";
+ break;
case 16:
+ CPU = "amdfam10";
*Type = X86::AMDFAM10H; // "amdfam10"
switch (Model) {
case 2:
@@ -936,63 +912,62 @@ static void getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
}
break;
case 20:
+ CPU = "btver1";
*Type = X86::AMD_BTVER1;
- break; // "btver1";
+ break;
case 21:
+ CPU = "bdver1";
*Type = X86::AMDFAM15H;
if (Model >= 0x60 && Model <= 0x7f) {
+ CPU = "bdver4";
*Subtype = X86::AMDFAM15H_BDVER4;
- break; // "bdver4"; 60h-7Fh: Excavator
+ break; // 60h-7Fh: Excavator
}
if (Model >= 0x30 && Model <= 0x3f) {
+ CPU = "bdver3";
*Subtype = X86::AMDFAM15H_BDVER3;
- break; // "bdver3"; 30h-3Fh: Steamroller
+ break; // 30h-3Fh: Steamroller
}
if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {
+ CPU = "bdver2";
*Subtype = X86::AMDFAM15H_BDVER2;
- break; // "bdver2"; 02h, 10h-1Fh: Piledriver
+ break; // 02h, 10h-1Fh: Piledriver
}
if (Model <= 0x0f) {
*Subtype = X86::AMDFAM15H_BDVER1;
- break; // "bdver1"; 00h-0Fh: Bulldozer
+ break; // 00h-0Fh: Bulldozer
}
break;
case 22:
+ CPU = "btver2";
*Type = X86::AMD_BTVER2;
- break; // "btver2"
+ break;
case 23:
+ CPU = "znver1";
*Type = X86::AMDFAM17H;
if ((Model >= 0x30 && Model <= 0x3f) || Model == 0x71) {
+ CPU = "znver2";
*Subtype = X86::AMDFAM17H_ZNVER2;
- break; // "znver2"; 30h-3fh, 71h: Zen2
+ break; // 30h-3fh, 71h: Zen2
}
if (Model <= 0x0f) {
*Subtype = X86::AMDFAM17H_ZNVER1;
- break; // "znver1"; 00h-0Fh: Zen1
+ break; // 00h-0Fh: Zen1
}
break;
default:
- break; // "generic"
+ break; // Unknown AMD CPU.
}
+
+ return CPU;
}
static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
- unsigned *FeaturesOut, unsigned *Features2Out,
- unsigned *Features3Out) {
- unsigned Features = 0;
- unsigned Features2 = 0;
- unsigned Features3 = 0;
+ unsigned *Features) {
unsigned EAX, EBX;
auto setFeature = [&](unsigned F) {
- if (F < 32)
- Features |= 1U << (F & 0x1f);
- else if (F < 64)
- Features2 |= 1U << ((F - 32) & 0x1f);
- else if (F < 96)
- Features3 |= 1U << ((F - 64) & 0x1f);
- else
- llvm_unreachable("Unexpected FeatureBit");
+ Features[F / 32] |= 1U << (F % 32);
};
if ((EDX >> 15) & 1)
@@ -1115,56 +1090,42 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
setFeature(X86::FEATURE_FMA4);
if (HasExtLeaf1 && ((EDX >> 29) & 1))
- setFeature(X86::FEATURE_EM64T);
-
- *FeaturesOut = Features;
- *Features2Out = Features2;
- *Features3Out = Features3;
+ setFeature(X86::FEATURE_64BIT);
}
StringRef sys::getHostCPUName() {
unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
unsigned MaxLeaf, Vendor;
-#if defined(__GNUC__) || defined(__clang__)
- //FIXME: include cpuid.h from clang or copy __get_cpuid_max here
- // and simplify it to not invoke __cpuid (like cpu_model.c in
- // compiler-rt/lib/builtins/cpu_model.c?
- // Opting for the second option.
- if(!isCpuIdSupported())
+ if (!isCpuIdSupported())
return "generic";
-#endif
+
if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1)
return "generic";
getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX);
- unsigned Brand_id = EBX & 0xff;
unsigned Family = 0, Model = 0;
- unsigned Features = 0, Features2 = 0, Features3 = 0;
+ unsigned Features[(X86::CPU_FEATURE_MAX + 31) / 32] = {0};
detectX86FamilyModel(EAX, &Family, &Model);
- getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2, &Features3);
+ getAvailableFeatures(ECX, EDX, MaxLeaf, Features);
+ // These aren't consumed in this file, but we try to keep some source code the
+ // same or similar to compiler-rt.
unsigned Type = 0;
unsigned Subtype = 0;
+ StringRef CPU;
+
if (Vendor == SIG_INTEL) {
- getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features,
- Features2, Features3, &Type, &Subtype);
+ CPU = getIntelProcessorTypeAndSubtype(Family, Model, Features, &Type,
+ &Subtype);
} else if (Vendor == SIG_AMD) {
- getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type, &Subtype);
+ CPU = getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type,
+ &Subtype);
}
- // Check subtypes first since those are more specific.
-#define X86_CPU_SUBTYPE(ARCHNAME, ENUM) \
- if (Subtype == X86::ENUM) \
- return ARCHNAME;
-#include "llvm/Support/X86TargetParser.def"
-
- // Now check types.
-#define X86_CPU_TYPE(ARCHNAME, ENUM) \
- if (Type == X86::ENUM) \
- return ARCHNAME;
-#include "llvm/Support/X86TargetParser.def"
+ if (!CPU.empty())
+ return CPU;
return "generic";
}
@@ -1255,18 +1216,25 @@ StringRef sys::getHostCPUName() {
return "swift";
default:;
}
-
+
return "generic";
}
#else
StringRef sys::getHostCPUName() { return "generic"; }
#endif
-#if defined(__linux__) && defined(__x86_64__)
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
// On Linux, the number of physical cores can be computed from /proc/cpuinfo,
// using the number of unique physical/core id pairs. The following
// implementation reads the /proc/cpuinfo format on an x86_64 system.
-static int computeHostNumPhysicalCores() {
+int computeHostNumPhysicalCores() {
+ // Enabled represents the number of physical id/core id pairs with at least
+ // one processor id enabled by the CPU affinity mask.
+ cpu_set_t Affinity, Enabled;
+ if (sched_getaffinity(0, sizeof(Affinity), &Affinity) != 0)
+ return -1;
+ CPU_ZERO(&Enabled);
+
// Read /proc/cpuinfo as a stream (until EOF reached). It cannot be
// mmapped because it appears to have 0 size.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
@@ -1279,40 +1247,36 @@ static int computeHostNumPhysicalCores() {
SmallVector<StringRef, 8> strs;
(*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1,
/*KeepEmpty=*/false);
+ int CurProcessor = -1;
int CurPhysicalId = -1;
+ int CurSiblings = -1;
int CurCoreId = -1;
- SmallSet<std::pair<int, int>, 32> UniqueItems;
- for (auto &Line : strs) {
- Line = Line.trim();
- if (!Line.startswith("physical id") && !Line.startswith("core id"))
- continue;
+ for (StringRef Line : strs) {
std::pair<StringRef, StringRef> Data = Line.split(':');
auto Name = Data.first.trim();
auto Val = Data.second.trim();
- if (Name == "physical id") {
- assert(CurPhysicalId == -1 &&
- "Expected a core id before seeing another physical id");
+ // These fields are available if the kernel is configured with CONFIG_SMP.
+ if (Name == "processor")
+ Val.getAsInteger(10, CurProcessor);
+ else if (Name == "physical id")
Val.getAsInteger(10, CurPhysicalId);
- }
- if (Name == "core id") {
- assert(CurCoreId == -1 &&
- "Expected a physical id before seeing another core id");
+ else if (Name == "siblings")
+ Val.getAsInteger(10, CurSiblings);
+ else if (Name == "core id") {
Val.getAsInteger(10, CurCoreId);
- }
- if (CurPhysicalId != -1 && CurCoreId != -1) {
- UniqueItems.insert(std::make_pair(CurPhysicalId, CurCoreId));
- CurPhysicalId = -1;
- CurCoreId = -1;
+ // The processor id corresponds to an index into cpu_set_t.
+ if (CPU_ISSET(CurProcessor, &Affinity))
+ CPU_SET(CurPhysicalId * CurSiblings + CurCoreId, &Enabled);
}
}
- return UniqueItems.size();
+ return CPU_COUNT(&Enabled);
}
#elif defined(__APPLE__) && defined(__x86_64__)
#include <sys/param.h>
#include <sys/sysctl.h>
// Gets the number of *physical cores* on the machine.
-static int computeHostNumPhysicalCores() {
+int computeHostNumPhysicalCores() {
uint32_t count;
size_t len = sizeof(count);
sysctlbyname("hw.physicalcpu", &count, &len, NULL, 0);
@@ -1326,6 +1290,9 @@ static int computeHostNumPhysicalCores() {
}
return count;
}
+#elif defined(_WIN32) && LLVM_ENABLE_THREADS != 0
+// Defined in llvm/lib/Support/Windows/Threading.inc
+int computeHostNumPhysicalCores();
#else
// On other systems, return -1 to indicate unknown.
static int computeHostNumPhysicalCores() { return -1; }
@@ -1341,13 +1308,8 @@ int sys::getHostNumPhysicalCores() {
bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
unsigned MaxLevel;
- union {
- unsigned u[3];
- char c[12];
- } text;
- if (getX86CpuIDAndInfo(0, &MaxLevel, text.u + 0, text.u + 2, text.u + 1) ||
- MaxLevel < 1)
+ if (getX86CpuIDAndInfo(0, &MaxLevel, &EBX, &ECX, &EDX) || MaxLevel < 1)
return false;
getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
@@ -1373,8 +1335,8 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
// If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
// indicates that the AVX registers will be saved and restored on context
// switch, then we have full AVX support.
- bool HasAVXSave = ((ECX >> 27) & 1) && ((ECX >> 28) & 1) &&
- !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6);
+ bool HasXSave = ((ECX >> 27) & 1) && !getX86XCR0(&EAX, &EDX);
+ bool HasAVXSave = HasXSave && ((ECX >> 28) & 1) && ((EAX & 0x6) == 0x6);
#if defined(__APPLE__)
// Darwin lazily saves the AVX512 context on first use: trust that the OS will
// save the AVX512 context if we use AVX512 instructions, even the bit is not
@@ -1384,6 +1346,9 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
// AVX512 requires additional context to be saved by the OS.
bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0);
#endif
+ // AMX requires additional context to be saved by the OS.
+ const unsigned AMXBits = (1 << 17) | (1 << 18);
+ bool HasAMXSave = HasXSave && ((EAX & AMXBits) == AMXBits);
Features["avx"] = HasAVXSave;
Features["fma"] = ((ECX >> 12) & 1) && HasAVXSave;
@@ -1459,6 +1424,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
Features["movdir64b"] = HasLeaf7 && ((ECX >> 28) & 1);
Features["enqcmd"] = HasLeaf7 && ((ECX >> 29) & 1);
+ Features["avx512vp2intersect"] =
+ HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save;
+ Features["serialize"] = HasLeaf7 && ((EDX >> 14) & 1);
+ Features["tsxldtrk"] = HasLeaf7 && ((EDX >> 16) & 1);
// There are two CPUID leafs which information associated with the pconfig
// instruction:
// EAX=0x7, ECX=0x0 indicates the availability of the instruction (via the 18th
@@ -1470,6 +1439,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);
+ Features["amx-bf16"] = HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave;
+ Features["amx-tile"] = HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave;
+ Features["amx-int8"] = HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave;
bool HasLeaf7Subleaf1 =
MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX);
Features["avx512bf16"] = HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save;
diff --git a/llvm/lib/Support/InitLLVM.cpp b/llvm/lib/Support/InitLLVM.cpp
index bb9b569d2de69..5c56b773ea698 100644
--- a/llvm/lib/Support/InitLLVM.cpp
+++ b/llvm/lib/Support/InitLLVM.cpp
@@ -15,7 +15,7 @@
#include <string>
#ifdef _WIN32
-#include "Windows/WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#endif
using namespace llvm;
diff --git a/llvm/lib/Support/IntEqClasses.cpp b/llvm/lib/Support/IntEqClasses.cpp
index 4a976dcefc65f..ebb02e6c01e52 100644
--- a/llvm/lib/Support/IntEqClasses.cpp
+++ b/llvm/lib/Support/IntEqClasses.cpp
@@ -18,6 +18,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/IntEqClasses.h"
+#include <cassert>
using namespace llvm;
diff --git a/llvm/lib/Support/IntervalMap.cpp b/llvm/lib/Support/IntervalMap.cpp
index f15c7c9403c36..674e0f962fa1b 100644
--- a/llvm/lib/Support/IntervalMap.cpp
+++ b/llvm/lib/Support/IntervalMap.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/IntervalMap.h"
+#include <cassert>
namespace llvm {
namespace IntervalMapImpl {
diff --git a/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp b/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp
index bbc06d186fba4..9d3cf61459dd8 100644
--- a/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp
+++ b/llvm/lib/Support/ItaniumManglingCanonicalizer.cpp
@@ -7,16 +7,12 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/ItaniumManglingCanonicalizer.h"
-
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Demangle/ItaniumDemangle.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/StringRef.h"
-
using namespace llvm;
using llvm::itanium_demangle::ForwardTemplateReference;
using llvm::itanium_demangle::Node;
@@ -30,9 +26,8 @@ struct FoldingSetNodeIDBuilder {
void operator()(StringView Str) {
ID.AddString(llvm::StringRef(Str.begin(), Str.size()));
}
- template<typename T>
- typename std::enable_if<std::is_integral<T>::value ||
- std::is_enum<T>::value>::type
+ template <typename T>
+ std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>
operator()(T V) {
ID.AddInteger((unsigned long long)V);
}
diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 8f3f4aa8caeaf..1ff66d504cbea 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/KnownBits.h"
+#include <cassert>
using namespace llvm;
@@ -81,3 +82,28 @@ KnownBits KnownBits::computeForAddSub(bool Add, bool NSW,
return KnownOut;
}
+
+KnownBits &KnownBits::operator&=(const KnownBits &RHS) {
+ // Result bit is 0 if either operand bit is 0.
+ Zero |= RHS.Zero;
+ // Result bit is 1 if both operand bits are 1.
+ One &= RHS.One;
+ return *this;
+}
+
+KnownBits &KnownBits::operator|=(const KnownBits &RHS) {
+ // Result bit is 0 if both operand bits are 0.
+ Zero &= RHS.Zero;
+ // Result bit is 1 if either operand bit is 1.
+ One |= RHS.One;
+ return *this;
+}
+
+KnownBits &KnownBits::operator^=(const KnownBits &RHS) {
+ // Result bit is 0 if both operand bits are 0 or both are 1.
+ APInt Z = (Zero & RHS.Zero) | (One & RHS.One);
+ // Result bit is 1 if one operand bit is 0 and the other is 1.
+ One = (Zero & RHS.One) | (One & RHS.Zero);
+ Zero = std::move(Z);
+ return *this;
+}
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index 5c6508c3b007b..a2b56ab295c42 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -14,15 +14,20 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cerrno>
+#include <chrono>
#include <ctime>
#include <memory>
+#include <random>
#include <sys/stat.h>
#include <sys/types.h>
#include <system_error>
+#include <thread>
#include <tuple>
+
#ifdef _WIN32
#include <windows.h>
#endif
@@ -158,7 +163,7 @@ LockFileManager::LockFileManager(StringRef FileName)
this->FileName = FileName;
if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
std::string S("failed to obtain absolute path for ");
- S.append(this->FileName.str());
+ S.append(std::string(this->FileName.str()));
setError(EC, S);
return;
}
@@ -177,7 +182,7 @@ LockFileManager::LockFileManager(StringRef FileName)
if (std::error_code EC = sys::fs::createUniqueFile(
UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
std::string S("failed to create unique file ");
- S.append(UniqueLockFileName.str());
+ S.append(std::string(UniqueLockFileName.str()));
setError(EC, S);
return;
}
@@ -191,19 +196,14 @@ LockFileManager::LockFileManager(StringRef FileName)
}
raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
- Out << HostID << ' ';
-#if LLVM_ON_UNIX
- Out << getpid();
-#else
- Out << "1";
-#endif
+ Out << HostID << ' ' << sys::Process::getProcessId();
Out.close();
if (Out.has_error()) {
// We failed to write out PID, so report the error, remove the
// unique lock file, and fail.
std::string S("failed to write to ");
- S.append(UniqueLockFileName.str());
+ S.append(std::string(UniqueLockFileName.str()));
setError(Out.error(), S);
sys::fs::remove(UniqueLockFileName);
return;
@@ -249,7 +249,7 @@ LockFileManager::LockFileManager(StringRef FileName)
// ownership.
if ((EC = sys::fs::remove(LockFileName))) {
std::string S("failed to remove lockfile ");
- S.append(UniqueLockFileName.str());
+ S.append(std::string(UniqueLockFileName.str()));
setError(EC, S);
return;
}
@@ -295,23 +295,29 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
if (getState() != LFS_Shared)
return Res_Success;
-#ifdef _WIN32
- unsigned long Interval = 1;
-#else
- struct timespec Interval;
- Interval.tv_sec = 0;
- Interval.tv_nsec = 1000000;
-#endif
+ // Since we don't yet have an event-based method to wait for the lock file,
+ // implement randomized exponential backoff, similar to Ethernet collision
+ // algorithm. This improves performance on machines with high core counts
+ // when the file lock is heavily contended by multiple clang processes
+ const unsigned long MinWaitDurationMS = 10;
+ const unsigned long MaxWaitMultiplier = 50; // 500ms max wait
+ unsigned long WaitMultiplier = 1;
+ unsigned long ElapsedTimeSeconds = 0;
+
+ std::random_device Device;
+ std::default_random_engine Engine(Device());
+
+ auto StartTime = std::chrono::steady_clock::now();
+
do {
+ // FIXME: implement event-based waiting
+
// Sleep for the designated interval, to allow the owning process time to
// finish up and remove the lock file.
- // FIXME: Should we hook in to system APIs to get a notification when the
- // lock file is deleted?
-#ifdef _WIN32
- Sleep(Interval);
-#else
- nanosleep(&Interval, nullptr);
-#endif
+ std::uniform_int_distribution<unsigned long> Distribution(1,
+ WaitMultiplier);
+ unsigned long WaitDurationMS = MinWaitDurationMS * Distribution(Engine);
+ std::this_thread::sleep_for(std::chrono::milliseconds(WaitDurationMS));
if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
errc::no_such_file_or_directory) {
@@ -325,24 +331,16 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
if (!processStillExecuting((*Owner).first, (*Owner).second))
return Res_OwnerDied;
- // Exponentially increase the time we wait for the lock to be removed.
-#ifdef _WIN32
- Interval *= 2;
-#else
- Interval.tv_sec *= 2;
- Interval.tv_nsec *= 2;
- if (Interval.tv_nsec >= 1000000000) {
- ++Interval.tv_sec;
- Interval.tv_nsec -= 1000000000;
+ WaitMultiplier *= 2;
+ if (WaitMultiplier > MaxWaitMultiplier) {
+ WaitMultiplier = MaxWaitMultiplier;
}
-#endif
- } while (
-#ifdef _WIN32
- Interval < MaxSeconds * 1000
-#else
- Interval.tv_sec < (time_t)MaxSeconds
-#endif
- );
+
+ ElapsedTimeSeconds = std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::steady_clock::now() - StartTime)
+ .count();
+
+ } while (ElapsedTimeSeconds < MaxSeconds);
// Give up.
return Res_Timeout;
diff --git a/llvm/lib/Support/MD5.cpp b/llvm/lib/Support/MD5.cpp
index 9b02f62912fa3..5e0b076f176e8 100644
--- a/llvm/lib/Support/MD5.cpp
+++ b/llvm/lib/Support/MD5.cpp
@@ -39,6 +39,7 @@
#include "llvm/Support/MD5.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
diff --git a/llvm/lib/Support/MemAlloc.cpp b/llvm/lib/Support/MemAlloc.cpp
new file mode 100644
index 0000000000000..7aaa0dc6e205a
--- /dev/null
+++ b/llvm/lib/Support/MemAlloc.cpp
@@ -0,0 +1,34 @@
+//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
+//
+// 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/MemAlloc.h"
+
+// These are out of line to have __cpp_aligned_new not affect ABI.
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
+llvm::allocate_buffer(size_t Size, size_t Alignment) {
+ return ::operator new(Size
+#ifdef __cpp_aligned_new
+ ,
+ std::align_val_t(Alignment)
+#endif
+ );
+}
+
+void llvm::deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
+ ::operator delete(Ptr
+#ifdef __cpp_sized_deallocation
+ ,
+ Size
+#endif
+#ifdef __cpp_aligned_new
+ ,
+ std::align_val_t(Alignment)
+#endif
+ );
+}
diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp
index e4027ca7bbfd5..248fb72c49689 100644
--- a/llvm/lib/Support/MemoryBuffer.cpp
+++ b/llvm/lib/Support/MemoryBuffer.cpp
@@ -162,6 +162,20 @@ MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize,
//===----------------------------------------------------------------------===//
namespace {
+
+template <typename MB>
+constexpr sys::fs::mapped_file_region::mapmode Mapmode =
+ sys::fs::mapped_file_region::readonly;
+template <>
+constexpr sys::fs::mapped_file_region::mapmode Mapmode<MemoryBuffer> =
+ sys::fs::mapped_file_region::readonly;
+template <>
+constexpr sys::fs::mapped_file_region::mapmode Mapmode<WritableMemoryBuffer> =
+ sys::fs::mapped_file_region::priv;
+template <>
+constexpr sys::fs::mapped_file_region::mapmode
+ Mapmode<WriteThroughMemoryBuffer> = sys::fs::mapped_file_region::readwrite;
+
/// Memory maps a file descriptor using sys::fs::mapped_file_region.
///
/// This handles converting the offset into a legal offset on the platform.
@@ -184,7 +198,7 @@ class MemoryBufferMMapFile : public MB {
public:
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),
+ : MFR(FD, Mapmode<MB>, getLegalMapSize(Len, Offset),
getLegalMapOffset(Offset), EC) {
if (!EC) {
const char *Start = getStart(Len, Offset);
@@ -315,7 +329,7 @@ static bool shouldUseMmap(sys::fs::file_t FD,
// mmap may leave the buffer without null terminator if the file size changed
// by the time the last page is mapped in, so avoid it if the file size is
// likely to change.
- if (IsVolatile)
+ if (IsVolatile && RequiresNullTerminator)
return false;
// We don't use mmap for small files because this can severely fragment our
diff --git a/llvm/lib/Support/NativeFormatting.cpp b/llvm/lib/Support/NativeFormatting.cpp
index 3731e0c563599..ae4bffbd94c1a 100644
--- a/llvm/lib/Support/NativeFormatting.cpp
+++ b/llvm/lib/Support/NativeFormatting.cpp
@@ -7,12 +7,11 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/NativeFormatting.h"
-
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Format.h"
-
+#include "llvm/Support/raw_ostream.h"
#include <float.h>
using namespace llvm;
@@ -89,7 +88,7 @@ static void write_signed(raw_ostream &S, T N, size_t MinDigits,
IntegerStyle Style) {
static_assert(std::is_signed<T>::value, "Value is not signed!");
- using UnsignedT = typename std::make_unsigned<T>::type;
+ using UnsignedT = std::make_unsigned_t<T>;
if (N >= 0) {
write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
diff --git a/llvm/lib/Support/OptimizedStructLayout.cpp b/llvm/lib/Support/OptimizedStructLayout.cpp
new file mode 100644
index 0000000000000..9bbd767c5ce9b
--- /dev/null
+++ b/llvm/lib/Support/OptimizedStructLayout.cpp
@@ -0,0 +1,449 @@
+//===--- OptimizedStructLayout.cpp - Optimal data layout algorithm ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the performOptimizedStructLayout interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/OptimizedStructLayout.h"
+
+using namespace llvm;
+
+using Field = OptimizedStructLayoutField;
+
+#ifndef NDEBUG
+static void checkValidLayout(ArrayRef<Field> Fields, uint64_t Size,
+ Align MaxAlign) {
+ uint64_t LastEnd = 0;
+ Align ComputedMaxAlign;
+ for (auto &Field : Fields) {
+ assert(Field.hasFixedOffset() &&
+ "didn't assign a fixed offset to field");
+ assert(isAligned(Field.Alignment, Field.Offset) &&
+ "didn't assign a correctly-aligned offset to field");
+ assert(Field.Offset >= LastEnd &&
+ "didn't assign offsets in ascending order");
+ LastEnd = Field.getEndOffset();
+ assert(Field.Alignment <= MaxAlign &&
+ "didn't compute MaxAlign correctly");
+ ComputedMaxAlign = std::max(Field.Alignment, MaxAlign);
+ }
+ assert(LastEnd == Size && "didn't compute LastEnd correctly");
+ assert(ComputedMaxAlign == MaxAlign && "didn't compute MaxAlign correctly");
+}
+#endif
+
+std::pair<uint64_t, Align>
+llvm::performOptimizedStructLayout(MutableArrayRef<Field> Fields) {
+#ifndef NDEBUG
+ // Do some simple precondition checks.
+ {
+ bool InFixedPrefix = true;
+ size_t LastEnd = 0;
+ for (auto &Field : Fields) {
+ assert(Field.Size > 0 && "field of zero size");
+ if (Field.hasFixedOffset()) {
+ assert(InFixedPrefix &&
+ "fixed-offset fields are not a strict prefix of array");
+ assert(LastEnd <= Field.Offset &&
+ "fixed-offset fields overlap or are not in order");
+ LastEnd = Field.getEndOffset();
+ assert(LastEnd > Field.Offset &&
+ "overflow in fixed-offset end offset");
+ } else {
+ InFixedPrefix = false;
+ }
+ }
+ }
+#endif
+
+ // Do an initial pass over the fields.
+ Align MaxAlign;
+
+ // Find the first flexible-offset field, tracking MaxAlign.
+ auto FirstFlexible = Fields.begin(), E = Fields.end();
+ while (FirstFlexible != E && FirstFlexible->hasFixedOffset()) {
+ MaxAlign = std::max(MaxAlign, FirstFlexible->Alignment);
+ ++FirstFlexible;
+ }
+
+ // If there are no flexible fields, we're done.
+ if (FirstFlexible == E) {
+ uint64_t Size = 0;
+ if (!Fields.empty())
+ Size = Fields.back().getEndOffset();
+
+#ifndef NDEBUG
+ checkValidLayout(Fields, Size, MaxAlign);
+#endif
+ return std::make_pair(Size, MaxAlign);
+ }
+
+ // Walk over the flexible-offset fields, tracking MaxAlign and
+ // assigning them a unique number in order of their appearance.
+ // We'll use this unique number in the comparison below so that
+ // we can use array_pod_sort, which isn't stable. We won't use it
+ // past that point.
+ {
+ uintptr_t UniqueNumber = 0;
+ for (auto I = FirstFlexible; I != E; ++I) {
+ I->Scratch = reinterpret_cast<void*>(UniqueNumber++);
+ MaxAlign = std::max(MaxAlign, I->Alignment);
+ }
+ }
+
+ // Sort the flexible elements in order of decreasing alignment,
+ // then decreasing size, and then the original order as recorded
+ // in Scratch. The decreasing-size aspect of this is only really
+ // important if we get into the gap-filling stage below, but it
+ // doesn't hurt here.
+ array_pod_sort(FirstFlexible, E,
+ [](const Field *lhs, const Field *rhs) -> int {
+ // Decreasing alignment.
+ if (lhs->Alignment != rhs->Alignment)
+ return (lhs->Alignment < rhs->Alignment ? 1 : -1);
+
+ // Decreasing size.
+ if (lhs->Size != rhs->Size)
+ return (lhs->Size < rhs->Size ? 1 : -1);
+
+ // Original order.
+ auto lhsNumber = reinterpret_cast<uintptr_t>(lhs->Scratch);
+ auto rhsNumber = reinterpret_cast<uintptr_t>(rhs->Scratch);
+ if (lhsNumber != rhsNumber)
+ return (lhsNumber < rhsNumber ? -1 : 1);
+
+ return 0;
+ });
+
+ // Do a quick check for whether that sort alone has given us a perfect
+ // layout with no interior padding. This is very common: if the
+ // fixed-layout fields have no interior padding, and they end at a
+ // sufficiently-aligned offset for all the flexible-layout fields,
+ // and the flexible-layout fields all have sizes that are multiples
+ // of their alignment, then this will reliably trigger.
+ {
+ bool HasPadding = false;
+ uint64_t LastEnd = 0;
+
+ // Walk the fixed-offset fields.
+ for (auto I = Fields.begin(); I != FirstFlexible; ++I) {
+ assert(I->hasFixedOffset());
+ if (LastEnd != I->Offset) {
+ HasPadding = true;
+ break;
+ }
+ LastEnd = I->getEndOffset();
+ }
+
+ // Walk the flexible-offset fields, optimistically assigning fixed
+ // offsets. Note that we maintain a strict division between the
+ // fixed-offset and flexible-offset fields, so if we end up
+ // discovering padding later in this loop, we can just abandon this
+ // work and we'll ignore the offsets we already assigned.
+ if (!HasPadding) {
+ for (auto I = FirstFlexible; I != E; ++I) {
+ auto Offset = alignTo(LastEnd, I->Alignment);
+ if (LastEnd != Offset) {
+ HasPadding = true;
+ break;
+ }
+ I->Offset = Offset;
+ LastEnd = I->getEndOffset();
+ }
+ }
+
+ // If we already have a perfect layout, we're done.
+ if (!HasPadding) {
+#ifndef NDEBUG
+ checkValidLayout(Fields, LastEnd, MaxAlign);
+#endif
+ return std::make_pair(LastEnd, MaxAlign);
+ }
+ }
+
+ // The algorithm sketch at this point is as follows.
+ //
+ // Consider the padding gaps between fixed-offset fields in ascending
+ // order. Let LastEnd be the offset of the first byte following the
+ // field before the gap, or 0 if the gap is at the beginning of the
+ // structure. Find the "best" flexible-offset field according to the
+ // criteria below. If no such field exists, proceed to the next gap.
+ // Otherwise, add the field at the first properly-aligned offset for
+ // that field that is >= LastEnd, then update LastEnd and repeat in
+ // order to fill any remaining gap following that field.
+ //
+ // Next, let LastEnd to be the offset of the first byte following the
+ // last fixed-offset field, or 0 if there are no fixed-offset fields.
+ // While there are flexible-offset fields remaining, find the "best"
+ // flexible-offset field according to the criteria below, add it at
+ // the first properly-aligned offset for that field that is >= LastEnd,
+ // and update LastEnd to the first byte following the field.
+ //
+ // The "best" field is chosen by the following criteria, considered
+ // strictly in order:
+ //
+ // - When filling a gap betweeen fields, the field must fit.
+ // - A field is preferred if it requires less padding following LastEnd.
+ // - A field is preferred if it is more aligned.
+ // - A field is preferred if it is larger.
+ // - A field is preferred if it appeared earlier in the initial order.
+ //
+ // Minimizing leading padding is a greedy attempt to avoid padding
+ // entirely. Preferring more-aligned fields is an attempt to eliminate
+ // stricter constraints earlier, with the idea that weaker alignment
+ // constraints may be resolvable with less padding elsewhere. These
+ // These two rules are sufficient to ensure that we get the optimal
+ // layout in the "C-style" case. Preferring larger fields tends to take
+ // better advantage of large gaps and may be more likely to have a size
+ // that's a multiple of a useful alignment. Preferring the initial
+ // order may help somewhat with locality but is mostly just a way of
+ // ensuring deterministic output.
+ //
+ // Note that this algorithm does not guarantee a minimal layout. Picking
+ // a larger object greedily may leave a gap that cannot be filled as
+ // efficiently. Unfortunately, solving this perfectly is an NP-complete
+ // problem (by reduction from bin-packing: let B_i be the bin sizes and
+ // O_j be the object sizes; add fixed-offset fields such that the gaps
+ // between them have size B_i, and add flexible-offset fields with
+ // alignment 1 and size O_j; if the layout size is equal to the end of
+ // the last fixed-layout field, the objects fit in the bins; note that
+ // this doesn't even require the complexity of alignment).
+
+ // The implementation below is essentially just an optimized version of
+ // scanning the list of remaining fields looking for the best, which
+ // would be O(n^2). In the worst case, it doesn't improve on that.
+ // However, in practice it'll just scan the array of alignment bins
+ // and consider the first few elements from one or two bins. The
+ // number of bins is bounded by a small constant: alignments are powers
+ // of two that are vanishingly unlikely to be over 64 and fairly unlikely
+ // to be over 8. And multiple elements only need to be considered when
+ // filling a gap between fixed-offset fields, which doesn't happen very
+ // often. We could use a data structure within bins that optimizes for
+ // finding the best-sized match, but it would require allocating memory
+ // and copying data, so it's unlikely to be worthwhile.
+
+
+ // Start by organizing the flexible-offset fields into bins according to
+ // their alignment. We expect a small enough number of bins that we
+ // don't care about the asymptotic costs of walking this.
+ struct AlignmentQueue {
+ /// The minimum size of anything currently in this queue.
+ uint64_t MinSize;
+
+ /// The head of the queue. A singly-linked list. The order here should
+ /// be consistent with the earlier sort, i.e. the elements should be
+ /// monotonically descending in size and otherwise in the original order.
+ ///
+ /// We remove the queue from the array as soon as this is empty.
+ OptimizedStructLayoutField *Head;
+
+ /// The alignment requirement of the queue.
+ Align Alignment;
+
+ static Field *getNext(Field *Cur) {
+ return static_cast<Field *>(Cur->Scratch);
+ }
+ };
+ SmallVector<AlignmentQueue, 8> FlexibleFieldsByAlignment;
+ for (auto I = FirstFlexible; I != E; ) {
+ auto Head = I;
+ auto Alignment = I->Alignment;
+
+ uint64_t MinSize = I->Size;
+ auto LastInQueue = I;
+ for (++I; I != E && I->Alignment == Alignment; ++I) {
+ LastInQueue->Scratch = I;
+ LastInQueue = I;
+ MinSize = std::min(MinSize, I->Size);
+ }
+ LastInQueue->Scratch = nullptr;
+
+ FlexibleFieldsByAlignment.push_back({MinSize, Head, Alignment});
+ }
+
+#ifndef NDEBUG
+ // Verify that we set the queues up correctly.
+ auto checkQueues = [&]{
+ bool FirstQueue = true;
+ Align LastQueueAlignment;
+ for (auto &Queue : FlexibleFieldsByAlignment) {
+ assert((FirstQueue || Queue.Alignment < LastQueueAlignment) &&
+ "bins not in order of descending alignment");
+ LastQueueAlignment = Queue.Alignment;
+ FirstQueue = false;
+
+ assert(Queue.Head && "queue was empty");
+ uint64_t LastSize = ~(uint64_t)0;
+ for (auto I = Queue.Head; I; I = Queue.getNext(I)) {
+ assert(I->Alignment == Queue.Alignment && "bad field in queue");
+ assert(I->Size <= LastSize && "queue not in descending size order");
+ LastSize = I->Size;
+ }
+ }
+ };
+ checkQueues();
+#endif
+
+ /// Helper function to remove a field from a queue.
+ auto spliceFromQueue = [&](AlignmentQueue *Queue, Field *Last, Field *Cur) {
+ assert(Last ? Queue->getNext(Last) == Cur : Queue->Head == Cur);
+
+ // If we're removing Cur from a non-initial position, splice it out
+ // of the linked list.
+ if (Last) {
+ Last->Scratch = Cur->Scratch;
+
+ // If Cur was the last field in the list, we need to update MinSize.
+ // We can just use the last field's size because the list is in
+ // descending order of size.
+ if (!Cur->Scratch)
+ Queue->MinSize = Last->Size;
+
+ // Otherwise, replace the head.
+ } else {
+ if (auto NewHead = Queue->getNext(Cur))
+ Queue->Head = NewHead;
+
+ // If we just emptied the queue, destroy its bin.
+ else
+ FlexibleFieldsByAlignment.erase(Queue);
+ }
+ };
+
+ // Do layout into a local array. Doing this in-place on Fields is
+ // not really feasible.
+ SmallVector<Field, 16> Layout;
+ Layout.reserve(Fields.size());
+
+ // The offset that we're currently looking to insert at (or after).
+ uint64_t LastEnd = 0;
+
+ // Helper function to splice Cur out of the given queue and add it
+ // to the layout at the given offset.
+ auto addToLayout = [&](AlignmentQueue *Queue, Field *Last, Field *Cur,
+ uint64_t Offset) -> bool {
+ assert(Offset == alignTo(LastEnd, Cur->Alignment));
+
+ // Splice out. This potentially invalidates Queue.
+ spliceFromQueue(Queue, Last, Cur);
+
+ // Add Cur to the layout.
+ Layout.push_back(*Cur);
+ Layout.back().Offset = Offset;
+ LastEnd = Layout.back().getEndOffset();
+
+ // Always return true so that we can be tail-called.
+ return true;
+ };
+
+ // Helper function to try to find a field in the given queue that'll
+ // fit starting at StartOffset but before EndOffset (if present).
+ // Note that this never fails if EndOffset is not provided.
+ auto tryAddFillerFromQueue = [&](AlignmentQueue *Queue,
+ uint64_t StartOffset,
+ Optional<uint64_t> EndOffset) -> bool {
+ assert(Queue->Head);
+ assert(StartOffset == alignTo(LastEnd, Queue->Alignment));
+
+ // Figure out the maximum size that a field can be, and ignore this
+ // queue if there's nothing in it that small.
+ auto MaxViableSize =
+ (EndOffset ? *EndOffset - StartOffset : ~(uint64_t)0);
+ if (Queue->MinSize > MaxViableSize) return false;
+
+ // Find the matching field. Note that this should always find
+ // something because of the MinSize check above.
+ for (Field *Cur = Queue->Head, *Last = nullptr; true;
+ Last = Cur, Cur = Queue->getNext(Cur)) {
+ assert(Cur && "didn't find a match in queue despite its MinSize");
+ if (Cur->Size <= MaxViableSize)
+ return addToLayout(Queue, Last, Cur, StartOffset);
+ }
+
+ llvm_unreachable("didn't find a match in queue despite its MinSize");
+ };
+
+ // Helper function to find the "best" flexible-offset field according
+ // to the criteria described above.
+ auto tryAddBestField = [&](Optional<uint64_t> BeforeOffset) -> bool {
+ auto QueueB = FlexibleFieldsByAlignment.begin();
+ auto QueueE = FlexibleFieldsByAlignment.end();
+
+ // Start by looking for the most-aligned queue that doesn't need any
+ // leading padding after LastEnd.
+ auto FirstQueueToSearch = QueueB;
+ for (; FirstQueueToSearch != QueueE; ++FirstQueueToSearch) {
+ if (isAligned(FirstQueueToSearch->Alignment, LastEnd))
+ break;
+ }
+
+ uint64_t Offset = LastEnd;
+ while (true) {
+ // Invariant: all of the queues in [FirstQueueToSearch, QueueE)
+ // require the same initial padding offset.
+
+ // Search those queues in descending order of alignment for a
+ // satisfactory field.
+ for (auto Queue = FirstQueueToSearch; Queue != QueueE; ++Queue) {
+ if (tryAddFillerFromQueue(Queue, Offset, BeforeOffset))
+ return true;
+ }
+
+ // Okay, we don't need to scan those again.
+ QueueE = FirstQueueToSearch;
+
+ // If we started from the first queue, we're done.
+ if (FirstQueueToSearch == QueueB)
+ return false;
+
+ // Otherwise, scan backwards to find the most-aligned queue that
+ // still has minimal leading padding after LastEnd.
+ --FirstQueueToSearch;
+ Offset = alignTo(LastEnd, FirstQueueToSearch->Alignment);
+ while (FirstQueueToSearch != QueueB &&
+ Offset == alignTo(LastEnd, FirstQueueToSearch[-1].Alignment))
+ --FirstQueueToSearch;
+ }
+ };
+
+ // Phase 1: fill the gaps between fixed-offset fields with the best
+ // flexible-offset field that fits.
+ for (auto I = Fields.begin(); I != FirstFlexible; ++I) {
+ while (LastEnd != I->Offset) {
+ if (!tryAddBestField(I->Offset))
+ break;
+ }
+ Layout.push_back(*I);
+ LastEnd = I->getEndOffset();
+ }
+
+#ifndef NDEBUG
+ checkQueues();
+#endif
+
+ // Phase 2: repeatedly add the best flexible-offset field until
+ // they're all gone.
+ while (!FlexibleFieldsByAlignment.empty()) {
+ bool Success = tryAddBestField(None);
+ assert(Success && "didn't find a field with no fixed limit?");
+ (void) Success;
+ }
+
+ // Copy the layout back into place.
+ assert(Layout.size() == Fields.size());
+ memcpy(Fields.data(), Layout.data(),
+ Fields.size() * sizeof(OptimizedStructLayoutField));
+
+#ifndef NDEBUG
+ // Make a final check that the layout is valid.
+ checkValidLayout(Fields, LastEnd, MaxAlign);
+#endif
+
+ return std::make_pair(LastEnd, MaxAlign);
+}
diff --git a/llvm/lib/Support/Parallel.cpp b/llvm/lib/Support/Parallel.cpp
index 523665d14b029..9a2e1003da5a2 100644
--- a/llvm/lib/Support/Parallel.cpp
+++ b/llvm/lib/Support/Parallel.cpp
@@ -9,9 +9,6 @@
#include "llvm/Support/Parallel.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/ManagedStatic.h"
-
-#if LLVM_ENABLE_THREADS
-
#include "llvm/Support/Threading.h"
#include <atomic>
@@ -20,6 +17,10 @@
#include <thread>
#include <vector>
+llvm::ThreadPoolStrategy llvm::parallel::strategy;
+
+#if LLVM_ENABLE_THREADS
+
namespace llvm {
namespace parallel {
namespace detail {
@@ -39,20 +40,21 @@ public:
/// in filo order.
class ThreadPoolExecutor : public Executor {
public:
- explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency()) {
+ explicit ThreadPoolExecutor(ThreadPoolStrategy S = hardware_concurrency()) {
+ unsigned ThreadCount = S.compute_thread_count();
// Spawn all but one of the threads in another thread as spawning threads
// can take a while.
Threads.reserve(ThreadCount);
Threads.resize(1);
std::lock_guard<std::mutex> Lock(Mutex);
- Threads[0] = std::thread([&, ThreadCount] {
- for (unsigned i = 1; i < ThreadCount; ++i) {
- Threads.emplace_back([=] { work(); });
+ Threads[0] = std::thread([this, ThreadCount, S] {
+ for (unsigned I = 1; I < ThreadCount; ++I) {
+ Threads.emplace_back([=] { work(S, I); });
if (Stop)
break;
}
ThreadsCreated.set_value();
- work();
+ work(S, 0);
});
}
@@ -77,6 +79,9 @@ public:
T.join();
}
+ struct Creator {
+ static void *call() { return new ThreadPoolExecutor(strategy); }
+ };
struct Deleter {
static void call(void *Ptr) { ((ThreadPoolExecutor *)Ptr)->stop(); }
};
@@ -90,7 +95,8 @@ public:
}
private:
- void work() {
+ void work(ThreadPoolStrategy S, unsigned ThreadID) {
+ S.apply_thread_strategy(ThreadID);
while (true) {
std::unique_lock<std::mutex> Lock(Mutex);
Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
@@ -129,7 +135,8 @@ Executor *Executor::getDefaultExecutor() {
// are more frequent with the debug static runtime.
//
// This also prevents intermittent deadlocks on exit with the MinGW runtime.
- static ManagedStatic<ThreadPoolExecutor, object_creator<ThreadPoolExecutor>,
+
+ static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
ThreadPoolExecutor::Deleter>
ManagedExec;
static std::unique_ptr<ThreadPoolExecutor> Exec(&(*ManagedExec));
diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp
index 3c9a08cb4077d..37b3086fddf5d 100644
--- a/llvm/lib/Support/Path.cpp
+++ b/llvm/lib/Support/Path.cpp
@@ -496,49 +496,44 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
path.append(ext.begin(), ext.end());
}
-bool replace_path_prefix(SmallVectorImpl<char> &Path,
- const StringRef &OldPrefix, const StringRef &NewPrefix,
- Style style, bool strict) {
+static bool starts_with(StringRef Path, StringRef Prefix,
+ Style style = Style::native) {
+ // Windows prefix matching : case and separator insensitive
+ if (real_style(style) == Style::windows) {
+ if (Path.size() < Prefix.size())
+ return false;
+ for (size_t I = 0, E = Prefix.size(); I != E; ++I) {
+ bool SepPath = is_separator(Path[I], style);
+ bool SepPrefix = is_separator(Prefix[I], style);
+ if (SepPath != SepPrefix)
+ return false;
+ if (!SepPath && toLower(Path[I]) != toLower(Prefix[I]))
+ return false;
+ }
+ return true;
+ }
+ return Path.startswith(Prefix);
+}
+
+bool replace_path_prefix(SmallVectorImpl<char> &Path, StringRef OldPrefix,
+ StringRef NewPrefix, Style style) {
if (OldPrefix.empty() && NewPrefix.empty())
return false;
StringRef OrigPath(Path.begin(), Path.size());
- StringRef OldPrefixDir;
-
- if (!strict && OldPrefix.size() > OrigPath.size())
+ if (!starts_with(OrigPath, OldPrefix, style))
return false;
- // Ensure OldPrefixDir does not have a trailing separator.
- if (!OldPrefix.empty() && is_separator(OldPrefix.back()))
- OldPrefixDir = parent_path(OldPrefix, style);
- else
- OldPrefixDir = OldPrefix;
-
- if (!OrigPath.startswith(OldPrefixDir))
- return false;
-
- if (OrigPath.size() > OldPrefixDir.size())
- if (!is_separator(OrigPath[OldPrefixDir.size()], style) && strict)
- return false;
-
// If prefixes have the same size we can simply copy the new one over.
- if (OldPrefixDir.size() == NewPrefix.size() && !strict) {
+ if (OldPrefix.size() == NewPrefix.size()) {
llvm::copy(NewPrefix, Path.begin());
return true;
}
- StringRef RelPath = OrigPath.substr(OldPrefixDir.size());
+ StringRef RelPath = OrigPath.substr(OldPrefix.size());
SmallString<256> NewPath;
- path::append(NewPath, style, NewPrefix);
- if (!RelPath.empty()) {
- if (!is_separator(RelPath[0], style) || !strict)
- path::append(NewPath, style, RelPath);
- else
- path::append(NewPath, style, relative_path(RelPath, style));
- }
-
+ (Twine(NewPrefix) + RelPath).toVector(NewPath);
Path.swap(NewPath);
-
return true;
}
@@ -564,21 +559,15 @@ void native(SmallVectorImpl<char> &Path, Style style) {
Path = PathHome;
}
} else {
- for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
- if (*PI == '\\') {
- auto PN = PI + 1;
- if (PN < PE && *PN == '\\')
- ++PI; // increment once, the for loop will move over the escaped slash
- else
- *PI = '/';
- }
- }
+ for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI)
+ if (*PI == '\\')
+ *PI = '/';
}
}
std::string convert_to_slash(StringRef path, Style style) {
if (real_style(style) != Style::windows)
- return path;
+ return std::string(path);
std::string s = path.str();
std::replace(s.begin(), s.end(), '\\', '/');
@@ -708,43 +697,69 @@ StringRef remove_leading_dotslash(StringRef Path, Style style) {
return Path;
}
-static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
- Style style) {
+// Remove path traversal components ("." and "..") when possible, and
+// canonicalize slashes.
+bool remove_dots(SmallVectorImpl<char> &the_path, bool remove_dot_dot,
+ Style style) {
+ style = real_style(style);
+ StringRef remaining(the_path.data(), the_path.size());
+ bool needs_change = false;
SmallVector<StringRef, 16> components;
- // Skip the root path, then look for traversal in the components.
- StringRef rel = path::relative_path(path, style);
- for (StringRef C :
- llvm::make_range(path::begin(rel, style), path::end(rel))) {
- if (C == ".")
- continue;
- // Leading ".." will remain in the path unless it's at the root.
- if (remove_dot_dot && C == "..") {
+ // Consume the root path, if present.
+ StringRef root = path::root_path(remaining, style);
+ bool absolute = !root.empty();
+ if (absolute)
+ remaining = remaining.drop_front(root.size());
+
+ // Loop over path components manually. This makes it easier to detect
+ // non-preferred slashes and double separators that must be canonicalized.
+ while (!remaining.empty()) {
+ size_t next_slash = remaining.find_first_of(separators(style));
+ if (next_slash == StringRef::npos)
+ next_slash = remaining.size();
+ StringRef component = remaining.take_front(next_slash);
+ remaining = remaining.drop_front(next_slash);
+
+ // Eat the slash, and check if it is the preferred separator.
+ if (!remaining.empty()) {
+ needs_change |= remaining.front() != preferred_separator(style);
+ remaining = remaining.drop_front();
+ // The path needs to be rewritten if it has a trailing slash.
+ // FIXME: This is emergent behavior that could be removed.
+ needs_change |= remaining.empty();
+ }
+
+ // Check for path traversal components or double separators.
+ if (component.empty() || component == ".") {
+ needs_change = true;
+ } else if (remove_dot_dot && component == "..") {
+ needs_change = true;
+ // Do not allow ".." to remove the root component. If this is the
+ // beginning of a relative path, keep the ".." component.
if (!components.empty() && components.back() != "..") {
components.pop_back();
- continue;
+ } else if (!absolute) {
+ components.push_back(component);
}
- if (path::is_absolute(path, style))
- continue;
+ } else {
+ components.push_back(component);
}
- components.push_back(C);
}
- SmallString<256> buffer = path::root_path(path, style);
- for (StringRef C : components)
- path::append(buffer, style, C);
- return buffer;
-}
-
-bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot,
- Style style) {
- StringRef p(path.data(), path.size());
-
- SmallString<256> result = remove_dots(p, remove_dot_dot, style);
- if (result == path)
+ // Avoid rewriting the path unless we have to.
+ if (!needs_change)
return false;
- path.swap(result);
+ SmallString<256> buffer = root;
+ if (!components.empty()) {
+ buffer += components[0];
+ for (StringRef C : makeArrayRef(components).drop_front()) {
+ buffer += preferred_separator(style);
+ buffer += C;
+ }
+ }
+ the_path.swap(buffer);
return true;
}
@@ -1114,7 +1129,7 @@ void directory_entry::replace_filename(const Twine &Filename, file_type Type,
basic_file_status Status) {
SmallString<128> PathStr = path::parent_path(Path);
path::append(PathStr, Filename);
- this->Path = PathStr.str();
+ this->Path = std::string(PathStr.str());
this->Type = Type;
this->Status = Status;
}
@@ -1142,7 +1157,8 @@ ErrorOr<perms> getPermissions(const Twine &Path) {
namespace llvm {
namespace sys {
namespace fs {
-TempFile::TempFile(StringRef Name, int FD) : TmpName(Name), FD(FD) {}
+TempFile::TempFile(StringRef Name, int FD)
+ : TmpName(std::string(Name)), FD(FD) {}
TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); }
TempFile &TempFile::operator=(TempFile &&Other) {
TmpName = std::move(Other.TmpName);
diff --git a/llvm/lib/Support/PrettyStackTrace.cpp b/llvm/lib/Support/PrettyStackTrace.cpp
index bfb238cc85391..9072f9d2d2eef 100644
--- a/llvm/lib/Support/PrettyStackTrace.cpp
+++ b/llvm/lib/Support/PrettyStackTrace.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/raw_ostream.h"
#include <atomic>
+#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <tuple>
@@ -32,6 +33,10 @@
using namespace llvm;
+static const char *BugReportMsg =
+ "PLEASE submit a bug report to " BUG_REPORT_URL
+ " and include the crash backtrace.\n";
+
// 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.
@@ -144,6 +149,8 @@ static CrashHandlerStringStorage crashHandlerStringStorage;
/// This callback is run if a fatal signal is delivered to the process, it
/// prints the pretty stack trace.
static void CrashHandler(void *) {
+ errs() << BugReportMsg ;
+
#ifndef __APPLE__
// On non-apple systems, just emit the crash stack trace to stderr.
PrintCurStackTrace(errs());
@@ -195,6 +202,14 @@ static void printForSigInfoIfNeeded() {
#endif // ENABLE_BACKTRACES
+void llvm::setBugReportMsg(const char *Msg) {
+ BugReportMsg = Msg;
+}
+
+const char *llvm::getBugReportMsg() {
+ return BugReportMsg;
+}
+
PrettyStackTraceEntry::PrettyStackTraceEntry() {
#if ENABLE_BACKTRACES
// Handle SIGINFO first, because we haven't finished constructing yet.
diff --git a/llvm/lib/Support/Process.cpp b/llvm/lib/Support/Process.cpp
index 5b64710081597..9e6e233b26ac2 100644
--- a/llvm/lib/Support/Process.cpp
+++ b/llvm/lib/Support/Process.cpp
@@ -13,8 +13,9 @@
#include "llvm/Support/Process.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
@@ -55,7 +56,7 @@ Optional<std::string> Process::FindInEnvPath(StringRef EnvName,
SmallString<128> FilePath(Dir);
path::append(FilePath, FileName);
if (fs::exists(Twine(FilePath))) {
- FoundPath = FilePath.str();
+ FoundPath = std::string(FilePath.str());
break;
}
}
@@ -88,6 +89,13 @@ static bool coreFilesPrevented = !LLVM_ENABLE_CRASH_DUMPS;
bool Process::AreCoreFilesPrevented() { return coreFilesPrevented; }
+LLVM_ATTRIBUTE_NORETURN
+void Process::Exit(int RetCode) {
+ if (CrashRecoveryContext *CRC = CrashRecoveryContext::GetCurrent())
+ CRC->HandleExit(RetCode);
+ ::exit(RetCode);
+}
+
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Process.inc"
diff --git a/llvm/lib/Support/Program.cpp b/llvm/lib/Support/Program.cpp
index 0a9363c59fc68..5294f65bd5a54 100644
--- a/llvm/lib/Support/Program.cpp
+++ b/llvm/lib/Support/Program.cpp
@@ -13,6 +13,7 @@
#include "llvm/Support/Program.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/raw_ostream.h"
#include <system_error>
using namespace llvm;
using namespace sys;
@@ -31,14 +32,16 @@ int sys::ExecuteAndWait(StringRef Program, ArrayRef<StringRef> Args,
Optional<ArrayRef<StringRef>> Env,
ArrayRef<Optional<StringRef>> Redirects,
unsigned SecondsToWait, unsigned MemoryLimit,
- std::string *ErrMsg, bool *ExecutionFailed) {
+ std::string *ErrMsg, bool *ExecutionFailed,
+ Optional<ProcessStatistics> *ProcStat) {
assert(Redirects.empty() || Redirects.size() == 3);
ProcessInfo PI;
if (Execute(PI, Program, Args, Env, Redirects, MemoryLimit, ErrMsg)) {
if (ExecutionFailed)
*ExecutionFailed = false;
- ProcessInfo Result = Wait(
- PI, SecondsToWait, /*WaitUntilTerminates=*/SecondsToWait == 0, ErrMsg);
+ ProcessInfo Result =
+ Wait(PI, SecondsToWait, /*WaitUntilTerminates=*/SecondsToWait == 0,
+ ErrMsg, ProcStat);
return Result.ReturnCode;
}
@@ -73,6 +76,24 @@ bool sys::commandLineFitsWithinSystemLimits(StringRef Program,
return commandLineFitsWithinSystemLimits(Program, StringRefArgs);
}
+void sys::printArg(raw_ostream &OS, StringRef Arg, bool Quote) {
+ const bool Escape = Arg.find_first_of(" \"\\$") != StringRef::npos;
+
+ if (!Quote && !Escape) {
+ OS << Arg;
+ return;
+ }
+
+ // Quote and escape. This isn't really complete, but good enough.
+ OS << '"';
+ for (const auto c : Arg) {
+ if (c == '"' || c == '\\' || c == '$')
+ OS << '\\';
+ OS << c;
+ }
+ OS << '"';
+}
+
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Program.inc"
diff --git a/llvm/lib/Support/RISCVAttributeParser.cpp b/llvm/lib/Support/RISCVAttributeParser.cpp
new file mode 100644
index 0000000000000..393861c73a4a9
--- /dev/null
+++ b/llvm/lib/Support/RISCVAttributeParser.cpp
@@ -0,0 +1,67 @@
+//===-- RISCVAttributeParser.cpp - RISCV Attribute Parser -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace llvm;
+
+const RISCVAttributeParser::DisplayHandler
+ RISCVAttributeParser::displayRoutines[] = {
+ {
+ RISCVAttrs::ARCH,
+ &ELFAttributeParser::stringAttribute,
+ },
+ {
+ RISCVAttrs::PRIV_SPEC,
+ &ELFAttributeParser::integerAttribute,
+ },
+ {
+ RISCVAttrs::PRIV_SPEC_MINOR,
+ &ELFAttributeParser::integerAttribute,
+ },
+ {
+ RISCVAttrs::PRIV_SPEC_REVISION,
+ &ELFAttributeParser::integerAttribute,
+ },
+ {
+ RISCVAttrs::STACK_ALIGN,
+ &RISCVAttributeParser::stackAlign,
+ },
+ {
+ RISCVAttrs::UNALIGNED_ACCESS,
+ &RISCVAttributeParser::unalignedAccess,
+ }};
+
+Error RISCVAttributeParser::unalignedAccess(unsigned tag) {
+ static const char *strings[] = {"No unaligned access", "Unaligned access"};
+ return parseStringAttribute("Unaligned_access", tag, makeArrayRef(strings));
+}
+
+Error RISCVAttributeParser::stackAlign(unsigned tag) {
+ uint64_t value = de.getULEB128(cursor);
+ std::string description =
+ "Stack alignment is " + utostr(value) + std::string("-bytes");
+ printAttribute(tag, value, description);
+ return Error::success();
+}
+
+Error RISCVAttributeParser::handler(uint64_t tag, bool &handled) {
+ handled = false;
+ for (unsigned AHI = 0, AHE = array_lengthof(displayRoutines); AHI != AHE;
+ ++AHI) {
+ if (uint64_t(displayRoutines[AHI].attribute) == tag) {
+ if (Error e = (this->*displayRoutines[AHI].routine)(tag))
+ return e;
+ handled = true;
+ break;
+ }
+ }
+
+ return Error::success();
+}
diff --git a/llvm/lib/Support/RISCVAttributes.cpp b/llvm/lib/Support/RISCVAttributes.cpp
new file mode 100644
index 0000000000000..201048e03009b
--- /dev/null
+++ b/llvm/lib/Support/RISCVAttributes.cpp
@@ -0,0 +1,25 @@
+//===-- RISCVAttributes.cpp - RISCV Attributes ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/RISCVAttributes.h"
+
+using namespace llvm;
+using namespace llvm::RISCVAttrs;
+
+static const TagNameItem tagData[] = {
+ {STACK_ALIGN, "Tag_stack_align"},
+ {ARCH, "Tag_arch"},
+ {UNALIGNED_ACCESS, "Tag_unaligned_access"},
+ {PRIV_SPEC, "Tag_priv_spec"},
+ {PRIV_SPEC_MINOR, "Tag_priv_spec_minor"},
+ {PRIV_SPEC_REVISION, "Tag_priv_spec_revision"},
+};
+
+const TagNameMap llvm::RISCVAttrs::RISCVAttributeTags(tagData,
+ sizeof(tagData) /
+ sizeof(TagNameItem));
diff --git a/llvm/lib/Support/RandomNumberGenerator.cpp b/llvm/lib/Support/RandomNumberGenerator.cpp
index 09fad19799859..f9c41ee5eaaf0 100644
--- a/llvm/lib/Support/RandomNumberGenerator.cpp
+++ b/llvm/lib/Support/RandomNumberGenerator.cpp
@@ -17,7 +17,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#ifdef _WIN32
-#include "Windows/WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#else
#include "Unix/Unix.h"
#endif
diff --git a/llvm/lib/Support/Regex.cpp b/llvm/lib/Support/Regex.cpp
index 8da345d4f1404..0d5cc1c00db11 100644
--- a/llvm/lib/Support/Regex.cpp
+++ b/llvm/lib/Support/Regex.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include <cassert>
#include <string>
// Important this comes last because it defines "_REGEX_H_". At least on
@@ -25,7 +26,7 @@ using namespace llvm;
Regex::Regex() : preg(nullptr), error(REG_BADPAT) {}
-Regex::Regex(StringRef regex, unsigned Flags) {
+Regex::Regex(StringRef regex, RegexFlags Flags) {
unsigned flags = 0;
preg = new llvm_regex();
preg->re_endp = regex.end();
@@ -38,6 +39,9 @@ Regex::Regex(StringRef regex, unsigned Flags) {
error = llvm_regcomp(preg, regex.data(), flags|REG_PEND);
}
+Regex::Regex(StringRef regex, unsigned Flags)
+ : Regex(regex, static_cast<RegexFlags>(Flags)) {}
+
Regex::Regex(Regex &&regex) {
preg = regex.preg;
error = regex.error;
@@ -135,7 +139,7 @@ std::string Regex::sub(StringRef Repl, StringRef String,
// Return the input if there was no match.
if (!match(String, &Matches, Error))
- return String;
+ return std::string(String);
// Otherwise splice in the replacement string, starting with the prefix before
// the match.
diff --git a/llvm/lib/Support/SHA1.cpp b/llvm/lib/Support/SHA1.cpp
index a98ca41a33545..417b13fea05a4 100644
--- a/llvm/lib/Support/SHA1.cpp
+++ b/llvm/lib/Support/SHA1.cpp
@@ -16,13 +16,13 @@
#include "llvm/Support/SHA1.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Host.h"
-using namespace llvm;
-
-#include <stdint.h>
#include <string.h>
+using namespace llvm;
+
#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
#define SHA_BIG_ENDIAN
#endif
@@ -238,6 +238,11 @@ void SHA1::update(ArrayRef<uint8_t> Data) {
addUncounted(C);
}
+void SHA1::update(StringRef Str) {
+ update(
+ ArrayRef<uint8_t>((uint8_t *)const_cast<char *>(Str.data()), Str.size()));
+}
+
void SHA1::pad() {
// Implement SHA-1 padding (fips180-2 5.1.1)
diff --git a/llvm/lib/Support/Signals.cpp b/llvm/lib/Support/Signals.cpp
index add6fde0eb5ea..2cfdf2d42a4a9 100644
--- a/llvm/lib/Support/Signals.cpp
+++ b/llvm/lib/Support/Signals.cpp
@@ -131,7 +131,7 @@ 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 =
- sys::fs::exists(Argv0) ? (std::string)Argv0
+ sys::fs::exists(Argv0) ? (std::string)std::string(Argv0)
: sys::fs::getMainExecutable(nullptr, nullptr);
BumpPtrAllocator Allocator;
StringSaver StrPool(Allocator);
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index 36f0a81f6b00d..6d5fe7165f633 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
+#include <cstdint>
using namespace llvm;
// Check that no bytes are wasted and everything is well-aligned.
@@ -37,17 +38,30 @@ static_assert(sizeof(SmallVector<void *, 1>) ==
sizeof(unsigned) * 2 + sizeof(void *) * 2,
"wasted space in SmallVector size 1");
-/// grow_pod - This is an implementation of the grow() method which only works
-/// on POD-like datatypes and is out of line to reduce code duplication.
-void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
- size_t TSize) {
- // Ensure we can fit the new capacity in 32 bits.
- if (MinCapacity > UINT32_MAX)
+static_assert(sizeof(SmallVector<char, 0>) ==
+ sizeof(void *) * 2 + sizeof(void *),
+ "1 byte elements have word-sized type for size and capacity");
+
+// Note: Moving this function into the header may cause performance regression.
+template <class Size_T>
+void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinCapacity,
+ size_t TSize) {
+ // Ensure we can fit the new capacity.
+ // This is only going to be applicable when the capacity is 32 bit.
+ if (MinCapacity > SizeTypeMax())
report_bad_alloc_error("SmallVector capacity overflow during allocation");
+ // Ensure we can meet the guarantee of space for at least one more element.
+ // The above check alone will not catch the case where grow is called with a
+ // default MinCapacity of 0, but the current capacity cannot be increased.
+ // This is only going to be applicable when the capacity is 32 bit.
+ if (capacity() == SizeTypeMax())
+ report_bad_alloc_error("SmallVector capacity unable to grow");
+
+ // In theory 2*capacity can overflow if the capacity is 64 bit, but the
+ // original capacity would never be large enough for this to be a problem.
size_t NewCapacity = 2 * capacity() + 1; // Always grow.
- NewCapacity =
- std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
+ NewCapacity = std::min(std::max(NewCapacity, MinCapacity), SizeTypeMax());
void *NewElts;
if (BeginX == FirstEl) {
@@ -63,3 +77,20 @@ void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
this->BeginX = NewElts;
this->Capacity = NewCapacity;
}
+
+template class llvm::SmallVectorBase<uint32_t>;
+
+// Disable the uint64_t instantiation for 32-bit builds.
+// Both uint32_t and uint64_t instantations are needed for 64-bit builds.
+// This instantiation will never be used in 32-bit builds, and will cause
+// warnings when sizeof(Size_T) > sizeof(size_t).
+#if SIZE_MAX > UINT32_MAX
+template class llvm::SmallVectorBase<uint64_t>;
+
+// Assertions to ensure this #if stays in sync with SmallVectorSizeType.
+static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint64_t),
+ "Expected SmallVectorBase<uint64_t> variant to be in use.");
+#else
+static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint32_t),
+ "Expected SmallVectorBase<uint32_t> variant to be in use.");
+#endif
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index 2a241f18c3627..9cc69732a9647 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -42,7 +42,7 @@ unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
std::string &IncludedFile) {
IncludedFile = Filename;
ErrorOr<std::unique_ptr<MemoryBuffer>> NewBufOrErr =
- MemoryBuffer::getFile(IncludedFile);
+ MemoryBuffer::getFile(IncludedFile);
// If the file didn't exist directly, see if it's in an include path.
for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBufOrErr;
@@ -69,54 +69,109 @@ unsigned SourceMgr::FindBufferContainingLoc(SMLoc Loc) const {
}
template <typename T>
-unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
-
- // Ensure OffsetCache is allocated and populated with offsets of all the
- // '\n' bytes.
- std::vector<T> *Offsets = nullptr;
- if (OffsetCache.isNull()) {
- Offsets = new std::vector<T>();
- OffsetCache = Offsets;
- size_t Sz = Buffer->getBufferSize();
- assert(Sz <= std::numeric_limits<T>::max());
- StringRef S = Buffer->getBuffer();
- for (size_t N = 0; N < Sz; ++N) {
- if (S[N] == '\n') {
- Offsets->push_back(static_cast<T>(N));
- }
- }
- } else {
- Offsets = OffsetCache.get<std::vector<T> *>();
+static std::vector<T> &GetOrCreateOffsetCache(void *&OffsetCache,
+ MemoryBuffer *Buffer) {
+ if (OffsetCache)
+ return *static_cast<std::vector<T> *>(OffsetCache);
+
+ // Lazily fill in the offset cache.
+ auto *Offsets = new std::vector<T>();
+ size_t Sz = Buffer->getBufferSize();
+ assert(Sz <= std::numeric_limits<T>::max());
+ StringRef S = Buffer->getBuffer();
+ for (size_t N = 0; N < Sz; ++N) {
+ if (S[N] == '\n')
+ Offsets->push_back(static_cast<T>(N));
}
+ OffsetCache = Offsets;
+ return *Offsets;
+}
+
+template <typename T>
+unsigned SourceMgr::SrcBuffer::getLineNumberSpecialized(const char *Ptr) const {
+ std::vector<T> &Offsets =
+ GetOrCreateOffsetCache<T>(OffsetCache, Buffer.get());
+
const char *BufStart = Buffer->getBufferStart();
assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
ptrdiff_t PtrDiff = Ptr - BufStart;
- assert(PtrDiff >= 0 && static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
+ assert(PtrDiff >= 0 &&
+ static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
T PtrOffset = static_cast<T>(PtrDiff);
// 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;
+ return llvm::lower_bound(Offsets, PtrOffset) - Offsets.begin() + 1;
+}
+
+/// Look up a given \p Ptr in in the buffer, determining which line it came
+/// from.
+unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
+ size_t Sz = Buffer->getBufferSize();
+ if (Sz <= std::numeric_limits<uint8_t>::max())
+ return getLineNumberSpecialized<uint8_t>(Ptr);
+ else if (Sz <= std::numeric_limits<uint16_t>::max())
+ return getLineNumberSpecialized<uint16_t>(Ptr);
+ else if (Sz <= std::numeric_limits<uint32_t>::max())
+ return getLineNumberSpecialized<uint32_t>(Ptr);
+ else
+ return getLineNumberSpecialized<uint64_t>(Ptr);
+}
+
+template <typename T>
+const char *SourceMgr::SrcBuffer::getPointerForLineNumberSpecialized(
+ unsigned LineNo) const {
+ std::vector<T> &Offsets =
+ GetOrCreateOffsetCache<T>(OffsetCache, Buffer.get());
+
+ // We start counting line and column numbers from 1.
+ if (LineNo != 0)
+ --LineNo;
+
+ const char *BufStart = Buffer->getBufferStart();
+
+ // The offset cache contains the location of the \n for the specified line,
+ // we want the start of the line. As such, we look for the previous entry.
+ if (LineNo == 0)
+ return BufStart;
+ if (LineNo > Offsets.size())
+ return nullptr;
+ return BufStart + Offsets[LineNo - 1] + 1;
+}
+
+/// Return a pointer to the first character of the specified line number or
+/// null if the line number is invalid.
+const char *
+SourceMgr::SrcBuffer::getPointerForLineNumber(unsigned LineNo) const {
+ size_t Sz = Buffer->getBufferSize();
+ if (Sz <= std::numeric_limits<uint8_t>::max())
+ return getPointerForLineNumberSpecialized<uint8_t>(LineNo);
+ else if (Sz <= std::numeric_limits<uint16_t>::max())
+ return getPointerForLineNumberSpecialized<uint16_t>(LineNo);
+ else if (Sz <= std::numeric_limits<uint32_t>::max())
+ return getPointerForLineNumberSpecialized<uint32_t>(LineNo);
+ else
+ return getPointerForLineNumberSpecialized<uint64_t>(LineNo);
}
SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&Other)
- : Buffer(std::move(Other.Buffer)),
- OffsetCache(Other.OffsetCache),
- IncludeLoc(Other.IncludeLoc) {
+ : Buffer(std::move(Other.Buffer)), OffsetCache(Other.OffsetCache),
+ IncludeLoc(Other.IncludeLoc) {
Other.OffsetCache = nullptr;
}
SourceMgr::SrcBuffer::~SrcBuffer() {
- if (!OffsetCache.isNull()) {
- if (OffsetCache.is<std::vector<uint8_t>*>())
- delete OffsetCache.get<std::vector<uint8_t>*>();
- else if (OffsetCache.is<std::vector<uint16_t>*>())
- delete OffsetCache.get<std::vector<uint16_t>*>();
- else if (OffsetCache.is<std::vector<uint32_t>*>())
- delete OffsetCache.get<std::vector<uint32_t>*>();
+ if (OffsetCache) {
+ size_t Sz = Buffer->getBufferSize();
+ if (Sz <= std::numeric_limits<uint8_t>::max())
+ delete static_cast<std::vector<uint8_t> *>(OffsetCache);
+ else if (Sz <= std::numeric_limits<uint16_t>::max())
+ delete static_cast<std::vector<uint16_t> *>(OffsetCache);
+ else if (Sz <= std::numeric_limits<uint32_t>::max())
+ delete static_cast<std::vector<uint32_t> *>(OffsetCache);
else
- delete OffsetCache.get<std::vector<uint64_t>*>();
+ delete static_cast<std::vector<uint64_t> *>(OffsetCache);
OffsetCache = nullptr;
}
}
@@ -130,39 +185,58 @@ SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
auto &SB = getBufferInfo(BufferID);
const char *Ptr = Loc.getPointer();
- size_t Sz = SB.Buffer->getBufferSize();
- unsigned LineNo;
- if (Sz <= std::numeric_limits<uint8_t>::max())
- LineNo = SB.getLineNumber<uint8_t>(Ptr);
- else if (Sz <= std::numeric_limits<uint16_t>::max())
- LineNo = SB.getLineNumber<uint16_t>(Ptr);
- else if (Sz <= std::numeric_limits<uint32_t>::max())
- LineNo = SB.getLineNumber<uint32_t>(Ptr);
- else
- LineNo = SB.getLineNumber<uint64_t>(Ptr);
-
+ unsigned LineNo = SB.getLineNumber(Ptr);
const char *BufStart = SB.Buffer->getBufferStart();
- size_t NewlineOffs = StringRef(BufStart, Ptr-BufStart).find_last_of("\n\r");
- if (NewlineOffs == StringRef::npos) NewlineOffs = ~(size_t)0;
- return std::make_pair(LineNo, Ptr-BufStart-NewlineOffs);
+ size_t NewlineOffs = StringRef(BufStart, Ptr - BufStart).find_last_of("\n\r");
+ if (NewlineOffs == StringRef::npos)
+ NewlineOffs = ~(size_t)0;
+ return std::make_pair(LineNo, Ptr - BufStart - NewlineOffs);
+}
+
+/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
+/// This will return a null SMLoc if the line/column location is invalid.
+SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
+ unsigned ColNo) {
+ auto &SB = getBufferInfo(BufferID);
+ const char *Ptr = SB.getPointerForLineNumber(LineNo);
+ if (!Ptr)
+ return SMLoc();
+
+ // We start counting line and column numbers from 1.
+ if (ColNo != 0)
+ --ColNo;
+
+ // If we have a column number, validate it.
+ if (ColNo) {
+ // Make sure the location is within the current line.
+ if (Ptr + ColNo > SB.Buffer->getBufferEnd())
+ return SMLoc();
+
+ // Make sure there is no newline in the way.
+ if (StringRef(Ptr, ColNo).find_first_of("\n\r") != StringRef::npos)
+ return SMLoc();
+
+ Ptr += ColNo;
+ }
+
+ return SMLoc::getFromPointer(Ptr);
}
void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const {
- if (IncludeLoc == SMLoc()) return; // Top of stack.
+ if (IncludeLoc == SMLoc())
+ return; // Top of stack.
unsigned CurBuf = FindBufferContainingLoc(IncludeLoc);
assert(CurBuf && "Invalid or unspecified location!");
PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc, OS);
- OS << "Included from "
- << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
+ OS << "Included from " << getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
<< ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n";
}
SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
- const Twine &Msg,
- ArrayRef<SMRange> Ranges,
+ const Twine &Msg, ArrayRef<SMRange> Ranges,
ArrayRef<SMFixIt> FixIts) const {
// First thing to do: find the current buffer containing the specified
// location to pull out the source line.
@@ -196,7 +270,8 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
// location.
for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
SMRange R = Ranges[i];
- if (!R.isValid()) continue;
+ if (!R.isValid())
+ continue;
// If the line doesn't contain any part of the range, then ignore it.
if (R.Start.getPointer() > LineEnd || R.End.getPointer() < LineStart)
@@ -210,16 +285,16 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
// Translate from SMLoc ranges to column ranges.
// FIXME: Handle multibyte characters.
- ColRanges.push_back(std::make_pair(R.Start.getPointer()-LineStart,
- R.End.getPointer()-LineStart));
+ ColRanges.push_back(std::make_pair(R.Start.getPointer() - LineStart,
+ R.End.getPointer() - LineStart));
}
LineAndCol = getLineAndColumn(Loc, CurBuf);
}
return SMDiagnostic(*this, Loc, BufferID, LineAndCol.first,
- LineAndCol.second-1, Kind, Msg.str(),
- LineStr, ColRanges, FixIts);
+ LineAndCol.second - 1, Kind, Msg.str(), LineStr,
+ ColRanges, FixIts);
}
void SourceMgr::PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
@@ -240,9 +315,9 @@ void SourceMgr::PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
}
void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc,
- SourceMgr::DiagKind Kind,
- const Twine &Msg, ArrayRef<SMRange> Ranges,
- ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
+ SourceMgr::DiagKind Kind, const Twine &Msg,
+ ArrayRef<SMRange> Ranges, ArrayRef<SMFixIt> FixIts,
+ bool ShowColors) const {
PrintMessage(OS, GetMessage(Loc, Kind, Msg, Ranges, FixIts), ShowColors);
}
@@ -253,22 +328,32 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
}
//===----------------------------------------------------------------------===//
+// SMFixIt Implementation
+//===----------------------------------------------------------------------===//
+
+SMFixIt::SMFixIt(SMRange R, const Twine &Replacement)
+ : Range(R), Text(Replacement.str()) {
+ assert(R.isValid());
+}
+
+//===----------------------------------------------------------------------===//
// SMDiagnostic Implementation
//===----------------------------------------------------------------------===//
-SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN,
- int Line, int Col, SourceMgr::DiagKind Kind,
- StringRef Msg, StringRef LineStr,
- ArrayRef<std::pair<unsigned,unsigned>> Ranges,
+SMDiagnostic::SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, int Line,
+ int Col, SourceMgr::DiagKind Kind, StringRef Msg,
+ StringRef LineStr,
+ ArrayRef<std::pair<unsigned, unsigned>> Ranges,
ArrayRef<SMFixIt> Hints)
- : SM(&sm), Loc(L), Filename(FN), LineNo(Line), ColumnNo(Col), Kind(Kind),
- Message(Msg), LineContents(LineStr), Ranges(Ranges.vec()),
- FixIts(Hints.begin(), Hints.end()) {
+ : SM(&sm), Loc(L), Filename(std::string(FN)), LineNo(Line), ColumnNo(Col),
+ Kind(Kind), Message(std::string(Msg)), LineContents(std::string(LineStr)),
+ Ranges(Ranges.vec()), FixIts(Hints.begin(), Hints.end()) {
llvm::sort(FixIts);
}
static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
- ArrayRef<SMFixIt> FixIts, ArrayRef<char> SourceLine){
+ ArrayRef<SMFixIt> FixIts,
+ ArrayRef<char> SourceLine) {
if (FixIts.empty())
return;
@@ -277,8 +362,8 @@ static void buildFixItLine(std::string &CaretLine, std::string &FixItLine,
size_t PrevHintEndCol = 0;
- for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end();
- I != E; ++I) {
+ for (ArrayRef<SMFixIt>::iterator I = FixIts.begin(), E = FixIts.end(); I != E;
+ ++I) {
// If the fixit contains a newline or tab, ignore it.
if (I->getText().find_first_of("\n\r\t") != StringRef::npos)
continue;
@@ -361,14 +446,14 @@ static void printSourceLine(raw_ostream &S, StringRef LineContents) {
S << '\n';
}
-static bool isNonASCII(char c) {
- return c & 0x80;
-}
+static bool isNonASCII(char c) { return c & 0x80; }
+
+void SMDiagnostic::print(const char *ProgName, raw_ostream &OS, bool ShowColors,
+ bool ShowKindLabel) const {
+ ColorMode Mode = ShowColors ? ColorMode::Auto : ColorMode::Disable;
-void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
- bool ShowColors, bool ShowKindLabel) const {
{
- WithColor S(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors);
+ WithColor S(OS, raw_ostream::SAVEDCOLOR, true, false, Mode);
if (ProgName && ProgName[0])
S << ProgName << ": ";
@@ -405,8 +490,7 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
}
}
- WithColor(OS, raw_ostream::SAVEDCOLOR, true, false, !ShowColors)
- << Message << '\n';
+ WithColor(OS, raw_ostream::SAVEDCOLOR, true, false, Mode) << Message << '\n';
if (LineNo == -1 || ColumnNo == -1)
return;
@@ -423,22 +507,21 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
size_t NumColumns = LineContents.size();
// Build the line with the caret and ranges.
- std::string CaretLine(NumColumns+1, ' ');
+ std::string CaretLine(NumColumns + 1, ' ');
// Expand any ranges.
for (unsigned r = 0, e = Ranges.size(); r != e; ++r) {
std::pair<unsigned, unsigned> R = Ranges[r];
std::fill(&CaretLine[R.first],
- &CaretLine[std::min((size_t)R.second, CaretLine.size())],
- '~');
+ &CaretLine[std::min((size_t)R.second, CaretLine.size())], '~');
}
// Add any fix-its.
// FIXME: Find the beginning of the line properly for multibyte characters.
std::string FixItInsertionLine;
- buildFixItLine(CaretLine, FixItInsertionLine, FixIts,
- makeArrayRef(Loc.getPointer() - ColumnNo,
- LineContents.size()));
+ buildFixItLine(
+ CaretLine, FixItInsertionLine, FixIts,
+ makeArrayRef(Loc.getPointer() - ColumnNo, LineContents.size()));
// Finally, plop on the caret.
if (unsigned(ColumnNo) <= NumColumns)
@@ -449,12 +532,13 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &OS,
// ... and remove trailing whitespace so the output doesn't wrap for it. We
// know that the line isn't completely empty because it has the caret in it at
// least.
- CaretLine.erase(CaretLine.find_last_not_of(' ')+1);
+ CaretLine.erase(CaretLine.find_last_not_of(' ') + 1);
printSourceLine(OS, LineContents);
{
- WithColor S(OS, raw_ostream::GREEN, true, false, !ShowColors);
+ ColorMode Mode = ShowColors ? ColorMode::Auto : ColorMode::Disable;
+ WithColor S(OS, raw_ostream::GREEN, true, false, Mode);
// Print out the caret line, matching tabs in the source line.
for (unsigned i = 0, e = CaretLine.size(), OutCol = 0; i != e; ++i) {
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index d1ff44cefb086..73f852624a697 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -126,7 +126,7 @@ bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
bool SpecialCaseList::parse(const MemoryBuffer *MB,
StringMap<size_t> &SectionsMap,
std::string &Error) {
- // Iterate through each line in the blacklist file.
+ // Iterate through each line in the exclusion list file.
SmallVector<StringRef, 16> Lines;
MB->getBuffer().split(Lines, '\n');
@@ -172,14 +172,14 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB,
}
std::pair<StringRef, StringRef> SplitRegexp = SplitLine.second.split("=");
- std::string Regexp = SplitRegexp.first;
+ std::string Regexp = std::string(SplitRegexp.first);
StringRef Category = SplitRegexp.second;
// Create this section if it has not been seen before.
if (SectionsMap.find(Section) == SectionsMap.end()) {
std::unique_ptr<Matcher> M = std::make_unique<Matcher>();
std::string REError;
- if (!M->insert(Section, LineNo, REError)) {
+ if (!M->insert(std::string(Section), LineNo, REError)) {
Error = (Twine("malformed section ") + Section + ": '" + REError).str();
return false;
}
diff --git a/llvm/lib/Support/Statistic.cpp b/llvm/lib/Support/Statistic.cpp
index 25f13871e2e42..e9308ab575abe 100644
--- a/llvm/lib/Support/Statistic.cpp
+++ b/llvm/lib/Support/Statistic.cpp
@@ -246,7 +246,7 @@ void llvm::PrintStatistics() {
// Get the stream to write to.
std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
(*OutStream) << "Statistics are disabled. "
- << "Build with asserts or with -DLLVM_ENABLE_STATS\n";
+ << "Build with asserts or with -DLLVM_FORCE_ENABLE_STATS\n";
}
#endif
}
diff --git a/llvm/lib/Support/StringExtras.cpp b/llvm/lib/Support/StringExtras.cpp
index af8dd463e125d..c206bd214519c 100644
--- a/llvm/lib/Support/StringExtras.cpp
+++ b/llvm/lib/Support/StringExtras.cpp
@@ -13,6 +13,8 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
+#include <cctype>
+
using namespace llvm;
/// StrInStrNoCase - Portable version of strcasestr. Locates the first
@@ -90,3 +92,46 @@ void llvm::printLowerCase(StringRef String, raw_ostream &Out) {
for (const char C : String)
Out << toLower(C);
}
+
+std::string llvm::convertToSnakeFromCamelCase(StringRef input) {
+ if (input.empty())
+ return "";
+
+ std::string snakeCase;
+ snakeCase.reserve(input.size());
+ for (char c : input) {
+ if (!std::isupper(c)) {
+ snakeCase.push_back(c);
+ continue;
+ }
+
+ if (!snakeCase.empty() && snakeCase.back() != '_')
+ snakeCase.push_back('_');
+ snakeCase.push_back(llvm::toLower(c));
+ }
+ return snakeCase;
+}
+
+std::string llvm::convertToCamelFromSnakeCase(StringRef input,
+ bool capitalizeFirst) {
+ if (input.empty())
+ return "";
+
+ std::string output;
+ output.reserve(input.size());
+
+ // Push the first character, capatilizing if necessary.
+ if (capitalizeFirst && std::islower(input.front()))
+ output.push_back(llvm::toUpper(input.front()));
+ else
+ output.push_back(input.front());
+
+ // Walk the input converting any `*_[a-z]` snake case into `*[A-Z]` camelCase.
+ for (size_t pos = 1, e = input.size(); pos < e; ++pos) {
+ if (input[pos] == '_' && pos != (e - 1) && std::islower(input[pos + 1]))
+ output.push_back(llvm::toUpper(input[++pos]));
+ else
+ output.push_back(input[pos]);
+ }
+ return output;
+}
diff --git a/llvm/lib/Support/StringMap.cpp b/llvm/lib/Support/StringMap.cpp
index 6b5ea020dd46d..f65d3846623c8 100644
--- a/llvm/lib/Support/StringMap.cpp
+++ b/llvm/lib/Support/StringMap.cpp
@@ -12,10 +12,8 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/MathExtras.h"
-#include <cassert>
using namespace llvm;
@@ -50,23 +48,22 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
}
void StringMapImpl::init(unsigned InitSize) {
- assert((InitSize & (InitSize-1)) == 0 &&
+ assert((InitSize & (InitSize - 1)) == 0 &&
"Init Size must be a power of 2 or zero!");
unsigned NewNumBuckets = InitSize ? InitSize : 16;
NumItems = 0;
NumTombstones = 0;
- TheTable = static_cast<StringMapEntryBase **>(
- safe_calloc(NewNumBuckets+1,
- sizeof(StringMapEntryBase **) + sizeof(unsigned)));
+ TheTable = static_cast<StringMapEntryBase **>(safe_calloc(
+ NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
// Set the member only if TheTable was successfully allocated
NumBuckets = NewNumBuckets;
// Allocate one extra bucket, set it to look filled so the iterators stop at
// end.
- TheTable[NumBuckets] = (StringMapEntryBase*)2;
+ TheTable[NumBuckets] = (StringMapEntryBase *)2;
}
/// LookupBucketFor - Look up the bucket that the specified string should end
@@ -76,12 +73,12 @@ void StringMapImpl::init(unsigned InitSize) {
/// of the string.
unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
unsigned HTSize = NumBuckets;
- if (HTSize == 0) { // Hash table unallocated so far?
+ if (HTSize == 0) { // Hash table unallocated so far?
init(16);
HTSize = NumBuckets;
}
unsigned FullHashValue = djbHash(Name, 0);
- unsigned BucketNo = FullHashValue & (HTSize-1);
+ unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
@@ -103,7 +100,8 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
if (BucketItem == getTombstoneVal()) {
// Skip over tombstones. However, remember the first one we see.
- if (FirstTombstone == -1) FirstTombstone = BucketNo;
+ if (FirstTombstone == -1)
+ FirstTombstone = BucketNo;
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
// If the full hash value matches, check deeply for a match. The common
// case here is that we are only looking at the buckets (for item info
@@ -112,7 +110,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
// Do the comparison like this because Name isn't necessarily
// null-terminated!
- char *ItemStr = (char*)BucketItem+ItemSize;
+ char *ItemStr = (char *)BucketItem + ItemSize;
if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) {
// We found a match!
return BucketNo;
@@ -120,7 +118,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
}
// Okay, we didn't find the item. Probe to the next bucket.
- BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
+ BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
// Use quadratic probing, it has fewer clumping artifacts than linear
// probing and has good cache behavior in the common case.
@@ -133,9 +131,10 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
/// This does not modify the map.
int StringMapImpl::FindKey(StringRef Key) const {
unsigned HTSize = NumBuckets;
- if (HTSize == 0) return -1; // Really empty table?
+ if (HTSize == 0)
+ return -1; // Really empty table?
unsigned FullHashValue = djbHash(Key, 0);
- unsigned BucketNo = FullHashValue & (HTSize-1);
+ unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
@@ -155,7 +154,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
// Do the comparison like this because NameStart isn't necessarily
// null-terminated!
- char *ItemStr = (char*)BucketItem+ItemSize;
+ char *ItemStr = (char *)BucketItem + ItemSize;
if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) {
// We found a match!
return BucketNo;
@@ -163,7 +162,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
}
// Okay, we didn't find the item. Probe to the next bucket.
- BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
+ BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
// Use quadratic probing, it has fewer clumping artifacts than linear
// probing and has good cache behavior in the common case.
@@ -174,7 +173,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
/// delete it. This aborts if the value isn't in the table.
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
- const char *VStr = (char*)V + ItemSize;
+ const char *VStr = (char *)V + ItemSize;
StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength()));
(void)V2;
assert(V == V2 && "Didn't find key?");
@@ -184,7 +183,8 @@ void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
/// table, returning it. If the key is not in the table, this returns null.
StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
int Bucket = FindKey(Key);
- if (Bucket == -1) return nullptr;
+ if (Bucket == -1)
+ return nullptr;
StringMapEntryBase *Result = TheTable[Bucket];
TheTable[Bucket] = getTombstoneVal();
@@ -205,7 +205,7 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
// the buckets are empty (meaning that many are filled with tombstones),
// grow/rehash the table.
if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
- NewSize = NumBuckets*2;
+ NewSize = NumBuckets * 2;
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
NumBuckets / 8)) {
NewSize = NumBuckets;
@@ -216,11 +216,11 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
unsigned NewBucketNo = BucketNo;
// Allocate one extra bucket which will always be non-empty. This allows the
// iterators to stop at end.
- auto NewTableArray = static_cast<StringMapEntryBase **>(
- safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
+ auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
+ NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
- NewTableArray[NewSize] = (StringMapEntryBase*)2;
+ NewTableArray[NewSize] = (StringMapEntryBase *)2;
// Rehash all the items into their new buckets. Luckily :) we already have
// the hash values available, so we don't have to rehash any strings.
@@ -229,10 +229,10 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
if (Bucket && Bucket != getTombstoneVal()) {
// Fast case, bucket available.
unsigned FullHash = HashTable[I];
- unsigned NewBucket = FullHash & (NewSize-1);
+ unsigned NewBucket = FullHash & (NewSize - 1);
if (!NewTableArray[NewBucket]) {
- NewTableArray[FullHash & (NewSize-1)] = Bucket;
- NewHashArray[FullHash & (NewSize-1)] = FullHash;
+ NewTableArray[FullHash & (NewSize - 1)] = Bucket;
+ NewHashArray[FullHash & (NewSize - 1)] = FullHash;
if (I == BucketNo)
NewBucketNo = NewBucket;
continue;
@@ -241,7 +241,7 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
// Otherwise probe for a spot.
unsigned ProbeSize = 1;
do {
- NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
+ NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
} while (NewTableArray[NewBucket]);
// Finally found a slot. Fill it in.
diff --git a/llvm/lib/Support/StringPool.cpp b/llvm/lib/Support/StringPool.cpp
deleted file mode 100644
index 82351017b8cca..0000000000000
--- a/llvm/lib/Support/StringPool.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//===-- StringPool.cpp - Interned string pool -----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the StringPool class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/StringPool.h"
-#include "llvm/ADT/StringRef.h"
-
-using namespace llvm;
-
-StringPool::StringPool() {}
-
-StringPool::~StringPool() {
- assert(InternTable.empty() && "PooledStringPtr leaked!");
-}
-
-PooledStringPtr StringPool::intern(StringRef Key) {
- table_t::iterator I = InternTable.find(Key);
- if (I != InternTable.end())
- return PooledStringPtr(&*I);
-
- entry_t *S = entry_t::Create(Key);
- S->getValue().Pool = this;
- InternTable.insert(S);
-
- return PooledStringPtr(S);
-}
diff --git a/llvm/lib/Support/StringRef.cpp b/llvm/lib/Support/StringRef.cpp
index 104482de4ad70..ab67ef9ce85c1 100644
--- a/llvm/lib/Support/StringRef.cpp
+++ b/llvm/lib/Support/StringRef.cpp
@@ -19,7 +19,7 @@ using namespace llvm;
// MSVC emits references to this into the translation units which reference it.
#ifndef _MSC_VER
-const size_t StringRef::npos;
+constexpr size_t StringRef::npos;
#endif
// strncasecmp() is not available on non-POSIX systems, so define an
@@ -106,19 +106,13 @@ unsigned StringRef::edit_distance(llvm::StringRef Other,
//===----------------------------------------------------------------------===//
std::string StringRef::lower() const {
- std::string Result(size(), char());
- for (size_type i = 0, e = size(); i != e; ++i) {
- Result[i] = toLower(Data[i]);
- }
- return Result;
+ return std::string(map_iterator(begin(), toLower),
+ map_iterator(end(), toLower));
}
std::string StringRef::upper() const {
- std::string Result(size(), char());
- for (size_type i = 0, e = size(); i != e; ++i) {
- Result[i] = toUpper(Data[i]);
- }
- return Result;
+ return std::string(map_iterator(begin(), toUpper),
+ map_iterator(end(), toUpper));
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Support/SuffixTree.cpp b/llvm/lib/Support/SuffixTree.cpp
new file mode 100644
index 0000000000000..0d419f12cd1d6
--- /dev/null
+++ b/llvm/lib/Support/SuffixTree.cpp
@@ -0,0 +1,210 @@
+//===- llvm/Support/SuffixTree.cpp - Implement Suffix Tree ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Suffix Tree class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/SuffixTree.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+using namespace llvm;
+
+SuffixTree::SuffixTree(const std::vector<unsigned> &Str) : Str(Str) {
+ Root = insertInternalNode(nullptr, EmptyIdx, EmptyIdx, 0);
+ Active.Node = Root;
+
+ // Keep track of the number of suffixes we have to add of the current
+ // prefix.
+ unsigned SuffixesToAdd = 0;
+
+ // Construct the suffix tree iteratively on each prefix of the string.
+ // PfxEndIdx is the end index of the current prefix.
+ // End is one past the last element in the string.
+ for (unsigned PfxEndIdx = 0, End = Str.size(); PfxEndIdx < End; PfxEndIdx++) {
+ SuffixesToAdd++;
+ LeafEndIdx = PfxEndIdx; // Extend each of the leaves.
+ SuffixesToAdd = extend(PfxEndIdx, SuffixesToAdd);
+ }
+
+ // Set the suffix indices of each leaf.
+ assert(Root && "Root node can't be nullptr!");
+ setSuffixIndices();
+}
+
+SuffixTreeNode *SuffixTree::insertLeaf(SuffixTreeNode &Parent,
+ unsigned StartIdx, unsigned Edge) {
+
+ assert(StartIdx <= LeafEndIdx && "String can't start after it ends!");
+
+ SuffixTreeNode *N = new (NodeAllocator.Allocate())
+ SuffixTreeNode(StartIdx, &LeafEndIdx, nullptr);
+ Parent.Children[Edge] = N;
+
+ return N;
+}
+
+SuffixTreeNode *SuffixTree::insertInternalNode(SuffixTreeNode *Parent,
+ unsigned StartIdx,
+ unsigned EndIdx, unsigned Edge) {
+
+ assert(StartIdx <= EndIdx && "String can't start after it ends!");
+ assert(!(!Parent && StartIdx != EmptyIdx) &&
+ "Non-root internal nodes must have parents!");
+
+ unsigned *E = new (InternalEndIdxAllocator) unsigned(EndIdx);
+ SuffixTreeNode *N =
+ new (NodeAllocator.Allocate()) SuffixTreeNode(StartIdx, E, Root);
+ if (Parent)
+ Parent->Children[Edge] = N;
+
+ return N;
+}
+
+void SuffixTree::setSuffixIndices() {
+ // List of nodes we need to visit along with the current length of the
+ // string.
+ std::vector<std::pair<SuffixTreeNode *, unsigned>> ToVisit;
+
+ // Current node being visited.
+ SuffixTreeNode *CurrNode = Root;
+
+ // Sum of the lengths of the nodes down the path to the current one.
+ unsigned CurrNodeLen = 0;
+ ToVisit.push_back({CurrNode, CurrNodeLen});
+ while (!ToVisit.empty()) {
+ std::tie(CurrNode, CurrNodeLen) = ToVisit.back();
+ ToVisit.pop_back();
+ CurrNode->ConcatLen = CurrNodeLen;
+ for (auto &ChildPair : CurrNode->Children) {
+ assert(ChildPair.second && "Node had a null child!");
+ ToVisit.push_back(
+ {ChildPair.second, CurrNodeLen + ChildPair.second->size()});
+ }
+
+ // No children, so we are at the end of the string.
+ if (CurrNode->Children.size() == 0 && !CurrNode->isRoot())
+ CurrNode->SuffixIdx = Str.size() - CurrNodeLen;
+ }
+}
+
+unsigned SuffixTree::extend(unsigned EndIdx, unsigned SuffixesToAdd) {
+ SuffixTreeNode *NeedsLink = nullptr;
+
+ while (SuffixesToAdd > 0) {
+
+ // Are we waiting to add anything other than just the last character?
+ if (Active.Len == 0) {
+ // If not, then say the active index is the end index.
+ Active.Idx = EndIdx;
+ }
+
+ assert(Active.Idx <= EndIdx && "Start index can't be after end index!");
+
+ // The first character in the current substring we're looking at.
+ unsigned FirstChar = Str[Active.Idx];
+
+ // Have we inserted anything starting with FirstChar at the current node?
+ if (Active.Node->Children.count(FirstChar) == 0) {
+ // If not, then we can just insert a leaf and move to the next step.
+ insertLeaf(*Active.Node, EndIdx, FirstChar);
+
+ // The active node is an internal node, and we visited it, so it must
+ // need a link if it doesn't have one.
+ if (NeedsLink) {
+ NeedsLink->Link = Active.Node;
+ NeedsLink = nullptr;
+ }
+ } else {
+ // There's a match with FirstChar, so look for the point in the tree to
+ // insert a new node.
+ SuffixTreeNode *NextNode = Active.Node->Children[FirstChar];
+
+ unsigned SubstringLen = NextNode->size();
+
+ // Is the current suffix we're trying to insert longer than the size of
+ // the child we want to move to?
+ if (Active.Len >= SubstringLen) {
+ // If yes, then consume the characters we've seen and move to the next
+ // node.
+ Active.Idx += SubstringLen;
+ Active.Len -= SubstringLen;
+ Active.Node = NextNode;
+ continue;
+ }
+
+ // Otherwise, the suffix we're trying to insert must be contained in the
+ // next node we want to move to.
+ unsigned LastChar = Str[EndIdx];
+
+ // Is the string we're trying to insert a substring of the next node?
+ if (Str[NextNode->StartIdx + Active.Len] == LastChar) {
+ // If yes, then we're done for this step. Remember our insertion point
+ // and move to the next end index. At this point, we have an implicit
+ // suffix tree.
+ if (NeedsLink && !Active.Node->isRoot()) {
+ NeedsLink->Link = Active.Node;
+ NeedsLink = nullptr;
+ }
+
+ Active.Len++;
+ break;
+ }
+
+ // The string we're trying to insert isn't a substring of the next node,
+ // but matches up to a point. Split the node.
+ //
+ // For example, say we ended our search at a node n and we're trying to
+ // insert ABD. Then we'll create a new node s for AB, reduce n to just
+ // representing C, and insert a new leaf node l to represent d. This
+ // allows us to ensure that if n was a leaf, it remains a leaf.
+ //
+ // | ABC ---split---> | AB
+ // n s
+ // C / \ D
+ // n l
+
+ // The node s from the diagram
+ SuffixTreeNode *SplitNode =
+ insertInternalNode(Active.Node, NextNode->StartIdx,
+ NextNode->StartIdx + Active.Len - 1, FirstChar);
+
+ // Insert the new node representing the new substring into the tree as
+ // a child of the split node. This is the node l from the diagram.
+ insertLeaf(*SplitNode, EndIdx, LastChar);
+
+ // Make the old node a child of the split node and update its start
+ // index. This is the node n from the diagram.
+ NextNode->StartIdx += Active.Len;
+ SplitNode->Children[Str[NextNode->StartIdx]] = NextNode;
+
+ // SplitNode is an internal node, update the suffix link.
+ if (NeedsLink)
+ NeedsLink->Link = SplitNode;
+
+ NeedsLink = SplitNode;
+ }
+
+ // We've added something new to the tree, so there's one less suffix to
+ // add.
+ SuffixesToAdd--;
+
+ if (Active.Node->isRoot()) {
+ if (Active.Len > 0) {
+ Active.Len--;
+ Active.Idx = EndIdx - SuffixesToAdd + 1;
+ }
+ } else {
+ // Start the next phase at the next smallest suffix.
+ Active.Node = Active.Node->Link;
+ }
+ }
+
+ return SuffixesToAdd;
+}
diff --git a/llvm/lib/Support/SystemUtils.cpp b/llvm/lib/Support/SystemUtils.cpp
index 47e0c72ec7c13..f1149e48dce5d 100644
--- a/llvm/lib/Support/SystemUtils.cpp
+++ b/llvm/lib/Support/SystemUtils.cpp
@@ -15,15 +15,12 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
-bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check,
- bool print_warning) {
+bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check) {
if (stream_to_check.is_displayed()) {
- if (print_warning) {
- errs() << "WARNING: You're attempting to print out a bitcode file.\n"
- "This is inadvisable as it may cause display problems. If\n"
- "you REALLY want to taste LLVM bitcode first-hand, you\n"
- "can force output with the `-f' option.\n\n";
- }
+ errs() << "WARNING: You're attempting to print out a bitcode file.\n"
+ "This is inadvisable as it may cause display problems. If\n"
+ "you REALLY want to taste LLVM bitcode first-hand, you\n"
+ "can force output with the `-f' option.\n\n";
return true;
}
return false;
diff --git a/llvm/lib/Support/TarWriter.cpp b/llvm/lib/Support/TarWriter.cpp
index 6136e92197672..c7a744f0fc98c 100644
--- a/llvm/lib/Support/TarWriter.cpp
+++ b/llvm/lib/Support/TarWriter.cpp
@@ -131,7 +131,17 @@ static bool splitUstar(StringRef Path, StringRef &Prefix, StringRef &Name) {
return true;
}
- size_t Sep = Path.rfind('/', sizeof(UstarHeader::Prefix) + 1);
+ // tar 1.13 and earlier unconditionally look at the tar header interpreted
+ // as an 'oldgnu_header', which has an 'isextended' byte at offset 482 in the
+ // header, corresponding to offset 137 in the prefix. That's the version of
+ // tar in gnuwin, so only use 137 of the 155 bytes in the prefix. This means
+ // we'll need a pax header after 237 bytes of path instead of after 255,
+ // but in return paths up to 237 bytes work with gnuwin, instead of just
+ // 137 bytes of directory + 100 bytes of basename previously.
+ // (tar-1.13 also doesn't support pax headers, but in practice all paths in
+ // llvm's test suite are short enough for that to not matter.)
+ const int MaxPrefix = 137;
+ size_t Sep = Path.rfind('/', MaxPrefix + 1);
if (Sep == StringRef::npos)
return false;
if (Path.size() - Sep - 1 >= sizeof(UstarHeader::Name))
@@ -167,7 +177,8 @@ Expected<std::unique_ptr<TarWriter>> TarWriter::create(StringRef OutputPath,
}
TarWriter::TarWriter(int FD, StringRef BaseDir)
- : OS(FD, /*shouldClose=*/true, /*unbuffered=*/false), BaseDir(BaseDir) {}
+ : OS(FD, /*shouldClose=*/true, /*unbuffered=*/false),
+ BaseDir(std::string(BaseDir)) {}
// Append a given file to an archive.
void TarWriter::append(StringRef Path, StringRef Data) {
diff --git a/llvm/lib/Support/TargetParser.cpp b/llvm/lib/Support/TargetParser.cpp
index 84ead58b98cd8..be9b541237c74 100644
--- a/llvm/lib/Support/TargetParser.cpp
+++ b/llvm/lib/Support/TargetParser.cpp
@@ -62,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[37] = {
+constexpr GPUInfo AMDGCNGPUs[38] = {
// Name Canonical Kind Features
// Name
{{"gfx600"}, {"gfx600"}, GK_GFX600, FEATURE_FAST_FMA_F32},
@@ -99,9 +99,10 @@ constexpr GPUInfo AMDGCNGPUs[37] = {
{{"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},
+ {{"gfx1010"}, {"gfx1010"}, GK_GFX1010, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32},
+ {{"gfx1011"}, {"gfx1011"}, GK_GFX1011, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32},
+ {{"gfx1012"}, {"gfx1012"}, GK_GFX1012, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32},
+ {{"gfx1030"}, {"gfx1030"}, GK_GFX1030, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32},
};
const GPUInfo *getArchEntry(AMDGPU::GPUKind AK, ArrayRef<GPUInfo> Table) {
@@ -203,6 +204,7 @@ AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) {
case GK_GFX1010: return {10, 1, 0};
case GK_GFX1011: return {10, 1, 1};
case GK_GFX1012: return {10, 1, 2};
+ case GK_GFX1030: return {10, 3, 0};
default: return {0, 0, 0};
}
}
diff --git a/llvm/lib/Support/ThreadPool.cpp b/llvm/lib/Support/ThreadPool.cpp
index 40982d777914d..46a1990cd7196 100644
--- a/llvm/lib/Support/ThreadPool.cpp
+++ b/llvm/lib/Support/ThreadPool.cpp
@@ -20,16 +20,14 @@ using namespace llvm;
#if LLVM_ENABLE_THREADS
-// Default to hardware_concurrency
-ThreadPool::ThreadPool() : ThreadPool(hardware_concurrency()) {}
-
-ThreadPool::ThreadPool(unsigned ThreadCount)
- : ActiveThreads(0), EnableFlag(true) {
+ThreadPool::ThreadPool(ThreadPoolStrategy S)
+ : ThreadCount(S.compute_thread_count()) {
// Create ThreadCount threads that will loop forever, wait on QueueCondition
// for tasks to be queued or the Pool to be destroyed.
Threads.reserve(ThreadCount);
for (unsigned ThreadID = 0; ThreadID < ThreadCount; ++ThreadID) {
- Threads.emplace_back([&] {
+ Threads.emplace_back([S, ThreadID, this] {
+ S.apply_thread_strategy(ThreadID);
while (true) {
PackagedTaskTy Task;
{
@@ -45,24 +43,24 @@ ThreadPool::ThreadPool(unsigned ThreadCount)
// We first need to signal that we are active before popping the queue
// in order for wait() to properly detect that even if the queue is
// empty, there is still a task in flight.
- {
- std::unique_lock<std::mutex> LockGuard(CompletionLock);
- ++ActiveThreads;
- }
+ ++ActiveThreads;
Task = std::move(Tasks.front());
Tasks.pop();
}
// Run the task we just grabbed
Task();
+ bool Notify;
{
// Adjust `ActiveThreads`, in case someone waits on ThreadPool::wait()
- std::unique_lock<std::mutex> LockGuard(CompletionLock);
+ std::lock_guard<std::mutex> LockGuard(QueueLock);
--ActiveThreads;
+ Notify = workCompletedUnlocked();
}
-
- // Notify task completion, in case someone waits on ThreadPool::wait()
- CompletionCondition.notify_all();
+ // Notify task completion if this is the last active thread, in case
+ // someone waits on ThreadPool::wait().
+ if (Notify)
+ CompletionCondition.notify_all();
}
});
}
@@ -70,12 +68,8 @@ ThreadPool::ThreadPool(unsigned ThreadCount)
void ThreadPool::wait() {
// Wait for all threads to complete and the queue to be empty
- std::unique_lock<std::mutex> LockGuard(CompletionLock);
- // The order of the checks for ActiveThreads and Tasks.empty() matters because
- // any active threads might be modifying the Tasks queue, and this would be a
- // race.
- CompletionCondition.wait(LockGuard,
- [&] { return !ActiveThreads && Tasks.empty(); });
+ std::unique_lock<std::mutex> LockGuard(QueueLock);
+ CompletionCondition.wait(LockGuard, [&] { return workCompletedUnlocked(); });
}
std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) {
@@ -108,12 +102,10 @@ ThreadPool::~ThreadPool() {
#else // LLVM_ENABLE_THREADS Disabled
-ThreadPool::ThreadPool() : ThreadPool(0) {}
-
// No threads are launched, issue a warning if ThreadCount is not 0
-ThreadPool::ThreadPool(unsigned ThreadCount)
- : ActiveThreads(0) {
- if (ThreadCount) {
+ThreadPool::ThreadPool(ThreadPoolStrategy S)
+ : ThreadCount(S.compute_thread_count()) {
+ if (ThreadCount != 1) {
errs() << "Warning: request a ThreadPool with " << ThreadCount
<< " threads, but LLVM_ENABLE_THREADS has been turned off\n";
}
@@ -138,8 +130,6 @@ std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) {
return Future;
}
-ThreadPool::~ThreadPool() {
- wait();
-}
+ThreadPool::~ThreadPool() { wait(); }
#endif
diff --git a/llvm/lib/Support/Threading.cpp b/llvm/lib/Support/Threading.cpp
index 48750cef5ec22..61f8ee5be5b31 100644
--- a/llvm/lib/Support/Threading.cpp
+++ b/llvm/lib/Support/Threading.cpp
@@ -45,10 +45,6 @@ void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
Fn(UserData);
}
-unsigned llvm::heavyweight_hardware_concurrency() { return 1; }
-
-unsigned llvm::hardware_concurrency() { return 1; }
-
uint64_t llvm::get_threadid() { return 0; }
uint32_t llvm::get_max_thread_name_length() { return 0; }
@@ -57,6 +53,13 @@ void llvm::set_thread_name(const Twine &Name) {}
void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); }
+llvm::BitVector llvm::get_thread_affinity_mask() { return {}; }
+
+unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
+ // When threads are disabled, ensure clients will loop at least once.
+ return 1;
+}
+
#if LLVM_ENABLE_THREADS == 0
void llvm::llvm_execute_on_thread_async(
llvm::unique_function<void()> Func,
@@ -78,30 +81,18 @@ void llvm::llvm_execute_on_thread_async(
#else
-#include <thread>
-unsigned llvm::heavyweight_hardware_concurrency() {
- // Since we can't get here unless LLVM_ENABLE_THREADS == 1, it is safe to use
- // `std::thread` directly instead of `llvm::thread` (and indeed, doing so
- // allows us to not define `thread` in the llvm namespace, which conflicts
- // with some platforms such as FreeBSD whose headers also define a struct
- // called `thread` in the global namespace which can cause ambiguity due to
- // ADL.
- int NumPhysical = sys::getHostNumPhysicalCores();
- if (NumPhysical == -1)
- return std::thread::hardware_concurrency();
- return NumPhysical;
-}
-
-unsigned llvm::hardware_concurrency() {
-#if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_CPU_COUNT)
- cpu_set_t Set;
- if (sched_getaffinity(0, sizeof(Set), &Set))
- return CPU_COUNT(&Set);
-#endif
- // Guard against std::thread::hardware_concurrency() returning 0.
- if (unsigned Val = std::thread::hardware_concurrency())
- return Val;
- return 1;
+int computeHostNumHardwareThreads();
+
+unsigned llvm::ThreadPoolStrategy::compute_thread_count() const {
+ int MaxThreadCount = UseHyperThreads ? computeHostNumHardwareThreads()
+ : sys::getHostNumPhysicalCores();
+ if (MaxThreadCount <= 0)
+ MaxThreadCount = 1;
+ if (ThreadsRequested == 0)
+ return MaxThreadCount;
+ if (!Limit)
+ return ThreadsRequested;
+ return std::min((unsigned)MaxThreadCount, ThreadsRequested);
}
namespace {
@@ -140,3 +131,23 @@ void llvm::llvm_execute_on_thread_async(
}
#endif
+
+Optional<ThreadPoolStrategy>
+llvm::get_threadpool_strategy(StringRef Num, ThreadPoolStrategy Default) {
+ if (Num == "all")
+ return llvm::hardware_concurrency();
+ if (Num.empty())
+ return Default;
+ unsigned V;
+ if (Num.getAsInteger(10, V))
+ return None; // malformed 'Num' value
+ if (V == 0)
+ return Default;
+
+ // Do not take the Default into account. This effectively disables
+ // heavyweight_hardware_concurrency() if the user asks for any number of
+ // threads on the cmd-line.
+ ThreadPoolStrategy S = llvm::hardware_concurrency();
+ S.ThreadsRequested = V;
+ return S;
+}
diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp
index a7c85509064ec..93bf6f57e3480 100644
--- a/llvm/lib/Support/TimeProfiler.cpp
+++ b/llvm/lib/Support/TimeProfiler.cpp
@@ -11,20 +11,33 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/TimeProfiler.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Threading.h"
+#include <algorithm>
#include <cassert>
#include <chrono>
+#include <mutex>
#include <string>
#include <vector>
using namespace std::chrono;
+using namespace llvm;
-namespace llvm {
+static std::mutex Mu;
+// List of all instances
+static std::vector<TimeTraceProfiler *>
+ ThreadTimeTraceProfilerInstances; // GUARDED_BY(Mu)
+// Per Thread instance
+static LLVM_THREAD_LOCAL TimeTraceProfiler *TimeTraceProfilerInstance = nullptr;
-TimeTraceProfiler *TimeTraceProfilerInstance = nullptr;
+TimeTraceProfiler *llvm::getTimeTraceProfilerInstance() {
+ return TimeTraceProfilerInstance;
+}
typedef duration<steady_clock::rep, steady_clock::period> DurationType;
typedef time_point<steady_clock> TimePointType;
@@ -32,6 +45,7 @@ typedef std::pair<size_t, DurationType> CountAndDurationType;
typedef std::pair<std::string, CountAndDurationType>
NameAndCountAndDurationType;
+namespace {
struct Entry {
const TimePointType Start;
TimePointType End;
@@ -57,11 +71,15 @@ struct Entry {
.count();
}
};
+} // namespace
-struct TimeTraceProfiler {
+struct llvm::TimeTraceProfiler {
TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "")
- : StartTime(steady_clock::now()), ProcName(ProcName),
- TimeTraceGranularity(TimeTraceGranularity) {}
+ : BeginningOfTime(system_clock::now()), StartTime(steady_clock::now()),
+ ProcName(ProcName), Pid(sys::Process::getProcessId()),
+ Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity) {
+ llvm::get_thread_name(ThreadName);
+ }
void begin(std::string Name, llvm::function_ref<std::string()> Detail) {
Stack.emplace_back(steady_clock::now(), TimePointType(), std::move(Name),
@@ -70,7 +88,7 @@ struct TimeTraceProfiler {
void end() {
assert(!Stack.empty() && "Must call begin() first");
- auto &E = Stack.back();
+ Entry &E = Stack.back();
E.End = steady_clock::now();
// Check that end times monotonically increase.
@@ -103,22 +121,30 @@ struct TimeTraceProfiler {
Stack.pop_back();
}
- void Write(raw_pwrite_stream &OS) {
+ // Write events from this TimeTraceProfilerInstance and
+ // ThreadTimeTraceProfilerInstances.
+ void write(raw_pwrite_stream &OS) {
+ // Acquire Mutex as reading ThreadTimeTraceProfilerInstances.
+ std::lock_guard<std::mutex> Lock(Mu);
assert(Stack.empty() &&
- "All profiler sections should be ended when calling Write");
+ "All profiler sections should be ended when calling write");
+ assert(llvm::all_of(ThreadTimeTraceProfilerInstances,
+ [](const auto &TTP) { return TTP->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 writeEvent = [&](const auto &E, uint64_t Tid) {
auto StartUs = E.getFlameGraphStartUs(StartTime);
auto DurUs = E.getFlameGraphDurUs();
- J.object([&]{
- J.attribute("pid", 1);
- J.attribute("tid", 0);
+ J.object([&] {
+ J.attribute("pid", Pid);
+ J.attribute("tid", int64_t(Tid));
J.attribute("ph", "X");
J.attribute("ts", StartUs);
J.attribute("dur", DurUs);
@@ -127,100 +153,178 @@ struct TimeTraceProfiler {
J.attributeObject("args", [&] { J.attribute("detail", E.Detail); });
}
});
- }
+ };
+ for (const Entry &E : Entries)
+ writeEvent(E, this->Tid);
+ for (const TimeTraceProfiler *TTP : ThreadTimeTraceProfilerInstances)
+ for (const Entry &E : TTP->Entries)
+ writeEvent(E, TTP->Tid);
// Emit totals by section name as additional "thread" events, sorted from
// longest one.
- int Tid = 1;
+ // Find highest used thread id.
+ uint64_t MaxTid = this->Tid;
+ for (const TimeTraceProfiler *TTP : ThreadTimeTraceProfilerInstances)
+ MaxTid = std::max(MaxTid, TTP->Tid);
+
+ // Combine all CountAndTotalPerName from threads into one.
+ StringMap<CountAndDurationType> AllCountAndTotalPerName;
+ auto combineStat = [&](const auto &Stat) {
+ StringRef Key = Stat.getKey();
+ auto Value = Stat.getValue();
+ auto &CountAndTotal = AllCountAndTotalPerName[Key];
+ CountAndTotal.first += Value.first;
+ CountAndTotal.second += Value.second;
+ };
+ for (const auto &Stat : CountAndTotalPerName)
+ combineStat(Stat);
+ for (const TimeTraceProfiler *TTP : ThreadTimeTraceProfilerInstances)
+ for (const auto &Stat : TTP->CountAndTotalPerName)
+ combineStat(Stat);
+
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);
+ SortedTotals.reserve(AllCountAndTotalPerName.size());
+ for (const auto &Total : AllCountAndTotalPerName)
+ SortedTotals.emplace_back(std::string(Total.getKey()), Total.getValue());
+
+ llvm::sort(SortedTotals, [](const NameAndCountAndDurationType &A,
+ const NameAndCountAndDurationType &B) {
+ return A.second.second > B.second.second;
+ });
+
+ // Report totals on separate threads of tracing file.
+ uint64_t TotalTid = MaxTid + 1;
+ for (const NameAndCountAndDurationType &Total : SortedTotals) {
+ auto DurUs = duration_cast<microseconds>(Total.second.second).count();
+ auto Count = AllCountAndTotalPerName[Total.first].first;
+
+ J.object([&] {
+ J.attribute("pid", Pid);
+ J.attribute("tid", int64_t(TotalTid));
J.attribute("ph", "X");
J.attribute("ts", 0);
J.attribute("dur", DurUs);
- J.attribute("name", "Total " + E.first);
+ J.attribute("name", "Total " + Total.first);
J.attributeObject("args", [&] {
J.attribute("count", int64_t(Count));
J.attribute("avg ms", int64_t(DurUs / Count / 1000));
});
});
- ++Tid;
+ ++TotalTid;
}
- // 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", ProcName); });
- });
+ auto writeMetadataEvent = [&](const char *Name, uint64_t Tid,
+ StringRef arg) {
+ J.object([&] {
+ J.attribute("cat", "");
+ J.attribute("pid", Pid);
+ J.attribute("tid", int64_t(Tid));
+ J.attribute("ts", 0);
+ J.attribute("ph", "M");
+ J.attribute("name", Name);
+ J.attributeObject("args", [&] { J.attribute("name", arg); });
+ });
+ };
+
+ writeMetadataEvent("process_name", Tid, ProcName);
+ writeMetadataEvent("thread_name", Tid, ThreadName);
+ for (const TimeTraceProfiler *TTP : ThreadTimeTraceProfilerInstances)
+ writeMetadataEvent("thread_name", TTP->Tid, TTP->ThreadName);
J.arrayEnd();
J.attributeEnd();
+
+ // Emit the absolute time when this TimeProfiler started.
+ // This can be used to combine the profiling data from
+ // multiple processes and preserve actual time intervals.
+ J.attribute("beginningOfTime",
+ time_point_cast<microseconds>(BeginningOfTime)
+ .time_since_epoch()
+ .count());
+
J.objectEnd();
}
SmallVector<Entry, 16> Stack;
SmallVector<Entry, 128> Entries;
StringMap<CountAndDurationType> CountAndTotalPerName;
+ const time_point<system_clock> BeginningOfTime;
const TimePointType StartTime;
const std::string ProcName;
+ const sys::Process::Pid Pid;
+ SmallString<0> ThreadName;
+ const uint64_t Tid;
// Minimum time granularity (in microseconds)
const unsigned TimeTraceGranularity;
};
-void timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
- StringRef ProcName) {
+void llvm::timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
+ StringRef ProcName) {
assert(TimeTraceProfilerInstance == nullptr &&
"Profiler should not be initialized");
TimeTraceProfilerInstance = new TimeTraceProfiler(
TimeTraceGranularity, llvm::sys::path::filename(ProcName));
}
-void timeTraceProfilerCleanup() {
+// Removes all TimeTraceProfilerInstances.
+// Called from main thread.
+void llvm::timeTraceProfilerCleanup() {
delete TimeTraceProfilerInstance;
+ std::lock_guard<std::mutex> Lock(Mu);
+ for (auto TTP : ThreadTimeTraceProfilerInstances)
+ delete TTP;
+ ThreadTimeTraceProfilerInstances.clear();
+}
+
+// Finish TimeTraceProfilerInstance on a worker thread.
+// This doesn't remove the instance, just moves the pointer to global vector.
+void llvm::timeTraceProfilerFinishThread() {
+ std::lock_guard<std::mutex> Lock(Mu);
+ ThreadTimeTraceProfilerInstances.push_back(TimeTraceProfilerInstance);
TimeTraceProfilerInstance = nullptr;
}
-void timeTraceProfilerWrite(raw_pwrite_stream &OS) {
+void llvm::timeTraceProfilerWrite(raw_pwrite_stream &OS) {
assert(TimeTraceProfilerInstance != nullptr &&
"Profiler object can't be null");
- TimeTraceProfilerInstance->Write(OS);
+ TimeTraceProfilerInstance->write(OS);
}
-void timeTraceProfilerBegin(StringRef Name, StringRef Detail) {
+Error llvm::timeTraceProfilerWrite(StringRef PreferredFileName,
+ StringRef FallbackFileName) {
+ assert(TimeTraceProfilerInstance != nullptr &&
+ "Profiler object can't be null");
+
+ std::string Path = PreferredFileName.str();
+ if (Path.empty()) {
+ Path = FallbackFileName == "-" ? "out" : FallbackFileName.str();
+ Path += ".time-trace";
+ }
+
+ std::error_code EC;
+ raw_fd_ostream OS(Path, EC, sys::fs::OF_Text);
+ if (EC)
+ return createStringError(EC, "Could not open " + Path);
+
+ timeTraceProfilerWrite(OS);
+ return Error::success();
+}
+
+void llvm::timeTraceProfilerBegin(StringRef Name, StringRef Detail) {
if (TimeTraceProfilerInstance != nullptr)
- TimeTraceProfilerInstance->begin(Name, [&]() { return Detail; });
+ TimeTraceProfilerInstance->begin(std::string(Name),
+ [&]() { return std::string(Detail); });
}
-void timeTraceProfilerBegin(StringRef Name,
- llvm::function_ref<std::string()> Detail) {
+void llvm::timeTraceProfilerBegin(StringRef Name,
+ llvm::function_ref<std::string()> Detail) {
if (TimeTraceProfilerInstance != nullptr)
- TimeTraceProfilerInstance->begin(Name, Detail);
+ TimeTraceProfilerInstance->begin(std::string(Name), Detail);
}
-void timeTraceProfilerEnd() {
+void llvm::timeTraceProfilerEnd() {
if (TimeTraceProfilerInstance != nullptr)
TimeTraceProfilerInstance->end();
}
-
-} // namespace llvm
diff --git a/llvm/lib/Support/Timer.cpp b/llvm/lib/Support/Timer.cpp
index 613d2eaae6d35..c97538cb560a3 100644
--- a/llvm/lib/Support/Timer.cpp
+++ b/llvm/lib/Support/Timer.cpp
@@ -247,7 +247,8 @@ TimerGroup::TimerGroup(StringRef Name, StringRef Description,
: TimerGroup(Name, Description) {
TimersToPrint.reserve(Records.size());
for (const auto &P : Records)
- TimersToPrint.emplace_back(P.getValue(), P.getKey(), P.getKey());
+ TimersToPrint.emplace_back(P.getValue(), std::string(P.getKey()),
+ std::string(P.getKey()));
assert(TimersToPrint.size() == Records.size() && "Size mismatch");
}
@@ -441,3 +442,7 @@ const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
void TimerGroup::ConstructTimerLists() {
(void)*NamedGroupedTimers;
}
+
+std::unique_ptr<TimerGroup> TimerGroup::aquireDefaultGroup() {
+ return std::unique_ptr<TimerGroup>(DefaultTimerGroup.claim());
+}
diff --git a/llvm/lib/Support/ToolOutputFile.cpp b/llvm/lib/Support/ToolOutputFile.cpp
index ed3a247f01155..c2ca97a59c620 100644
--- a/llvm/lib/Support/ToolOutputFile.cpp
+++ b/llvm/lib/Support/ToolOutputFile.cpp
@@ -15,31 +15,45 @@
#include "llvm/Support/Signals.h"
using namespace llvm;
+static bool isStdout(StringRef Filename) { return Filename == "-"; }
+
ToolOutputFile::CleanupInstaller::CleanupInstaller(StringRef Filename)
- : Filename(Filename), Keep(false) {
+ : Filename(std::string(Filename)), Keep(false) {
// Arrange for the file to be deleted if the process is killed.
- if (Filename != "-")
+ if (!isStdout(Filename))
sys::RemoveFileOnSignal(Filename);
}
ToolOutputFile::CleanupInstaller::~CleanupInstaller() {
+ if (isStdout(Filename))
+ return;
+
// Delete the file if the client hasn't told us not to.
- if (!Keep && Filename != "-")
+ if (!Keep)
sys::fs::remove(Filename);
// Ok, the file is successfully written and closed, or deleted. There's no
// further need to clean it up on signals.
- if (Filename != "-")
- sys::DontRemoveFileOnSignal(Filename);
+ sys::DontRemoveFileOnSignal(Filename);
}
ToolOutputFile::ToolOutputFile(StringRef Filename, std::error_code &EC,
sys::fs::OpenFlags Flags)
- : Installer(Filename), OS(Filename, EC, Flags) {
+ : Installer(Filename) {
+ if (isStdout(Filename)) {
+ OS = &outs();
+ EC = std::error_code();
+ return;
+ }
+ OSHolder.emplace(Filename, EC, Flags);
+ OS = OSHolder.getPointer();
// If open fails, no cleanup is needed.
if (EC)
Installer.Keep = true;
}
ToolOutputFile::ToolOutputFile(StringRef Filename, int FD)
- : Installer(Filename), OS(FD, true) {}
+ : Installer(Filename) {
+ OSHolder.emplace(FD, true);
+ OS = OSHolder.getPointer();
+}
diff --git a/llvm/lib/Support/TrigramIndex.cpp b/llvm/lib/Support/TrigramIndex.cpp
index 94810b56db8ec..88375e6e78639 100644
--- a/llvm/lib/Support/TrigramIndex.cpp
+++ b/llvm/lib/Support/TrigramIndex.cpp
@@ -16,6 +16,7 @@
#include "llvm/Support/TrigramIndex.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include <set>
#include <string>
diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp
index 2c480c1094a5c..fec1985ccacae 100644
--- a/llvm/lib/Support/Triple.cpp
+++ b/llvm/lib/Support/Triple.cpp
@@ -9,10 +9,14 @@
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/VersionTuple.h"
+#include <cassert>
#include <cstring>
using namespace llvm;
@@ -625,6 +629,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
return Triple::ARMSubArch_v8_4a;
case ARM::ArchKind::ARMV8_5A:
return Triple::ARMSubArch_v8_5a;
+ case ARM::ArchKind::ARMV8_6A:
+ return Triple::ARMSubArch_v8_6a;
case ARM::ArchKind::ARMV8R:
return Triple::ARMSubArch_v8r;
case ARM::ArchKind::ARMV8MBaseline:
@@ -710,9 +716,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::ppc64:
case Triple::ppc:
- if (T.isOSDarwin())
- return Triple::MachO;
- else if (T.isOSAIX())
+ if (T.isOSAIX())
return Triple::XCOFF;
return Triple::ELF;
@@ -983,12 +987,7 @@ std::string Triple::normalize(StringRef Str) {
}
// Stick the corrected components back together to form the normalized string.
- std::string Normalized;
- for (unsigned i = 0, e = Components.size(); i != e; ++i) {
- if (i) Normalized += '-';
- Normalized += Components[i];
- }
- return Normalized;
+ return join(Components, "-");
}
StringRef Triple::getArchName() const {
@@ -1088,17 +1087,23 @@ bool Triple::getMacOSXVersion(unsigned &Major, unsigned &Minor,
// Darwin version numbers are skewed from OS X versions.
if (Major < 4)
return false;
- Micro = 0;
- Minor = Major - 4;
- Major = 10;
+ if (Major <= 19) {
+ Micro = 0;
+ Minor = Major - 4;
+ Major = 10;
+ } else {
+ Micro = 0;
+ Minor = 0;
+ // darwin20+ corresponds to macOS 11+.
+ Major = 11 + Major - 20;
+ }
break;
case MacOSX:
// Default to 10.4.
if (Major == 0) {
Major = 10;
Minor = 4;
- }
- if (Major != 10)
+ } else if (Major < 10)
return false;
break;
case IOS:
@@ -1602,6 +1607,52 @@ std::string Triple::merge(const Triple &Other) const {
return Other.str();
}
+bool Triple::isMacOSXVersionLT(unsigned Major, unsigned Minor,
+ unsigned Micro) const {
+ assert(isMacOSX() && "Not an OS X triple!");
+
+ // If this is OS X, expect a sane version number.
+ if (getOS() == Triple::MacOSX)
+ return isOSVersionLT(Major, Minor, Micro);
+
+ // Otherwise, compare to the "Darwin" number.
+ if (Major == 10) {
+ return isOSVersionLT(Minor + 4, Micro, 0);
+ } else {
+ assert(Major >= 11 && "Unexpected major version");
+ return isOSVersionLT(Major - 11 + 20, Minor, Micro);
+ }
+}
+
+VersionTuple Triple::getMinimumSupportedOSVersion() const {
+ if (getVendor() != Triple::Apple || getArch() != Triple::aarch64)
+ return VersionTuple();
+ switch (getOS()) {
+ case Triple::MacOSX:
+ // ARM64 slice is supported starting from macOS 11.0+.
+ return VersionTuple(11, 0, 0);
+ case Triple::IOS:
+ // ARM64 slice is supported starting from Mac Catalyst 14 (macOS 11).
+ // ARM64 simulators are supported for iOS 14+.
+ if (isMacCatalystEnvironment() || isSimulatorEnvironment())
+ return VersionTuple(14, 0, 0);
+ break;
+ case Triple::TvOS:
+ // ARM64 simulators are supported for tvOS 14+.
+ if (isSimulatorEnvironment())
+ return VersionTuple(14, 0, 0);
+ break;
+ case Triple::WatchOS:
+ // ARM64 simulators are supported for watchOS 7+.
+ if (isSimulatorEnvironment())
+ return VersionTuple(7, 0, 0);
+ break;
+ default:
+ break;
+ }
+ return VersionTuple();
+}
+
StringRef Triple::getARMCPUForArch(StringRef MArch) const {
if (MArch.empty())
MArch = getArchName();
@@ -1664,3 +1715,16 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const {
llvm_unreachable("invalid arch name");
}
+
+VersionTuple Triple::getCanonicalVersionForOS(OSType OSKind,
+ const VersionTuple &Version) {
+ switch (OSKind) {
+ case MacOSX:
+ // macOS 10.16 is canonicalized to macOS 11.
+ if (Version == VersionTuple(10, 16))
+ return VersionTuple(11, 0);
+ LLVM_FALLTHROUGH;
+ default:
+ return Version;
+ }
+}
diff --git a/llvm/lib/Support/Unix/Host.inc b/llvm/lib/Support/Unix/Host.inc
index 17d78dc18be75..dfcfdd0dee68c 100644
--- a/llvm/lib/Support/Unix/Host.inc
+++ b/llvm/lib/Support/Unix/Host.inc
@@ -56,7 +56,7 @@ static std::string updateTripleOSVersion(std::string TargetTripleString) {
if (TT.getOS() == Triple::AIX && !TT.getOSMajorVersion()) {
struct utsname name;
if (uname(&name) != -1) {
- std::string NewOSName = Triple::getOSTypeName(Triple::AIX);
+ std::string NewOSName = std::string(Triple::getOSTypeName(Triple::AIX));
NewOSName += name.version;
NewOSName += '.';
NewOSName += name.release;
diff --git a/llvm/lib/Support/Unix/Memory.inc b/llvm/lib/Support/Unix/Memory.inc
index 79b1759359e1f..be88e7db14002 100644
--- a/llvm/lib/Support/Unix/Memory.inc
+++ b/llvm/lib/Support/Unix/Memory.inc
@@ -12,6 +12,7 @@
#include "Unix.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Process.h"
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 2a03dc682bced..d91b269cc6d33 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -48,6 +48,8 @@ extern char **environ;
#endif
#elif defined(__DragonFly__)
#include <sys/mount.h>
+#elif defined(__MVS__)
+#include <sys/ps.h>
#endif
// Both stdio.h and cstdio are included via different paths and
@@ -56,10 +58,13 @@ extern char **environ;
#undef ferror
#undef feof
+#if !defined(PATH_MAX)
// For GNU Hurd
-#if defined(__GNU__) && !defined(PATH_MAX)
-# define PATH_MAX 4096
-# define MAXPATHLEN 4096
+#if defined(__GNU__)
+#define PATH_MAX 4096
+#elif defined(__MVS__)
+#define PATH_MAX _XOPEN_PATH_MAX
+#endif
#endif
#include <sys/types.h>
@@ -101,7 +106,8 @@ typedef uint_t uint;
#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize)
#endif
-#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__)
+#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__) || \
+ defined(__MVS__)
#define STATVFS_F_FLAG(vfs) (vfs).f_flag
#else
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
@@ -184,10 +190,10 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// On OS X the executable path is saved to the stack by dyld. Reading it
// from there is much faster than calling dladdr, especially for large
// binaries with symbols.
- char exe_path[MAXPATHLEN];
+ char exe_path[PATH_MAX];
uint32_t size = sizeof(exe_path);
if (_NSGetExecutablePath(exe_path, &size) == 0) {
- char link_path[MAXPATHLEN];
+ char link_path[PATH_MAX];
if (realpath(exe_path, link_path))
return link_path;
}
@@ -208,14 +214,9 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
while (*p++ != 0)
;
// Iterate through auxiliary vectors for AT_EXECPATH.
- for (;;) {
- switch (*(uintptr_t *)p++) {
- case AT_EXECPATH:
+ for (; *(uintptr_t *)p != AT_NULL; p++) {
+ if (*(uintptr_t *)p++ == AT_EXECPATH)
return *p;
- case AT_NULL:
- break;
- }
- p++;
}
#endif
// Fall back to argv[0] if auxiliary vectors are not available.
@@ -239,7 +240,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
if (getprogpath(exe_path, argv0) != NULL)
return exe_path;
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__)
- char exe_path[MAXPATHLEN];
+ char exe_path[PATH_MAX];
const char *aPath = "/proc/self/exe";
if (sys::fs::exists(aPath)) {
// /proc is not always mounted under Linux (chroot for example).
@@ -263,7 +264,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
return ret;
}
#else
- char real_path[MAXPATHLEN];
+ char real_path[PATH_MAX];
if (realpath(exe_path, real_path))
return std::string(real_path);
#endif
@@ -271,6 +272,26 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// Fall back to the classical detection.
if (getprogpath(exe_path, argv0))
return exe_path;
+#elif defined(__MVS__)
+ int token = 0;
+ W_PSPROC buf;
+ char exe_path[PS_PATHBLEN];
+ pid_t pid = getpid();
+
+ memset(&buf, 0, sizeof(buf));
+ buf.ps_pathptr = exe_path;
+ buf.ps_pathlen = sizeof(exe_path);
+
+ while (true) {
+ if ((token = w_getpsent(token, &buf, sizeof(buf))) <= 0)
+ break;
+ if (buf.ps_pid != pid)
+ continue;
+ char real_path[PATH_MAX];
+ if (realpath(exe_path, real_path))
+ return std::string(real_path);
+ break; // Found entry, but realpath failed.
+ }
#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
// Use dladdr to get executable path if available.
Dl_info DLInfo;
@@ -280,7 +301,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// If the filename is a symlink, we need to resolve and return the location of
// the actual executable.
- char link_path[MAXPATHLEN];
+ char link_path[PATH_MAX];
if (realpath(DLInfo.dli_fname, link_path))
return link_path;
#else
@@ -330,12 +351,7 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
return std::error_code();
}
-#ifdef MAXPATHLEN
- result.reserve(MAXPATHLEN);
-#else
-// For GNU Hurd
- result.reserve(1024);
-#endif
+ result.reserve(PATH_MAX);
while (true) {
if (::getcwd(result.data(), result.capacity()) == nullptr) {
@@ -504,6 +520,10 @@ static bool is_local_impl(struct STATVFS &Vfs) {
// vmount entry not found; "remote" is the conservative answer.
return false;
+#elif defined(__MVS__)
+ // The file system can have an arbitrary structure on z/OS; must go with the
+ // conservative answer.
+ return false;
#else
return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
#endif
@@ -998,7 +1018,7 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
#if defined(F_GETPATH)
// When F_GETPATH is availble, it is the quickest way to get
// the real path name.
- char Buffer[MAXPATHLEN];
+ char Buffer[PATH_MAX];
if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1)
RealPath->append(Buffer, Buffer + strlen(Buffer));
#else
@@ -1169,6 +1189,51 @@ static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
return false;
}
+bool user_config_directory(SmallVectorImpl<char> &result) {
+#ifdef __APPLE__
+ // Mac: ~/Library/Preferences/
+ if (home_directory(result)) {
+ append(result, "Library", "Preferences");
+ return true;
+ }
+#else
+ // XDG_CONFIG_HOME as defined in the XDG Base Directory Specification:
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ if (const char *RequestedDir = getenv("XDG_CONFIG_HOME")) {
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
+ }
+#endif
+ // Fallback: ~/.config
+ if (!home_directory(result)) {
+ return false;
+ }
+ append(result, ".config");
+ return true;
+}
+
+bool cache_directory(SmallVectorImpl<char> &result) {
+#ifdef __APPLE__
+ if (getDarwinConfDir(false/*tempDir*/, result)) {
+ return true;
+ }
+#else
+ // XDG_CACHE_HOME as defined in the XDG Base Directory Specification:
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ if (const char *RequestedDir = getenv("XDG_CACHE_HOME")) {
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
+ }
+#endif
+ if (!home_directory(result)) {
+ return false;
+ }
+ append(result, ".cache");
+ return true;
+}
+
static const char *getEnvTempDir() {
// Check whether the temporary directory is specified by an environment
// variable.
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc
index dfe81d7e28337..24f16b51af7be 100644
--- a/llvm/lib/Support/Unix/Process.inc
+++ b/llvm/lib/Support/Unix/Process.inc
@@ -66,6 +66,12 @@ static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsage
#endif
}
+Process::Pid Process::getProcessId() {
+ static_assert(sizeof(Pid) >= sizeof(pid_t),
+ "Process::Pid should be big enough to store pid_t");
+ return Pid(::getpid());
+}
+
// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
// offset in mmap(3) should be aligned to the AllocationGranularity.
Expected<unsigned> Process::getPageSize() {
@@ -280,7 +286,7 @@ bool Process::FileDescriptorIsDisplayed(int fd) {
#endif
}
-static unsigned getColumns(int FileID) {
+static unsigned getColumns() {
// If COLUMNS is defined in the environment, wrap to that many columns.
if (const char *ColumnsStr = std::getenv("COLUMNS")) {
int Columns = std::atoi(ColumnsStr);
@@ -288,31 +294,23 @@ static unsigned getColumns(int FileID) {
return Columns;
}
- unsigned Columns = 0;
-
-#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)
- Columns = ws.ws_col;
-#endif
-
- return Columns;
+ // We used to call ioctl TIOCGWINSZ to determine the width. It is considered
+ // unuseful.
+ return 0;
}
unsigned Process::StandardOutColumns() {
if (!StandardOutIsDisplayed())
return 0;
- return getColumns(1);
+ return getColumns();
}
unsigned Process::StandardErrColumns() {
if (!StandardErrIsDisplayed())
return 0;
- return getColumns(2);
+ return getColumns();
}
#ifdef HAVE_TERMINFO
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index 520685a0e9878..8f41fc0151635 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -15,6 +15,8 @@
//=== is guaranteed to work on *all* UNIX variants.
//===----------------------------------------------------------------------===//
+#include "llvm/Support/Program.h"
+
#include "Unix.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
@@ -59,8 +61,7 @@
#endif
#endif
-namespace llvm {
-
+using namespace llvm;
using namespace sys;
ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}
@@ -70,8 +71,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
assert(!Name.empty() && "Must have a name!");
// Use the given path verbatim if it contains any slashes; this matches
// the behavior of sh(1) and friends.
- if (Name.find('/') != StringRef::npos)
- return std::string(Name);
+ if (Name.find('/') != StringRef::npos) return std::string(Name);
SmallVector<StringRef, 16> EnvironmentPaths;
if (Paths.empty())
@@ -88,7 +88,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
SmallString<128> FilePath(Path);
sys::path::append(FilePath, Name);
if (sys::fs::can_execute(FilePath.c_str()))
- return std::string(FilePath.str()); // Found the executable!
+ return std::string(FilePath.str()); // Found the executable!
}
return errc::no_such_file_or_directory;
}
@@ -101,7 +101,7 @@ static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) {
// Redirect empty paths to /dev/null
File = "/dev/null";
else
- File = *Path;
+ File = std::string(*Path);
// Open the file
int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
@@ -162,8 +162,6 @@ static void SetMemoryLimits(unsigned size) {
#endif
}
-}
-
static std::vector<const char *>
toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) {
std::vector<const char *> Result;
@@ -213,7 +211,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};
for (int I = 0; I < 3; ++I) {
if (Redirects[I]) {
- RedirectsStorage[I] = *Redirects[I];
+ RedirectsStorage[I] = std::string(*Redirects[I]);
RedirectsStr[I] = &RedirectsStorage[I];
}
}
@@ -304,7 +302,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
}
// Execute!
- std::string PathStr = Program;
+ std::string PathStr = std::string(Program);
if (Envp != nullptr)
execve(PathStr.c_str(), const_cast<char **>(Argv),
const_cast<char **>(Envp));
@@ -331,9 +329,54 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
}
namespace llvm {
+namespace sys {
+
+#ifndef _AIX
+using ::wait4;
+#else
+static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage);
+#endif
-ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
- bool WaitUntilTerminates, std::string *ErrMsg) {
+} // namespace sys
+} // namespace llvm
+
+#ifdef _AIX
+#ifndef _ALL_SOURCE
+extern "C" pid_t (wait4)(pid_t pid, int *status, int options,
+ struct rusage *usage);
+#endif
+pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options,
+ struct rusage *usage) {
+ assert(pid > 0 && "Only expecting to handle actual PID values!");
+ assert((options & ~WNOHANG) == 0 && "Expecting WNOHANG at most!");
+ assert(usage && "Expecting usage collection!");
+
+ // AIX wait4 does not work well with WNOHANG.
+ if (!(options & WNOHANG))
+ return ::wait4(pid, status, options, usage);
+
+ // For WNOHANG, we use waitid (which supports WNOWAIT) until the child process
+ // has terminated.
+ siginfo_t WaitIdInfo;
+ WaitIdInfo.si_pid = 0;
+ int WaitIdRetVal =
+ waitid(P_PID, pid, &WaitIdInfo, WNOWAIT | WEXITED | options);
+
+ if (WaitIdRetVal == -1 || WaitIdInfo.si_pid == 0)
+ return WaitIdRetVal;
+
+ assert(WaitIdInfo.si_pid == pid);
+
+ // The child has already terminated, so a blocking wait on it is okay in the
+ // absence of indiscriminate `wait` calls from the current process (which
+ // would cause the call here to fail with ECHILD).
+ return ::wait4(pid, status, options & ~WNOHANG, usage);
+}
+#endif
+
+ProcessInfo llvm::sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
+ bool WaitUntilTerminates, std::string *ErrMsg,
+ Optional<ProcessStatistics> *ProcStat) {
struct sigaction Act, Old;
assert(PI.Pid && "invalid pid to wait on, process not started?");
@@ -349,6 +392,7 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
Act.sa_handler = TimeOutHandler;
sigemptyset(&Act.sa_mask);
sigaction(SIGALRM, &Act, &Old);
+ // FIXME The alarm signal may be delivered to another thread.
alarm(SecondsToWait);
} else if (SecondsToWait == 0)
WaitPidOptions = WNOHANG;
@@ -356,9 +400,12 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
// Parent process: Wait for the child process to terminate.
int status;
ProcessInfo WaitResult;
+ rusage Info;
+ if (ProcStat)
+ ProcStat->reset();
do {
- WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions);
+ WaitResult.Pid = sys::wait4(ChildPid, &status, WaitPidOptions, &Info);
} while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR);
if (WaitResult.Pid != PI.Pid) {
@@ -375,6 +422,8 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
sigaction(SIGALRM, &Old, nullptr);
// Wait for child to die
+ // FIXME This could grab some other child process out from another
+ // waiting thread and then leave a zombie anyway.
if (wait(&status) != ChildPid)
MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
else
@@ -396,6 +445,13 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
sigaction(SIGALRM, &Old, nullptr);
}
+ if (ProcStat) {
+ std::chrono::microseconds UserT = toDuration(Info.ru_utime);
+ std::chrono::microseconds KernelT = toDuration(Info.ru_stime);
+ uint64_t PeakMemory = static_cast<uint64_t>(Info.ru_maxrss);
+ *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};
+ }
+
// Return the proper exit status. Detect error conditions
// so we can return -1 for them and set ErrMsg informatively.
int result = 0;
@@ -430,12 +486,12 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
return WaitResult;
}
-std::error_code sys::ChangeStdinToBinary() {
+std::error_code llvm::sys::ChangeStdinToBinary() {
// Do nothing, as Unix doesn't differentiate between text and binary.
return std::error_code();
}
-std::error_code sys::ChangeStdoutToBinary() {
+std::error_code llvm::sys::ChangeStdoutToBinary() {
// Do nothing, as Unix doesn't differentiate between text and binary.
return std::error_code();
}
@@ -497,4 +553,3 @@ bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
return true;
}
-}
diff --git a/llvm/lib/Support/Unix/Threading.inc b/llvm/lib/Support/Unix/Threading.inc
index afb887fc10960..2d0aacabf0920 100644
--- a/llvm/lib/Support/Unix/Threading.inc
+++ b/llvm/lib/Support/Unix/Threading.inc
@@ -37,7 +37,12 @@
#include <lwp.h> // For _lwp_self()
#endif
+#if defined(__OpenBSD__)
+#include <unistd.h> // For getthrid()
+#endif
+
#if defined(__linux__)
+#include <sched.h> // For sched_getaffinity
#include <sys/syscall.h> // For syscall codes
#include <unistd.h> // For syscall()
#endif
@@ -89,6 +94,10 @@ llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
ReportErrnumFatal("pthread_join failed", errnum);
}
+ } else if (JP == JoiningPolicy::Detach) {
+ if ((errnum = ::pthread_detach(Thread)) != 0) {
+ ReportErrnumFatal("pthread_detach failed", errnum);
+ }
}
}
@@ -104,6 +113,8 @@ uint64_t llvm::get_threadid() {
return uint64_t(pthread_getthreadid_np());
#elif defined(__NetBSD__)
return uint64_t(_lwp_self());
+#elif defined(__OpenBSD__)
+ return uint64_t(getthrid());
#elif defined(__ANDROID__)
return uint64_t(gettid());
#elif defined(__linux__)
@@ -267,3 +278,27 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
#endif
return SetThreadPriorityResult::FAILURE;
}
+
+#include <thread>
+
+int computeHostNumHardwareThreads() {
+#ifdef __linux__
+ cpu_set_t Set;
+ if (sched_getaffinity(0, sizeof(Set), &Set) == 0)
+ return CPU_COUNT(&Set);
+#endif
+ // Guard against std::thread::hardware_concurrency() returning 0.
+ if (unsigned Val = std::thread::hardware_concurrency())
+ return Val;
+ return 1;
+}
+
+void llvm::ThreadPoolStrategy::apply_thread_strategy(
+ unsigned ThreadPoolNum) const {}
+
+llvm::BitVector llvm::get_thread_affinity_mask() {
+ // FIXME: Implement
+ llvm_unreachable("Not implemented!");
+}
+
+unsigned llvm::get_cpus() { return 1; }
diff --git a/llvm/lib/Support/Unix/Unix.h b/llvm/lib/Support/Unix/Unix.h
index 1fc9a414f7494..60929139598b9 100644
--- a/llvm/lib/Support/Unix/Unix.h
+++ b/llvm/lib/Support/Unix/Unix.h
@@ -36,10 +36,6 @@
#include <unistd.h>
#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
diff --git a/llvm/lib/Support/VersionTuple.cpp b/llvm/lib/Support/VersionTuple.cpp
index 60b59424fbb49..6a516481ac25c 100644
--- a/llvm/lib/Support/VersionTuple.cpp
+++ b/llvm/lib/Support/VersionTuple.cpp
@@ -10,8 +10,11 @@
// the form major[.minor[.subminor]].
//
//===----------------------------------------------------------------------===//
+
#include "llvm/Support/VersionTuple.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
+#include <cassert>
using namespace llvm;
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index edd4234fe5016..5b757c9ea80db 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -306,12 +306,12 @@ RealFileSystem::openFileForRead(const Twine &Name) {
llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
if (WD)
- return WD->Specified.str();
+ return std::string(WD->Specified.str());
SmallString<128> Dir;
if (std::error_code EC = llvm::sys::fs::current_path(Dir))
return EC;
- return Dir.str();
+ return std::string(Dir.str());
}
std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
@@ -535,7 +535,8 @@ class InMemoryNode {
public:
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
- : Kind(Kind), FileName(llvm::sys::path::filename(FileName)) {}
+ : Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {
+ }
virtual ~InMemoryNode() = default;
/// Get the filename of this node (the name without the directory part).
@@ -904,7 +905,7 @@ class InMemoryDirIterator : public llvm::vfs::detail::DirIterImpl {
Type = sys::fs::file_type::directory_file;
break;
}
- CurrentEntry = directory_entry(Path.str(), Type);
+ CurrentEntry = directory_entry(std::string(Path.str()), Type);
} else {
// When we're at the end, make CurrentEntry invalid and DirIterImpl will
// do the rest.
@@ -960,7 +961,7 @@ std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
if (!Path.empty())
- WorkingDirectory = Path.str();
+ WorkingDirectory = std::string(Path.str());
return {};
}
@@ -989,6 +990,28 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
// RedirectingFileSystem implementation
//===-----------------------------------------------------------------------===/
+namespace {
+
+/// Removes leading "./" as well as path components like ".." and ".".
+static llvm::SmallString<256> canonicalize(llvm::StringRef Path) {
+ // First detect the path style in use by checking the first separator.
+ llvm::sys::path::Style style = llvm::sys::path::Style::native;
+ const size_t n = Path.find_first_of("/\\");
+ if (n != static_cast<size_t>(-1))
+ style = (Path[n] == '/') ? llvm::sys::path::Style::posix
+ : llvm::sys::path::Style::windows;
+
+ // Now remove the dots. Explicitly specifying the path style prevents the
+ // direction of the slashes from changing.
+ llvm::SmallString<256> result =
+ llvm::sys::path::remove_leading_dotslash(Path, style);
+ llvm::sys::path::remove_dots(result, /*remove_dot_dot=*/true, style);
+ return result;
+}
+
+} // anonymous namespace
+
+
RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
: ExternalFS(std::move(FS)) {
if (ExternalFS)
@@ -1064,7 +1087,7 @@ RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
Path.toVector(AbsolutePath);
if (std::error_code EC = makeAbsolute(AbsolutePath))
return EC;
- WorkingDirectory = AbsolutePath.str();
+ WorkingDirectory = std::string(AbsolutePath.str());
return {};
}
@@ -1082,7 +1105,23 @@ std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path)
if (!WorkingDir)
return WorkingDir.getError();
- llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
+ // We can't use sys::fs::make_absolute because that assumes the path style
+ // is native and there is no way to override that. Since we know WorkingDir
+ // is absolute, we can use it to determine which style we actually have and
+ // append Path ourselves.
+ sys::path::Style style = sys::path::Style::windows;
+ if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) {
+ style = sys::path::Style::posix;
+ }
+
+ std::string Result = WorkingDir.get();
+ StringRef Dir(Result);
+ if (!Dir.endswith(sys::path::get_separator(style))) {
+ Result += sys::path::get_separator(style);
+ }
+ Result.append(Path.data(), Path.size());
+ Path.assign(Result.begin(), Result.end());
+
return {};
}
@@ -1317,8 +1356,8 @@ class llvm::vfs::RedirectingFileSystemParser {
bool HasContents = false; // external or otherwise
std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
EntryArrayContents;
- std::string ExternalContentsPath;
- std::string Name;
+ SmallString<256> ExternalContentsPath;
+ SmallString<256> Name;
yaml::Node *NameValueNode = nullptr;
auto UseExternalName =
RedirectingFileSystem::RedirectingFileEntry::NK_NotSet;
@@ -1341,16 +1380,9 @@ class llvm::vfs::RedirectingFileSystemParser {
return nullptr;
NameValueNode = I.getValue();
- if (FS->UseCanonicalizedPaths) {
- SmallString<256> Path(Value);
- // Guarantee that old YAML files containing paths with ".." and "."
- // are properly canonicalized before read into the VFS.
- Path = sys::path::remove_leading_dotslash(Path);
- sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
- Name = Path.str();
- } else {
- Name = Value;
- }
+ // Guarantee that old YAML files containing paths with ".." and "."
+ // are properly canonicalized before read into the VFS.
+ Name = canonicalize(Value).str();
} else if (Key == "type") {
if (!parseScalarString(I.getValue(), Value, Buffer))
return nullptr;
@@ -1403,12 +1435,9 @@ class llvm::vfs::RedirectingFileSystemParser {
FullPath = Value;
}
- if (FS->UseCanonicalizedPaths) {
- // Guarantee that old YAML files containing paths with ".." and "."
- // are properly canonicalized before read into the VFS.
- FullPath = sys::path::remove_leading_dotslash(FullPath);
- sys::path::remove_dots(FullPath, /*remove_dot_dot=*/true);
- }
+ // Guarantee that old YAML files containing paths with ".." and "."
+ // are properly canonicalized before read into the VFS.
+ FullPath = canonicalize(FullPath);
ExternalContentsPath = FullPath.str();
} else if (Key == "use-external-name") {
bool Val;
@@ -1653,14 +1682,10 @@ RedirectingFileSystem::lookupPath(const Twine &Path_) const {
if (std::error_code EC = makeAbsolute(Path))
return EC;
- // Canonicalize path by removing ".", "..", "./", etc components. This is
- // a VFS request, do bot bother about symlinks in the path components
+ // Canonicalize path by removing ".", "..", "./", components. This is
+ // a VFS request, do not bother about symlinks in the path components
// but canonicalize in order to perform the correct entry search.
- if (UseCanonicalizedPaths) {
- Path = sys::path::remove_leading_dotslash(Path);
- sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
- }
-
+ Path = canonicalize(Path);
if (Path.empty())
return make_error_code(llvm::errc::invalid_argument);
@@ -1679,16 +1704,9 @@ ErrorOr<RedirectingFileSystem::Entry *>
RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
sys::path::const_iterator End,
RedirectingFileSystem::Entry *From) const {
-#ifndef _WIN32
assert(!isTraversalComponent(*Start) &&
!isTraversalComponent(From->getName()) &&
"Paths should not contain traversal components");
-#else
- // FIXME: this is here to support windows, remove it once canonicalized
- // paths become globally default.
- if (Start->equals("."))
- ++Start;
-#endif
StringRef FromName = From->getName();
@@ -1894,11 +1912,21 @@ UniqueID vfs::getNextVirtualUniqueID() {
return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
}
-void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
+void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
+ bool IsDirectory) {
assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
assert(sys::path::is_absolute(RealPath) && "real path not absolute");
assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
- Mappings.emplace_back(VirtualPath, RealPath);
+ Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
+}
+
+void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
+ addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
+}
+
+void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath,
+ StringRef RealPath) {
+ addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
}
namespace {
@@ -1999,7 +2027,10 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
if (!Entries.empty()) {
const YAMLVFSEntry &Entry = Entries.front();
- startDirectory(path::parent_path(Entry.VPath));
+
+ startDirectory(
+ Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath)
+ );
StringRef RPath = Entry.RPath;
if (UseOverlayRelative) {
@@ -2009,19 +2040,31 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
RPath = RPath.slice(OverlayDirLen, RPath.size());
}
- writeEntry(path::filename(Entry.VPath), RPath);
+ bool IsCurrentDirEmpty = true;
+ if (!Entry.IsDirectory) {
+ writeEntry(path::filename(Entry.VPath), RPath);
+ IsCurrentDirEmpty = false;
+ }
for (const auto &Entry : Entries.slice(1)) {
- StringRef Dir = path::parent_path(Entry.VPath);
- if (Dir == DirStack.back())
- OS << ",\n";
- else {
+ StringRef Dir =
+ Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
+ if (Dir == DirStack.back()) {
+ if (!IsCurrentDirEmpty) {
+ OS << ",\n";
+ }
+ } else {
+ bool IsDirPoppedFromStack = false;
while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
OS << "\n";
endDirectory();
+ IsDirPoppedFromStack = true;
+ }
+ if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
+ OS << ",\n";
}
- OS << ",\n";
startDirectory(Dir);
+ IsCurrentDirEmpty = true;
}
StringRef RPath = Entry.RPath;
if (UseOverlayRelative) {
@@ -2030,7 +2073,10 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
"Overlay dir must be contained in RPath");
RPath = RPath.slice(OverlayDirLen, RPath.size());
}
- writeEntry(path::filename(Entry.VPath), RPath);
+ if (!Entry.IsDirectory) {
+ writeEntry(path::filename(Entry.VPath), RPath);
+ IsCurrentDirEmpty = false;
+ }
}
while (!DirStack.empty()) {
@@ -2104,7 +2150,7 @@ std::error_code VFSFromYamlDirIterImpl::incrementContent(bool IsFirstTime) {
Type = sys::fs::file_type::regular_file;
break;
}
- CurrentEntry = directory_entry(PathStr.str(), Type);
+ CurrentEntry = directory_entry(std::string(PathStr.str()), Type);
return {};
}
return incrementExternal();
diff --git a/llvm/lib/Support/Windows/DynamicLibrary.inc b/llvm/lib/Support/Windows/DynamicLibrary.inc
index 71b206c4cf9ee..a3f78fb0d6ba5 100644
--- a/llvm/lib/Support/Windows/DynamicLibrary.inc
+++ b/llvm/lib/Support/Windows/DynamicLibrary.inc
@@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/llvm/lib/Support/Windows/Host.inc b/llvm/lib/Support/Windows/Host.inc
index 21b947f26df3e..5583db909045a 100644
--- a/llvm/lib/Support/Windows/Host.inc
+++ b/llvm/lib/Support/Windows/Host.inc
@@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include <cstdio>
#include <string>
diff --git a/llvm/lib/Support/Windows/Memory.inc b/llvm/lib/Support/Windows/Memory.inc
index c5566f9910a56..1b2de1915ec46 100644
--- a/llvm/lib/Support/Windows/Memory.inc
+++ b/llvm/lib/Support/Windows/Memory.inc
@@ -17,7 +17,7 @@
#include "llvm/Support/WindowsError.h"
// The Windows.h header must be the last one included.
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
static DWORD getWindowsProtectionFlags(unsigned Flags) {
switch (Flags & llvm::sys::Memory::MF_RWE_MASK) {
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index c3b13abef5def..e352beb77616b 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -25,7 +25,7 @@
// These two headers must be included last, and make sure shlobj is required
// after Windows.h to make sure it picks up our definition of _WIN32_WINNT
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include <shellapi.h>
#include <shlobj.h>
@@ -47,7 +47,7 @@ using namespace llvm;
using llvm::sys::windows::UTF8ToUTF16;
using llvm::sys::windows::CurCPToUTF16;
using llvm::sys::windows::UTF16ToUTF8;
-using llvm::sys::path::widenPath;
+using llvm::sys::windows::widenPath;
static bool is_separator(const wchar_t value) {
switch (value) {
@@ -61,64 +61,64 @@ static bool is_separator(const wchar_t value) {
namespace llvm {
namespace sys {
-namespace path {
+namespace windows {
-// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the
-// path is longer than CreateDirectory can tolerate, make it absolute and
-// prefixed by '\\?\'.
-std::error_code widenPath(const Twine &Path8,
- SmallVectorImpl<wchar_t> &Path16) {
- const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename.
+// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the path
+// is longer than the limit that the Win32 Unicode File API can tolerate, make
+// it an absolute normalized path prefixed by '\\?\'.
+std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
+ size_t MaxPathLen) {
+ assert(MaxPathLen <= MAX_PATH);
- // Several operations would convert Path8 to SmallString; more efficient to
- // do it once up front.
- SmallString<128> Path8Str;
+ // Several operations would convert Path8 to SmallString; more efficient to do
+ // it once up front.
+ SmallString<MAX_PATH> Path8Str;
Path8.toVector(Path8Str);
- // If we made this path absolute, how much longer would it get?
+ if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16))
+ return EC;
+
+ const bool IsAbsolute = llvm::sys::path::is_absolute(Path8);
size_t CurPathLen;
- if (llvm::sys::path::is_absolute(Twine(Path8Str)))
+ if (IsAbsolute)
CurPathLen = 0; // No contribution from current_path needed.
else {
- CurPathLen = ::GetCurrentDirectoryW(0, NULL);
+ CurPathLen = ::GetCurrentDirectoryW(
+ 0, NULL); // Returns the size including the null terminator.
if (CurPathLen == 0)
return mapWindowsError(::GetLastError());
}
- // Would the absolute path be longer than our limit?
- if ((Path8Str.size() + CurPathLen) >= MaxDirLen &&
- !Path8Str.startswith("\\\\?\\")) {
- SmallString<2*MAX_PATH> FullPath("\\\\?\\");
- if (CurPathLen) {
- SmallString<80> CurPath;
- if (std::error_code EC = llvm::sys::fs::current_path(CurPath))
- return EC;
- FullPath.append(CurPath);
- }
- // Traverse the requested path, canonicalizing . and .. (because the \\?\
- // prefix is documented to treat them as real components). Ignore
- // separators, which can be returned from the iterator if the path has a
- // drive name. We don't need to call native() on the result since append()
- // always attaches preferred_separator.
- for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str),
- E = llvm::sys::path::end(Path8Str);
- I != E; ++I) {
- if (I->size() == 1 && is_separator((*I)[0]))
- continue;
- if (I->size() == 1 && *I == ".")
- continue;
- if (I->size() == 2 && *I == "..")
- llvm::sys::path::remove_filename(FullPath);
- else
- llvm::sys::path::append(FullPath, *I);
- }
- return UTF8ToUTF16(FullPath, Path16);
+ const char *const LongPathPrefix = "\\\\?\\";
+
+ if ((Path16.size() + CurPathLen) < MaxPathLen ||
+ Path8Str.startswith(LongPathPrefix))
+ return std::error_code();
+
+ if (!IsAbsolute) {
+ if (std::error_code EC = llvm::sys::fs::make_absolute(Path8Str))
+ return EC;
}
- // Just use the caller's original path.
- return UTF8ToUTF16(Path8Str, Path16);
+ // Remove '.' and '..' because long paths treat these as real path components.
+ llvm::sys::path::native(Path8Str, path::Style::windows);
+ llvm::sys::path::remove_dots(Path8Str, true);
+
+ const StringRef RootName = llvm::sys::path::root_name(Path8Str);
+ assert(!RootName.empty() &&
+ "Root name cannot be empty for an absolute path!");
+
+ SmallString<2 * MAX_PATH> FullPath(LongPathPrefix);
+ if (RootName[1] != ':') { // Check if UNC.
+ FullPath.append("UNC\\");
+ FullPath.append(Path8Str.begin() + 2, Path8Str.end());
+ } else
+ FullPath.append(Path8Str);
+
+ return UTF8ToUTF16(FullPath, Path16);
}
-} // end namespace path
+
+} // end namespace windows
namespace fs {
@@ -227,7 +227,9 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting,
perms Perms) {
SmallVector<wchar_t, 128> path_utf16;
- if (std::error_code ec = widenPath(path, path_utf16))
+ // CreateDirectoryW has a lower maximum path length as it must leave room for
+ // an 8.3 filename.
+ if (std::error_code ec = widenPath(path, path_utf16, MAX_PATH - 12))
return ec;
if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
@@ -553,6 +555,11 @@ std::error_code rename(const Twine &From, const Twine &To) {
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FromHandle)
break;
+
+ // We don't want to loop if the file doesn't exist.
+ auto EC = mapWindowsError(GetLastError());
+ if (EC == errc::no_such_file_or_directory)
+ return EC;
}
if (!FromHandle)
return mapWindowsError(GetLastError());
@@ -950,9 +957,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &IT,
return EC;
// Convert path to the format that Windows is happy with.
- if (PathUTF16.size() > 0 &&
- !is_separator(PathUTF16[Path.size() - 1]) &&
- PathUTF16[Path.size() - 1] != L':') {
+ size_t PathUTF16Len = PathUTF16.size();
+ if (PathUTF16Len > 0 && !is_separator(PathUTF16[PathUTF16Len - 1]) &&
+ PathUTF16[PathUTF16Len - 1] != L':') {
PathUTF16.push_back(L'\\');
PathUTF16.push_back(L'*');
} else {
@@ -1365,6 +1372,16 @@ bool home_directory(SmallVectorImpl<char> &result) {
return getKnownFolderPath(FOLDERID_Profile, result);
}
+bool user_config_directory(SmallVectorImpl<char> &result) {
+ // Either local or roaming appdata may be suitable in some cases, depending
+ // on the data. Local is more conservative, Roaming may not always be correct.
+ return getKnownFolderPath(FOLDERID_LocalAppData, result);
+}
+
+bool cache_directory(SmallVectorImpl<char> &result) {
+ return getKnownFolderPath(FOLDERID_LocalAppData, result);
+}
+
static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) {
SmallVector<wchar_t, 1024> Buf;
size_t Size = 1024;
diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc
index 3526e3dee6fa1..8064d4e17b295 100644
--- a/llvm/lib/Support/Windows/Process.inc
+++ b/llvm/lib/Support/Windows/Process.inc
@@ -19,7 +19,7 @@
#include <malloc.h>
// The Windows.h header must be after LLVM and standard headers.
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include <direct.h>
#include <io.h>
@@ -43,6 +43,12 @@
using namespace llvm;
+Process::Pid Process::getProcessId() {
+ static_assert(sizeof(Pid) >= sizeof(DWORD),
+ "Process::Pid should be big enough to store DWORD");
+ return Pid(::GetCurrentProcessId());
+}
+
// This function retrieves the page size using GetNativeSystemInfo() and is
// present solely so it can be called once to initialize the self_process member
// below.
@@ -439,18 +445,38 @@ const char *Process::ResetColor() {
return 0;
}
+static unsigned GetRandomNumberSeed() {
+ // Generate a random number seed from the millisecond-resolution Windows
+ // system clock and the current process id.
+ FILETIME Time;
+ GetSystemTimeAsFileTime(&Time);
+ DWORD Pid = GetCurrentProcessId();
+ return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid);
+}
+
+static unsigned GetPseudoRandomNumber() {
+ // Arrange to call srand once when this function is first used, and
+ // otherwise (if GetRandomNumber always succeeds in using
+ // CryptGenRandom) don't bother at all.
+ static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);
+ (void)x;
+ return ::rand();
+}
+
unsigned Process::GetRandomNumber() {
+ // Try to use CryptGenRandom.
HCRYPTPROV HCPC;
- if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT))
- ReportLastErrorFatal("Could not acquire a cryptographic context");
-
- ScopedCryptContext CryptoProvider(HCPC);
- unsigned Ret;
- if (!::CryptGenRandom(CryptoProvider, sizeof(Ret),
- reinterpret_cast<BYTE *>(&Ret)))
- ReportLastErrorFatal("Could not generate a random number");
- return Ret;
+ if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ ScopedCryptContext CryptoProvider(HCPC);
+ unsigned Ret;
+ if (::CryptGenRandom(CryptoProvider, sizeof(Ret),
+ reinterpret_cast<BYTE *>(&Ret)))
+ return Ret;
+ }
+
+ // If that fails, fall back to pseudo-random numbers.
+ return GetPseudoRandomNumber();
}
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
diff --git a/llvm/lib/Support/Windows/Program.inc b/llvm/lib/Support/Windows/Program.inc
index a1482bf17c604..9fe05d24ec2eb 100644
--- a/llvm/lib/Support/Windows/Program.inc
+++ b/llvm/lib/Support/Windows/Program.inc
@@ -10,14 +10,15 @@
//
//===----------------------------------------------------------------------===//
-#include "WindowsSupport.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include "llvm/Support/WindowsError.h"
#include "llvm/Support/raw_ostream.h"
+#include <psapi.h>
#include <cstdio>
#include <fcntl.h>
#include <io.h>
@@ -138,7 +139,7 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd,
if (Path->empty())
fname = "NUL";
else
- fname = *Path;
+ fname = std::string(*Path);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
@@ -151,7 +152,7 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd,
if (windows::UTF8ToUTF16(fname, fnameUnicode))
return INVALID_HANDLE_VALUE;
} else {
- if (path::widenPath(fname, fnameUnicode))
+ if (sys::windows::widenPath(fname, fnameUnicode))
return INVALID_HANDLE_VALUE;
}
h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
@@ -263,7 +264,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
fflush(stderr);
SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
- if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) {
+ if (std::error_code ec = sys::windows::widenPath(Program, ProgramUtf16)) {
SetLastError(ec.value());
MakeErrMsg(ErrMsg,
std::string("Unable to convert application name to UTF-16"));
@@ -390,7 +391,8 @@ std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) {
}
ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
- bool WaitUntilChildTerminates, std::string *ErrMsg) {
+ bool WaitUntilChildTerminates, std::string *ErrMsg,
+ Optional<ProcessStatistics> *ProcStat) {
assert(PI.Pid && "invalid pid to wait on, process not started?");
assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) &&
"invalid process handle to wait on, process not started?");
@@ -401,6 +403,8 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
milliSecondsToWait = SecondsToWait * 1000;
ProcessInfo WaitResult = PI;
+ if (ProcStat)
+ ProcStat->reset();
DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait);
if (WaitStatus == WAIT_TIMEOUT) {
if (SecondsToWait) {
@@ -421,6 +425,22 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
}
}
+ // Get process execution statistics.
+ if (ProcStat) {
+ FILETIME CreationTime, ExitTime, KernelTime, UserTime;
+ PROCESS_MEMORY_COUNTERS MemInfo;
+ if (GetProcessTimes(PI.Process, &CreationTime, &ExitTime, &KernelTime,
+ &UserTime) &&
+ GetProcessMemoryInfo(PI.Process, &MemInfo, sizeof(MemInfo))) {
+ auto UserT = std::chrono::duration_cast<std::chrono::microseconds>(
+ toDuration(UserTime));
+ auto KernelT = std::chrono::duration_cast<std::chrono::microseconds>(
+ toDuration(KernelTime));
+ uint64_t PeakMemory = MemInfo.PeakPagefileUsage / 1024;
+ *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};
+ }
+ }
+
// Get its exit status.
DWORD status;
BOOL rc = GetExitCodeProcess(PI.Process, &status);
diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc
index 8b525f1bd4ac4..0c3681fa96548 100644
--- a/llvm/lib/Support/Windows/Signals.inc
+++ b/llvm/lib/Support/Windows/Signals.inc
@@ -23,7 +23,7 @@
#include "llvm/Support/raw_ostream.h"
// The Windows.h header must be after LLVM and standard headers.
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#ifdef __MINGW32__
#include <imagehlp.h>
@@ -460,7 +460,7 @@ bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
if (FilesToRemove == NULL)
FilesToRemove = new std::vector<std::string>;
- FilesToRemove->push_back(Filename);
+ FilesToRemove->push_back(std::string(Filename));
LeaveCriticalSection(&CriticalSection);
return false;
@@ -584,7 +584,7 @@ void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
LeaveCriticalSection(&CriticalSection);
}
-static void Cleanup() {
+static void Cleanup(bool ExecuteSignalHandlers) {
if (CleanupExecuted)
return;
@@ -600,7 +600,10 @@ static void Cleanup() {
llvm::sys::fs::remove(FilesToRemove->back());
FilesToRemove->pop_back();
}
- llvm::sys::RunSignalHandlers();
+
+ if (ExecuteSignalHandlers)
+ llvm::sys::RunSignalHandlers();
+
LeaveCriticalSection(&CriticalSection);
}
@@ -610,7 +613,7 @@ void llvm::sys::RunInterruptHandlers() {
// error handler). We must ensure that the critical section is properly
// initialized.
InitializeThreading();
- Cleanup();
+ Cleanup(true);
}
/// Find the Windows Registry Key for a given location.
@@ -803,7 +806,7 @@ void sys::CleanupOnSignal(uintptr_t Context) {
}
static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
- Cleanup();
+ Cleanup(true);
// We'll automatically write a Minidump file here to help diagnose
// the nasty sorts of crashes that aren't 100% reproducible from a set of
@@ -820,7 +823,13 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
<< "\n";
}
- LocalPrintStackTrace(llvm::errs(), ep ? ep->ContextRecord : nullptr);
+ // Stack unwinding appears to modify the context. Copy it to preserve the
+ // caller's context.
+ CONTEXT ContextCopy;
+ if (ep)
+ memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy));
+
+ LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr);
return EXCEPTION_EXECUTE_HANDLER;
}
@@ -828,7 +837,10 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
// We are running in our very own thread, courtesy of Windows.
EnterCriticalSection(&CriticalSection);
- Cleanup();
+ // This function is only ever called when a CTRL-C or similar control signal
+ // is fired. Killing a process in this way is normal, so don't trigger the
+ // signal handlers.
+ Cleanup(false);
// If an interrupt function has been set, go and run one it; otherwise,
// the process dies.
diff --git a/llvm/lib/Support/Windows/ThreadLocal.inc b/llvm/lib/Support/Windows/ThreadLocal.inc
index 1e0ed955e9abe..696e5c843ead4 100644
--- a/llvm/lib/Support/Windows/ThreadLocal.inc
+++ b/llvm/lib/Support/Windows/ThreadLocal.inc
@@ -15,7 +15,7 @@
//=== is guaranteed to work on *all* Win32 variants.
//===----------------------------------------------------------------------===//
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include "llvm/Support/ThreadLocal.h"
namespace llvm {
diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc
index 9456efa686ffc..296e87b776959 100644
--- a/llvm/lib/Support/Windows/Threading.inc
+++ b/llvm/lib/Support/Windows/Threading.inc
@@ -13,9 +13,11 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
-#include "WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#include <process.h>
+#include <bitset>
+
// Windows will at times define MemoryFence.
#ifdef MemoryFence
#undef MemoryFence
@@ -122,3 +124,175 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
? SetThreadPriorityResult::SUCCESS
: SetThreadPriorityResult::FAILURE;
}
+
+struct ProcessorGroup {
+ unsigned ID;
+ unsigned AllThreads;
+ unsigned UsableThreads;
+ unsigned ThreadsPerCore;
+ uint64_t Affinity;
+
+ unsigned useableCores() const {
+ return std::max(1U, UsableThreads / ThreadsPerCore);
+ }
+};
+
+template <typename F>
+static bool IterateProcInfo(LOGICAL_PROCESSOR_RELATIONSHIP Relationship, F Fn) {
+ DWORD Len = 0;
+ BOOL R = ::GetLogicalProcessorInformationEx(Relationship, NULL, &Len);
+ if (R || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ return false;
+ }
+ auto *Info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)calloc(1, Len);
+ R = ::GetLogicalProcessorInformationEx(Relationship, Info, &Len);
+ if (R) {
+ auto *End =
+ (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Info + Len);
+ for (auto *Curr = Info; Curr < End;
+ Curr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Curr +
+ Curr->Size)) {
+ if (Curr->Relationship != Relationship)
+ continue;
+ Fn(Curr);
+ }
+ }
+ free(Info);
+ return true;
+}
+
+static ArrayRef<ProcessorGroup> getProcessorGroups() {
+ auto computeGroups = []() {
+ SmallVector<ProcessorGroup, 4> Groups;
+
+ auto HandleGroup = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) {
+ GROUP_RELATIONSHIP &El = ProcInfo->Group;
+ for (unsigned J = 0; J < El.ActiveGroupCount; ++J) {
+ ProcessorGroup G;
+ G.ID = Groups.size();
+ G.AllThreads = El.GroupInfo[J].MaximumProcessorCount;
+ G.UsableThreads = El.GroupInfo[J].ActiveProcessorCount;
+ assert(G.UsableThreads <= 64);
+ G.Affinity = El.GroupInfo[J].ActiveProcessorMask;
+ Groups.push_back(G);
+ }
+ };
+
+ if (!IterateProcInfo(RelationGroup, HandleGroup))
+ return std::vector<ProcessorGroup>();
+
+ auto HandleProc = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) {
+ PROCESSOR_RELATIONSHIP &El = ProcInfo->Processor;
+ assert(El.GroupCount == 1);
+ unsigned NumHyperThreads = 1;
+ // If the flag is set, each core supports more than one hyper-thread.
+ if (El.Flags & LTP_PC_SMT)
+ NumHyperThreads = std::bitset<64>(El.GroupMask[0].Mask).count();
+ unsigned I = El.GroupMask[0].Group;
+ Groups[I].ThreadsPerCore = NumHyperThreads;
+ };
+
+ if (!IterateProcInfo(RelationProcessorCore, HandleProc))
+ return std::vector<ProcessorGroup>();
+
+ // If there's an affinity mask set on one of the CPUs, then assume the user
+ // wants to constrain the current process to only a single CPU.
+ for (auto &G : Groups) {
+ if (G.UsableThreads != G.AllThreads) {
+ ProcessorGroup NewG{G};
+ Groups.clear();
+ Groups.push_back(NewG);
+ break;
+ }
+ }
+
+ return std::vector<ProcessorGroup>(Groups.begin(), Groups.end());
+ };
+ static auto Groups = computeGroups();
+ return ArrayRef<ProcessorGroup>(Groups);
+}
+
+template <typename R, typename UnaryPredicate>
+static unsigned aggregate(R &&Range, UnaryPredicate P) {
+ unsigned I{};
+ for (const auto &It : Range)
+ I += P(It);
+ return I;
+}
+
+// for sys::getHostNumPhysicalCores
+int computeHostNumPhysicalCores() {
+ static unsigned Cores =
+ aggregate(getProcessorGroups(), [](const ProcessorGroup &G) {
+ return G.UsableThreads / G.ThreadsPerCore;
+ });
+ return Cores;
+}
+
+int computeHostNumHardwareThreads() {
+ static unsigned Threads =
+ aggregate(getProcessorGroups(),
+ [](const ProcessorGroup &G) { return G.UsableThreads; });
+ return Threads;
+}
+
+// Finds the proper CPU socket where a thread number should go. Returns 'None'
+// if the thread shall remain on the actual CPU socket.
+Optional<unsigned>
+llvm::ThreadPoolStrategy::compute_cpu_socket(unsigned ThreadPoolNum) const {
+ ArrayRef<ProcessorGroup> Groups = getProcessorGroups();
+ // Only one CPU socket in the system or process affinity was set, no need to
+ // move the thread(s) to another CPU socket.
+ if (Groups.size() <= 1)
+ return None;
+
+ // We ask for less threads than there are hardware threads per CPU socket, no
+ // need to dispatch threads to other CPU sockets.
+ unsigned MaxThreadsPerSocket =
+ UseHyperThreads ? Groups[0].UsableThreads : Groups[0].useableCores();
+ if (compute_thread_count() <= MaxThreadsPerSocket)
+ return None;
+
+ assert(ThreadPoolNum < compute_thread_count() &&
+ "The thread index is not within thread strategy's range!");
+
+ // Assumes the same number of hardware threads per CPU socket.
+ return (ThreadPoolNum * Groups.size()) / compute_thread_count();
+}
+
+// Assign the current thread to a more appropriate CPU socket or CPU group
+void llvm::ThreadPoolStrategy::apply_thread_strategy(
+ unsigned ThreadPoolNum) const {
+ Optional<unsigned> Socket = compute_cpu_socket(ThreadPoolNum);
+ if (!Socket)
+ return;
+ ArrayRef<ProcessorGroup> Groups = getProcessorGroups();
+ GROUP_AFFINITY Affinity{};
+ Affinity.Group = Groups[*Socket].ID;
+ Affinity.Mask = Groups[*Socket].Affinity;
+ SetThreadGroupAffinity(GetCurrentThread(), &Affinity, nullptr);
+}
+
+llvm::BitVector llvm::get_thread_affinity_mask() {
+ GROUP_AFFINITY Affinity{};
+ GetThreadGroupAffinity(GetCurrentThread(), &Affinity);
+
+ static unsigned All =
+ aggregate(getProcessorGroups(),
+ [](const ProcessorGroup &G) { return G.AllThreads; });
+
+ unsigned StartOffset =
+ aggregate(getProcessorGroups(), [&](const ProcessorGroup &G) {
+ return G.ID < Affinity.Group ? G.AllThreads : 0;
+ });
+
+ llvm::BitVector V;
+ V.resize(All);
+ for (unsigned I = 0; I < sizeof(KAFFINITY) * 8; ++I) {
+ if ((Affinity.Mask >> I) & 1)
+ V.set(StartOffset + I);
+ }
+ return V;
+}
+
+unsigned llvm::get_cpus() { return getProcessorGroups().size(); }
diff --git a/llvm/lib/Support/Windows/WindowsSupport.h b/llvm/lib/Support/Windows/WindowsSupport.h
deleted file mode 100644
index bb7e79b860180..0000000000000
--- a/llvm/lib/Support/Windows/WindowsSupport.h
+++ /dev/null
@@ -1,243 +0,0 @@
-//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines things specific to Windows implementations. In addition to
-// providing some helpers for working with win32 APIs, this header wraps
-// <windows.h> with some portability macros. Always include WindowsSupport.h
-// instead of including <windows.h> directly.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Win32 code that
-//=== is guaranteed to work on *all* Win32 variants.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H
-#define LLVM_SUPPORT_WINDOWSSUPPORT_H
-
-// mingw-w64 tends to define it as 0x0502 in its headers.
-#undef _WIN32_WINNT
-#undef _WIN32_IE
-
-// Require at least Windows 7 API.
-#define _WIN32_WINNT 0x0601
-#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed.
-#define WIN32_LEAN_AND_MEAN
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Config/config.h" // Get build system configuration settings
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Chrono.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/VersionTuple.h"
-#include <cassert>
-#include <string>
-#include <system_error>
-#include <windows.h>
-
-// Must be included after windows.h
-#include <wincrypt.h>
-
-namespace llvm {
-
-/// Determines if the program is running on Windows 8 or newer. This
-/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
-/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't
-/// yet have VersionHelpers.h, so we have our own helper.
-bool RunningWindows8OrGreater();
-
-/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
-/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
-/// GetVersionEx is deprecated, but this API exposes the build number which can
-/// be useful for working around certain kernel bugs.
-llvm::VersionTuple GetWindowsOSVersion();
-
-bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix);
-
-// Include GetLastError() in a fatal error message.
-LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) {
- std::string ErrMsg;
- MakeErrMsg(&ErrMsg, Msg);
- llvm::report_fatal_error(ErrMsg);
-}
-
-template <typename HandleTraits>
-class ScopedHandle {
- typedef typename HandleTraits::handle_type handle_type;
- handle_type Handle;
-
- ScopedHandle(const ScopedHandle &other) = delete;
- void operator=(const ScopedHandle &other) = delete;
-public:
- ScopedHandle()
- : Handle(HandleTraits::GetInvalid()) {}
-
- explicit ScopedHandle(handle_type h)
- : Handle(h) {}
-
- ~ScopedHandle() {
- if (HandleTraits::IsValid(Handle))
- HandleTraits::Close(Handle);
- }
-
- handle_type take() {
- handle_type t = Handle;
- Handle = HandleTraits::GetInvalid();
- return t;
- }
-
- ScopedHandle &operator=(handle_type h) {
- if (HandleTraits::IsValid(Handle))
- HandleTraits::Close(Handle);
- Handle = h;
- return *this;
- }
-
- // True if Handle is valid.
- explicit operator bool() const {
- return HandleTraits::IsValid(Handle) ? true : false;
- }
-
- operator handle_type() const {
- return Handle;
- }
-};
-
-struct CommonHandleTraits {
- typedef HANDLE handle_type;
-
- static handle_type GetInvalid() {
- return INVALID_HANDLE_VALUE;
- }
-
- static void Close(handle_type h) {
- ::CloseHandle(h);
- }
-
- static bool IsValid(handle_type h) {
- return h != GetInvalid();
- }
-};
-
-struct JobHandleTraits : CommonHandleTraits {
- static handle_type GetInvalid() {
- return NULL;
- }
-};
-
-struct CryptContextTraits : CommonHandleTraits {
- typedef HCRYPTPROV handle_type;
-
- static handle_type GetInvalid() {
- return 0;
- }
-
- static void Close(handle_type h) {
- ::CryptReleaseContext(h, 0);
- }
-
- static bool IsValid(handle_type h) {
- return h != GetInvalid();
- }
-};
-
-struct RegTraits : CommonHandleTraits {
- typedef HKEY handle_type;
-
- static handle_type GetInvalid() {
- return NULL;
- }
-
- static void Close(handle_type h) {
- ::RegCloseKey(h);
- }
-
- static bool IsValid(handle_type h) {
- return h != GetInvalid();
- }
-};
-
-struct FindHandleTraits : CommonHandleTraits {
- static void Close(handle_type h) {
- ::FindClose(h);
- }
-};
-
-struct FileHandleTraits : CommonHandleTraits {};
-
-typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
-typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
-typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
-typedef ScopedHandle<RegTraits> ScopedRegHandle;
-typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
-typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
-
-template <class T>
-class SmallVectorImpl;
-
-template <class T>
-typename SmallVectorImpl<T>::const_pointer
-c_str(SmallVectorImpl<T> &str) {
- str.push_back(0);
- str.pop_back();
- return str.data();
-}
-
-namespace sys {
-
-inline std::chrono::nanoseconds toDuration(FILETIME Time) {
- ULARGE_INTEGER TimeInteger;
- TimeInteger.LowPart = Time.dwLowDateTime;
- TimeInteger.HighPart = Time.dwHighDateTime;
-
- // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
- return std::chrono::nanoseconds(100 * TimeInteger.QuadPart);
-}
-
-inline TimePoint<> toTimePoint(FILETIME Time) {
- ULARGE_INTEGER TimeInteger;
- TimeInteger.LowPart = Time.dwLowDateTime;
- TimeInteger.HighPart = Time.dwHighDateTime;
-
- // Adjust for different epoch
- TimeInteger.QuadPart -= 11644473600ll * 10000000;
-
- // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
- return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart));
-}
-
-inline FILETIME toFILETIME(TimePoint<> TP) {
- ULARGE_INTEGER TimeInteger;
- TimeInteger.QuadPart = TP.time_since_epoch().count() / 100;
- TimeInteger.QuadPart += 11644473600ll * 10000000;
-
- FILETIME Time;
- Time.dwLowDateTime = TimeInteger.LowPart;
- Time.dwHighDateTime = TimeInteger.HighPart;
- return Time;
-}
-
-namespace windows {
-// Returns command line arguments. Unlike arguments given to main(),
-// this function guarantees that the returned arguments are encoded in
-// UTF-8 regardless of the current code page setting.
-std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args,
- BumpPtrAllocator &Alloc);
-} // end namespace windows
-} // end namespace sys
-} // end namespace llvm.
-
-#endif
diff --git a/llvm/lib/Support/WithColor.cpp b/llvm/lib/Support/WithColor.cpp
index 345dd9cf39492..cb5f413d44b78 100644
--- a/llvm/lib/Support/WithColor.cpp
+++ b/llvm/lib/Support/WithColor.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/WithColor.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/CommandLine.h"
using namespace llvm;
@@ -18,8 +18,8 @@ static cl::opt<cl::boolOrDefault>
cl::desc("Use colors in output (default=autodetect)"),
cl::init(cl::BOU_UNSET));
-WithColor::WithColor(raw_ostream &OS, HighlightColor Color, bool DisableColors)
- : OS(OS), DisableColors(DisableColors) {
+WithColor::WithColor(raw_ostream &OS, HighlightColor Color, ColorMode Mode)
+ : OS(OS), Mode(Mode) {
// Detect color from terminal type unless the user passed the --color option.
if (colorsEnabled()) {
switch (Color) {
@@ -69,7 +69,9 @@ raw_ostream &WithColor::error(raw_ostream &OS, StringRef Prefix,
bool DisableColors) {
if (!Prefix.empty())
OS << Prefix << ": ";
- return WithColor(OS, HighlightColor::Error, DisableColors).get()
+ return WithColor(OS, HighlightColor::Error,
+ DisableColors ? ColorMode::Disable : ColorMode::Auto)
+ .get()
<< "error: ";
}
@@ -77,7 +79,9 @@ raw_ostream &WithColor::warning(raw_ostream &OS, StringRef Prefix,
bool DisableColors) {
if (!Prefix.empty())
OS << Prefix << ": ";
- return WithColor(OS, HighlightColor::Warning, DisableColors).get()
+ return WithColor(OS, HighlightColor::Warning,
+ DisableColors ? ColorMode::Disable : ColorMode::Auto)
+ .get()
<< "warning: ";
}
@@ -85,23 +89,33 @@ raw_ostream &WithColor::note(raw_ostream &OS, StringRef Prefix,
bool DisableColors) {
if (!Prefix.empty())
OS << Prefix << ": ";
- return WithColor(OS, HighlightColor::Note, DisableColors).get() << "note: ";
+ return WithColor(OS, HighlightColor::Note,
+ DisableColors ? ColorMode::Disable : ColorMode::Auto)
+ .get()
+ << "note: ";
}
raw_ostream &WithColor::remark(raw_ostream &OS, StringRef Prefix,
bool DisableColors) {
if (!Prefix.empty())
OS << Prefix << ": ";
- return WithColor(OS, HighlightColor::Remark, DisableColors).get()
+ return WithColor(OS, HighlightColor::Remark,
+ DisableColors ? ColorMode::Disable : ColorMode::Auto)
+ .get()
<< "remark: ";
}
bool WithColor::colorsEnabled() {
- if (DisableColors)
+ switch (Mode) {
+ case ColorMode::Enable:
+ return true;
+ case ColorMode::Disable:
return false;
- if (UseColor == cl::BOU_UNSET)
- return OS.has_colors();
- return UseColor == cl::BOU_TRUE;
+ case ColorMode::Auto:
+ return UseColor == cl::BOU_UNSET ? OS.has_colors()
+ : UseColor == cl::BOU_TRUE;
+ }
+ llvm_unreachable("All cases handled above.");
}
WithColor &WithColor::changeColor(raw_ostream::Colors Color, bool Bold,
@@ -118,3 +132,15 @@ WithColor &WithColor::resetColor() {
}
WithColor::~WithColor() { resetColor(); }
+
+void WithColor::defaultErrorHandler(Error Err) {
+ handleAllErrors(std::move(Err), [](ErrorInfoBase &Info) {
+ WithColor::error() << Info.message() << '\n';
+ });
+}
+
+void WithColor::defaultWarningHandler(Error Warning) {
+ handleAllErrors(std::move(Warning), [](ErrorInfoBase &Info) {
+ WithColor::warning() << Info.message() << '\n';
+ });
+}
diff --git a/llvm/lib/Support/X86TargetParser.cpp b/llvm/lib/Support/X86TargetParser.cpp
new file mode 100644
index 0000000000000..572d1203aaf21
--- /dev/null
+++ b/llvm/lib/Support/X86TargetParser.cpp
@@ -0,0 +1,595 @@
+//===-- X86TargetParser - Parser for X86 features ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a target parser to recognise X86 hardware features.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/X86TargetParser.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace llvm;
+using namespace llvm::X86;
+
+namespace {
+
+/// Container class for CPU features.
+/// This is a constexpr reimplementation of a subset of std::bitset. It would be
+/// nice to use std::bitset directly, but it doesn't support constant
+/// initialization.
+class FeatureBitset {
+ static constexpr unsigned NUM_FEATURE_WORDS =
+ (X86::CPU_FEATURE_MAX + 31) / 32;
+
+ // This cannot be a std::array, operator[] is not constexpr until C++17.
+ uint32_t Bits[NUM_FEATURE_WORDS] = {};
+
+public:
+ constexpr FeatureBitset() = default;
+ constexpr FeatureBitset(std::initializer_list<unsigned> Init) {
+ for (auto I : Init)
+ set(I);
+ }
+
+ constexpr FeatureBitset &set(unsigned I) {
+ // GCC <6.2 crashes if this is written in a single statement.
+ uint32_t NewBits = Bits[I / 32] | (uint32_t(1) << (I % 32));
+ Bits[I / 32] = NewBits;
+ return *this;
+ }
+
+ constexpr bool operator[](unsigned I) const {
+ uint32_t Mask = uint32_t(1) << (I % 32);
+ return (Bits[I / 32] & Mask) != 0;
+ }
+
+ constexpr FeatureBitset &operator&=(const FeatureBitset &RHS) {
+ for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
+ // GCC <6.2 crashes if this is written in a single statement.
+ uint32_t NewBits = Bits[I] & RHS.Bits[I];
+ Bits[I] = NewBits;
+ }
+ return *this;
+ }
+
+ constexpr FeatureBitset &operator|=(const FeatureBitset &RHS) {
+ for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I) {
+ // GCC <6.2 crashes if this is written in a single statement.
+ uint32_t NewBits = Bits[I] | RHS.Bits[I];
+ Bits[I] = NewBits;
+ }
+ return *this;
+ }
+
+ // gcc 5.3 miscompiles this if we try to write this using operator&=.
+ constexpr FeatureBitset operator&(const FeatureBitset &RHS) const {
+ FeatureBitset Result;
+ for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
+ Result.Bits[I] = Bits[I] & RHS.Bits[I];
+ return Result;
+ }
+
+ // gcc 5.3 miscompiles this if we try to write this using operator&=.
+ constexpr FeatureBitset operator|(const FeatureBitset &RHS) const {
+ FeatureBitset Result;
+ for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
+ Result.Bits[I] = Bits[I] | RHS.Bits[I];
+ return Result;
+ }
+
+ constexpr FeatureBitset operator~() const {
+ FeatureBitset Result;
+ for (unsigned I = 0, E = array_lengthof(Bits); I != E; ++I)
+ Result.Bits[I] = ~Bits[I];
+ return Result;
+ }
+};
+
+struct ProcInfo {
+ StringLiteral Name;
+ X86::CPUKind Kind;
+ unsigned KeyFeature;
+ FeatureBitset Features;
+};
+
+struct FeatureInfo {
+ StringLiteral Name;
+ FeatureBitset ImpliedFeatures;
+};
+
+} // end anonymous namespace
+
+#define X86_FEATURE(ENUM, STRING) \
+ static constexpr FeatureBitset Feature##ENUM = {X86::FEATURE_##ENUM};
+#include "llvm/Support/X86TargetParser.def"
+
+// Pentium with MMX.
+static constexpr FeatureBitset FeaturesPentiumMMX =
+ FeatureX87 | FeatureCMPXCHG8B | FeatureMMX;
+
+// Pentium 2 and 3.
+static constexpr FeatureBitset FeaturesPentium2 =
+ FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | FeatureFXSR;
+static constexpr FeatureBitset FeaturesPentium3 = FeaturesPentium2 | FeatureSSE;
+
+// Pentium 4 CPUs
+static constexpr FeatureBitset FeaturesPentium4 =
+ FeaturesPentium3 | FeatureSSE2;
+static constexpr FeatureBitset FeaturesPrescott =
+ FeaturesPentium4 | FeatureSSE3;
+static constexpr FeatureBitset FeaturesNocona =
+ FeaturesPrescott | Feature64BIT | FeatureCMPXCHG16B;
+
+// Basic 64-bit capable CPU.
+static constexpr FeatureBitset FeaturesX86_64 = FeaturesPentium4 | Feature64BIT;
+
+// Intel Core CPUs
+static constexpr FeatureBitset FeaturesCore2 =
+ FeaturesNocona | FeatureSAHF | FeatureSSSE3;
+static constexpr FeatureBitset FeaturesPenryn = FeaturesCore2 | FeatureSSE4_1;
+static constexpr FeatureBitset FeaturesNehalem =
+ FeaturesPenryn | FeaturePOPCNT | FeatureSSE4_2;
+static constexpr FeatureBitset FeaturesWestmere =
+ FeaturesNehalem | FeaturePCLMUL;
+static constexpr FeatureBitset FeaturesSandyBridge =
+ FeaturesWestmere | FeatureAVX | FeatureXSAVE | FeatureXSAVEOPT;
+static constexpr FeatureBitset FeaturesIvyBridge =
+ FeaturesSandyBridge | FeatureF16C | FeatureFSGSBASE | FeatureRDRND;
+static constexpr FeatureBitset FeaturesHaswell =
+ FeaturesIvyBridge | FeatureAVX2 | FeatureBMI | FeatureBMI2 | FeatureFMA |
+ FeatureINVPCID | FeatureLZCNT | FeatureMOVBE;
+static constexpr FeatureBitset FeaturesBroadwell =
+ FeaturesHaswell | FeatureADX | FeaturePRFCHW | FeatureRDSEED;
+
+// Intel Knights Landing and Knights Mill
+// Knights Landing has feature parity with Broadwell.
+static constexpr FeatureBitset FeaturesKNL =
+ FeaturesBroadwell | FeatureAES | FeatureAVX512F | FeatureAVX512CD |
+ FeatureAVX512ER | FeatureAVX512PF | FeaturePREFETCHWT1;
+static constexpr FeatureBitset FeaturesKNM =
+ FeaturesKNL | FeatureAVX512VPOPCNTDQ;
+
+// Intel Skylake processors.
+static constexpr FeatureBitset FeaturesSkylakeClient =
+ FeaturesBroadwell | FeatureAES | FeatureCLFLUSHOPT | FeatureXSAVEC |
+ FeatureXSAVES | FeatureSGX;
+// SkylakeServer inherits all SkylakeClient features except SGX.
+// FIXME: That doesn't match gcc.
+static constexpr FeatureBitset FeaturesSkylakeServer =
+ (FeaturesSkylakeClient & ~FeatureSGX) | FeatureAVX512F | FeatureAVX512CD |
+ FeatureAVX512DQ | FeatureAVX512BW | FeatureAVX512VL | FeatureCLWB |
+ FeaturePKU;
+static constexpr FeatureBitset FeaturesCascadeLake =
+ FeaturesSkylakeServer | FeatureAVX512VNNI;
+static constexpr FeatureBitset FeaturesCooperLake =
+ FeaturesCascadeLake | FeatureAVX512BF16;
+
+// Intel 10nm processors.
+static constexpr FeatureBitset FeaturesCannonlake =
+ FeaturesSkylakeClient | FeatureAVX512F | FeatureAVX512CD | FeatureAVX512DQ |
+ FeatureAVX512BW | FeatureAVX512VL | FeatureAVX512IFMA | FeatureAVX512VBMI |
+ FeaturePKU | FeatureSHA;
+static constexpr FeatureBitset FeaturesICLClient =
+ FeaturesCannonlake | FeatureAVX512BITALG | FeatureAVX512VBMI2 |
+ FeatureAVX512VNNI | FeatureAVX512VPOPCNTDQ | FeatureCLWB | FeatureGFNI |
+ FeatureRDPID | FeatureVAES | FeatureVPCLMULQDQ;
+static constexpr FeatureBitset FeaturesICLServer =
+ FeaturesICLClient | FeaturePCONFIG | FeatureWBNOINVD;
+static constexpr FeatureBitset FeaturesTigerlake =
+ FeaturesICLClient | FeatureAVX512VP2INTERSECT | FeatureMOVDIR64B |
+ FeatureMOVDIRI | FeatureSHSTK;
+
+// Intel Atom processors.
+// Bonnell has feature parity with Core2 and adds MOVBE.
+static constexpr FeatureBitset FeaturesBonnell = FeaturesCore2 | FeatureMOVBE;
+// Silvermont has parity with Westmere and Bonnell plus PRFCHW and RDRND.
+static constexpr FeatureBitset FeaturesSilvermont =
+ FeaturesBonnell | FeaturesWestmere | FeaturePRFCHW | FeatureRDRND;
+static constexpr FeatureBitset FeaturesGoldmont =
+ FeaturesSilvermont | FeatureAES | FeatureCLFLUSHOPT | FeatureFSGSBASE |
+ FeatureRDSEED | FeatureSHA | FeatureXSAVE | FeatureXSAVEC |
+ FeatureXSAVEOPT | FeatureXSAVES;
+static constexpr FeatureBitset FeaturesGoldmontPlus =
+ FeaturesGoldmont | FeaturePTWRITE | FeatureRDPID | FeatureSGX;
+static constexpr FeatureBitset FeaturesTremont =
+ FeaturesGoldmontPlus | FeatureCLWB | FeatureGFNI;
+
+// Geode Processor.
+static constexpr FeatureBitset FeaturesGeode =
+ FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA;
+
+// K6 processor.
+static constexpr FeatureBitset FeaturesK6 =
+ FeatureX87 | FeatureCMPXCHG8B | FeatureMMX;
+
+// K7 and K8 architecture processors.
+static constexpr FeatureBitset FeaturesAthlon =
+ FeatureX87 | FeatureCMPXCHG8B | FeatureMMX | Feature3DNOW | Feature3DNOWA;
+static constexpr FeatureBitset FeaturesAthlonXP =
+ FeaturesAthlon | FeatureFXSR | FeatureSSE;
+static constexpr FeatureBitset FeaturesK8 =
+ FeaturesAthlonXP | FeatureSSE2 | Feature64BIT;
+static constexpr FeatureBitset FeaturesK8SSE3 = FeaturesK8 | FeatureSSE3;
+static constexpr FeatureBitset FeaturesAMDFAM10 =
+ FeaturesK8SSE3 | FeatureCMPXCHG16B | FeatureLZCNT | FeaturePOPCNT |
+ FeaturePRFCHW | FeatureSAHF | FeatureSSE4_A;
+
+// Bobcat architecture processors.
+static constexpr FeatureBitset FeaturesBTVER1 =
+ FeatureX87 | FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT |
+ FeatureFXSR | FeatureLZCNT | FeatureMMX | FeaturePOPCNT | FeaturePRFCHW |
+ FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_A |
+ FeatureSAHF;
+static constexpr FeatureBitset FeaturesBTVER2 =
+ FeaturesBTVER1 | FeatureAES | FeatureAVX | FeatureBMI | FeatureF16C |
+ FeatureMOVBE | FeaturePCLMUL | FeatureXSAVE | FeatureXSAVEOPT;
+
+// AMD Bulldozer architecture processors.
+static constexpr FeatureBitset FeaturesBDVER1 =
+ FeatureX87 | FeatureAES | FeatureAVX | FeatureCMPXCHG8B |
+ FeatureCMPXCHG16B | Feature64BIT | FeatureFMA4 | FeatureFXSR | FeatureLWP |
+ FeatureLZCNT | FeatureMMX | FeaturePCLMUL | FeaturePOPCNT | FeaturePRFCHW |
+ FeatureSAHF | FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 |
+ FeatureSSE4_1 | FeatureSSE4_2 | FeatureSSE4_A | FeatureXOP | FeatureXSAVE;
+static constexpr FeatureBitset FeaturesBDVER2 =
+ FeaturesBDVER1 | FeatureBMI | FeatureFMA | FeatureF16C | FeatureTBM;
+static constexpr FeatureBitset FeaturesBDVER3 =
+ FeaturesBDVER2 | FeatureFSGSBASE | FeatureXSAVEOPT;
+static constexpr FeatureBitset FeaturesBDVER4 =
+ FeaturesBDVER3 | FeatureAVX2 | FeatureBMI2 | FeatureMOVBE | FeatureMWAITX |
+ FeatureRDRND;
+
+// AMD Zen architecture processors.
+static constexpr FeatureBitset FeaturesZNVER1 =
+ FeatureX87 | FeatureADX | FeatureAES | FeatureAVX | FeatureAVX2 |
+ FeatureBMI | FeatureBMI2 | FeatureCLFLUSHOPT | FeatureCLZERO |
+ FeatureCMPXCHG8B | FeatureCMPXCHG16B | Feature64BIT | FeatureF16C |
+ FeatureFMA | FeatureFSGSBASE | FeatureFXSR | FeatureLZCNT | FeatureMMX |
+ FeatureMOVBE | FeatureMWAITX | FeaturePCLMUL | FeaturePOPCNT |
+ FeaturePRFCHW | FeatureRDRND | FeatureRDSEED | FeatureSAHF | FeatureSHA |
+ FeatureSSE | FeatureSSE2 | FeatureSSE3 | FeatureSSSE3 | FeatureSSE4_1 |
+ FeatureSSE4_2 | FeatureSSE4_A | FeatureXSAVE | FeatureXSAVEC |
+ FeatureXSAVEOPT | FeatureXSAVES;
+static constexpr FeatureBitset FeaturesZNVER2 =
+ FeaturesZNVER1 | FeatureCLWB | FeatureRDPID | FeatureWBNOINVD;
+
+static constexpr ProcInfo Processors[] = {
+ // Empty processor. Include X87 and CMPXCHG8 for backwards compatibility.
+ { {""}, CK_None, ~0U, FeatureX87 | FeatureCMPXCHG8B },
+ // i386-generation processors.
+ { {"i386"}, CK_i386, ~0U, FeatureX87 },
+ // i486-generation processors.
+ { {"i486"}, CK_i486, ~0U, FeatureX87 },
+ { {"winchip-c6"}, CK_WinChipC6, ~0U, FeaturesPentiumMMX },
+ { {"winchip2"}, CK_WinChip2, ~0U, FeaturesPentiumMMX | Feature3DNOW },
+ { {"c3"}, CK_C3, ~0U, FeaturesPentiumMMX | Feature3DNOW },
+ // i586-generation processors, P5 microarchitecture based.
+ { {"i586"}, CK_i586, ~0U, FeatureX87 | FeatureCMPXCHG8B },
+ { {"pentium"}, CK_Pentium, ~0U, FeatureX87 | FeatureCMPXCHG8B },
+ { {"pentium-mmx"}, CK_PentiumMMX, ~0U, FeaturesPentiumMMX },
+ // i686-generation processors, P6 / Pentium M microarchitecture based.
+ { {"pentiumpro"}, CK_PentiumPro, ~0U, FeatureX87 | FeatureCMPXCHG8B },
+ { {"i686"}, CK_i686, ~0U, FeatureX87 | FeatureCMPXCHG8B },
+ { {"pentium2"}, CK_Pentium2, ~0U, FeaturesPentium2 },
+ { {"pentium3"}, CK_Pentium3, ~0U, FeaturesPentium3 },
+ { {"pentium3m"}, CK_Pentium3, ~0U, FeaturesPentium3 },
+ { {"pentium-m"}, CK_PentiumM, ~0U, FeaturesPentium4 },
+ { {"c3-2"}, CK_C3_2, ~0U, FeaturesPentium3 },
+ { {"yonah"}, CK_Yonah, ~0U, FeaturesPrescott },
+ // Netburst microarchitecture based processors.
+ { {"pentium4"}, CK_Pentium4, ~0U, FeaturesPentium4 },
+ { {"pentium4m"}, CK_Pentium4, ~0U, FeaturesPentium4 },
+ { {"prescott"}, CK_Prescott, ~0U, FeaturesPrescott },
+ { {"nocona"}, CK_Nocona, ~0U, FeaturesNocona },
+ // Core microarchitecture based processors.
+ { {"core2"}, CK_Core2, ~0U, FeaturesCore2 },
+ { {"penryn"}, CK_Penryn, ~0U, FeaturesPenryn },
+ // Atom processors
+ { {"bonnell"}, CK_Bonnell, FEATURE_SSSE3, FeaturesBonnell },
+ { {"atom"}, CK_Bonnell, FEATURE_SSSE3, FeaturesBonnell },
+ { {"silvermont"}, CK_Silvermont, FEATURE_SSE4_2, FeaturesSilvermont },
+ { {"slm"}, CK_Silvermont, FEATURE_SSE4_2, FeaturesSilvermont },
+ { {"goldmont"}, CK_Goldmont, FEATURE_SSE4_2, FeaturesGoldmont },
+ { {"goldmont-plus"}, CK_GoldmontPlus, FEATURE_SSE4_2, FeaturesGoldmontPlus },
+ { {"tremont"}, CK_Tremont, FEATURE_SSE4_2, FeaturesTremont },
+ // Nehalem microarchitecture based processors.
+ { {"nehalem"}, CK_Nehalem, FEATURE_SSE4_2, FeaturesNehalem },
+ { {"corei7"}, CK_Nehalem, FEATURE_SSE4_2, FeaturesNehalem },
+ // Westmere microarchitecture based processors.
+ { {"westmere"}, CK_Westmere, FEATURE_PCLMUL, FeaturesWestmere },
+ // Sandy Bridge microarchitecture based processors.
+ { {"sandybridge"}, CK_SandyBridge, FEATURE_AVX, FeaturesSandyBridge },
+ { {"corei7-avx"}, CK_SandyBridge, FEATURE_AVX, FeaturesSandyBridge },
+ // Ivy Bridge microarchitecture based processors.
+ { {"ivybridge"}, CK_IvyBridge, FEATURE_AVX, FeaturesIvyBridge },
+ { {"core-avx-i"}, CK_IvyBridge, FEATURE_AVX, FeaturesIvyBridge },
+ // Haswell microarchitecture based processors.
+ { {"haswell"}, CK_Haswell, FEATURE_AVX2, FeaturesHaswell },
+ { {"core-avx2"}, CK_Haswell, FEATURE_AVX2, FeaturesHaswell },
+ // Broadwell microarchitecture based processors.
+ { {"broadwell"}, CK_Broadwell, FEATURE_AVX2, FeaturesBroadwell },
+ // Skylake client microarchitecture based processors.
+ { {"skylake"}, CK_SkylakeClient, FEATURE_AVX2, FeaturesSkylakeClient },
+ // Skylake server microarchitecture based processors.
+ { {"skylake-avx512"}, CK_SkylakeServer, FEATURE_AVX512F, FeaturesSkylakeServer },
+ { {"skx"}, CK_SkylakeServer, FEATURE_AVX512F, FeaturesSkylakeServer },
+ // Cascadelake Server microarchitecture based processors.
+ { {"cascadelake"}, CK_Cascadelake, FEATURE_AVX512VNNI, FeaturesCascadeLake },
+ // Cooperlake Server microarchitecture based processors.
+ { {"cooperlake"}, CK_Cooperlake, FEATURE_AVX512BF16, FeaturesCooperLake },
+ // Cannonlake client microarchitecture based processors.
+ { {"cannonlake"}, CK_Cannonlake, FEATURE_AVX512VBMI, FeaturesCannonlake },
+ // Icelake client microarchitecture based processors.
+ { {"icelake-client"}, CK_IcelakeClient, FEATURE_AVX512VBMI2, FeaturesICLClient },
+ // Icelake server microarchitecture based processors.
+ { {"icelake-server"}, CK_IcelakeServer, FEATURE_AVX512VBMI2, FeaturesICLServer },
+ // Tigerlake microarchitecture based processors.
+ { {"tigerlake"}, CK_Tigerlake, FEATURE_AVX512VP2INTERSECT, FeaturesTigerlake },
+ // Knights Landing processor.
+ { {"knl"}, CK_KNL, FEATURE_AVX512F, FeaturesKNL },
+ // Knights Mill processor.
+ { {"knm"}, CK_KNM, FEATURE_AVX5124FMAPS, FeaturesKNM },
+ // Lakemont microarchitecture based processors.
+ { {"lakemont"}, CK_Lakemont, ~0U, FeatureCMPXCHG8B },
+ // K6 architecture processors.
+ { {"k6"}, CK_K6, ~0U, FeaturesK6 },
+ { {"k6-2"}, CK_K6_2, ~0U, FeaturesK6 | Feature3DNOW },
+ { {"k6-3"}, CK_K6_3, ~0U, FeaturesK6 | Feature3DNOW },
+ // K7 architecture processors.
+ { {"athlon"}, CK_Athlon, ~0U, FeaturesAthlon },
+ { {"athlon-tbird"}, CK_Athlon, ~0U, FeaturesAthlon },
+ { {"athlon-xp"}, CK_AthlonXP, ~0U, FeaturesAthlonXP },
+ { {"athlon-mp"}, CK_AthlonXP, ~0U, FeaturesAthlonXP },
+ { {"athlon-4"}, CK_AthlonXP, ~0U, FeaturesAthlonXP },
+ // K8 architecture processors.
+ { {"k8"}, CK_K8, ~0U, FeaturesK8 },
+ { {"athlon64"}, CK_K8, ~0U, FeaturesK8 },
+ { {"athlon-fx"}, CK_K8, ~0U, FeaturesK8 },
+ { {"opteron"}, CK_K8, ~0U, FeaturesK8 },
+ { {"k8-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 },
+ { {"athlon64-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 },
+ { {"opteron-sse3"}, CK_K8SSE3, ~0U, FeaturesK8SSE3 },
+ { {"amdfam10"}, CK_AMDFAM10, FEATURE_SSE4_A, FeaturesAMDFAM10 },
+ { {"barcelona"}, CK_AMDFAM10, FEATURE_SSE4_A, FeaturesAMDFAM10 },
+ // Bobcat architecture processors.
+ { {"btver1"}, CK_BTVER1, FEATURE_SSE4_A, FeaturesBTVER1 },
+ { {"btver2"}, CK_BTVER2, FEATURE_BMI, FeaturesBTVER2 },
+ // Bulldozer architecture processors.
+ { {"bdver1"}, CK_BDVER1, FEATURE_XOP, FeaturesBDVER1 },
+ { {"bdver2"}, CK_BDVER2, FEATURE_FMA, FeaturesBDVER2 },
+ { {"bdver3"}, CK_BDVER3, FEATURE_FMA, FeaturesBDVER3 },
+ { {"bdver4"}, CK_BDVER4, FEATURE_AVX2, FeaturesBDVER4 },
+ // Zen architecture processors.
+ { {"znver1"}, CK_ZNVER1, FEATURE_AVX2, FeaturesZNVER1 },
+ { {"znver2"}, CK_ZNVER2, FEATURE_AVX2, FeaturesZNVER2 },
+ // Generic 64-bit processor.
+ { {"x86-64"}, CK_x86_64, ~0U, FeaturesX86_64 },
+ // Geode processors.
+ { {"geode"}, CK_Geode, ~0U, FeaturesGeode },
+};
+
+X86::CPUKind llvm::X86::parseArchX86(StringRef CPU, bool Only64Bit) {
+ for (const auto &P : Processors)
+ if (P.Name == CPU && (P.Features[FEATURE_64BIT] || !Only64Bit))
+ return P.Kind;
+
+ return CK_None;
+}
+
+void llvm::X86::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values,
+ bool Only64Bit) {
+ for (const auto &P : Processors)
+ if (!P.Name.empty() && (P.Features[FEATURE_64BIT] || !Only64Bit))
+ Values.emplace_back(P.Name);
+}
+
+ProcessorFeatures llvm::X86::getKeyFeature(X86::CPUKind Kind) {
+ // FIXME: Can we avoid a linear search here? The table might be sorted by
+ // CPUKind so we could binary search?
+ for (const auto &P : Processors) {
+ if (P.Kind == Kind) {
+ assert(P.KeyFeature != ~0U && "Processor does not have a key feature.");
+ return static_cast<ProcessorFeatures>(P.KeyFeature);
+ }
+ }
+
+ llvm_unreachable("Unable to find CPU kind!");
+}
+
+// Features with no dependencies.
+static constexpr FeatureBitset ImpliedFeatures64BIT = {};
+static constexpr FeatureBitset ImpliedFeaturesADX = {};
+static constexpr FeatureBitset ImpliedFeaturesBMI = {};
+static constexpr FeatureBitset ImpliedFeaturesBMI2 = {};
+static constexpr FeatureBitset ImpliedFeaturesCLDEMOTE = {};
+static constexpr FeatureBitset ImpliedFeaturesCLFLUSHOPT = {};
+static constexpr FeatureBitset ImpliedFeaturesCLWB = {};
+static constexpr FeatureBitset ImpliedFeaturesCLZERO = {};
+static constexpr FeatureBitset ImpliedFeaturesCMOV = {};
+static constexpr FeatureBitset ImpliedFeaturesCMPXCHG16B = {};
+static constexpr FeatureBitset ImpliedFeaturesCMPXCHG8B = {};
+static constexpr FeatureBitset ImpliedFeaturesENQCMD = {};
+static constexpr FeatureBitset ImpliedFeaturesFSGSBASE = {};
+static constexpr FeatureBitset ImpliedFeaturesFXSR = {};
+static constexpr FeatureBitset ImpliedFeaturesINVPCID = {};
+static constexpr FeatureBitset ImpliedFeaturesLWP = {};
+static constexpr FeatureBitset ImpliedFeaturesLZCNT = {};
+static constexpr FeatureBitset ImpliedFeaturesMWAITX = {};
+static constexpr FeatureBitset ImpliedFeaturesMOVBE = {};
+static constexpr FeatureBitset ImpliedFeaturesMOVDIR64B = {};
+static constexpr FeatureBitset ImpliedFeaturesMOVDIRI = {};
+static constexpr FeatureBitset ImpliedFeaturesPCONFIG = {};
+static constexpr FeatureBitset ImpliedFeaturesPOPCNT = {};
+static constexpr FeatureBitset ImpliedFeaturesPKU = {};
+static constexpr FeatureBitset ImpliedFeaturesPREFETCHWT1 = {};
+static constexpr FeatureBitset ImpliedFeaturesPRFCHW = {};
+static constexpr FeatureBitset ImpliedFeaturesPTWRITE = {};
+static constexpr FeatureBitset ImpliedFeaturesRDPID = {};
+static constexpr FeatureBitset ImpliedFeaturesRDRND = {};
+static constexpr FeatureBitset ImpliedFeaturesRDSEED = {};
+static constexpr FeatureBitset ImpliedFeaturesRTM = {};
+static constexpr FeatureBitset ImpliedFeaturesSAHF = {};
+static constexpr FeatureBitset ImpliedFeaturesSERIALIZE = {};
+static constexpr FeatureBitset ImpliedFeaturesSGX = {};
+static constexpr FeatureBitset ImpliedFeaturesSHSTK = {};
+static constexpr FeatureBitset ImpliedFeaturesTBM = {};
+static constexpr FeatureBitset ImpliedFeaturesTSXLDTRK = {};
+static constexpr FeatureBitset ImpliedFeaturesWAITPKG = {};
+static constexpr FeatureBitset ImpliedFeaturesWBNOINVD = {};
+static constexpr FeatureBitset ImpliedFeaturesVZEROUPPER = {};
+static constexpr FeatureBitset ImpliedFeaturesX87 = {};
+static constexpr FeatureBitset ImpliedFeaturesXSAVE = {};
+
+// Not really CPU features, but need to be in the table because clang uses
+// target features to communicate them to the backend.
+static constexpr FeatureBitset ImpliedFeaturesRETPOLINE_EXTERNAL_THUNK = {};
+static constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_BRANCHES = {};
+static constexpr FeatureBitset ImpliedFeaturesRETPOLINE_INDIRECT_CALLS = {};
+static constexpr FeatureBitset ImpliedFeaturesLVI_CFI = {};
+static constexpr FeatureBitset ImpliedFeaturesLVI_LOAD_HARDENING = {};
+
+// XSAVE features are dependent on basic XSAVE.
+static constexpr FeatureBitset ImpliedFeaturesXSAVEC = FeatureXSAVE;
+static constexpr FeatureBitset ImpliedFeaturesXSAVEOPT = FeatureXSAVE;
+static constexpr FeatureBitset ImpliedFeaturesXSAVES = FeatureXSAVE;
+
+// MMX->3DNOW->3DNOWA chain.
+static constexpr FeatureBitset ImpliedFeaturesMMX = {};
+static constexpr FeatureBitset ImpliedFeatures3DNOW = FeatureMMX;
+static constexpr FeatureBitset ImpliedFeatures3DNOWA = Feature3DNOW;
+
+// SSE/AVX/AVX512F chain.
+static constexpr FeatureBitset ImpliedFeaturesSSE = {};
+static constexpr FeatureBitset ImpliedFeaturesSSE2 = FeatureSSE;
+static constexpr FeatureBitset ImpliedFeaturesSSE3 = FeatureSSE2;
+static constexpr FeatureBitset ImpliedFeaturesSSSE3 = FeatureSSE3;
+static constexpr FeatureBitset ImpliedFeaturesSSE4_1 = FeatureSSSE3;
+static constexpr FeatureBitset ImpliedFeaturesSSE4_2 = FeatureSSE4_1;
+static constexpr FeatureBitset ImpliedFeaturesAVX = FeatureSSE4_2;
+static constexpr FeatureBitset ImpliedFeaturesAVX2 = FeatureAVX;
+static constexpr FeatureBitset ImpliedFeaturesAVX512F =
+ FeatureAVX2 | FeatureF16C | FeatureFMA;
+
+// Vector extensions that build on SSE or AVX.
+static constexpr FeatureBitset ImpliedFeaturesAES = FeatureSSE2;
+static constexpr FeatureBitset ImpliedFeaturesF16C = FeatureAVX;
+static constexpr FeatureBitset ImpliedFeaturesFMA = FeatureAVX;
+static constexpr FeatureBitset ImpliedFeaturesGFNI = FeatureSSE2;
+static constexpr FeatureBitset ImpliedFeaturesPCLMUL = FeatureSSE2;
+static constexpr FeatureBitset ImpliedFeaturesSHA = FeatureSSE2;
+static constexpr FeatureBitset ImpliedFeaturesVAES = FeatureAES | FeatureAVX;
+static constexpr FeatureBitset ImpliedFeaturesVPCLMULQDQ =
+ FeatureAVX | FeaturePCLMUL;
+
+// AVX512 features.
+static constexpr FeatureBitset ImpliedFeaturesAVX512CD = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512BW = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512DQ = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512ER = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512PF = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512VL = FeatureAVX512F;
+
+static constexpr FeatureBitset ImpliedFeaturesAVX512BF16 = FeatureAVX512BW;
+static constexpr FeatureBitset ImpliedFeaturesAVX512BITALG = FeatureAVX512BW;
+static constexpr FeatureBitset ImpliedFeaturesAVX512IFMA = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512VNNI = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512VPOPCNTDQ = FeatureAVX512F;
+static constexpr FeatureBitset ImpliedFeaturesAVX512VBMI = FeatureAVX512BW;
+static constexpr FeatureBitset ImpliedFeaturesAVX512VBMI2 = FeatureAVX512BW;
+static constexpr FeatureBitset ImpliedFeaturesAVX512VP2INTERSECT =
+ FeatureAVX512F;
+
+// FIXME: These two aren't really implemented and just exist in the feature
+// list for __builtin_cpu_supports. So omit their dependencies.
+static constexpr FeatureBitset ImpliedFeaturesAVX5124FMAPS = {};
+static constexpr FeatureBitset ImpliedFeaturesAVX5124VNNIW = {};
+
+// SSE4_A->FMA4->XOP chain.
+static constexpr FeatureBitset ImpliedFeaturesSSE4_A = FeatureSSSE3;
+static constexpr FeatureBitset ImpliedFeaturesFMA4 = FeatureAVX | FeatureSSE4_A;
+static constexpr FeatureBitset ImpliedFeaturesXOP = FeatureFMA4;
+
+// AMX Features
+static constexpr FeatureBitset ImpliedFeaturesAMX_TILE = {};
+static constexpr FeatureBitset ImpliedFeaturesAMX_BF16 = FeatureAMX_TILE;
+static constexpr FeatureBitset ImpliedFeaturesAMX_INT8 = FeatureAMX_TILE;
+
+static constexpr FeatureInfo FeatureInfos[X86::CPU_FEATURE_MAX] = {
+#define X86_FEATURE(ENUM, STR) {{STR}, ImpliedFeatures##ENUM},
+#include "llvm/Support/X86TargetParser.def"
+};
+
+// Convert the set bits in FeatureBitset to a list of strings.
+static void getFeatureBitsAsStrings(const FeatureBitset &Bits,
+ SmallVectorImpl<StringRef> &Features) {
+ for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i)
+ if (Bits[i] && !FeatureInfos[i].Name.empty())
+ Features.push_back(FeatureInfos[i].Name);
+}
+
+void llvm::X86::getFeaturesForCPU(StringRef CPU,
+ SmallVectorImpl<StringRef> &EnabledFeatures) {
+ auto I = llvm::find_if(Processors,
+ [&](const ProcInfo &P) { return P.Name == CPU; });
+ assert(I != std::end(Processors) && "Processor not found!");
+
+ FeatureBitset Bits = I->Features;
+
+ // Remove the 64-bit feature which we only use to validate if a CPU can
+ // be used with 64-bit mode.
+ Bits &= ~Feature64BIT;
+
+ // Add the string version of all set bits.
+ getFeatureBitsAsStrings(Bits, EnabledFeatures);
+}
+
+// For each feature that is (transitively) implied by this feature, set it.
+static void getImpliedEnabledFeatures(FeatureBitset &Bits,
+ const FeatureBitset &Implies) {
+ Bits |= Implies;
+ for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) {
+ if (Implies[i])
+ getImpliedEnabledFeatures(Bits, FeatureInfos[i].ImpliedFeatures);
+ }
+}
+
+/// Create bit vector of features that are implied disabled if the feature
+/// passed in Value is disabled.
+static void getImpliedDisabledFeatures(FeatureBitset &Bits, unsigned Value) {
+ // Check all features looking for any dependent on this feature. If we find
+ // one, mark it and recursively find any feature that depend on it.
+ for (unsigned i = 0; i != CPU_FEATURE_MAX; ++i) {
+ if (FeatureInfos[i].ImpliedFeatures[Value]) {
+ Bits.set(i);
+ getImpliedDisabledFeatures(Bits, i);
+ }
+ }
+}
+
+void llvm::X86::getImpliedFeatures(
+ StringRef Feature, bool Enabled,
+ SmallVectorImpl<StringRef> &ImpliedFeatures) {
+ auto I = llvm::find_if(
+ FeatureInfos, [&](const FeatureInfo &FI) { return FI.Name == Feature; });
+ if (I == std::end(FeatureInfos)) {
+ // FIXME: This shouldn't happen, but may not have all features in the table
+ // yet.
+ return;
+ }
+
+ FeatureBitset ImpliedBits;
+ if (Enabled)
+ getImpliedEnabledFeatures(ImpliedBits, I->ImpliedFeatures);
+ else
+ getImpliedDisabledFeatures(ImpliedBits,
+ std::distance(std::begin(FeatureInfos), I));
+
+ // Convert all the found bits into strings.
+ getFeatureBitsAsStrings(ImpliedBits, ImpliedFeatures);
+}
diff --git a/llvm/lib/Support/YAMLParser.cpp b/llvm/lib/Support/YAMLParser.cpp
index d17e7b227f4a8..ca8ffdc47afa6 100644
--- a/llvm/lib/Support/YAMLParser.cpp
+++ b/llvm/lib/Support/YAMLParser.cpp
@@ -268,8 +268,8 @@ public:
}
void setError(const Twine &Message, StringRef::iterator Position) {
- if (Current >= End)
- Current = End - 1;
+ if (Position >= End)
+ Position = End - 1;
// propagate the error if possible
if (EC)
@@ -278,14 +278,10 @@ public:
// Don't print out more errors after the first one we encounter. The rest
// are just the result of the first, and have no meaning.
if (!Failed)
- printError(SMLoc::getFromPointer(Current), SourceMgr::DK_Error, Message);
+ printError(SMLoc::getFromPointer(Position), SourceMgr::DK_Error, Message);
Failed = true;
}
- void setError(const Twine &Message) {
- setError(Message, Current);
- }
-
/// Returns true if an error occurred while parsing.
bool failed() {
return Failed;
@@ -934,13 +930,13 @@ void Scanner::scan_ns_uri_char() {
bool Scanner::consume(uint32_t Expected) {
if (Expected >= 0x80) {
- setError("Cannot consume non-ascii characters");
+ setError("Cannot consume non-ascii characters", Current);
return false;
}
if (Current == End)
return false;
if (uint8_t(*Current) >= 0x80) {
- setError("Cannot consume non-ascii characters");
+ setError("Cannot consume non-ascii characters", Current);
return false;
}
if (uint8_t(*Current) == Expected) {
@@ -1642,7 +1638,7 @@ bool Scanner::scanBlockScalar(bool IsLiteral) {
Token T;
T.Kind = Token::TK_BlockScalar;
T.Range = StringRef(Start, Current - Start);
- T.Value = Str.str().str();
+ T.Value = std::string(Str);
TokenQueue.push_back(T);
return true;
}
@@ -1763,7 +1759,7 @@ bool Scanner::fetchMoreTokens() {
&& !isBlankOrBreak(Current + 2)))
return scanPlainScalar();
- setError("Unrecognized character while tokenizing.");
+ setError("Unrecognized character while tokenizing.", Current);
return false;
}
@@ -1819,11 +1815,11 @@ std::string Node::getVerbatimTag() const {
if (!Raw.empty() && Raw != "!") {
std::string Ret;
if (Raw.find_last_of('!') == 0) {
- Ret = Doc->getTagMap().find("!")->second;
+ Ret = std::string(Doc->getTagMap().find("!")->second);
Ret += Raw.substr(1);
return Ret;
} else if (Raw.startswith("!!")) {
- Ret = Doc->getTagMap().find("!!")->second;
+ Ret = std::string(Doc->getTagMap().find("!!")->second);
Ret += Raw.substr(2);
return Ret;
} else {
@@ -1831,7 +1827,7 @@ std::string Node::getVerbatimTag() const {
std::map<StringRef, StringRef>::const_iterator It =
Doc->getTagMap().find(TagHandle);
if (It != Doc->getTagMap().end())
- Ret = It->second;
+ Ret = std::string(It->second);
else {
Token T;
T.Kind = Token::TK_Tag;
diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp
index 5f0cedc71829a..9ac7c65e19f73 100644
--- a/llvm/lib/Support/YAMLTraits.cpp
+++ b/llvm/lib/Support/YAMLTraits.cpp
@@ -166,6 +166,8 @@ bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault,
if (!MN) {
if (Required || !isa<EmptyHNode>(CurrentNode))
setError(CurrentNode, "not a mapping");
+ else
+ UseDefault = true;
return false;
}
MN->ValidKeys.push_back(Key);
@@ -738,7 +740,7 @@ bool Output::canElideEmptySequence() {
// the whole key/value can be not written. But, that produces wrong yaml
// if the key/value is the only thing in the map and the map is used in
// a sequence. This detects if the this sequence is the first key/value
- // in map that itself is embedded in a sequnce.
+ // in map that itself is embedded in a sequence.
if (StateStack.size() < 2)
return true;
if (StateStack.back() != inMapFirstKey)
@@ -876,12 +878,12 @@ StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *,
}
void ScalarTraits<std::string>::output(const std::string &Val, void *,
- raw_ostream &Out) {
+ raw_ostream &Out) {
Out << Val;
}
StringRef ScalarTraits<std::string>::input(StringRef Scalar, void *,
- std::string &Val) {
+ std::string &Val) {
Val = Scalar.str();
return StringRef();
}
diff --git a/llvm/lib/Support/Z3Solver.cpp b/llvm/lib/Support/Z3Solver.cpp
index a83d0f441a4bd..9485536d13120 100644
--- a/llvm/lib/Support/Z3Solver.cpp
+++ b/llvm/lib/Support/Z3Solver.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/config.h"
#include "llvm/Support/SMTAPI.h"
@@ -516,16 +517,16 @@ public:
SMTExprRef RoundingMode = getFloatRoundingMode();
return newExprRef(
Z3Expr(Context,
- Z3_mk_fpa_mul(Context.Context, toZ3Expr(*LHS).AST,
- toZ3Expr(*RHS).AST, toZ3Expr(*RoundingMode).AST)));
+ Z3_mk_fpa_mul(Context.Context, toZ3Expr(*RoundingMode).AST,
+ toZ3Expr(*LHS).AST, toZ3Expr(*RHS).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)));
+ Z3_mk_fpa_div(Context.Context, toZ3Expr(*RoundingMode).AST,
+ toZ3Expr(*LHS).AST, toZ3Expr(*RHS).AST)));
}
SMTExprRef mkFPRem(const SMTExprRef &LHS, const SMTExprRef &RHS) override {
@@ -538,16 +539,16 @@ public:
SMTExprRef RoundingMode = getFloatRoundingMode();
return newExprRef(
Z3Expr(Context,
- Z3_mk_fpa_add(Context.Context, toZ3Expr(*LHS).AST,
- toZ3Expr(*RHS).AST, toZ3Expr(*RoundingMode).AST)));
+ Z3_mk_fpa_add(Context.Context, toZ3Expr(*RoundingMode).AST,
+ toZ3Expr(*LHS).AST, toZ3Expr(*RHS).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)));
+ Z3_mk_fpa_sub(Context.Context, toZ3Expr(*RoundingMode).AST,
+ toZ3Expr(*LHS).AST, toZ3Expr(*RHS).AST)));
}
SMTExprRef mkFPLt(const SMTExprRef &LHS, const SMTExprRef &RHS) override {
@@ -723,10 +724,25 @@ public:
}
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)));
+ const Z3_sort Z3Sort = toZ3Sort(*getBitvectorSort(BitWidth)).Sort;
+
+ // Slow path, when 64 bits are not enough.
+ if (LLVM_UNLIKELY(Int.getBitWidth() > 64u)) {
+ SmallString<40> Buffer;
+ Int.toString(Buffer, 10);
+ return newExprRef(Z3Expr(
+ Context, Z3_mk_numeral(Context.Context, Buffer.c_str(), Z3Sort)));
+ }
+
+ const int64_t BitReprAsSigned = Int.getExtValue();
+ const uint64_t BitReprAsUnsigned =
+ reinterpret_cast<const uint64_t &>(BitReprAsSigned);
+
+ Z3_ast Literal =
+ Int.isSigned()
+ ? Z3_mk_int64(Context.Context, BitReprAsSigned, Z3Sort)
+ : Z3_mk_unsigned_int64(Context.Context, BitReprAsUnsigned, Z3Sort);
+ return newExprRef(Z3Expr(Context, Literal));
}
SMTExprRef mkFloat(const llvm::APFloat Float) override {
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 4bb315f824af2..f2d78d7732397 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -60,21 +60,21 @@
#ifdef _WIN32
#include "llvm/Support/ConvertUTF.h"
-#include "Windows/WindowsSupport.h"
+#include "llvm/Support/Windows/WindowsSupport.h"
#endif
using namespace llvm;
-const raw_ostream::Colors raw_ostream::BLACK;
-const raw_ostream::Colors raw_ostream::RED;
-const raw_ostream::Colors raw_ostream::GREEN;
-const raw_ostream::Colors raw_ostream::YELLOW;
-const raw_ostream::Colors raw_ostream::BLUE;
-const raw_ostream::Colors raw_ostream::MAGENTA;
-const raw_ostream::Colors raw_ostream::CYAN;
-const raw_ostream::Colors raw_ostream::WHITE;
-const raw_ostream::Colors raw_ostream::SAVEDCOLOR;
-const raw_ostream::Colors raw_ostream::RESET;
+constexpr raw_ostream::Colors raw_ostream::BLACK;
+constexpr raw_ostream::Colors raw_ostream::RED;
+constexpr raw_ostream::Colors raw_ostream::GREEN;
+constexpr raw_ostream::Colors raw_ostream::YELLOW;
+constexpr raw_ostream::Colors raw_ostream::BLUE;
+constexpr raw_ostream::Colors raw_ostream::MAGENTA;
+constexpr raw_ostream::Colors raw_ostream::CYAN;
+constexpr raw_ostream::Colors raw_ostream::WHITE;
+constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR;
+constexpr raw_ostream::Colors raw_ostream::RESET;
raw_ostream::~raw_ostream() {
// raw_ostream's subclasses should take care to flush the buffer
@@ -216,7 +216,7 @@ void raw_ostream::flush_nonempty() {
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
size_t Length = OutBufCur - OutBufStart;
OutBufCur = OutBufStart;
- write_impl(OutBufStart, Length);
+ flush_tied_then_write(OutBufStart, Length);
}
raw_ostream &raw_ostream::write(unsigned char C) {
@@ -224,7 +224,7 @@ raw_ostream &raw_ostream::write(unsigned char C) {
if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
if (LLVM_UNLIKELY(!OutBufStart)) {
if (BufferMode == BufferKind::Unbuffered) {
- write_impl(reinterpret_cast<char*>(&C), 1);
+ flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
return *this;
}
// Set up a buffer and start over.
@@ -244,7 +244,7 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
if (LLVM_UNLIKELY(!OutBufStart)) {
if (BufferMode == BufferKind::Unbuffered) {
- write_impl(Ptr, Size);
+ flush_tied_then_write(Ptr, Size);
return *this;
}
// Set up a buffer and start over.
@@ -260,7 +260,7 @@ raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
assert(NumBytes != 0 && "undefined behavior");
size_t BytesToWrite = Size - (Size % NumBytes);
- write_impl(Ptr, BytesToWrite);
+ flush_tied_then_write(Ptr, BytesToWrite);
size_t BytesRemaining = Size - BytesToWrite;
if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
// Too much left over to copy into our buffer.
@@ -301,6 +301,12 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
OutBufCur += Size;
}
+void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
+ if (TiedStream)
+ TiedStream->flush();
+ write_impl(Ptr, Size);
+}
+
// Formatted output.
raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
// If we have more than a few bytes left in our output buffer, try
@@ -343,36 +349,33 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
}
raw_ostream &raw_ostream::operator<<(const formatv_object_base &Obj) {
- SmallString<128> S;
Obj.format(*this);
return *this;
}
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
- if (FS.Str.size() >= FS.Width || FS.Justify == FormattedString::JustifyNone) {
- this->operator<<(FS.Str);
- return *this;
- }
- const size_t Difference = FS.Width - FS.Str.size();
- switch (FS.Justify) {
- case FormattedString::JustifyLeft:
- this->operator<<(FS.Str);
- this->indent(Difference);
- break;
- case FormattedString::JustifyRight:
- this->indent(Difference);
- this->operator<<(FS.Str);
- break;
- case FormattedString::JustifyCenter: {
- int PadAmount = Difference / 2;
- this->indent(PadAmount);
- this->operator<<(FS.Str);
- this->indent(Difference - PadAmount);
- break;
- }
- default:
- llvm_unreachable("Bad Justification");
+ unsigned LeftIndent = 0;
+ unsigned RightIndent = 0;
+ const ssize_t Difference = FS.Width - FS.Str.size();
+ if (Difference > 0) {
+ switch (FS.Justify) {
+ case FormattedString::JustifyNone:
+ break;
+ case FormattedString::JustifyLeft:
+ RightIndent = Difference;
+ break;
+ case FormattedString::JustifyRight:
+ LeftIndent = Difference;
+ break;
+ case FormattedString::JustifyCenter:
+ LeftIndent = Difference / 2;
+ RightIndent = Difference - LeftIndent;
+ break;
+ }
}
+ indent(LeftIndent);
+ (*this) << FS.Str;
+ indent(RightIndent);
return *this;
}
@@ -502,6 +505,53 @@ raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
return write_padding<'\0'>(*this, NumZeros);
}
+bool raw_ostream::prepare_colors() {
+ // Colors were explicitly disabled.
+ if (!ColorEnabled)
+ return false;
+
+ // Colors require changing the terminal but this stream is not going to a
+ // terminal.
+ if (sys::Process::ColorNeedsFlush() && !is_displayed())
+ return false;
+
+ if (sys::Process::ColorNeedsFlush())
+ flush();
+
+ return true;
+}
+
+raw_ostream &raw_ostream::changeColor(enum Colors colors, bool bold, bool bg) {
+ if (!prepare_colors())
+ return *this;
+
+ const char *colorcode =
+ (colors == SAVEDCOLOR)
+ ? sys::Process::OutputBold(bg)
+ : sys::Process::OutputColor(static_cast<char>(colors), bold, bg);
+ if (colorcode)
+ write(colorcode, strlen(colorcode));
+ return *this;
+}
+
+raw_ostream &raw_ostream::resetColor() {
+ if (!prepare_colors())
+ return *this;
+
+ if (const char *colorcode = sys::Process::ResetColor())
+ write(colorcode, strlen(colorcode));
+ return *this;
+}
+
+raw_ostream &raw_ostream::reverseColor() {
+ if (!prepare_colors())
+ return *this;
+
+ if (const char *colorcode = sys::Process::OutputReverse())
+ write(colorcode, strlen(colorcode));
+ return *this;
+}
+
void raw_ostream::anchor() {}
//===----------------------------------------------------------------------===//
@@ -577,6 +627,8 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
return;
}
+ enable_colors(true);
+
// Do not attempt to close stdout or stderr. We used to try to maintain the
// property that tools that support writing file to stdout should not also
// write informational output to stdout, but in practice we were never able to
@@ -792,7 +844,7 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
// If this is a terminal, don't use buffering. Line buffering
// would be a more traditional thing to do, but it's not worth
// the complexity.
- if (S_ISCHR(statbuf.st_mode) && isatty(FD))
+ if (S_ISCHR(statbuf.st_mode) && is_displayed())
return 0;
// Return the preferred block size.
return statbuf.st_blksize;
@@ -801,58 +853,6 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
#endif
}
-raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
- bool bg) {
- if (!ColorEnabled)
- return *this;
-
- if (sys::Process::ColorNeedsFlush())
- flush();
- const char *colorcode =
- (colors == SAVEDCOLOR)
- ? sys::Process::OutputBold(bg)
- : sys::Process::OutputColor(static_cast<char>(colors), bold, bg);
- if (colorcode) {
- size_t len = strlen(colorcode);
- write(colorcode, len);
- // don't account colors towards output characters
- pos -= len;
- }
- return *this;
-}
-
-raw_ostream &raw_fd_ostream::resetColor() {
- if (!ColorEnabled)
- return *this;
-
- if (sys::Process::ColorNeedsFlush())
- flush();
- const char *colorcode = sys::Process::ResetColor();
- if (colorcode) {
- size_t len = strlen(colorcode);
- write(colorcode, len);
- // don't account colors towards output characters
- pos -= len;
- }
- return *this;
-}
-
-raw_ostream &raw_fd_ostream::reverseColor() {
- if (!ColorEnabled)
- return *this;
-
- if (sys::Process::ColorNeedsFlush())
- flush();
- const char *colorcode = sys::Process::OutputReverse();
- if (colorcode) {
- size_t len = strlen(colorcode);
- write(colorcode, len);
- // don't account colors towards output characters
- pos -= len;
- }
- return *this;
-}
-
bool raw_fd_ostream::is_displayed() const {
return sys::Process::FileDescriptorIsDisplayed(FD);
}
@@ -867,9 +867,7 @@ void raw_fd_ostream::anchor() {}
// outs(), errs(), nulls()
//===----------------------------------------------------------------------===//
-/// outs() - This returns a reference to a raw_ostream for standard output.
-/// Use it like: outs() << "foo" << "bar";
-raw_ostream &llvm::outs() {
+raw_fd_ostream &llvm::outs() {
// Set buffer settings to model stdout behavior.
std::error_code EC;
static raw_fd_ostream S("-", EC, sys::fs::OF_None);
@@ -877,10 +875,8 @@ raw_ostream &llvm::outs() {
return S;
}
-/// errs() - This returns a reference to a raw_ostream for standard error.
-/// Use it like: errs() << "foo" << "bar";
-raw_ostream &llvm::errs() {
- // Set standard error to be unbuffered by default.
+raw_fd_ostream &llvm::errs() {
+ // Set standard error to be unbuffered and tied to outs() by default.
static raw_fd_ostream S(STDERR_FILENO, false, true);
return S;
}