diff options
author | dim <dim@FreeBSD.org> | 2017-09-26 19:56:36 +0000 |
---|---|---|
committer | Luiz Souza <luiz@netgate.com> | 2018-02-21 15:12:19 -0300 |
commit | 1dcd2e8d24b295bc73e513acec2ed1514bb66be4 (patch) | |
tree | 4bd13a34c251e980e1a6b13584ca1f63b0dfe670 /contrib/llvm/lib/Support | |
parent | f45541ca2a56a1ba1202f94c080b04e96c1fa239 (diff) | |
download | FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.zip FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.tar.gz |
Merge clang, llvm, lld, lldb, compiler-rt and libc++ 5.0.0 release.
MFC r309126 (by emaste):
Correct lld llvm-tblgen dependency file name
MFC r309169:
Get rid of separate Subversion mergeinfo properties for llvm-dwarfdump
and llvm-lto. The mergeinfo confuses Subversion enormously, and these
directories will just use the mergeinfo for llvm itself.
MFC r312765:
Pull in r276136 from upstream llvm trunk (by Wei Mi):
Use ValueOffsetPair to enhance value reuse during SCEV expansion.
In D12090, the ExprValueMap was added to reuse existing value during
SCEV expansion. However, const folding and sext/zext distribution can
make the reuse still difficult.
A simplified case is: suppose we know S1 expands to V1 in
ExprValueMap, and
S1 = S2 + C_a
S3 = S2 + C_b
where C_a and C_b are different SCEVConstants. Then we'd like to
expand S3 as V1 - C_a + C_b instead of expanding S2 literally. It is
helpful when S2 is a complex SCEV expr and S2 has no entry in
ExprValueMap, which is usually caused by the fact that S3 is
generated from S1 after const folding.
In order to do that, we represent ExprValueMap as a mapping from SCEV
to ValueOffsetPair. We will save both S1->{V1, 0} and S2->{V1, C_a}
into the ExprValueMap when we create SCEV for V1. When S3 is
expanded, it will first expand S2 to V1 - C_a because of S2->{V1,
C_a} in the map, then expand S3 to V1 - C_a + C_b.
Differential Revision: https://reviews.llvm.org/D21313
This should fix assertion failures when building OpenCV >= 3.1.
PR: 215649
MFC r312831:
Revert r312765 for now, since it causes assertions when building
lang/spidermonkey24.
Reported by: antoine
PR: 215649
MFC r316511 (by jhb):
Add an implementation of __ffssi2() derived from __ffsdi2().
Newer versions of GCC include an __ffssi2() symbol in libgcc and the
compiler can emit calls to it in generated code. This is true for at
least GCC 6.2 when compiling world for mips and mips64.
Reviewed by: jmallett, dim
Sponsored by: DARPA / AFRL
Differential Revision: https://reviews.freebsd.org/D10086
MFC r318601 (by adrian):
[libcompiler-rt] add bswapdi2/bswapsi2
This is required for mips gcc 6.3 userland to build/run.
Reviewed by: emaste, dim
Approved by: emaste
Differential Revision: https://reviews.freebsd.org/D10838
MFC r318884 (by emaste):
lldb: map TRAP_CAP to a trace trap
In the absense of a more specific handler for TRAP_CAP (generated by
ENOTCAPABLE or ECAPMODE while in capability mode) treat it as a trace
trap.
Example usage (testing the bug in PR219173):
% proccontrol -m trapcap lldb usr.bin/hexdump/obj/hexdump -- -Cv -s 1 /bin/ls
...
(lldb) run
Process 12980 launching
Process 12980 launched: '.../usr.bin/hexdump/obj/hexdump' (x86_64)
Process 12980 stopped
* thread #1, stop reason = trace
frame #0: 0x0000004b80c65f1a libc.so.7`__sys_lseek + 10
...
In the future we should have LLDB control the trapcap procctl itself
(as it does with ASLR), as well as report a specific stop reason.
This change eliminates an assertion failure from LLDB for now.
MFC r319796:
Remove a few unneeded files from libllvm, libclang and liblldb.
MFC r319885 (by emaste):
lld: ELF: Fix ICF crash on absolute symbol relocations.
If two sections contained relocations to absolute symbols with the same
value we would crash when trying to access their sections. Add a check that
both symbols point to sections before accessing their sections, and treat
absolute symbols as equal if their values are equal.
Obtained from: LLD commit r292578
MFC r319918:
Revert r319796 for now, it can cause undefined references when linking
in some circumstances.
Reported by: Shawn Webb <shawn.webb@hardenedbsd.org>
MFC r319957 (by emaste):
lld: Add armelf emulation mode
Obtained from: LLD r305375
MFC r321369:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
5.0.0 (trunk r308421). Upstream has branched for the 5.0.0 release,
which should be in about a month. Please report bugs and regressions,
so we can get them into the release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
MFC r321420:
Add a few more object files to liblldb, which should solve errors when
linking the lldb executable in some cases. In particular, when the
-ffunction-sections -fdata-sections options are turned off, or
ineffective.
Reported by: Shawn Webb, Mark Millard
MFC r321433:
Cleanup stale Options.inc files from the previous libllvm build for
clang 4.0.0. Otherwise, these can get included before the two newly
generated ones (which are different) for clang 5.0.0.
Reported by: Mark Millard
MFC r321439 (by bdrewery):
Move llvm Options.inc hack from r321433 for NO_CLEAN to lib/clang/libllvm.
The files are only ever generated to .OBJDIR, not to WORLDTMP (as a
sysroot) and are only ever included from a compilation. So using
a beforebuild target here removes the file before the compilation
tries to include it.
MFC r321664:
Pull in r308891 from upstream llvm trunk (by Benjamin Kramer):
[CodeGenPrepare] Cut off FindAllMemoryUses if there are too many uses.
This avoids excessive compile time. The case I'm looking at is
Function.cpp from an old version of LLVM that still had the giant
memcmp string matcher in it. Before r308322 this compiled in about 2
minutes, after it, clang takes infinite* time to compile it. With
this patch we're at 5 min, which is still bad but this is a
pathological case.
The cut off at 20 uses was chosen by looking at other cut-offs in LLVM
for user scanning. It's probably too high, but does the job and is
very unlikely to regress anything.
Fixes PR33900.
* I'm impatient and aborted after 15 minutes, on the bug report it was
killed after 2h.
Pull in r308986 from upstream llvm trunk (by Simon Pilgrim):
[X86][CGP] Reduce memcmp() expansion to 2 load pairs (PR33914)
D35067/rL308322 attempted to support up to 4 load pairs for memcmp
inlining which resulted in regressions for some optimized libc memcmp
implementations (PR33914).
Until we can match these more optimal cases, this patch reduces the
memcmp expansion to a maximum of 2 load pairs (which matches what we
do for -Os).
This patch should be considered for the 5.0.0 release branch as well
Differential Revision: https://reviews.llvm.org/D35830
These fix a hang (or extremely long compile time) when building older
LLVM ports.
Reported by: antoine
PR: 219139
MFC r321719:
Pull in r309503 from upstream clang trunk (by Richard Smith):
PR33902: Invalidate line number cache when adding more text to
existing buffer.
This led to crashes as the line number cache would report a bogus
line number for a line of code, and we'd try to find a nonexistent
column within the line when printing diagnostics.
This fixes an assertion when building the graphics/champlain port.
Reported by: antoine, kwm
PR: 219139
MFC r321723:
Upgrade our copies of clang, llvm, lld and lldb to r309439 from the
upstream release_50 branch. This is just after upstream's 5.0.0-rc1.
MFC r322320:
Upgrade our copies of clang, llvm and libc++ to r310316 from the
upstream release_50 branch.
MFC r322326 (by emaste):
lldb: Make i386-*-freebsd expression work on JIT path
* Enable i386 ABI creation for freebsd
* Added an extra argument in ABISysV_i386::PrepareTrivialCall for mmap
syscall
* Unlike linux, the last argument of mmap is actually 64-bit(off_t).
This requires us to push an additional word for the higher order bits.
* Prior to this change, ktrace dump will show mmap failures due to
invalid argument coming from the 6th mmap argument.
Submitted by: Karnajit Wangkhem
Differential Revision: https://reviews.llvm.org/D34776
MFC r322360 (by emaste):
lldb: Report inferior signals as signals, not exceptions, on FreeBSD
This is the FreeBSD equivalent of LLVM r238549.
This serves 2 purposes:
* LLDB should handle inferior process signals SIGSEGV/SIGILL/SIGBUS/
SIGFPE the way it is suppose to be handled. Prior to this fix these
signals will neither create a coredump, nor exit from the debugger
or work for signal handling scenario.
* eInvalidCrashReason need not report "unknown crash reason" if we have
a valid si_signo
llvm.org/pr23699
Patch by Karnajit Wangkhem
Differential Revision: https://reviews.llvm.org/D35223
Submitted by: Karnajit Wangkhem
Obtained from: LLVM r310591
MFC r322474 (by emaste):
lld: Add `-z muldefs` option.
Obtained from: LLVM r310757
MFC r322740:
Upgrade our copies of clang, llvm, lld and libc++ to r311219 from the
upstream release_50 branch.
MFC r322855:
Upgrade our copies of clang, llvm, lldb and compiler-rt to r311606 from
the upstream release_50 branch.
As of this version, lib/msun's trig test should also work correctly
again (see bug 220989 for more information).
PR: 220989
MFC r323112:
Upgrade our copies of clang, llvm, lldb and compiler-rt to r312293 from
the upstream release_50 branch. This corresponds to 5.0.0 rc4.
As of this version, the cad/stepcode port should now compile in a more
reasonable time on i386 (see bug 221836 for more information).
PR: 221836
MFC r323245:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
5.0.0 release (upstream r312559).
Release notes for llvm, clang and lld will be available here soon:
<http://releases.llvm.org/5.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/5.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/5.0.0/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
(cherry picked from commit 12cd91cf4c6b96a24427c0de5374916f2808d263)
Diffstat (limited to 'contrib/llvm/lib/Support')
81 files changed, 6030 insertions, 3437 deletions
diff --git a/contrib/llvm/lib/Support/AMDGPUCodeObjectMetadata.cpp b/contrib/llvm/lib/Support/AMDGPUCodeObjectMetadata.cpp new file mode 100644 index 0000000..863093a --- /dev/null +++ b/contrib/llvm/lib/Support/AMDGPUCodeObjectMetadata.cpp @@ -0,0 +1,216 @@ +//===--- AMDGPUCodeObjectMetadata.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// \brief AMDGPU Code Object Metadata definitions and in-memory +/// representations. +/// +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/AMDGPUCodeObjectMetadata.h" +#include "llvm/Support/YAMLTraits.h" + +using namespace llvm::AMDGPU; +using namespace llvm::AMDGPU::CodeObject; + +LLVM_YAML_IS_SEQUENCE_VECTOR(Kernel::Arg::Metadata) +LLVM_YAML_IS_SEQUENCE_VECTOR(Kernel::Metadata) + +namespace llvm { +namespace yaml { + +template <> +struct ScalarEnumerationTraits<AccessQualifier> { + static void enumeration(IO &YIO, AccessQualifier &EN) { + YIO.enumCase(EN, "Default", AccessQualifier::Default); + YIO.enumCase(EN, "ReadOnly", AccessQualifier::ReadOnly); + YIO.enumCase(EN, "WriteOnly", AccessQualifier::WriteOnly); + YIO.enumCase(EN, "ReadWrite", AccessQualifier::ReadWrite); + } +}; + +template <> +struct ScalarEnumerationTraits<AddressSpaceQualifier> { + static void enumeration(IO &YIO, AddressSpaceQualifier &EN) { + YIO.enumCase(EN, "Private", AddressSpaceQualifier::Private); + YIO.enumCase(EN, "Global", AddressSpaceQualifier::Global); + YIO.enumCase(EN, "Constant", AddressSpaceQualifier::Constant); + YIO.enumCase(EN, "Local", AddressSpaceQualifier::Local); + YIO.enumCase(EN, "Generic", AddressSpaceQualifier::Generic); + YIO.enumCase(EN, "Region", AddressSpaceQualifier::Region); + } +}; + +template <> +struct ScalarEnumerationTraits<ValueKind> { + static void enumeration(IO &YIO, ValueKind &EN) { + YIO.enumCase(EN, "ByValue", ValueKind::ByValue); + YIO.enumCase(EN, "GlobalBuffer", ValueKind::GlobalBuffer); + YIO.enumCase(EN, "DynamicSharedPointer", ValueKind::DynamicSharedPointer); + YIO.enumCase(EN, "Sampler", ValueKind::Sampler); + YIO.enumCase(EN, "Image", ValueKind::Image); + YIO.enumCase(EN, "Pipe", ValueKind::Pipe); + YIO.enumCase(EN, "Queue", ValueKind::Queue); + YIO.enumCase(EN, "HiddenGlobalOffsetX", ValueKind::HiddenGlobalOffsetX); + YIO.enumCase(EN, "HiddenGlobalOffsetY", ValueKind::HiddenGlobalOffsetY); + YIO.enumCase(EN, "HiddenGlobalOffsetZ", ValueKind::HiddenGlobalOffsetZ); + YIO.enumCase(EN, "HiddenNone", ValueKind::HiddenNone); + YIO.enumCase(EN, "HiddenPrintfBuffer", ValueKind::HiddenPrintfBuffer); + YIO.enumCase(EN, "HiddenDefaultQueue", ValueKind::HiddenDefaultQueue); + YIO.enumCase(EN, "HiddenCompletionAction", + ValueKind::HiddenCompletionAction); + } +}; + +template <> +struct ScalarEnumerationTraits<ValueType> { + static void enumeration(IO &YIO, ValueType &EN) { + YIO.enumCase(EN, "Struct", ValueType::Struct); + YIO.enumCase(EN, "I8", ValueType::I8); + YIO.enumCase(EN, "U8", ValueType::U8); + YIO.enumCase(EN, "I16", ValueType::I16); + YIO.enumCase(EN, "U16", ValueType::U16); + YIO.enumCase(EN, "F16", ValueType::F16); + YIO.enumCase(EN, "I32", ValueType::I32); + YIO.enumCase(EN, "U32", ValueType::U32); + YIO.enumCase(EN, "F32", ValueType::F32); + YIO.enumCase(EN, "I64", ValueType::I64); + YIO.enumCase(EN, "U64", ValueType::U64); + YIO.enumCase(EN, "F64", ValueType::F64); + } +}; + +template <> +struct MappingTraits<Kernel::Attrs::Metadata> { + static void mapping(IO &YIO, Kernel::Attrs::Metadata &MD) { + YIO.mapOptional(Kernel::Attrs::Key::ReqdWorkGroupSize, + MD.mReqdWorkGroupSize, std::vector<uint32_t>()); + YIO.mapOptional(Kernel::Attrs::Key::WorkGroupSizeHint, + MD.mWorkGroupSizeHint, std::vector<uint32_t>()); + YIO.mapOptional(Kernel::Attrs::Key::VecTypeHint, + MD.mVecTypeHint, std::string()); + } +}; + +template <> +struct MappingTraits<Kernel::Arg::Metadata> { + static void mapping(IO &YIO, Kernel::Arg::Metadata &MD) { + 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); + YIO.mapOptional(Kernel::Arg::Key::PointeeAlign, MD.mPointeeAlign, + uint32_t(0)); + YIO.mapOptional(Kernel::Arg::Key::AccQual, MD.mAccQual, + AccessQualifier::Unknown); + YIO.mapOptional(Kernel::Arg::Key::AddrSpaceQual, MD.mAddrSpaceQual, + AddressSpaceQualifier::Unknown); + YIO.mapOptional(Kernel::Arg::Key::IsConst, MD.mIsConst, false); + YIO.mapOptional(Kernel::Arg::Key::IsPipe, MD.mIsPipe, false); + YIO.mapOptional(Kernel::Arg::Key::IsRestrict, MD.mIsRestrict, false); + YIO.mapOptional(Kernel::Arg::Key::IsVolatile, MD.mIsVolatile, false); + YIO.mapOptional(Kernel::Arg::Key::Name, MD.mName, std::string()); + YIO.mapOptional(Kernel::Arg::Key::TypeName, MD.mTypeName, std::string()); + } +}; + +template <> +struct MappingTraits<Kernel::CodeProps::Metadata> { + static void mapping(IO &YIO, Kernel::CodeProps::Metadata &MD) { + YIO.mapOptional(Kernel::CodeProps::Key::KernargSegmentSize, + MD.mKernargSegmentSize, uint64_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::WorkgroupGroupSegmentSize, + MD.mWorkgroupGroupSegmentSize, uint32_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::WorkitemPrivateSegmentSize, + MD.mWorkitemPrivateSegmentSize, uint32_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::WavefrontNumSGPRs, + MD.mWavefrontNumSGPRs, uint16_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::WorkitemNumVGPRs, + MD.mWorkitemNumVGPRs, uint16_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::KernargSegmentAlign, + MD.mKernargSegmentAlign, uint8_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::GroupSegmentAlign, + MD.mGroupSegmentAlign, uint8_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::PrivateSegmentAlign, + MD.mPrivateSegmentAlign, uint8_t(0)); + YIO.mapOptional(Kernel::CodeProps::Key::WavefrontSize, + MD.mWavefrontSize, uint8_t(0)); + } +}; + +template <> +struct MappingTraits<Kernel::DebugProps::Metadata> { + static void mapping(IO &YIO, Kernel::DebugProps::Metadata &MD) { + YIO.mapOptional(Kernel::DebugProps::Key::DebuggerABIVersion, + MD.mDebuggerABIVersion, std::vector<uint32_t>()); + YIO.mapOptional(Kernel::DebugProps::Key::ReservedNumVGPRs, + MD.mReservedNumVGPRs, uint16_t(0)); + YIO.mapOptional(Kernel::DebugProps::Key::ReservedFirstVGPR, + MD.mReservedFirstVGPR, uint16_t(-1)); + YIO.mapOptional(Kernel::DebugProps::Key::PrivateSegmentBufferSGPR, + MD.mPrivateSegmentBufferSGPR, uint16_t(-1)); + YIO.mapOptional(Kernel::DebugProps::Key::WavefrontPrivateSegmentOffsetSGPR, + MD.mWavefrontPrivateSegmentOffsetSGPR, uint16_t(-1)); + } +}; + +template <> +struct MappingTraits<Kernel::Metadata> { + static void mapping(IO &YIO, Kernel::Metadata &MD) { + YIO.mapRequired(Kernel::Key::Name, MD.mName); + YIO.mapOptional(Kernel::Key::Language, MD.mLanguage, std::string()); + YIO.mapOptional(Kernel::Key::LanguageVersion, MD.mLanguageVersion, + std::vector<uint32_t>()); + if (!MD.mAttrs.empty() || !YIO.outputting()) + YIO.mapOptional(Kernel::Key::Attrs, MD.mAttrs); + if (!MD.mArgs.empty() || !YIO.outputting()) + YIO.mapOptional(Kernel::Key::Args, MD.mArgs); + if (!MD.mCodeProps.empty() || !YIO.outputting()) + YIO.mapOptional(Kernel::Key::CodeProps, MD.mCodeProps); + if (!MD.mDebugProps.empty() || !YIO.outputting()) + YIO.mapOptional(Kernel::Key::DebugProps, MD.mDebugProps); + } +}; + +template <> +struct MappingTraits<CodeObject::Metadata> { + static void mapping(IO &YIO, CodeObject::Metadata &MD) { + YIO.mapRequired(Key::Version, MD.mVersion); + YIO.mapOptional(Key::Printf, MD.mPrintf, std::vector<std::string>()); + if (!MD.mKernels.empty() || !YIO.outputting()) + YIO.mapOptional(Key::Kernels, MD.mKernels); + } +}; + +} // end namespace yaml + +namespace AMDGPU { +namespace CodeObject { + +/* static */ +std::error_code Metadata::fromYamlString( + std::string YamlString, Metadata &CodeObjectMetadata) { + yaml::Input YamlInput(YamlString); + YamlInput >> CodeObjectMetadata; + return YamlInput.error(); +} + +/* static */ +std::error_code Metadata::toYamlString( + Metadata CodeObjectMetadata, std::string &YamlString) { + raw_string_ostream YamlStream(YamlString); + yaml::Output YamlOutput(YamlStream, nullptr, std::numeric_limits<int>::max()); + YamlOutput << CodeObjectMetadata; + return std::error_code(); +} + +} // end namespace CodeObject +} // end namespace AMDGPU +} // end namespace llvm diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp index 4cfbbf8..deb76cb 100644 --- a/contrib/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -26,6 +26,15 @@ #include <cstring> #include <limits.h> +#define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL) \ + do { \ + if (usesLayout<IEEEFloat>(getSemantics())) \ + return U.IEEE.METHOD_CALL; \ + if (usesLayout<DoubleAPFloat>(getSemantics())) \ + return U.Double.METHOD_CALL; \ + llvm_unreachable("Unexpected semantics"); \ + } while (false) + using namespace llvm; /// A macro used to combine two fcCategory enums into one key which can be used @@ -38,7 +47,7 @@ using namespace llvm; /* Assumed in hexadecimal significand parsing, and conversion to hexadecimal strings. */ -static_assert(integerPartWidth % 4 == 0, "Part width must be divisible by 4!"); +static_assert(APFloatBase::integerPartWidth % 4 == 0, "Part width must be divisible by 4!"); namespace llvm { /* Represents floating point arithmetic semantics. */ @@ -66,33 +75,43 @@ namespace llvm { static const fltSemantics semX87DoubleExtended = {16383, -16382, 64, 80}; static const fltSemantics semBogus = {0, 0, 0, 0}; - /* The PowerPC format consists of two doubles. It does not map cleanly - onto the usual format above. It is approximated using twice the - mantissa bits. Note that for exponents near the double minimum, - we no longer can represent the full 106 mantissa bits, so those - will be treated as denormal numbers. - - FIXME: While this approximation is equivalent to what GCC uses for - compile-time arithmetic on PPC double-double numbers, it is not able - to represent all possible values held by a PPC double-double number, - for example: (long double) 1.0 + (long double) 0x1p-106 - Should this be replaced by a full emulation of PPC double-double? + /* The IBM double-double semantics. Such a number consists of a pair of IEEE + 64-bit doubles (Hi, Lo), where |Hi| > |Lo|, and if normal, + (double)(Hi + Lo) == Hi. The numeric value it's modeling is Hi + Lo. + Therefore it has two 53-bit mantissa parts that aren't necessarily adjacent + to each other, and two 11-bit exponents. Note: we need to make the value different from semBogus as otherwise an unsafe optimization may collapse both values to a single address, and we heavily rely on them having distinct addresses. */ static const fltSemantics semPPCDoubleDouble = {-1, 0, 0, 0}; - /* There are temporary semantics for the real PPCDoubleDouble implementation. - Currently, APFloat of PPCDoubleDouble holds one PPCDoubleDoubleImpl as the - high part of double double, and one IEEEdouble as the low part, so that - the old operations operate on PPCDoubleDoubleImpl, while the newly added - operations also populate the IEEEdouble. + /* These are legacy semantics for the fallback, inaccrurate implementation of + IBM double-double, if the accurate semPPCDoubleDouble doesn't handle the + operation. It's equivalent to having an IEEE number with consecutive 106 + bits of mantissa and 11 bits of exponent. + + It's not equivalent to IBM double-double. For example, a legit IBM + double-double, 1 + epsilon: + + 1 + epsilon = 1 + (1 >> 1076) + + is not representable by a consecutive 106 bits of mantissa. - TODO: Once all functions support DoubleAPFloat mode, we'll change all - PPCDoubleDoubleImpl to IEEEdouble and remove PPCDoubleDoubleImpl. */ - static const fltSemantics semPPCDoubleDoubleImpl = {1023, -1022 + 53, 53 + 53, - 128}; + Currently, these semantics are used in the following way: + + semPPCDoubleDouble -> (IEEEdouble, IEEEdouble) -> + (64-bit APInt, 64-bit APInt) -> (128-bit APInt) -> + semPPCDoubleDoubleLegacy -> IEEE operations + + We use bitcastToAPInt() to get the bit representation (in APInt) of the + underlying IEEEdouble, then use the APInt constructor to construct the + legacy IEEE float. + + TODO: Implement all operations in semPPCDoubleDouble, and delete these + semantics. */ + static const fltSemantics semPPCDoubleDoubleLegacy = {1023, -1022 + 53, + 53 + 53, 128}; const fltSemantics &APFloatBase::IEEEhalf() { return semIEEEhalf; @@ -130,8 +149,7 @@ namespace llvm { const unsigned int maxExponent = 16383; const unsigned int maxPrecision = 113; const unsigned int maxPowerOfFiveExponent = maxExponent + maxPrecision - 1; - const unsigned int maxPowerOfFiveParts = 2 + ((maxPowerOfFiveExponent * 815) - / (351 * integerPartWidth)); + const unsigned int maxPowerOfFiveParts = 2 + ((maxPowerOfFiveExponent * 815) / (351 * APFloatBase::integerPartWidth)); unsigned int APFloatBase::semanticsPrecision(const fltSemantics &semantics) { return semantics.precision; @@ -157,7 +175,7 @@ namespace llvm { static inline unsigned int partCountForBits(unsigned int bits) { - return ((bits) + integerPartWidth - 1) / integerPartWidth; + return ((bits) + APFloatBase::integerPartWidth - 1) / APFloatBase::integerPartWidth; } /* Returns 0U-9U. Return values >= 10U are not digits. */ @@ -397,7 +415,7 @@ trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end, /* Return the fraction lost were a bignum truncated losing the least significant BITS bits. */ static lostFraction -lostFractionThroughTruncation(const integerPart *parts, +lostFractionThroughTruncation(const APFloatBase::integerPart *parts, unsigned int partCount, unsigned int bits) { @@ -410,7 +428,7 @@ lostFractionThroughTruncation(const integerPart *parts, return lfExactlyZero; if (bits == lsb + 1) return lfExactlyHalf; - if (bits <= partCount * integerPartWidth && + if (bits <= partCount * APFloatBase::integerPartWidth && APInt::tcExtractBit(parts, bits - 1)) return lfMoreThanHalf; @@ -419,7 +437,7 @@ lostFractionThroughTruncation(const integerPart *parts, /* Shift DST right BITS bits noting lost fraction. */ static lostFraction -shiftRight(integerPart *dst, unsigned int parts, unsigned int bits) +shiftRight(APFloatBase::integerPart *dst, unsigned int parts, unsigned int bits) { lostFraction lost_fraction; @@ -466,22 +484,22 @@ HUerrBound(bool inexactMultiply, unsigned int HUerr1, unsigned int HUerr2) /* The number of ulps from the boundary (zero, or half if ISNEAREST) when the least significant BITS are truncated. BITS cannot be zero. */ -static integerPart -ulpsFromBoundary(const integerPart *parts, unsigned int bits, bool isNearest) -{ +static APFloatBase::integerPart +ulpsFromBoundary(const APFloatBase::integerPart *parts, unsigned int bits, + bool isNearest) { unsigned int count, partBits; - integerPart part, boundary; + APFloatBase::integerPart part, boundary; assert(bits != 0); bits--; - count = bits / integerPartWidth; - partBits = bits % integerPartWidth + 1; + count = bits / APFloatBase::integerPartWidth; + partBits = bits % APFloatBase::integerPartWidth + 1; - part = parts[count] & (~(integerPart) 0 >> (integerPartWidth - partBits)); + part = parts[count] & (~(APFloatBase::integerPart) 0 >> (APFloatBase::integerPartWidth - partBits)); if (isNearest) - boundary = (integerPart) 1 << (partBits - 1); + boundary = (APFloatBase::integerPart) 1 << (partBits - 1); else boundary = 0; @@ -495,32 +513,30 @@ ulpsFromBoundary(const integerPart *parts, unsigned int bits, bool isNearest) if (part == boundary) { while (--count) if (parts[count]) - return ~(integerPart) 0; /* A lot. */ + return ~(APFloatBase::integerPart) 0; /* A lot. */ return parts[0]; } else if (part == boundary - 1) { while (--count) if (~parts[count]) - return ~(integerPart) 0; /* A lot. */ + return ~(APFloatBase::integerPart) 0; /* A lot. */ return -parts[0]; } - return ~(integerPart) 0; /* A lot. */ + return ~(APFloatBase::integerPart) 0; /* A lot. */ } /* Place pow(5, power) in DST, and return the number of parts used. DST must be at least one part larger than size of the answer. */ static unsigned int -powerOf5(integerPart *dst, unsigned int power) -{ - static const integerPart firstEightPowers[] = { 1, 5, 25, 125, 625, 3125, - 15625, 78125 }; - integerPart pow5s[maxPowerOfFiveParts * 2 + 5]; +powerOf5(APFloatBase::integerPart *dst, unsigned int power) { + static const APFloatBase::integerPart firstEightPowers[] = { 1, 5, 25, 125, 625, 3125, 15625, 78125 }; + APFloatBase::integerPart pow5s[maxPowerOfFiveParts * 2 + 5]; pow5s[0] = 78125 * 5; unsigned int partsCount[16] = { 1 }; - integerPart scratch[maxPowerOfFiveParts], *p1, *p2, *pow5; + APFloatBase::integerPart scratch[maxPowerOfFiveParts], *p1, *p2, *pow5; unsigned int result; assert(power <= maxExponent); @@ -549,7 +565,7 @@ powerOf5(integerPart *dst, unsigned int power) } if (power & 1) { - integerPart *tmp; + APFloatBase::integerPart *tmp; APInt::tcFullMultiply(p2, p1, pow5, result, pc); result += pc; @@ -585,14 +601,14 @@ static const char NaNU[] = "NAN"; significant nibble. Write out exactly COUNT hexdigits, return COUNT. */ static unsigned int -partAsHex (char *dst, integerPart part, unsigned int count, +partAsHex (char *dst, APFloatBase::integerPart part, unsigned int count, const char *hexDigitChars) { unsigned int result = count; - assert(count != 0 && count <= integerPartWidth / 4); + assert(count != 0 && count <= APFloatBase::integerPartWidth / 4); - part >>= (integerPartWidth - 4 * count); + part >>= (APFloatBase::integerPartWidth - 4 * count); while (count--) { dst[count] = hexDigitChars[part & 0xf]; part >>= 4; @@ -742,7 +758,7 @@ IEEEFloat &IEEEFloat::operator=(IEEEFloat &&rhs) { bool IEEEFloat::isDenormal() const { return isFiniteNonZero() && (exponent == semantics->minExponent) && - (APInt::tcExtractBit(significandParts(), + (APInt::tcExtractBit(significandParts(), semantics->precision - 1) == 0); } @@ -862,20 +878,15 @@ IEEEFloat::IEEEFloat(IEEEFloat &&rhs) : semantics(&semBogus) { IEEEFloat::~IEEEFloat() { freeSignificand(); } -// Profile - This method 'profiles' an APFloat for use with FoldingSet. -void IEEEFloat::Profile(FoldingSetNodeID &ID) const { - ID.Add(bitcastToAPInt()); -} - unsigned int IEEEFloat::partCount() const { return partCountForBits(semantics->precision + 1); } -const integerPart *IEEEFloat::significandParts() const { +const IEEEFloat::integerPart *IEEEFloat::significandParts() const { return const_cast<IEEEFloat *>(this)->significandParts(); } -integerPart *IEEEFloat::significandParts() { +IEEEFloat::integerPart *IEEEFloat::significandParts() { if (partCount() > 1) return significand.parts; else @@ -898,7 +909,7 @@ void IEEEFloat::incrementSignificand() { } /* Add the significand of the RHS. Returns the carry flag. */ -integerPart IEEEFloat::addSignificand(const IEEEFloat &rhs) { +IEEEFloat::integerPart IEEEFloat::addSignificand(const IEEEFloat &rhs) { integerPart *parts; parts = significandParts(); @@ -911,8 +922,8 @@ integerPart IEEEFloat::addSignificand(const IEEEFloat &rhs) { /* Subtract the significand of the RHS with a borrow flag. Returns the borrow flag. */ -integerPart IEEEFloat::subtractSignificand(const IEEEFloat &rhs, - integerPart borrow) { +IEEEFloat::integerPart IEEEFloat::subtractSignificand(const IEEEFloat &rhs, + integerPart borrow) { integerPart *parts; parts = significandParts(); @@ -966,14 +977,14 @@ lostFraction IEEEFloat::multiplySignificand(const IEEEFloat &rhs, // rhs = b23 . b22 ... b0 * 2^e2 // the result of multiplication is: // *this = c48 c47 c46 . c45 ... c0 * 2^(e1+e2) - // Note that there are three significant bits at the left-hand side of the + // Note that there are three significant bits at the left-hand side of the // radix point: two for the multiplication, and an overflow bit for the // addition (that will always be zero at this point). Move the radix point // toward left by two bits, and adjust exponent accordingly. exponent += 2; if (addend && addend->isNonZero()) { - // The intermediate result of the multiplication has "2 * precision" + // The intermediate result of the multiplication has "2 * precision" // signicant bit; adjust the addend to be consistent with mul result. // Significand savedSignificand = significand; @@ -1025,7 +1036,7 @@ lostFraction IEEEFloat::multiplySignificand(const IEEEFloat &rhs, } // Convert the result having "2 * precision" significant-bits back to the one - // having "precision" significant-bits. First, move the radix point from + // having "precision" significant-bits. First, move the radix point from // poision "2*precision - 1" to "precision - 1". The exponent need to be // adjusted by "2*precision - 1" - "precision - 1" = "precision". exponent -= precision + 1; @@ -1541,11 +1552,13 @@ IEEEFloat::opStatus IEEEFloat::divideSpecials(const IEEEFloat &rhs) { case PackCategoriesIntoKey(fcInfinity, fcNaN): category = fcNaN; copySignificand(rhs); + LLVM_FALLTHROUGH; case PackCategoriesIntoKey(fcNaN, fcZero): case PackCategoriesIntoKey(fcNaN, fcNormal): case PackCategoriesIntoKey(fcNaN, fcInfinity): case PackCategoriesIntoKey(fcNaN, fcNaN): sign = false; + LLVM_FALLTHROUGH; case PackCategoriesIntoKey(fcInfinity, fcZero): case PackCategoriesIntoKey(fcInfinity, fcNormal): case PackCategoriesIntoKey(fcZero, fcInfinity): @@ -1611,16 +1624,6 @@ void IEEEFloat::changeSign() { sign = !sign; } -void IEEEFloat::clearSign() { - /* So is this one. */ - sign = 0; -} - -void IEEEFloat::copySign(const IEEEFloat &rhs) { - /* And this one. */ - sign = rhs.sign; -} - /* Normalized addition or subtraction. */ IEEEFloat::opStatus IEEEFloat::addOrSubtract(const IEEEFloat &rhs, roundingMode rounding_mode, @@ -1712,9 +1715,10 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) { int parts = partCount(); integerPart *x = new integerPart[parts]; bool ignored; - fs = V.convertToInteger(x, parts * integerPartWidth, true, - rmNearestTiesToEven, &ignored); - if (fs==opInvalidOp) { + fs = V.convertToInteger(makeMutableArrayRef(x, parts), + parts * integerPartWidth, true, rmNearestTiesToEven, + &ignored); + if (fs == opInvalidOp) { delete[] x; return fs; } @@ -1735,43 +1739,20 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) { return fs; } -/* Normalized llvm frem (C fmod). - This is not currently correct in all cases. */ +/* Normalized llvm frem (C fmod). */ IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) { opStatus fs; fs = modSpecials(rhs); - if (isFiniteNonZero() && rhs.isFiniteNonZero()) { - IEEEFloat V = *this; - unsigned int origSign = sign; - - fs = V.divide(rhs, rmNearestTiesToEven); - if (fs == opDivByZero) - return fs; - - int parts = partCount(); - integerPart *x = new integerPart[parts]; - bool ignored; - fs = V.convertToInteger(x, parts * integerPartWidth, true, - rmTowardZero, &ignored); - if (fs==opInvalidOp) { - delete[] x; - return fs; - } - - fs = V.convertFromZeroExtendedInteger(x, parts * integerPartWidth, true, - rmNearestTiesToEven); - assert(fs==opOK); // should always work - - fs = V.multiply(rhs, rmNearestTiesToEven); - assert(fs==opOK || fs==opInexact); // should not overflow or underflow - + while (isFiniteNonZero() && rhs.isFiniteNonZero() && + compareAbsoluteValue(rhs) != cmpLessThan) { + IEEEFloat V = scalbn(rhs, ilogb(*this) - ilogb(rhs), rmNearestTiesToEven); + if (compareAbsoluteValue(V) == cmpLessThan) + V = scalbn(V, -1, rmNearestTiesToEven); + V.sign = sign; + fs = subtract(V, rmNearestTiesToEven); - assert(fs==opOK || fs==opInexact); // likewise - - if (isZero()) - sign = origSign; // IEEE754 requires this - delete[] x; + assert(fs==opOK); } return fs; } @@ -1840,7 +1821,7 @@ IEEEFloat::opStatus IEEEFloat::roundToIntegral(roundingMode rounding_mode) { IEEEFloat MagicConstant(*semantics); fs = MagicConstant.convertFromAPInt(IntegerConstant, false, rmNearestTiesToEven); - MagicConstant.copySign(*this); + MagicConstant.sign = sign; if (fs != opOK) return fs; @@ -2047,7 +2028,7 @@ IEEEFloat::opStatus IEEEFloat::convert(const fltSemantics &toSemantics, Note that for conversions to integer type the C standard requires round-to-zero to always be used. */ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( - integerPart *parts, unsigned int width, bool isSigned, + MutableArrayRef<integerPart> parts, unsigned int width, bool isSigned, roundingMode rounding_mode, bool *isExact) const { lostFraction lost_fraction; const integerPart *src; @@ -2060,9 +2041,10 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( return opInvalidOp; dstPartsCount = partCountForBits(width); + assert(dstPartsCount <= parts.size() && "Integer too big"); if (category == fcZero) { - APInt::tcSet(parts, 0, dstPartsCount); + APInt::tcSet(parts.data(), 0, dstPartsCount); // Negative zero can't be represented as an int. *isExact = !sign; return opOK; @@ -2074,7 +2056,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( the destination. */ if (exponent < 0) { /* Our absolute value is less than one; truncate everything. */ - APInt::tcSet(parts, 0, dstPartsCount); + APInt::tcSet(parts.data(), 0, dstPartsCount); /* For exponent -1 the integer bit represents .5, look at that. For smaller exponents leftmost truncated bit is 0. */ truncatedBits = semantics->precision -1U - exponent; @@ -2090,11 +2072,13 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( if (bits < semantics->precision) { /* We truncate (semantics->precision - bits) bits. */ truncatedBits = semantics->precision - bits; - APInt::tcExtract(parts, dstPartsCount, src, bits, truncatedBits); + APInt::tcExtract(parts.data(), dstPartsCount, src, bits, truncatedBits); } else { /* We want at least as many bits as are available. */ - APInt::tcExtract(parts, dstPartsCount, src, semantics->precision, 0); - APInt::tcShiftLeft(parts, dstPartsCount, bits - semantics->precision); + APInt::tcExtract(parts.data(), dstPartsCount, src, semantics->precision, + 0); + APInt::tcShiftLeft(parts.data(), dstPartsCount, + bits - semantics->precision); truncatedBits = 0; } } @@ -2106,7 +2090,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( truncatedBits); if (lost_fraction != lfExactlyZero && roundAwayFromZero(rounding_mode, lost_fraction, truncatedBits)) { - if (APInt::tcIncrement(parts, dstPartsCount)) + if (APInt::tcIncrement(parts.data(), dstPartsCount)) return opInvalidOp; /* Overflow. */ } } else { @@ -2114,7 +2098,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( } /* Step 3: check if we fit in the destination. */ - unsigned int omsb = APInt::tcMSB(parts, dstPartsCount) + 1; + unsigned int omsb = APInt::tcMSB(parts.data(), dstPartsCount) + 1; if (sign) { if (!isSigned) { @@ -2125,7 +2109,8 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( /* It takes omsb bits to represent the unsigned integer value. We lose a bit for the sign, but care is needed as the maximally negative integer is a special case. */ - if (omsb == width && APInt::tcLSB(parts, dstPartsCount) + 1 != omsb) + if (omsb == width && + APInt::tcLSB(parts.data(), dstPartsCount) + 1 != omsb) return opInvalidOp; /* This case can happen because of rounding. */ @@ -2133,7 +2118,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( return opInvalidOp; } - APInt::tcNegate (parts, dstPartsCount); + APInt::tcNegate (parts.data(), dstPartsCount); } else { if (omsb >= width + !isSigned) return opInvalidOp; @@ -2155,11 +2140,10 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( the original value. This is almost equivalent to result==opOK, except for negative zeroes. */ -IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts, - unsigned int width, - bool isSigned, - roundingMode rounding_mode, - bool *isExact) const { +IEEEFloat::opStatus +IEEEFloat::convertToInteger(MutableArrayRef<integerPart> parts, + unsigned int width, bool isSigned, + roundingMode rounding_mode, bool *isExact) const { opStatus fs; fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode, @@ -2169,6 +2153,7 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts, unsigned int bits, dstPartsCount; dstPartsCount = partCountForBits(width); + assert(dstPartsCount <= parts.size() && "Integer too big"); if (category == fcNaN) bits = 0; @@ -2177,30 +2162,14 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts, else bits = width - isSigned; - APInt::tcSetLeastSignificantBits(parts, dstPartsCount, bits); + APInt::tcSetLeastSignificantBits(parts.data(), dstPartsCount, bits); if (sign && isSigned) - APInt::tcShiftLeft(parts, dstPartsCount, width - 1); + APInt::tcShiftLeft(parts.data(), dstPartsCount, width - 1); } return fs; } -/* Same as convertToInteger(integerPart*, ...), except the result is returned in - an APSInt, whose initial bit-width and signed-ness are used to determine the - precision of the conversion. - */ -IEEEFloat::opStatus IEEEFloat::convertToInteger(APSInt &result, - roundingMode rounding_mode, - bool *isExact) const { - unsigned bitWidth = result.getBitWidth(); - SmallVector<uint64_t, 4> parts(result.getNumWords()); - opStatus status = convertToInteger( - parts.data(), bitWidth, result.isSigned(), rounding_mode, isExact); - // Keeps the original signed-ness. - result = APInt(bitWidth, parts); - return status; -} - /* Convert an unsigned integer SRC to a floating point number, rounding according to ROUNDING_MODE. The sign of the floating point number is not modified. */ @@ -2484,7 +2453,7 @@ IEEEFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) { // Test if we have a zero number allowing for strings with no null terminators // and zero decimals with non-zero exponents. - // + // // We computed firstSigDigit by ignoring all zeros and dots. Thus if // D->firstSigDigit equals str.end(), every digit must be a zero and there can // be at most one dot. On the other hand, if we have a zero with a non-zero @@ -2852,7 +2821,7 @@ APInt IEEEFloat::convertF80LongDoubleAPFloatToAPInt() const { } APInt IEEEFloat::convertPPCDoubleDoubleAPFloatToAPInt() const { - assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl); + assert(semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy); assert(partCount()==2); uint64_t words[2]; @@ -3033,7 +3002,7 @@ APInt IEEEFloat::bitcastToAPInt() const { if (semantics == (const llvm::fltSemantics*)&semIEEEquad) return convertQuadrupleAPFloatToAPInt(); - if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleImpl) + if (semantics == (const llvm::fltSemantics *)&semPPCDoubleDoubleLegacy) return convertPPCDoubleDoubleAPFloatToAPInt(); assert(semantics == (const llvm::fltSemantics*)&semX87DoubleExtended && @@ -3103,14 +3072,14 @@ void IEEEFloat::initFromPPCDoubleDoubleAPInt(const APInt &api) { // Get the first double and convert to our format. initFromDoubleAPInt(APInt(64, i1)); - fs = convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo); + fs = convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo); assert(fs == opOK && !losesInfo); (void)fs; // Unless we have a special case, add in second double. if (isFiniteNonZero()) { IEEEFloat v(semIEEEdouble, APInt(64, i2)); - fs = v.convert(semPPCDoubleDoubleImpl, rmNearestTiesToEven, &losesInfo); + fs = v.convert(semPPCDoubleDoubleLegacy, rmNearestTiesToEven, &losesInfo); assert(fs == opOK && !losesInfo); (void)fs; @@ -3264,7 +3233,7 @@ void IEEEFloat::initFromAPInt(const fltSemantics *Sem, const APInt &api) { return initFromF80LongDoubleAPInt(api); if (Sem == &semIEEEquad) return initFromQuadrupleAPInt(api); - if (Sem == &semPPCDoubleDoubleImpl) + if (Sem == &semPPCDoubleDoubleLegacy) return initFromPPCDoubleDoubleAPInt(api); llvm_unreachable(nullptr); @@ -3419,7 +3388,7 @@ namespace { } void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, - unsigned FormatMaxPadding) const { + unsigned FormatMaxPadding, bool TruncateZero) const { switch (category) { case fcInfinity: if (isNegative()) @@ -3433,9 +3402,16 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, if (isNegative()) Str.push_back('-'); - if (!FormatMaxPadding) - append(Str, "0.0E+0"); - else + if (!FormatMaxPadding) { + if (TruncateZero) + append(Str, "0.0E+0"); + else { + append(Str, "0.0"); + if (FormatPrecision > 1) + Str.append(FormatPrecision - 1, '0'); + append(Str, "e+00"); + } + } else Str.push_back('0'); return; @@ -3468,7 +3444,7 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, // Ignore trailing binary zeros. int trailingZeros = significand.countTrailingZeros(); exp += trailingZeros; - significand = significand.lshr(trailingZeros); + significand.lshrInPlace(trailingZeros); // Change the exponent from 2^e to 10^e. if (exp == 0) { @@ -3569,12 +3545,16 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, Str.push_back(buffer[NDigits-1]); Str.push_back('.'); - if (NDigits == 1) + if (NDigits == 1 && TruncateZero) Str.push_back('0'); else for (unsigned I = 1; I != NDigits; ++I) Str.push_back(buffer[NDigits-1-I]); - Str.push_back('E'); + // Fill with zeros up to FormatPrecision. + if (!TruncateZero && FormatPrecision > NDigits - 1) + Str.append(FormatPrecision - NDigits + 1, '0'); + // For !TruncateZero we use lower 'e'. + Str.push_back(TruncateZero ? 'E' : 'e'); Str.push_back(exp >= 0 ? '+' : '-'); if (exp < 0) exp = -exp; @@ -3583,6 +3563,9 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, expbuf.push_back((char) ('0' + (exp % 10))); exp /= 10; } while (exp); + // Exponent always at least two digits if we do not truncate zeros. + if (!TruncateZero && expbuf.size() < 2) + expbuf.push_back('0'); for (unsigned I = 0, E = expbuf.size(); I != E; ++I) Str.push_back(expbuf[E-1-I]); return; @@ -3620,7 +3603,7 @@ void IEEEFloat::toString(SmallVectorImpl<char> &Str, unsigned FormatPrecision, Str.push_back(buffer[NDigits-I-1]); } -bool IEEEFloat::getExactInverse(IEEEFloat *inv) const { +bool IEEEFloat::getExactInverse(APFloat *inv) const { // Special floats and denormals have no exact inverse. if (!isFiniteNonZero()) return false; @@ -3644,7 +3627,7 @@ bool IEEEFloat::getExactInverse(IEEEFloat *inv) const { reciprocal.significandLSB() == reciprocal.semantics->precision - 1); if (inv) - *inv = reciprocal; + *inv = APFloat(reciprocal, *semantics); return true; } @@ -3856,28 +3839,29 @@ IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM) { } DoubleAPFloat::DoubleAPFloat(const fltSemantics &S) - : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl), - APFloat(semIEEEdouble)}) { + : Semantics(&S), + Floats(new APFloat[2]{APFloat(semIEEEdouble), APFloat(semIEEEdouble)}) { assert(Semantics == &semPPCDoubleDouble); } DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, uninitializedTag) : Semantics(&S), - Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, uninitialized), + Floats(new APFloat[2]{APFloat(semIEEEdouble, uninitialized), APFloat(semIEEEdouble, uninitialized)}) { assert(Semantics == &semPPCDoubleDouble); } DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I) - : Semantics(&S), Floats(new APFloat[2]{APFloat(semPPCDoubleDoubleImpl, I), + : Semantics(&S), Floats(new APFloat[2]{APFloat(semIEEEdouble, I), APFloat(semIEEEdouble)}) { assert(Semantics == &semPPCDoubleDouble); } DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I) - : Semantics(&S), Floats(new APFloat[2]{ - APFloat(semPPCDoubleDoubleImpl, I), - APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) { + : Semantics(&S), + Floats(new APFloat[2]{ + APFloat(semIEEEdouble, APInt(64, I.getRawData()[0])), + APFloat(semIEEEdouble, APInt(64, I.getRawData()[1]))}) { assert(Semantics == &semPPCDoubleDouble); } @@ -3886,9 +3870,7 @@ DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, APFloat &&First, : Semantics(&S), Floats(new APFloat[2]{std::move(First), std::move(Second)}) { assert(Semantics == &semPPCDoubleDouble); - // TODO Check for First == &IEEEdouble once the transition is done. - assert(&Floats[0].getSemantics() == &semPPCDoubleDoubleImpl || - &Floats[0].getSemantics() == &semIEEEdouble); + assert(&Floats[0].getSemantics() == &semIEEEdouble); assert(&Floats[1].getSemantics() == &semIEEEdouble); } @@ -3917,6 +3899,7 @@ DoubleAPFloat &DoubleAPFloat::operator=(const DoubleAPFloat &RHS) { return *this; } +// Implement addition, subtraction, multiplication and division based on: // "Software for Doubled-Precision Floating-Point Computations", // by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283. APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa, @@ -3928,7 +3911,7 @@ APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa, if (!z.isFinite()) { if (!z.isInfinity()) { Floats[0] = std::move(z); - Floats[1].makeZero(false); + Floats[1].makeZero(/* Neg = */ false); return (opStatus)Status; } Status = opOK; @@ -3946,7 +3929,7 @@ APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa, } if (!z.isFinite()) { Floats[0] = std::move(z); - Floats[1].makeZero(false); + Floats[1].makeZero(/* Neg = */ false); return (opStatus)Status; } Floats[0] = z; @@ -3982,13 +3965,13 @@ APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa, Status |= zz.add(cc, RM); if (zz.isZero() && !zz.isNegative()) { Floats[0] = std::move(z); - Floats[1].makeZero(false); + Floats[1].makeZero(/* Neg = */ false); return opOK; } Floats[0] = z; Status |= Floats[0].add(zz, RM); if (!Floats[0].isFinite()) { - Floats[1].makeZero(false); + Floats[1].makeZero(/* Neg = */ false); return (opStatus)Status; } Floats[1] = std::move(z); @@ -4033,25 +4016,15 @@ APFloat::opStatus DoubleAPFloat::addWithSpecial(const DoubleAPFloat &LHS, } assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal); - // These conversions will go away once PPCDoubleDoubleImpl goes away. - // (PPCDoubleDoubleImpl, IEEEDouble) -> (IEEEDouble, IEEEDouble) - APFloat A(semIEEEdouble, - APInt(64, LHS.Floats[0].bitcastToAPInt().getRawData()[0])), - AA(LHS.Floats[1]), - C(semIEEEdouble, APInt(64, RHS.Floats[0].bitcastToAPInt().getRawData()[0])), + APFloat A(LHS.Floats[0]), AA(LHS.Floats[1]), C(RHS.Floats[0]), CC(RHS.Floats[1]); + assert(&A.getSemantics() == &semIEEEdouble); assert(&AA.getSemantics() == &semIEEEdouble); + assert(&C.getSemantics() == &semIEEEdouble); assert(&CC.getSemantics() == &semIEEEdouble); - Out.Floats[0] = APFloat(semIEEEdouble); + assert(&Out.Floats[0].getSemantics() == &semIEEEdouble); assert(&Out.Floats[1].getSemantics() == &semIEEEdouble); - - auto Ret = Out.addImpl(A, AA, C, CC, RM); - - // (IEEEDouble, IEEEDouble) -> (PPCDoubleDoubleImpl, IEEEDouble) - uint64_t Buffer[] = {Out.Floats[0].bitcastToAPInt().getRawData()[0], - Out.Floats[1].bitcastToAPInt().getRawData()[0]}; - Out.Floats[0] = APFloat(semPPCDoubleDoubleImpl, APInt(128, 2, Buffer)); - return Ret; + return Out.addImpl(A, AA, C, CC, RM); } APFloat::opStatus DoubleAPFloat::add(const DoubleAPFloat &RHS, @@ -4067,6 +4040,140 @@ APFloat::opStatus DoubleAPFloat::subtract(const DoubleAPFloat &RHS, return Ret; } +APFloat::opStatus DoubleAPFloat::multiply(const DoubleAPFloat &RHS, + APFloat::roundingMode RM) { + const auto &LHS = *this; + auto &Out = *this; + /* Interesting observation: For special categories, finding the lowest + common ancestor of the following layered graph gives the correct + return category: + + NaN + / \ + Zero Inf + \ / + Normal + + e.g. NaN * NaN = NaN + Zero * Inf = NaN + Normal * Zero = Zero + Normal * Inf = Inf + */ + if (LHS.getCategory() == fcNaN) { + Out = LHS; + return opOK; + } + if (RHS.getCategory() == fcNaN) { + Out = RHS; + return opOK; + } + if ((LHS.getCategory() == fcZero && RHS.getCategory() == fcInfinity) || + (LHS.getCategory() == fcInfinity && RHS.getCategory() == fcZero)) { + Out.makeNaN(false, false, nullptr); + return opOK; + } + if (LHS.getCategory() == fcZero || LHS.getCategory() == fcInfinity) { + Out = LHS; + return opOK; + } + if (RHS.getCategory() == fcZero || RHS.getCategory() == fcInfinity) { + Out = RHS; + return opOK; + } + assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal && + "Special cases not handled exhaustively"); + + int Status = opOK; + APFloat A = Floats[0], B = Floats[1], C = RHS.Floats[0], D = RHS.Floats[1]; + // t = a * c + APFloat T = A; + Status |= T.multiply(C, RM); + if (!T.isFiniteNonZero()) { + Floats[0] = T; + Floats[1].makeZero(/* Neg = */ false); + return (opStatus)Status; + } + + // tau = fmsub(a, c, t), that is -fmadd(-a, c, t). + APFloat Tau = A; + T.changeSign(); + Status |= Tau.fusedMultiplyAdd(C, T, RM); + T.changeSign(); + { + // v = a * d + APFloat V = A; + Status |= V.multiply(D, RM); + // w = b * c + APFloat W = B; + Status |= W.multiply(C, RM); + Status |= V.add(W, RM); + // tau += v + w + Status |= Tau.add(V, RM); + } + // u = t + tau + APFloat U = T; + Status |= U.add(Tau, RM); + + Floats[0] = U; + if (!U.isFinite()) { + Floats[1].makeZero(/* Neg = */ false); + } else { + // Floats[1] = (t - u) + tau + Status |= T.subtract(U, RM); + Status |= T.add(Tau, RM); + Floats[1] = T; + } + return (opStatus)Status; +} + +APFloat::opStatus DoubleAPFloat::divide(const DoubleAPFloat &RHS, + APFloat::roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + auto Ret = + Tmp.divide(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt()), RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus DoubleAPFloat::remainder(const DoubleAPFloat &RHS) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + auto Ret = + Tmp.remainder(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt())); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus DoubleAPFloat::mod(const DoubleAPFloat &RHS) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + auto Ret = Tmp.mod(APFloat(semPPCDoubleDoubleLegacy, RHS.bitcastToAPInt())); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus +DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand, + const DoubleAPFloat &Addend, + APFloat::roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + auto Ret = Tmp.fusedMultiplyAdd( + APFloat(semPPCDoubleDoubleLegacy, Multiplicand.bitcastToAPInt()), + APFloat(semPPCDoubleDoubleLegacy, Addend.bitcastToAPInt()), RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus DoubleAPFloat::roundToIntegral(APFloat::roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + auto Ret = Tmp.roundToIntegral(RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + void DoubleAPFloat::changeSign() { Floats[0].changeSign(); Floats[1].changeSign(); @@ -4101,12 +4208,201 @@ bool DoubleAPFloat::isNegative() const { return Floats[0].isNegative(); } void DoubleAPFloat::makeInf(bool Neg) { Floats[0].makeInf(Neg); - Floats[1].makeZero(false); + Floats[1].makeZero(/* Neg = */ false); +} + +void DoubleAPFloat::makeZero(bool Neg) { + Floats[0].makeZero(Neg); + Floats[1].makeZero(/* Neg = */ false); +} + +void DoubleAPFloat::makeLargest(bool Neg) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x7fefffffffffffffull)); + Floats[1] = APFloat(semIEEEdouble, APInt(64, 0x7c8ffffffffffffeull)); + if (Neg) + changeSign(); +} + +void DoubleAPFloat::makeSmallest(bool Neg) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + Floats[0].makeSmallest(Neg); + Floats[1].makeZero(/* Neg = */ false); +} + +void DoubleAPFloat::makeSmallestNormalized(bool Neg) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + Floats[0] = APFloat(semIEEEdouble, APInt(64, 0x0360000000000000ull)); + if (Neg) + Floats[0].changeSign(); + Floats[1].makeZero(/* Neg = */ false); } void DoubleAPFloat::makeNaN(bool SNaN, bool Neg, const APInt *fill) { Floats[0].makeNaN(SNaN, Neg, fill); - Floats[1].makeZero(false); + Floats[1].makeZero(/* Neg = */ false); +} + +APFloat::cmpResult DoubleAPFloat::compare(const DoubleAPFloat &RHS) const { + auto Result = Floats[0].compare(RHS.Floats[0]); + // |Float[0]| > |Float[1]| + if (Result == APFloat::cmpEqual) + return Floats[1].compare(RHS.Floats[1]); + return Result; +} + +bool DoubleAPFloat::bitwiseIsEqual(const DoubleAPFloat &RHS) const { + return Floats[0].bitwiseIsEqual(RHS.Floats[0]) && + Floats[1].bitwiseIsEqual(RHS.Floats[1]); +} + +hash_code hash_value(const DoubleAPFloat &Arg) { + if (Arg.Floats) + return hash_combine(hash_value(Arg.Floats[0]), hash_value(Arg.Floats[1])); + return hash_combine(Arg.Semantics); +} + +APInt DoubleAPFloat::bitcastToAPInt() const { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + uint64_t Data[] = { + Floats[0].bitcastToAPInt().getRawData()[0], + Floats[1].bitcastToAPInt().getRawData()[0], + }; + return APInt(128, 2, Data); +} + +APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S, + roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy); + auto Ret = Tmp.convertFromString(S, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus DoubleAPFloat::next(bool nextDown) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + auto Ret = Tmp.next(nextDown); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus +DoubleAPFloat::convertToInteger(MutableArrayRef<integerPart> Input, + unsigned int Width, bool IsSigned, + roundingMode RM, bool *IsExact) const { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt()) + .convertToInteger(Input, Width, IsSigned, RM, IsExact); +} + +APFloat::opStatus DoubleAPFloat::convertFromAPInt(const APInt &Input, + bool IsSigned, + roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy); + auto Ret = Tmp.convertFromAPInt(Input, IsSigned, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus +DoubleAPFloat::convertFromSignExtendedInteger(const integerPart *Input, + unsigned int InputSize, + bool IsSigned, roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy); + auto Ret = Tmp.convertFromSignExtendedInteger(Input, InputSize, IsSigned, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +APFloat::opStatus +DoubleAPFloat::convertFromZeroExtendedInteger(const integerPart *Input, + unsigned int InputSize, + bool IsSigned, roundingMode RM) { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy); + auto Ret = Tmp.convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM); + *this = DoubleAPFloat(semPPCDoubleDouble, Tmp.bitcastToAPInt()); + return Ret; +} + +unsigned int DoubleAPFloat::convertToHexString(char *DST, + unsigned int HexDigits, + bool UpperCase, + roundingMode RM) const { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt()) + .convertToHexString(DST, HexDigits, UpperCase, RM); +} + +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); +} + +bool DoubleAPFloat::isSmallest() const { + if (getCategory() != fcNormal) + return false; + DoubleAPFloat Tmp(*this); + Tmp.makeSmallest(this->isNegative()); + return Tmp.compare(*this) == cmpEqual; +} + +bool DoubleAPFloat::isLargest() const { + if (getCategory() != fcNormal) + return false; + DoubleAPFloat Tmp(*this); + Tmp.makeLargest(this->isNegative()); + return Tmp.compare(*this) == cmpEqual; +} + +bool DoubleAPFloat::isInteger() const { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy); + (void)Tmp.add(Floats[0], rmNearestTiesToEven); + (void)Tmp.add(Floats[1], rmNearestTiesToEven); + return Tmp.isInteger(); +} + +void DoubleAPFloat::toString(SmallVectorImpl<char> &Str, + unsigned FormatPrecision, + unsigned FormatMaxPadding, + bool TruncateZero) const { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt()) + .toString(Str, FormatPrecision, FormatMaxPadding, TruncateZero); +} + +bool DoubleAPFloat::getExactInverse(APFloat *inv) const { + assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat Tmp(semPPCDoubleDoubleLegacy, bitcastToAPInt()); + if (!inv) + return Tmp.getExactInverse(nullptr); + APFloat Inv(semPPCDoubleDoubleLegacy); + auto Ret = Tmp.getExactInverse(&Inv); + *inv = APFloat(semPPCDoubleDouble, Inv.bitcastToAPInt()); + return Ret; +} + +DoubleAPFloat scalbn(DoubleAPFloat Arg, int Exp, APFloat::roundingMode RM) { + assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + return DoubleAPFloat(semPPCDoubleDouble, scalbn(Arg.Floats[0], Exp, RM), + scalbn(Arg.Floats[1], Exp, RM)); +} + +DoubleAPFloat frexp(const DoubleAPFloat &Arg, int &Exp, + APFloat::roundingMode RM) { + assert(Arg.Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); + APFloat First = frexp(Arg.Floats[0], Exp, RM); + APFloat Second = Arg.Floats[1]; + if (Arg.getCategory() == APFloat::fcNormal) + Second = scalbn(Second, -Exp, RM); + return DoubleAPFloat(semPPCDoubleDouble, std::move(First), std::move(Second)); } } // End detail namespace @@ -4126,10 +4422,16 @@ APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) { } APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) { - return getIEEE().convertFromString(Str, RM); + APFLOAT_DISPATCH_ON_SEMANTICS(convertFromString(Str, RM)); } -hash_code hash_value(const APFloat &Arg) { return hash_value(Arg.getIEEE()); } +hash_code hash_value(const APFloat &Arg) { + if (APFloat::usesLayout<detail::IEEEFloat>(Arg.getSemantics())) + return hash_value(Arg.U.IEEE); + if (APFloat::usesLayout<detail::DoubleAPFloat>(Arg.getSemantics())) + return hash_value(Arg.U.Double); + llvm_unreachable("Unexpected semantics"); +} APFloat::APFloat(const fltSemantics &Semantics, StringRef S) : APFloat(Semantics) { @@ -4146,10 +4448,8 @@ APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics, if (usesLayout<IEEEFloat>(getSemantics()) && usesLayout<DoubleAPFloat>(ToSemantics)) { assert(&ToSemantics == &semPPCDoubleDouble); - auto Ret = U.IEEE.convert(semPPCDoubleDoubleImpl, RM, losesInfo); - *this = APFloat(DoubleAPFloat(semPPCDoubleDouble, std::move(*this), - APFloat(semIEEEdouble)), - ToSemantics); + auto Ret = U.IEEE.convert(semPPCDoubleDoubleLegacy, RM, losesInfo); + *this = APFloat(ToSemantics, U.IEEE.bitcastToAPInt()); return Ret; } if (usesLayout<DoubleAPFloat>(getSemantics()) && @@ -4189,6 +4489,30 @@ void APFloat::print(raw_ostream &OS) const { OS << Buffer << "\n"; } -void APFloat::dump() const { print(dbgs()); } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void APFloat::dump() const { print(dbgs()); } +#endif + +void APFloat::Profile(FoldingSetNodeID &NID) const { + NID.Add(bitcastToAPInt()); +} + +/* Same as convertToInteger(integerPart*, ...), except the result is returned in + an APSInt, whose initial bit-width and signed-ness are used to determine the + precision of the conversion. + */ +APFloat::opStatus APFloat::convertToInteger(APSInt &result, + roundingMode rounding_mode, + bool *isExact) const { + unsigned bitWidth = result.getBitWidth(); + SmallVector<uint64_t, 4> parts(result.getNumWords()); + opStatus status = convertToInteger(parts, bitWidth, result.isSigned(), + rounding_mode, isExact); + // Keeps the original signed-ness. + result = APInt(bitWidth, parts); + return status; +} } // End llvm namespace + +#undef APFLOAT_DISPATCH_ON_SEMANTICS diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp index fb8b451..c558ddd 100644 --- a/contrib/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -63,7 +63,7 @@ inline static unsigned getDigit(char cdigit, uint8_t radix) { r = cdigit - 'a'; if (r <= radix - 11U) return r + 10; - + radix = 10; } @@ -76,91 +76,84 @@ inline static unsigned getDigit(char cdigit, uint8_t radix) { void APInt::initSlowCase(uint64_t val, bool isSigned) { - pVal = getClearedMemory(getNumWords()); - pVal[0] = val; + U.pVal = getClearedMemory(getNumWords()); + U.pVal[0] = val; if (isSigned && int64_t(val) < 0) for (unsigned i = 1; i < getNumWords(); ++i) - pVal[i] = -1ULL; + U.pVal[i] = WORD_MAX; + clearUnusedBits(); } void APInt::initSlowCase(const APInt& that) { - pVal = getMemory(getNumWords()); - memcpy(pVal, that.pVal, getNumWords() * APINT_WORD_SIZE); + U.pVal = getMemory(getNumWords()); + memcpy(U.pVal, that.U.pVal, getNumWords() * APINT_WORD_SIZE); } void APInt::initFromArray(ArrayRef<uint64_t> bigVal) { assert(BitWidth && "Bitwidth too small"); assert(bigVal.data() && "Null pointer detected!"); if (isSingleWord()) - VAL = bigVal[0]; + U.VAL = bigVal[0]; else { // Get memory, cleared to 0 - pVal = getClearedMemory(getNumWords()); + U.pVal = getClearedMemory(getNumWords()); // Calculate the number of words to copy unsigned words = std::min<unsigned>(bigVal.size(), getNumWords()); // Copy the words from bigVal to pVal - memcpy(pVal, bigVal.data(), words * APINT_WORD_SIZE); + memcpy(U.pVal, bigVal.data(), words * APINT_WORD_SIZE); } // Make sure unused high bits are cleared clearUnusedBits(); } APInt::APInt(unsigned numBits, ArrayRef<uint64_t> bigVal) - : BitWidth(numBits), VAL(0) { + : BitWidth(numBits) { initFromArray(bigVal); } APInt::APInt(unsigned numBits, unsigned numWords, const uint64_t bigVal[]) - : BitWidth(numBits), VAL(0) { + : BitWidth(numBits) { initFromArray(makeArrayRef(bigVal, numWords)); } APInt::APInt(unsigned numbits, StringRef Str, uint8_t radix) - : BitWidth(numbits), VAL(0) { + : BitWidth(numbits) { assert(BitWidth && "Bitwidth too small"); fromString(numbits, Str, radix); } -APInt& APInt::AssignSlowCase(const APInt& RHS) { - // Don't do anything for X = X - if (this == &RHS) - return *this; - - if (BitWidth == RHS.getBitWidth()) { - // assume same bit-width single-word case is already handled - assert(!isSingleWord()); - memcpy(pVal, RHS.pVal, getNumWords() * APINT_WORD_SIZE); - return *this; +void APInt::reallocate(unsigned NewBitWidth) { + // If the number of words is the same we can just change the width and stop. + if (getNumWords() == getNumWords(NewBitWidth)) { + BitWidth = NewBitWidth; + return; } - if (isSingleWord()) { - // assume case where both are single words is already handled - assert(!RHS.isSingleWord()); - VAL = 0; - pVal = getMemory(RHS.getNumWords()); - memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); - } else if (getNumWords() == RHS.getNumWords()) - memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); - else if (RHS.isSingleWord()) { - delete [] pVal; - VAL = RHS.VAL; - } else { - delete [] pVal; - pVal = getMemory(RHS.getNumWords()); - memcpy(pVal, RHS.pVal, RHS.getNumWords() * APINT_WORD_SIZE); - } - BitWidth = RHS.BitWidth; - return clearUnusedBits(); + // If we have an allocation, delete it. + if (!isSingleWord()) + delete [] U.pVal; + + // Update BitWidth. + BitWidth = NewBitWidth; + + // If we are supposed to have an allocation, create it. + if (!isSingleWord()) + U.pVal = getMemory(getNumWords()); } -APInt& APInt::operator=(uint64_t RHS) { +void APInt::AssignSlowCase(const APInt& RHS) { + // Don't do anything for X = X + if (this == &RHS) + return; + + // Adjust the bit width and handle allocations as necessary. + reallocate(RHS.getBitWidth()); + + // Copy the data. if (isSingleWord()) - VAL = RHS; - else { - pVal[0] = RHS; - memset(pVal+1, 0, (getNumWords() - 1) * APINT_WORD_SIZE); - } - return clearUnusedBits(); + U.VAL = RHS.U.VAL; + else + memcpy(U.pVal, RHS.U.pVal, getNumWords() * APINT_WORD_SIZE); } /// This method 'profiles' an APInt for use with FoldingSet. @@ -168,374 +161,132 @@ void APInt::Profile(FoldingSetNodeID& ID) const { ID.AddInteger(BitWidth); if (isSingleWord()) { - ID.AddInteger(VAL); + ID.AddInteger(U.VAL); return; } unsigned NumWords = getNumWords(); for (unsigned i = 0; i < NumWords; ++i) - ID.AddInteger(pVal[i]); -} - -/// This function adds a single "digit" integer, y, to the multiple -/// "digit" integer array, x[]. x[] is modified to reflect the addition and -/// 1 is returned if there is a carry out, otherwise 0 is returned. -/// @returns the carry of the addition. -static bool add_1(uint64_t dest[], uint64_t x[], unsigned len, uint64_t y) { - for (unsigned i = 0; i < len; ++i) { - dest[i] = y + x[i]; - if (dest[i] < y) - y = 1; // Carry one to next digit. - else { - y = 0; // No need to carry so exit early - break; - } - } - return y; + ID.AddInteger(U.pVal[i]); } /// @brief Prefix increment operator. Increments the APInt by one. APInt& APInt::operator++() { if (isSingleWord()) - ++VAL; + ++U.VAL; else - add_1(pVal, pVal, getNumWords(), 1); + tcIncrement(U.pVal, getNumWords()); return clearUnusedBits(); } -/// This function subtracts a single "digit" (64-bit word), y, from -/// the multi-digit integer array, x[], propagating the borrowed 1 value until -/// no further borrowing is needed or it runs out of "digits" in x. The result -/// is 1 if "borrowing" exhausted the digits in x, or 0 if x was not exhausted. -/// In other words, if y > x then this function returns 1, otherwise 0. -/// @returns the borrow out of the subtraction -static bool sub_1(uint64_t x[], unsigned len, uint64_t y) { - for (unsigned i = 0; i < len; ++i) { - uint64_t X = x[i]; - x[i] -= y; - if (y > X) - y = 1; // We have to "borrow 1" from next "digit" - else { - y = 0; // No need to borrow - break; // Remaining digits are unchanged so exit early - } - } - return bool(y); -} - /// @brief Prefix decrement operator. Decrements the APInt by one. APInt& APInt::operator--() { if (isSingleWord()) - --VAL; + --U.VAL; else - sub_1(pVal, getNumWords(), 1); + tcDecrement(U.pVal, getNumWords()); return clearUnusedBits(); } -/// This function adds the integer array x to the integer array Y and -/// places the result in dest. -/// @returns the carry out from the addition -/// @brief General addition of 64-bit integer arrays -static bool add(uint64_t *dest, const uint64_t *x, const uint64_t *y, - unsigned len) { - bool carry = false; - for (unsigned i = 0; i< len; ++i) { - uint64_t limit = std::min(x[i],y[i]); // must come first in case dest == x - dest[i] = x[i] + y[i] + carry; - carry = dest[i] < limit || (carry && dest[i] == limit); - } - return carry; -} - /// Adds the RHS APint to this APInt. /// @returns this, after addition of RHS. /// @brief Addition assignment operator. APInt& APInt::operator+=(const APInt& RHS) { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) - VAL += RHS.VAL; - else { - add(pVal, pVal, RHS.pVal, getNumWords()); - } + U.VAL += RHS.U.VAL; + else + tcAdd(U.pVal, RHS.U.pVal, 0, getNumWords()); return clearUnusedBits(); } APInt& APInt::operator+=(uint64_t RHS) { if (isSingleWord()) - VAL += RHS; + U.VAL += RHS; else - add_1(pVal, pVal, getNumWords(), RHS); + tcAddPart(U.pVal, RHS, getNumWords()); return clearUnusedBits(); } -/// Subtracts the integer array y from the integer array x -/// @returns returns the borrow out. -/// @brief Generalized subtraction of 64-bit integer arrays. -static bool sub(uint64_t *dest, const uint64_t *x, const uint64_t *y, - unsigned len) { - bool borrow = false; - for (unsigned i = 0; i < len; ++i) { - uint64_t x_tmp = borrow ? x[i] - 1 : x[i]; - borrow = y[i] > x_tmp || (borrow && x[i] == 0); - dest[i] = x_tmp - y[i]; - } - return borrow; -} - /// Subtracts the RHS APInt from this APInt /// @returns this, after subtraction /// @brief Subtraction assignment operator. APInt& APInt::operator-=(const APInt& RHS) { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) - VAL -= RHS.VAL; + U.VAL -= RHS.U.VAL; else - sub(pVal, pVal, RHS.pVal, getNumWords()); + tcSubtract(U.pVal, RHS.U.pVal, 0, getNumWords()); return clearUnusedBits(); } APInt& APInt::operator-=(uint64_t RHS) { if (isSingleWord()) - VAL -= RHS; + U.VAL -= RHS; else - sub_1(pVal, getNumWords(), RHS); + tcSubtractPart(U.pVal, RHS, getNumWords()); return clearUnusedBits(); } -/// Multiplies an integer array, x, by a uint64_t integer and places the result -/// into dest. -/// @returns the carry out of the multiplication. -/// @brief Multiply a multi-digit APInt by a single digit (64-bit) integer. -static uint64_t mul_1(uint64_t dest[], uint64_t x[], unsigned len, uint64_t y) { - // Split y into high 32-bit part (hy) and low 32-bit part (ly) - uint64_t ly = y & 0xffffffffULL, hy = y >> 32; - uint64_t carry = 0; - - // For each digit of x. - for (unsigned i = 0; i < len; ++i) { - // Split x into high and low words - uint64_t lx = x[i] & 0xffffffffULL; - uint64_t hx = x[i] >> 32; - // hasCarry - A flag to indicate if there is a carry to the next digit. - // hasCarry == 0, no carry - // hasCarry == 1, has carry - // hasCarry == 2, no carry and the calculation result == 0. - uint8_t hasCarry = 0; - dest[i] = carry + lx * ly; - // Determine if the add above introduces carry. - hasCarry = (dest[i] < carry) ? 1 : 0; - carry = hx * ly + (dest[i] >> 32) + (hasCarry ? (1ULL << 32) : 0); - // The upper limit of carry can be (2^32 - 1)(2^32 - 1) + - // (2^32 - 1) + 2^32 = 2^64. - hasCarry = (!carry && hasCarry) ? 1 : (!carry ? 2 : 0); - - carry += (lx * hy) & 0xffffffffULL; - dest[i] = (carry << 32) | (dest[i] & 0xffffffffULL); - carry = (((!carry && hasCarry != 2) || hasCarry == 1) ? (1ULL << 32) : 0) + - (carry >> 32) + ((lx * hy) >> 32) + hx * hy; - } - return carry; -} - -/// Multiplies integer array x by integer array y and stores the result into -/// the integer array dest. Note that dest's size must be >= xlen + ylen. -/// @brief Generalized multiplicate of integer arrays. -static void mul(uint64_t dest[], uint64_t x[], unsigned xlen, uint64_t y[], - unsigned ylen) { - dest[xlen] = mul_1(dest, x, xlen, y[0]); - for (unsigned i = 1; i < ylen; ++i) { - uint64_t ly = y[i] & 0xffffffffULL, hy = y[i] >> 32; - uint64_t carry = 0, lx = 0, hx = 0; - for (unsigned j = 0; j < xlen; ++j) { - lx = x[j] & 0xffffffffULL; - hx = x[j] >> 32; - // hasCarry - A flag to indicate if has carry. - // hasCarry == 0, no carry - // hasCarry == 1, has carry - // hasCarry == 2, no carry and the calculation result == 0. - uint8_t hasCarry = 0; - uint64_t resul = carry + lx * ly; - hasCarry = (resul < carry) ? 1 : 0; - carry = (hasCarry ? (1ULL << 32) : 0) + hx * ly + (resul >> 32); - hasCarry = (!carry && hasCarry) ? 1 : (!carry ? 2 : 0); - - carry += (lx * hy) & 0xffffffffULL; - resul = (carry << 32) | (resul & 0xffffffffULL); - dest[i+j] += resul; - carry = (((!carry && hasCarry != 2) || hasCarry == 1) ? (1ULL << 32) : 0)+ - (carry >> 32) + (dest[i+j] < resul ? 1 : 0) + - ((lx * hy) >> 32) + hx * hy; - } - dest[i+xlen] = carry; - } -} - -APInt& APInt::operator*=(const APInt& RHS) { +APInt APInt::operator*(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) { - VAL *= RHS.VAL; - clearUnusedBits(); - return *this; - } - - // Get some bit facts about LHS and check for zero - unsigned lhsBits = getActiveBits(); - unsigned lhsWords = !lhsBits ? 0 : whichWord(lhsBits - 1) + 1; - if (!lhsWords) - // 0 * X ===> 0 - return *this; + if (isSingleWord()) + return APInt(BitWidth, U.VAL * RHS.U.VAL); - // Get some bit facts about RHS and check for zero - unsigned rhsBits = RHS.getActiveBits(); - unsigned rhsWords = !rhsBits ? 0 : whichWord(rhsBits - 1) + 1; - if (!rhsWords) { - // X * 0 ===> 0 - clearAllBits(); - return *this; - } + APInt Result(getMemory(getNumWords()), getBitWidth()); - // Allocate space for the result - unsigned destWords = rhsWords + lhsWords; - uint64_t *dest = getMemory(destWords); + tcMultiply(Result.U.pVal, U.pVal, RHS.U.pVal, getNumWords()); - // Perform the long multiply - mul(dest, pVal, lhsWords, RHS.pVal, rhsWords); + Result.clearUnusedBits(); + return Result; +} - // Copy result back into *this - clearAllBits(); - unsigned wordsToCopy = destWords >= getNumWords() ? getNumWords() : destWords; - memcpy(pVal, dest, wordsToCopy * APINT_WORD_SIZE); - clearUnusedBits(); +void APInt::AndAssignSlowCase(const APInt& RHS) { + tcAnd(U.pVal, RHS.U.pVal, getNumWords()); +} - // delete dest array and return - delete[] dest; - return *this; +void APInt::OrAssignSlowCase(const APInt& RHS) { + tcOr(U.pVal, RHS.U.pVal, getNumWords()); } -APInt& APInt::operator&=(const APInt& RHS) { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) { - VAL &= RHS.VAL; - return *this; - } - unsigned numWords = getNumWords(); - for (unsigned i = 0; i < numWords; ++i) - pVal[i] &= RHS.pVal[i]; - return *this; +void APInt::XorAssignSlowCase(const APInt& RHS) { + tcXor(U.pVal, RHS.U.pVal, getNumWords()); } -APInt& APInt::operator|=(const APInt& RHS) { +APInt& APInt::operator*=(const APInt& RHS) { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) { - VAL |= RHS.VAL; - return *this; - } - unsigned numWords = getNumWords(); - for (unsigned i = 0; i < numWords; ++i) - pVal[i] |= RHS.pVal[i]; + *this = *this * RHS; return *this; } -APInt& APInt::operator^=(const APInt& RHS) { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); +APInt& APInt::operator*=(uint64_t RHS) { if (isSingleWord()) { - VAL ^= RHS.VAL; - this->clearUnusedBits(); - return *this; + U.VAL *= RHS; + } else { + unsigned NumWords = getNumWords(); + tcMultiplyPart(U.pVal, U.pVal, RHS, 0, NumWords, NumWords, false); } - unsigned numWords = getNumWords(); - for (unsigned i = 0; i < numWords; ++i) - pVal[i] ^= RHS.pVal[i]; return clearUnusedBits(); } -APInt APInt::AndSlowCase(const APInt& RHS) const { - unsigned numWords = getNumWords(); - uint64_t* val = getMemory(numWords); - for (unsigned i = 0; i < numWords; ++i) - val[i] = pVal[i] & RHS.pVal[i]; - return APInt(val, getBitWidth()); -} - -APInt APInt::OrSlowCase(const APInt& RHS) const { - unsigned numWords = getNumWords(); - uint64_t *val = getMemory(numWords); - for (unsigned i = 0; i < numWords; ++i) - val[i] = pVal[i] | RHS.pVal[i]; - return APInt(val, getBitWidth()); -} - -APInt APInt::XorSlowCase(const APInt& RHS) const { - unsigned numWords = getNumWords(); - uint64_t *val = getMemory(numWords); - for (unsigned i = 0; i < numWords; ++i) - val[i] = pVal[i] ^ RHS.pVal[i]; - - APInt Result(val, getBitWidth()); - // 0^0==1 so clear the high bits in case they got set. - Result.clearUnusedBits(); - return Result; -} - -APInt APInt::operator*(const APInt& RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(BitWidth, VAL * RHS.VAL); - APInt Result(*this); - Result *= RHS; - return Result; -} - bool APInt::EqualSlowCase(const APInt& RHS) const { - return std::equal(pVal, pVal + getNumWords(), RHS.pVal); + return std::equal(U.pVal, U.pVal + getNumWords(), RHS.U.pVal); } -bool APInt::EqualSlowCase(uint64_t Val) const { - unsigned n = getActiveBits(); - if (n <= APINT_BITS_PER_WORD) - return pVal[0] == Val; - else - return false; -} - -bool APInt::ult(const APInt& RHS) const { +int APInt::compare(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); if (isSingleWord()) - return VAL < RHS.VAL; - - // Get active bit length of both operands - unsigned n1 = getActiveBits(); - unsigned n2 = RHS.getActiveBits(); + return U.VAL < RHS.U.VAL ? -1 : U.VAL > RHS.U.VAL; - // If magnitude of LHS is less than RHS, return true. - if (n1 < n2) - return true; - - // If magnitude of RHS is greather than LHS, return false. - if (n2 < n1) - return false; - - // If they bot fit in a word, just compare the low order word - if (n1 <= APINT_BITS_PER_WORD && n2 <= APINT_BITS_PER_WORD) - return pVal[0] < RHS.pVal[0]; - - // Otherwise, compare all words - unsigned topWord = whichWord(std::max(n1,n2)-1); - for (int i = topWord; i >= 0; --i) { - if (pVal[i] > RHS.pVal[i]) - return false; - if (pVal[i] < RHS.pVal[i]) - return true; - } - return false; + return tcCompare(U.pVal, RHS.U.pVal, getNumWords()); } -bool APInt::slt(const APInt& RHS) const { +int APInt::compareSigned(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be same for comparison"); if (isSingleWord()) { - int64_t lhsSext = SignExtend64(VAL, BitWidth); - int64_t rhsSext = SignExtend64(RHS.VAL, BitWidth); - return lhsSext < rhsSext; + int64_t lhsSext = SignExtend64(U.VAL, BitWidth); + int64_t rhsSext = SignExtend64(RHS.U.VAL, BitWidth); + return lhsSext < rhsSext ? -1 : lhsSext > rhsSext; } bool lhsNeg = isNegative(); @@ -543,30 +294,45 @@ bool APInt::slt(const APInt& RHS) const { // If the sign bits don't match, then (LHS < RHS) if LHS is negative if (lhsNeg != rhsNeg) - return lhsNeg; + return lhsNeg ? -1 : 1; - // Otherwise we can just use an unsigned comparision, because even negative + // Otherwise we can just use an unsigned comparison, because even negative // numbers compare correctly this way if both have the same signed-ness. - return ult(RHS); + return tcCompare(U.pVal, RHS.U.pVal, getNumWords()); } -void APInt::setBit(unsigned bitPosition) { - if (isSingleWord()) - VAL |= maskBit(bitPosition); - else - pVal[whichWord(bitPosition)] |= maskBit(bitPosition); -} +void APInt::setBitsSlowCase(unsigned loBit, unsigned hiBit) { + unsigned loWord = whichWord(loBit); + unsigned hiWord = whichWord(hiBit); -/// Set the given bit to 0 whose position is given as "bitPosition". -/// @brief Set a given bit to 0. -void APInt::clearBit(unsigned bitPosition) { - if (isSingleWord()) - VAL &= ~maskBit(bitPosition); - else - pVal[whichWord(bitPosition)] &= ~maskBit(bitPosition); + // Create an initial mask for the low word with zeros below loBit. + uint64_t loMask = WORD_MAX << whichBit(loBit); + + // If hiBit is not aligned, we need a high mask. + unsigned hiShiftAmt = whichBit(hiBit); + if (hiShiftAmt != 0) { + // Create a high mask with zeros above hiBit. + uint64_t hiMask = WORD_MAX >> (APINT_BITS_PER_WORD - hiShiftAmt); + // If loWord and hiWord are equal, then we combine the masks. Otherwise, + // set the bits in hiWord. + if (hiWord == loWord) + loMask &= hiMask; + else + U.pVal[hiWord] |= hiMask; + } + // Apply the mask to the low word. + U.pVal[loWord] |= loMask; + + // Fill any words between loWord and hiWord with all ones. + for (unsigned word = loWord + 1; word < hiWord; ++word) + U.pVal[word] = WORD_MAX; } /// @brief Toggle every bit to its opposite value. +void APInt::flipAllBitsSlowCase() { + tcComplement(U.pVal, getNumWords()); + clearUnusedBits(); +} /// Toggle a given bit to its opposite value whose position is given /// as "bitPosition". @@ -577,9 +343,104 @@ void APInt::flipBit(unsigned bitPosition) { else setBit(bitPosition); } +void APInt::insertBits(const APInt &subBits, unsigned bitPosition) { + unsigned subBitWidth = subBits.getBitWidth(); + assert(0 < subBitWidth && (subBitWidth + bitPosition) <= BitWidth && + "Illegal bit insertion"); + + // Insertion is a direct copy. + if (subBitWidth == BitWidth) { + *this = subBits; + return; + } + + // Single word result can be done as a direct bitmask. + if (isSingleWord()) { + uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - subBitWidth); + U.VAL &= ~(mask << bitPosition); + U.VAL |= (subBits.U.VAL << bitPosition); + return; + } + + unsigned loBit = whichBit(bitPosition); + unsigned loWord = whichWord(bitPosition); + unsigned hi1Word = whichWord(bitPosition + subBitWidth - 1); + + // Insertion within a single word can be done as a direct bitmask. + if (loWord == hi1Word) { + uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - subBitWidth); + U.pVal[loWord] &= ~(mask << loBit); + U.pVal[loWord] |= (subBits.U.VAL << loBit); + return; + } + + // Insert on word boundaries. + if (loBit == 0) { + // Direct copy whole words. + unsigned numWholeSubWords = subBitWidth / APINT_BITS_PER_WORD; + memcpy(U.pVal + loWord, subBits.getRawData(), + numWholeSubWords * APINT_WORD_SIZE); + + // Mask+insert remaining bits. + unsigned remainingBits = subBitWidth % APINT_BITS_PER_WORD; + if (remainingBits != 0) { + uint64_t mask = WORD_MAX >> (APINT_BITS_PER_WORD - remainingBits); + U.pVal[hi1Word] &= ~mask; + U.pVal[hi1Word] |= subBits.getWord(subBitWidth - 1); + } + return; + } + + // General case - set/clear individual bits in dst based on src. + // TODO - there is scope for optimization here, but at the moment this code + // path is barely used so prefer readability over performance. + for (unsigned i = 0; i != subBitWidth; ++i) { + if (subBits[i]) + setBit(bitPosition + i); + else + clearBit(bitPosition + i); + } +} + +APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const { + assert(numBits > 0 && "Can't extract zero bits"); + assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth && + "Illegal bit extraction"); + + if (isSingleWord()) + return APInt(numBits, U.VAL >> bitPosition); + + unsigned loBit = whichBit(bitPosition); + unsigned loWord = whichWord(bitPosition); + unsigned hiWord = whichWord(bitPosition + numBits - 1); + + // Single word result extracting bits from a single word source. + if (loWord == hiWord) + return APInt(numBits, U.pVal[loWord] >> loBit); + + // Extracting bits that start on a source word boundary can be done + // as a fast memory copy. + if (loBit == 0) + return APInt(numBits, makeArrayRef(U.pVal + loWord, 1 + hiWord - loWord)); + + // General case - shift + copy source words directly into place. + APInt Result(numBits, 0); + unsigned NumSrcWords = getNumWords(); + unsigned NumDstWords = Result.getNumWords(); + + for (unsigned word = 0; word < NumDstWords; ++word) { + uint64_t w0 = U.pVal[loWord + word]; + uint64_t w1 = + (loWord + word + 1) < NumSrcWords ? U.pVal[loWord + word + 1] : 0; + Result.U.pVal[word] = (w0 >> loBit) | (w1 << (APINT_BITS_PER_WORD - loBit)); + } + + return Result.clearUnusedBits(); +} + unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { assert(!str.empty() && "Invalid string length"); - assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || + assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || radix == 36) && "Radix should be 2, 8, 10, 16, or 36!"); @@ -604,7 +465,7 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { return slen * 4 + isNegative; // FIXME: base 36 - + // This is grossly inefficient but accurate. We could probably do something // with a computation of roughly slen*64/20 and then adjust by the value of // the first few digits. But, I'm not sure how accurate that could be. @@ -613,7 +474,7 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { // be too large. This avoids the assertion in the constructor. This // calculation doesn't work appropriately for the numbers 0-9, so just use 4 // bits in that case. - unsigned sufficient + unsigned sufficient = radix == 10? (slen == 1 ? 4 : slen * 64/18) : (slen == 1 ? 7 : slen * 16/3); @@ -632,9 +493,9 @@ unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { hash_code llvm::hash_value(const APInt &Arg) { if (Arg.isSingleWord()) - return hash_combine(Arg.VAL); + return hash_combine(Arg.U.VAL); - return hash_combine_range(Arg.pVal, Arg.pVal + Arg.getNumWords()); + return hash_combine_range(Arg.U.pVal, Arg.U.pVal + Arg.getNumWords()); } bool APInt::isSplat(unsigned SplatSizeInBits) const { @@ -647,19 +508,31 @@ bool APInt::isSplat(unsigned SplatSizeInBits) const { /// This function returns the high "numBits" bits of this APInt. APInt APInt::getHiBits(unsigned numBits) const { - return APIntOps::lshr(*this, BitWidth - numBits); + return this->lshr(BitWidth - numBits); } /// This function returns the low "numBits" bits of this APInt. APInt APInt::getLoBits(unsigned numBits) const { - return APIntOps::lshr(APIntOps::shl(*this, BitWidth - numBits), - BitWidth - numBits); + APInt Result(getLowBitsSet(BitWidth, numBits)); + Result &= *this; + return Result; +} + +/// Return a value containing V broadcasted over NewLen bits. +APInt APInt::getSplat(unsigned NewLen, const APInt &V) { + assert(NewLen >= V.getBitWidth() && "Can't splat to smaller bit width!"); + + APInt Val = V.zextOrSelf(NewLen); + for (unsigned I = V.getBitWidth(); I < NewLen; I <<= 1) + Val |= Val << I; + + return Val; } unsigned APInt::countLeadingZerosSlowCase() const { unsigned Count = 0; for (int i = getNumWords()-1; i >= 0; --i) { - integerPart V = pVal[i]; + uint64_t V = U.pVal[i]; if (V == 0) Count += APINT_BITS_PER_WORD; else { @@ -673,10 +546,7 @@ unsigned APInt::countLeadingZerosSlowCase() const { return Count; } -unsigned APInt::countLeadingOnes() const { - if (isSingleWord()) - return llvm::countLeadingOnes(VAL << (APINT_BITS_PER_WORD - BitWidth)); - +unsigned APInt::countLeadingOnesSlowCase() const { unsigned highWordBits = BitWidth % APINT_BITS_PER_WORD; unsigned shift; if (!highWordBits) { @@ -686,13 +556,13 @@ unsigned APInt::countLeadingOnes() const { shift = APINT_BITS_PER_WORD - highWordBits; } int i = getNumWords() - 1; - unsigned Count = llvm::countLeadingOnes(pVal[i] << shift); + unsigned Count = llvm::countLeadingOnes(U.pVal[i] << shift); if (Count == highWordBits) { for (i--; i >= 0; --i) { - if (pVal[i] == -1ULL) + if (U.pVal[i] == WORD_MAX) Count += APINT_BITS_PER_WORD; else { - Count += llvm::countLeadingOnes(pVal[i]); + Count += llvm::countLeadingOnes(U.pVal[i]); break; } } @@ -700,69 +570,71 @@ unsigned APInt::countLeadingOnes() const { return Count; } -unsigned APInt::countTrailingZeros() const { - if (isSingleWord()) - return std::min(unsigned(llvm::countTrailingZeros(VAL)), BitWidth); +unsigned APInt::countTrailingZerosSlowCase() const { unsigned Count = 0; unsigned i = 0; - for (; i < getNumWords() && pVal[i] == 0; ++i) + for (; i < getNumWords() && U.pVal[i] == 0; ++i) Count += APINT_BITS_PER_WORD; if (i < getNumWords()) - Count += llvm::countTrailingZeros(pVal[i]); + Count += llvm::countTrailingZeros(U.pVal[i]); return std::min(Count, BitWidth); } unsigned APInt::countTrailingOnesSlowCase() const { unsigned Count = 0; unsigned i = 0; - for (; i < getNumWords() && pVal[i] == -1ULL; ++i) + for (; i < getNumWords() && U.pVal[i] == WORD_MAX; ++i) Count += APINT_BITS_PER_WORD; if (i < getNumWords()) - Count += llvm::countTrailingOnes(pVal[i]); - return std::min(Count, BitWidth); + Count += llvm::countTrailingOnes(U.pVal[i]); + assert(Count <= BitWidth); + return Count; } unsigned APInt::countPopulationSlowCase() const { unsigned Count = 0; for (unsigned i = 0; i < getNumWords(); ++i) - Count += llvm::countPopulation(pVal[i]); + Count += llvm::countPopulation(U.pVal[i]); return Count; } -/// Perform a logical right-shift from Src to Dst, which must be equal or -/// non-overlapping, of Words words, by Shift, which must be less than 64. -static void lshrNear(uint64_t *Dst, uint64_t *Src, unsigned Words, - unsigned Shift) { - uint64_t Carry = 0; - for (int I = Words - 1; I >= 0; --I) { - uint64_t Tmp = Src[I]; - Dst[I] = (Tmp >> Shift) | Carry; - Carry = Tmp << (64 - Shift); - } +bool APInt::intersectsSlowCase(const APInt &RHS) const { + for (unsigned i = 0, e = getNumWords(); i != e; ++i) + if ((U.pVal[i] & RHS.U.pVal[i]) != 0) + return true; + + return false; +} + +bool APInt::isSubsetOfSlowCase(const APInt &RHS) const { + for (unsigned i = 0, e = getNumWords(); i != e; ++i) + if ((U.pVal[i] & ~RHS.U.pVal[i]) != 0) + return false; + + return true; } APInt APInt::byteSwap() const { assert(BitWidth >= 16 && BitWidth % 16 == 0 && "Cannot byteswap!"); if (BitWidth == 16) - return APInt(BitWidth, ByteSwap_16(uint16_t(VAL))); + return APInt(BitWidth, ByteSwap_16(uint16_t(U.VAL))); if (BitWidth == 32) - return APInt(BitWidth, ByteSwap_32(unsigned(VAL))); + return APInt(BitWidth, ByteSwap_32(unsigned(U.VAL))); if (BitWidth == 48) { - unsigned Tmp1 = unsigned(VAL >> 16); + unsigned Tmp1 = unsigned(U.VAL >> 16); Tmp1 = ByteSwap_32(Tmp1); - uint16_t Tmp2 = uint16_t(VAL); + uint16_t Tmp2 = uint16_t(U.VAL); Tmp2 = ByteSwap_16(Tmp2); return APInt(BitWidth, (uint64_t(Tmp2) << 32) | Tmp1); } if (BitWidth == 64) - return APInt(BitWidth, ByteSwap_64(VAL)); + return APInt(BitWidth, ByteSwap_64(U.VAL)); APInt Result(getNumWords() * APINT_BITS_PER_WORD, 0); for (unsigned I = 0, N = getNumWords(); I != N; ++I) - Result.pVal[I] = ByteSwap_64(pVal[N - I - 1]); + Result.U.pVal[I] = ByteSwap_64(U.pVal[N - I - 1]); if (Result.BitWidth != BitWidth) { - lshrNear(Result.pVal, Result.pVal, getNumWords(), - Result.BitWidth - BitWidth); + Result.lshrInPlace(Result.BitWidth - BitWidth); Result.BitWidth = BitWidth; } return Result; @@ -771,26 +643,24 @@ APInt APInt::byteSwap() const { APInt APInt::reverseBits() const { switch (BitWidth) { case 64: - return APInt(BitWidth, llvm::reverseBits<uint64_t>(VAL)); + return APInt(BitWidth, llvm::reverseBits<uint64_t>(U.VAL)); case 32: - return APInt(BitWidth, llvm::reverseBits<uint32_t>(VAL)); + return APInt(BitWidth, llvm::reverseBits<uint32_t>(U.VAL)); case 16: - return APInt(BitWidth, llvm::reverseBits<uint16_t>(VAL)); + return APInt(BitWidth, llvm::reverseBits<uint16_t>(U.VAL)); case 8: - return APInt(BitWidth, llvm::reverseBits<uint8_t>(VAL)); + return APInt(BitWidth, llvm::reverseBits<uint8_t>(U.VAL)); default: break; } APInt Val(*this); - APInt Reversed(*this); - int S = BitWidth - 1; - - const APInt One(BitWidth, 1); + APInt Reversed(BitWidth, 0); + unsigned S = BitWidth; - for ((Val = Val.lshr(1)); Val != 0; (Val = Val.lshr(1))) { + for (; Val != 0; Val.lshrInPlace(1)) { Reversed <<= 1; - Reversed |= (Val & One); + Reversed |= Val[0]; --S; } @@ -798,14 +668,46 @@ APInt APInt::reverseBits() const { return Reversed; } -APInt llvm::APIntOps::GreatestCommonDivisor(const APInt& API1, - const APInt& API2) { - APInt A = API1, B = API2; - while (!!B) { - APInt T = B; - B = APIntOps::urem(A, B); - A = T; +APInt llvm::APIntOps::GreatestCommonDivisor(APInt A, APInt B) { + // Fast-path a common case. + if (A == B) return A; + + // Corner cases: if either operand is zero, the other is the gcd. + if (!A) return B; + if (!B) return A; + + // Count common powers of 2 and remove all other powers of 2. + unsigned Pow2; + { + unsigned Pow2_A = A.countTrailingZeros(); + unsigned Pow2_B = B.countTrailingZeros(); + if (Pow2_A > Pow2_B) { + A.lshrInPlace(Pow2_A - Pow2_B); + Pow2 = Pow2_B; + } else if (Pow2_B > Pow2_A) { + B.lshrInPlace(Pow2_B - Pow2_A); + Pow2 = Pow2_A; + } else { + Pow2 = Pow2_A; + } + } + + // Both operands are odd multiples of 2^Pow_2: + // + // gcd(a, b) = gcd(|a - b| / 2^i, min(a, b)) + // + // This is a modified version of Stein's algorithm, taking advantage of + // efficient countTrailingZeros(). + while (A != B) { + if (A.ugt(B)) { + A -= B; + A.lshrInPlace(A.countTrailingZeros() - Pow2); + } else { + B -= A; + B.lshrInPlace(B.countTrailingZeros() - Pow2); + } } + return A; } @@ -841,7 +743,7 @@ APInt llvm::APIntOps::RoundDoubleToAPInt(double Double, unsigned width) { // Otherwise, we have to shift the mantissa bits up to the right location APInt Tmp(width, mantissa); - Tmp = Tmp.shl((unsigned)exp - 52); + Tmp <<= (unsigned)exp - 52; return isNeg ? -Tmp : Tmp; } @@ -892,13 +794,13 @@ double APInt::roundToDouble(bool isSigned) const { uint64_t mantissa; unsigned hiWord = whichWord(n-1); if (hiWord == 0) { - mantissa = Tmp.pVal[0]; + mantissa = Tmp.U.pVal[0]; if (n > 52) mantissa >>= n - 52; // shift down, we want the top 52 bits. } else { assert(hiWord > 0 && "huh?"); - uint64_t hibits = Tmp.pVal[hiWord] << (52 - n % APINT_BITS_PER_WORD); - uint64_t lobits = Tmp.pVal[hiWord-1] >> (11 + n % APINT_BITS_PER_WORD); + uint64_t hibits = Tmp.U.pVal[hiWord] << (52 - n % APINT_BITS_PER_WORD); + uint64_t lobits = Tmp.U.pVal[hiWord-1] >> (11 + n % APINT_BITS_PER_WORD); mantissa = hibits | lobits; } @@ -925,54 +827,37 @@ APInt APInt::trunc(unsigned width) const { // Copy full words. unsigned i; for (i = 0; i != width / APINT_BITS_PER_WORD; i++) - Result.pVal[i] = pVal[i]; + Result.U.pVal[i] = U.pVal[i]; // Truncate and copy any partial word. unsigned bits = (0 - width) % APINT_BITS_PER_WORD; if (bits != 0) - Result.pVal[i] = pVal[i] << bits >> bits; + Result.U.pVal[i] = U.pVal[i] << bits >> bits; return Result; } // Sign extend to a new width. -APInt APInt::sext(unsigned width) const { - assert(width > BitWidth && "Invalid APInt SignExtend request"); - - if (width <= APINT_BITS_PER_WORD) { - uint64_t val = VAL << (APINT_BITS_PER_WORD - BitWidth); - val = (int64_t)val >> (width - BitWidth); - return APInt(width, val >> (APINT_BITS_PER_WORD - width)); - } +APInt APInt::sext(unsigned Width) const { + assert(Width > BitWidth && "Invalid APInt SignExtend request"); - APInt Result(getMemory(getNumWords(width)), width); + if (Width <= APINT_BITS_PER_WORD) + return APInt(Width, SignExtend64(U.VAL, BitWidth)); - // Copy full words. - unsigned i; - uint64_t word = 0; - for (i = 0; i != BitWidth / APINT_BITS_PER_WORD; i++) { - word = getRawData()[i]; - Result.pVal[i] = word; - } + APInt Result(getMemory(getNumWords(Width)), Width); - // Read and sign-extend any partial word. - unsigned bits = (0 - BitWidth) % APINT_BITS_PER_WORD; - if (bits != 0) - word = (int64_t)getRawData()[i] << bits >> bits; - else - word = (int64_t)word >> (APINT_BITS_PER_WORD - 1); - - // Write remaining full words. - for (; i != width / APINT_BITS_PER_WORD; i++) { - Result.pVal[i] = word; - word = (int64_t)word >> (APINT_BITS_PER_WORD - 1); - } + // Copy words. + std::memcpy(Result.U.pVal, getRawData(), getNumWords() * APINT_WORD_SIZE); - // Write any partial word. - bits = (0 - width) % APINT_BITS_PER_WORD; - if (bits != 0) - Result.pVal[i] = word << bits >> bits; + // Sign extend the last word since there may be unused bits in the input. + Result.U.pVal[getNumWords() - 1] = + SignExtend64(Result.U.pVal[getNumWords() - 1], + ((BitWidth - 1) % APINT_BITS_PER_WORD) + 1); + // Fill with sign bits. + std::memset(Result.U.pVal + getNumWords(), isNegative() ? -1 : 0, + (Result.getNumWords() - getNumWords()) * APINT_WORD_SIZE); + Result.clearUnusedBits(); return Result; } @@ -981,17 +866,16 @@ APInt APInt::zext(unsigned width) const { assert(width > BitWidth && "Invalid APInt ZeroExtend request"); if (width <= APINT_BITS_PER_WORD) - return APInt(width, VAL); + return APInt(width, U.VAL); APInt Result(getMemory(getNumWords(width)), width); // Copy words. - unsigned i; - for (i = 0; i != getNumWords(); i++) - Result.pVal[i] = getRawData()[i]; + std::memcpy(Result.U.pVal, getRawData(), getNumWords() * APINT_WORD_SIZE); // Zero remaining words. - memset(&Result.pVal[i], 0, (Result.getNumWords() - i) * APINT_WORD_SIZE); + std::memset(Result.U.pVal + getNumWords(), 0, + (Result.getNumWords() - getNumWords()) * APINT_WORD_SIZE); return Result; } @@ -1026,226 +910,93 @@ APInt APInt::sextOrSelf(unsigned width) const { /// Arithmetic right-shift this APInt by shiftAmt. /// @brief Arithmetic right-shift function. -APInt APInt::ashr(const APInt &shiftAmt) const { - return ashr((unsigned)shiftAmt.getLimitedValue(BitWidth)); +void APInt::ashrInPlace(const APInt &shiftAmt) { + ashrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth)); } /// Arithmetic right-shift this APInt by shiftAmt. /// @brief Arithmetic right-shift function. -APInt APInt::ashr(unsigned shiftAmt) const { - assert(shiftAmt <= BitWidth && "Invalid shift amount"); - // Handle a degenerate case - if (shiftAmt == 0) - return *this; +void APInt::ashrSlowCase(unsigned ShiftAmt) { + // Don't bother performing a no-op shift. + if (!ShiftAmt) + return; - // Handle single word shifts with built-in ashr - if (isSingleWord()) { - if (shiftAmt == BitWidth) - return APInt(BitWidth, 0); // undefined - return APInt(BitWidth, SignExtend64(VAL, BitWidth) >> shiftAmt); - } + // Save the original sign bit for later. + bool Negative = isNegative(); - // If all the bits were shifted out, the result is, technically, undefined. - // We return -1 if it was negative, 0 otherwise. We check this early to avoid - // issues in the algorithm below. - if (shiftAmt == BitWidth) { - if (isNegative()) - return APInt(BitWidth, -1ULL, true); - else - return APInt(BitWidth, 0); - } - - // Create some space for the result. - uint64_t * val = new uint64_t[getNumWords()]; - - // Compute some values needed by the following shift algorithms - unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; // bits to shift per word - unsigned offset = shiftAmt / APINT_BITS_PER_WORD; // word offset for shift - unsigned breakWord = getNumWords() - 1 - offset; // last word affected - unsigned bitsInWord = whichBit(BitWidth); // how many bits in last word? - if (bitsInWord == 0) - bitsInWord = APINT_BITS_PER_WORD; - - // If we are shifting whole words, just move whole words - if (wordShift == 0) { - // Move the words containing significant bits - for (unsigned i = 0; i <= breakWord; ++i) - val[i] = pVal[i+offset]; // move whole word - - // Adjust the top significant word for sign bit fill, if negative - if (isNegative()) - if (bitsInWord < APINT_BITS_PER_WORD) - val[breakWord] |= ~0ULL << bitsInWord; // set high bits - } else { - // Shift the low order words - for (unsigned i = 0; i < breakWord; ++i) { - // This combines the shifted corresponding word with the low bits from - // the next word (shifted into this word's high bits). - val[i] = (pVal[i+offset] >> wordShift) | - (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift)); - } + // WordShift is the inter-part shift; BitShift is is intra-part shift. + unsigned WordShift = ShiftAmt / APINT_BITS_PER_WORD; + unsigned BitShift = ShiftAmt % APINT_BITS_PER_WORD; + + unsigned WordsToMove = getNumWords() - WordShift; + if (WordsToMove != 0) { + // Sign extend the last word to fill in the unused bits. + U.pVal[getNumWords() - 1] = SignExtend64( + U.pVal[getNumWords() - 1], ((BitWidth - 1) % APINT_BITS_PER_WORD) + 1); - // Shift the break word. In this case there are no bits from the next word - // to include in this word. - val[breakWord] = pVal[breakWord+offset] >> wordShift; - - // Deal with sign extension in the break word, and possibly the word before - // it. - if (isNegative()) { - if (wordShift > bitsInWord) { - if (breakWord > 0) - val[breakWord-1] |= - ~0ULL << (APINT_BITS_PER_WORD - (wordShift - bitsInWord)); - val[breakWord] |= ~0ULL; - } else - val[breakWord] |= (~0ULL << (bitsInWord - wordShift)); + // Fastpath for moving by whole words. + if (BitShift == 0) { + std::memmove(U.pVal, U.pVal + WordShift, WordsToMove * APINT_WORD_SIZE); + } else { + // Move the words containing significant bits. + for (unsigned i = 0; i != WordsToMove - 1; ++i) + U.pVal[i] = (U.pVal[i + WordShift] >> BitShift) | + (U.pVal[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift)); + + // Handle the last word which has no high bits to copy. + U.pVal[WordsToMove - 1] = U.pVal[WordShift + WordsToMove - 1] >> BitShift; + // Sign extend one more time. + U.pVal[WordsToMove - 1] = + SignExtend64(U.pVal[WordsToMove - 1], APINT_BITS_PER_WORD - BitShift); } } - // Remaining words are 0 or -1, just assign them. - uint64_t fillValue = (isNegative() ? -1ULL : 0); - for (unsigned i = breakWord+1; i < getNumWords(); ++i) - val[i] = fillValue; - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; + // Fill in the remainder based on the original sign. + std::memset(U.pVal + WordsToMove, Negative ? -1 : 0, + WordShift * APINT_WORD_SIZE); + clearUnusedBits(); } /// Logical right-shift this APInt by shiftAmt. /// @brief Logical right-shift function. -APInt APInt::lshr(const APInt &shiftAmt) const { - return lshr((unsigned)shiftAmt.getLimitedValue(BitWidth)); +void APInt::lshrInPlace(const APInt &shiftAmt) { + lshrInPlace((unsigned)shiftAmt.getLimitedValue(BitWidth)); } /// Logical right-shift this APInt by shiftAmt. /// @brief Logical right-shift function. -APInt APInt::lshr(unsigned shiftAmt) const { - if (isSingleWord()) { - if (shiftAmt >= BitWidth) - return APInt(BitWidth, 0); - else - return APInt(BitWidth, this->VAL >> shiftAmt); - } - - // If all the bits were shifted out, the result is 0. This avoids issues - // with shifting by the size of the integer type, which produces undefined - // results. We define these "undefined results" to always be 0. - if (shiftAmt >= BitWidth) - return APInt(BitWidth, 0); - - // If none of the bits are shifted out, the result is *this. This avoids - // issues with shifting by the size of the integer type, which produces - // undefined results in the code below. This is also an optimization. - if (shiftAmt == 0) - return *this; - - // Create some space for the result. - uint64_t * val = new uint64_t[getNumWords()]; - - // If we are shifting less than a word, compute the shift with a simple carry - if (shiftAmt < APINT_BITS_PER_WORD) { - lshrNear(val, pVal, getNumWords(), shiftAmt); - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; - } - - // Compute some values needed by the remaining shift algorithms - unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; - unsigned offset = shiftAmt / APINT_BITS_PER_WORD; - - // If we are shifting whole words, just move whole words - if (wordShift == 0) { - for (unsigned i = 0; i < getNumWords() - offset; ++i) - val[i] = pVal[i+offset]; - for (unsigned i = getNumWords()-offset; i < getNumWords(); i++) - val[i] = 0; - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; - } - - // Shift the low order words - unsigned breakWord = getNumWords() - offset -1; - for (unsigned i = 0; i < breakWord; ++i) - val[i] = (pVal[i+offset] >> wordShift) | - (pVal[i+offset+1] << (APINT_BITS_PER_WORD - wordShift)); - // Shift the break word. - val[breakWord] = pVal[breakWord+offset] >> wordShift; - - // Remaining words are 0 - for (unsigned i = breakWord+1; i < getNumWords(); ++i) - val[i] = 0; - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; +void APInt::lshrSlowCase(unsigned ShiftAmt) { + tcShiftRight(U.pVal, getNumWords(), ShiftAmt); } /// Left-shift this APInt by shiftAmt. /// @brief Left-shift function. -APInt APInt::shl(const APInt &shiftAmt) const { +APInt &APInt::operator<<=(const APInt &shiftAmt) { // It's undefined behavior in C to shift by BitWidth or greater. - return shl((unsigned)shiftAmt.getLimitedValue(BitWidth)); + *this <<= (unsigned)shiftAmt.getLimitedValue(BitWidth); + return *this; } -APInt APInt::shlSlowCase(unsigned shiftAmt) const { - // If all the bits were shifted out, the result is 0. This avoids issues - // with shifting by the size of the integer type, which produces undefined - // results. We define these "undefined results" to always be 0. - if (shiftAmt == BitWidth) - return APInt(BitWidth, 0); - - // If none of the bits are shifted out, the result is *this. This avoids a - // lshr by the words size in the loop below which can produce incorrect - // results. It also avoids the expensive computation below for a common case. - if (shiftAmt == 0) - return *this; - - // Create some space for the result. - uint64_t * val = new uint64_t[getNumWords()]; +void APInt::shlSlowCase(unsigned ShiftAmt) { + tcShiftLeft(U.pVal, getNumWords(), ShiftAmt); + clearUnusedBits(); +} - // If we are shifting less than a word, do it the easy way - if (shiftAmt < APINT_BITS_PER_WORD) { - uint64_t carry = 0; - for (unsigned i = 0; i < getNumWords(); i++) { - val[i] = pVal[i] << shiftAmt | carry; - carry = pVal[i] >> (APINT_BITS_PER_WORD - shiftAmt); - } - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; - } - - // Compute some values needed by the remaining shift algorithms - unsigned wordShift = shiftAmt % APINT_BITS_PER_WORD; - unsigned offset = shiftAmt / APINT_BITS_PER_WORD; - - // If we are shifting whole words, just move whole words - if (wordShift == 0) { - for (unsigned i = 0; i < offset; i++) - val[i] = 0; - for (unsigned i = offset; i < getNumWords(); i++) - val[i] = pVal[i-offset]; - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; - } - - // Copy whole words from this to Result. - unsigned i = getNumWords() - 1; - for (; i > offset; --i) - val[i] = pVal[i-offset] << wordShift | - pVal[i-offset-1] >> (APINT_BITS_PER_WORD - wordShift); - val[offset] = pVal[0] << wordShift; - for (i = 0; i < offset; ++i) - val[i] = 0; - APInt Result(val, BitWidth); - Result.clearUnusedBits(); - return Result; +// Calculate the rotate amount modulo the bit width. +static unsigned rotateModulo(unsigned BitWidth, const APInt &rotateAmt) { + unsigned rotBitWidth = rotateAmt.getBitWidth(); + APInt rot = rotateAmt; + if (rotBitWidth < BitWidth) { + // Extend the rotate APInt, so that the urem doesn't divide by 0. + // e.g. APInt(1, 32) would give APInt(1, 0). + rot = rotateAmt.zext(BitWidth); + } + rot = rot.urem(APInt(rot.getBitWidth(), BitWidth)); + return rot.getLimitedValue(BitWidth); } APInt APInt::rotl(const APInt &rotateAmt) const { - return rotl((unsigned)rotateAmt.getLimitedValue(BitWidth)); + return rotl(rotateModulo(BitWidth, rotateAmt)); } APInt APInt::rotl(unsigned rotateAmt) const { @@ -1256,7 +1007,7 @@ APInt APInt::rotl(unsigned rotateAmt) const { } APInt APInt::rotr(const APInt &rotateAmt) const { - return rotr((unsigned)rotateAmt.getLimitedValue(BitWidth)); + return rotr(rotateModulo(BitWidth, rotateAmt)); } APInt APInt::rotr(unsigned rotateAmt) const { @@ -1290,7 +1041,7 @@ APInt APInt::sqrt() const { /* 21-30 */ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, /* 31 */ 6 }; - return APInt(BitWidth, results[ (isSingleWord() ? VAL : pVal[0]) ]); + return APInt(BitWidth, results[ (isSingleWord() ? U.VAL : U.pVal[0]) ]); } // If the magnitude of the value fits in less than 52 bits (the precision of @@ -1299,7 +1050,8 @@ APInt APInt::sqrt() const { // This should be faster than the algorithm below. if (magnitude < 52) { return APInt(BitWidth, - uint64_t(::round(::sqrt(double(isSingleWord()?VAL:pVal[0]))))); + uint64_t(::round(::sqrt(double(isSingleWord() ? U.VAL + : U.pVal[0]))))); } // Okay, all the short cuts are exhausted. We must compute it. The following @@ -1384,10 +1136,13 @@ APInt APInt::multiplicativeInverse(const APInt& modulo) const { return APInt(BitWidth, 0); // The next-to-last t is the multiplicative inverse. However, we are - // interested in a positive inverse. Calcuate a positive one from a negative + // interested in a positive inverse. Calculate a positive one from a negative // one if necessary. A simple addition of the modulo suffices because // abs(t[i]) is known to be less than *this/2 (see the link above). - return t[i].isNegative() ? t[i] + modulo : t[i]; + if (t[i].isNegative()) + t[i] += modulo; + + return std::move(t[i]); } /// Calculate the magic numbers required to implement a signed integer division @@ -1486,7 +1241,7 @@ APInt::mu APInt::magicu(unsigned LeadingZeros) const { /// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The /// variables here have the same names as in the algorithm. Comments explain /// the algorithm and any deviation from it. -static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, +static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r, unsigned m, unsigned n) { assert(u && "Must provide dividend"); assert(v && "Must provide divisor"); @@ -1512,16 +1267,16 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, // overflow. Note that this can require an extra word in u so that u must // be of length m+n+1. unsigned shift = countLeadingZeros(v[n-1]); - unsigned v_carry = 0; - unsigned u_carry = 0; + uint32_t v_carry = 0; + uint32_t u_carry = 0; if (shift) { for (unsigned i = 0; i < m+n; ++i) { - unsigned u_tmp = u[i] >> (32 - shift); + uint32_t u_tmp = u[i] >> (32 - shift); u[i] = (u[i] << shift) | u_carry; u_carry = u_tmp; } for (unsigned i = 0; i < n; ++i) { - unsigned v_tmp = v[i] >> (32 - shift); + uint32_t v_tmp = v[i] >> (32 - shift); v[i] = (v[i] << shift) | v_carry; v_carry = v_tmp; } @@ -1542,11 +1297,11 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q') // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r') // Now test if qp == b or qp*v[n-2] > b*rp + u[j+n-2]; if so, decrease - // qp by 1, inrease rp by v[n-1], and repeat this test if rp < b. The test + // qp by 1, increase rp by v[n-1], and repeat this test if rp < b. The test // on v[n-2] determines at high speed most of the cases in which the trial // value qp is one too large, and it eliminates all cases where qp is two // too large. - uint64_t dividend = ((uint64_t(u[j+n]) << 32) + u[j+n-1]); + uint64_t dividend = Make_64(u[j+n], u[j+n-1]); DEBUG(dbgs() << "KnuthDiv: dividend == " << dividend << '\n'); uint64_t qp = dividend / v[n-1]; uint64_t rp = dividend % v[n-1]; @@ -1569,14 +1324,14 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, int64_t borrow = 0; for (unsigned i = 0; i < n; ++i) { uint64_t p = uint64_t(qp) * uint64_t(v[i]); - int64_t subres = int64_t(u[j+i]) - borrow - (unsigned)p; - u[j+i] = (unsigned)subres; - borrow = (p >> 32) - (subres >> 32); + int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p); + u[j+i] = Lo_32(subres); + borrow = Hi_32(p) - Hi_32(subres); DEBUG(dbgs() << "KnuthDiv: u[j+i] = " << u[j+i] << ", borrow = " << borrow << '\n'); } bool isNeg = u[j+n] < borrow; - u[j+n] -= (unsigned)borrow; + u[j+n] -= Lo_32(borrow); DEBUG(dbgs() << "KnuthDiv: after subtraction:"); DEBUG(for (int i = m+n; i >=0; i--) dbgs() << " " << u[i]); @@ -1584,7 +1339,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was // negative, go to step D6; otherwise go on to step D7. - q[j] = (unsigned)qp; + q[j] = Lo_32(qp); if (isNeg) { // D6. [Add back]. The probability that this step is necessary is very // small, on the order of only 2/b. Make sure that test data accounts for @@ -1595,7 +1350,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, // since it cancels with the borrow that occurred in D4. bool carry = false; for (unsigned i = 0; i < n; i++) { - unsigned limit = std::min(u[j+i],v[i]); + uint32_t limit = std::min(u[j+i],v[i]); u[j+i] += v[i] + carry; carry = u[j+i] < limit || (carry && u[j+i] == limit); } @@ -1618,9 +1373,9 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, if (r) { // The value d is expressed by the "shift" value above since we avoided // multiplication by d by using a shift left. So, all we have to do is - // shift right here. In order to mak + // shift right here. if (shift) { - unsigned carry = 0; + uint32_t carry = 0; DEBUG(dbgs() << "KnuthDiv: remainder:"); for (int i = n-1; i >= 0; i--) { r[i] = (u[i] >> shift) | carry; @@ -1638,8 +1393,8 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r, DEBUG(dbgs() << '\n'); } -void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, - unsigned rhsWords, APInt *Quotient, APInt *Remainder) { +void APInt::divide(const WordType *LHS, unsigned lhsWords, const WordType *RHS, + unsigned rhsWords, WordType *Quotient, WordType *Remainder) { assert(lhsWords >= rhsWords && "Fractional result"); // First, compose the values into an array of 32-bit words instead of @@ -1649,17 +1404,16 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, // can't use 64-bit operands here because we don't have native results of // 128-bits. Furthermore, casting the 64-bit values to 32-bit values won't // work on large-endian machines. - uint64_t mask = ~0ull >> (sizeof(unsigned)*CHAR_BIT); unsigned n = rhsWords * 2; unsigned m = (lhsWords * 2) - n; // Allocate space for the temporary values we need either on the stack, if // it will fit, or on the heap if it won't. - unsigned SPACE[128]; - unsigned *U = nullptr; - unsigned *V = nullptr; - unsigned *Q = nullptr; - unsigned *R = nullptr; + uint32_t SPACE[128]; + uint32_t *U = nullptr; + uint32_t *V = nullptr; + uint32_t *Q = nullptr; + uint32_t *R = nullptr; if ((Remainder?4:3)*n+2*m+1 <= 128) { U = &SPACE[0]; V = &SPACE[m+n+1]; @@ -1667,34 +1421,34 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, if (Remainder) R = &SPACE[(m+n+1) + n + (m+n)]; } else { - U = new unsigned[m + n + 1]; - V = new unsigned[n]; - Q = new unsigned[m+n]; + U = new uint32_t[m + n + 1]; + V = new uint32_t[n]; + Q = new uint32_t[m+n]; if (Remainder) - R = new unsigned[n]; + R = new uint32_t[n]; } // Initialize the dividend - memset(U, 0, (m+n+1)*sizeof(unsigned)); + memset(U, 0, (m+n+1)*sizeof(uint32_t)); for (unsigned i = 0; i < lhsWords; ++i) { - uint64_t tmp = (LHS.getNumWords() == 1 ? LHS.VAL : LHS.pVal[i]); - U[i * 2] = (unsigned)(tmp & mask); - U[i * 2 + 1] = (unsigned)(tmp >> (sizeof(unsigned)*CHAR_BIT)); + uint64_t tmp = LHS[i]; + U[i * 2] = Lo_32(tmp); + U[i * 2 + 1] = Hi_32(tmp); } U[m+n] = 0; // this extra word is for "spill" in the Knuth algorithm. // Initialize the divisor - memset(V, 0, (n)*sizeof(unsigned)); + memset(V, 0, (n)*sizeof(uint32_t)); for (unsigned i = 0; i < rhsWords; ++i) { - uint64_t tmp = (RHS.getNumWords() == 1 ? RHS.VAL : RHS.pVal[i]); - V[i * 2] = (unsigned)(tmp & mask); - V[i * 2 + 1] = (unsigned)(tmp >> (sizeof(unsigned)*CHAR_BIT)); + uint64_t tmp = RHS[i]; + V[i * 2] = Lo_32(tmp); + V[i * 2 + 1] = Hi_32(tmp); } // initialize the quotient and remainder - memset(Q, 0, (m+n) * sizeof(unsigned)); + memset(Q, 0, (m+n) * sizeof(uint32_t)); if (Remainder) - memset(R, 0, n * sizeof(unsigned)); + memset(R, 0, n * sizeof(uint32_t)); // Now, adjust m and n for the Knuth division. n is the number of words in // the divisor. m is the number of words by which the dividend exceeds the @@ -1715,22 +1469,22 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, // are using base 2^32 instead of base 10. assert(n != 0 && "Divide by zero?"); if (n == 1) { - unsigned divisor = V[0]; - unsigned remainder = 0; - for (int i = m+n-1; i >= 0; i--) { - uint64_t partial_dividend = uint64_t(remainder) << 32 | U[i]; + uint32_t divisor = V[0]; + uint32_t remainder = 0; + for (int i = m; i >= 0; i--) { + uint64_t partial_dividend = Make_64(remainder, U[i]); if (partial_dividend == 0) { Q[i] = 0; remainder = 0; } else if (partial_dividend < divisor) { Q[i] = 0; - remainder = (unsigned)partial_dividend; + remainder = Lo_32(partial_dividend); } else if (partial_dividend == divisor) { Q[i] = 1; remainder = 0; } else { - Q[i] = (unsigned)(partial_dividend / divisor); - remainder = (unsigned)(partial_dividend - (Q[i] * divisor)); + Q[i] = Lo_32(partial_dividend / divisor); + remainder = Lo_32(partial_dividend - (Q[i] * divisor)); } } if (R) @@ -1743,66 +1497,14 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, // If the caller wants the quotient if (Quotient) { - // Set up the Quotient value's memory. - if (Quotient->BitWidth != LHS.BitWidth) { - if (Quotient->isSingleWord()) - Quotient->VAL = 0; - else - delete [] Quotient->pVal; - Quotient->BitWidth = LHS.BitWidth; - if (!Quotient->isSingleWord()) - Quotient->pVal = getClearedMemory(Quotient->getNumWords()); - } else - Quotient->clearAllBits(); - - // The quotient is in Q. Reconstitute the quotient into Quotient's low - // order words. - // This case is currently dead as all users of divide() handle trivial cases - // earlier. - if (lhsWords == 1) { - uint64_t tmp = - uint64_t(Q[0]) | (uint64_t(Q[1]) << (APINT_BITS_PER_WORD / 2)); - if (Quotient->isSingleWord()) - Quotient->VAL = tmp; - else - Quotient->pVal[0] = tmp; - } else { - assert(!Quotient->isSingleWord() && "Quotient APInt not large enough"); - for (unsigned i = 0; i < lhsWords; ++i) - Quotient->pVal[i] = - uint64_t(Q[i*2]) | (uint64_t(Q[i*2+1]) << (APINT_BITS_PER_WORD / 2)); - } + for (unsigned i = 0; i < lhsWords; ++i) + Quotient[i] = Make_64(Q[i*2+1], Q[i*2]); } // If the caller wants the remainder if (Remainder) { - // Set up the Remainder value's memory. - if (Remainder->BitWidth != RHS.BitWidth) { - if (Remainder->isSingleWord()) - Remainder->VAL = 0; - else - delete [] Remainder->pVal; - Remainder->BitWidth = RHS.BitWidth; - if (!Remainder->isSingleWord()) - Remainder->pVal = getClearedMemory(Remainder->getNumWords()); - } else - Remainder->clearAllBits(); - - // The remainder is in R. Reconstitute the remainder into Remainder's low - // order words. - if (rhsWords == 1) { - uint64_t tmp = - uint64_t(R[0]) | (uint64_t(R[1]) << (APINT_BITS_PER_WORD / 2)); - if (Remainder->isSingleWord()) - Remainder->VAL = tmp; - else - Remainder->pVal[0] = tmp; - } else { - assert(!Remainder->isSingleWord() && "Remainder APInt not large enough"); - for (unsigned i = 0; i < rhsWords; ++i) - Remainder->pVal[i] = - uint64_t(R[i*2]) | (uint64_t(R[i*2+1]) << (APINT_BITS_PER_WORD / 2)); - } + for (unsigned i = 0; i < rhsWords; ++i) + Remainder[i] = Make_64(R[i*2+1], R[i*2]); } // Clean up the memory we allocated. @@ -1814,40 +1516,74 @@ void APInt::divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, } } -APInt APInt::udiv(const APInt& RHS) const { +APInt APInt::udiv(const APInt &RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); // First, deal with the easy case if (isSingleWord()) { - assert(RHS.VAL != 0 && "Divide by zero?"); - return APInt(BitWidth, VAL / RHS.VAL); + assert(RHS.U.VAL != 0 && "Divide by zero?"); + return APInt(BitWidth, U.VAL / RHS.U.VAL); } // Get some facts about the LHS and RHS number of bits and words - unsigned rhsBits = RHS.getActiveBits(); - unsigned rhsWords = !rhsBits ? 0 : (APInt::whichWord(rhsBits - 1) + 1); + unsigned lhsWords = getNumWords(getActiveBits()); + unsigned rhsBits = RHS.getActiveBits(); + unsigned rhsWords = getNumWords(rhsBits); assert(rhsWords && "Divided by zero???"); - unsigned lhsBits = this->getActiveBits(); - unsigned lhsWords = !lhsBits ? 0 : (APInt::whichWord(lhsBits - 1) + 1); // Deal with some degenerate cases if (!lhsWords) // 0 / X ===> 0 return APInt(BitWidth, 0); - else if (lhsWords < rhsWords || this->ult(RHS)) { + if (rhsBits == 1) + // X / 1 ===> X + return *this; + if (lhsWords < rhsWords || this->ult(RHS)) // X / Y ===> 0, iff X < Y return APInt(BitWidth, 0); - } else if (*this == RHS) { + if (*this == RHS) // X / X ===> 1 return APInt(BitWidth, 1); - } else if (lhsWords == 1 && rhsWords == 1) { + if (lhsWords == 1) // rhsWords is 1 if lhsWords is 1. // All high words are zero, just use native divide - return APInt(BitWidth, this->pVal[0] / RHS.pVal[0]); - } + return APInt(BitWidth, this->U.pVal[0] / RHS.U.pVal[0]); + + // We have to compute it the hard way. Invoke the Knuth divide algorithm. + APInt Quotient(BitWidth, 0); // to hold result. + divide(U.pVal, lhsWords, RHS.U.pVal, rhsWords, Quotient.U.pVal, nullptr); + return Quotient; +} + +APInt APInt::udiv(uint64_t RHS) const { + assert(RHS != 0 && "Divide by zero?"); + + // First, deal with the easy case + if (isSingleWord()) + return APInt(BitWidth, U.VAL / RHS); + + // Get some facts about the LHS words. + unsigned lhsWords = getNumWords(getActiveBits()); + + // Deal with some degenerate cases + if (!lhsWords) + // 0 / X ===> 0 + return APInt(BitWidth, 0); + if (RHS == 1) + // X / 1 ===> X + return *this; + if (this->ult(RHS)) + // X / Y ===> 0, iff X < Y + return APInt(BitWidth, 0); + if (*this == RHS) + // X / X ===> 1 + return APInt(BitWidth, 1); + if (lhsWords == 1) // rhsWords is 1 if lhsWords is 1. + // All high words are zero, just use native divide + return APInt(BitWidth, this->U.pVal[0] / RHS); // We have to compute it the hard way. Invoke the Knuth divide algorithm. - APInt Quotient(1,0); // to hold result. - divide(*this, lhsWords, RHS, rhsWords, &Quotient, nullptr); + APInt Quotient(BitWidth, 0); // to hold result. + divide(U.pVal, lhsWords, &RHS, 1, Quotient.U.pVal, nullptr); return Quotient; } @@ -1862,40 +1598,84 @@ APInt APInt::sdiv(const APInt &RHS) const { return this->udiv(RHS); } -APInt APInt::urem(const APInt& RHS) const { +APInt APInt::sdiv(int64_t RHS) const { + if (isNegative()) { + if (RHS < 0) + return (-(*this)).udiv(-RHS); + return -((-(*this)).udiv(RHS)); + } + if (RHS < 0) + return -(this->udiv(-RHS)); + return this->udiv(RHS); +} + +APInt APInt::urem(const APInt &RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) { - assert(RHS.VAL != 0 && "Remainder by zero?"); - return APInt(BitWidth, VAL % RHS.VAL); + assert(RHS.U.VAL != 0 && "Remainder by zero?"); + return APInt(BitWidth, U.VAL % RHS.U.VAL); } // Get some facts about the LHS - unsigned lhsBits = getActiveBits(); - unsigned lhsWords = !lhsBits ? 0 : (whichWord(lhsBits - 1) + 1); + unsigned lhsWords = getNumWords(getActiveBits()); // Get some facts about the RHS unsigned rhsBits = RHS.getActiveBits(); - unsigned rhsWords = !rhsBits ? 0 : (APInt::whichWord(rhsBits - 1) + 1); + unsigned rhsWords = getNumWords(rhsBits); assert(rhsWords && "Performing remainder operation by zero ???"); // Check the degenerate cases - if (lhsWords == 0) { + if (lhsWords == 0) // 0 % Y ===> 0 return APInt(BitWidth, 0); - } else if (lhsWords < rhsWords || this->ult(RHS)) { + if (rhsBits == 1) + // X % 1 ===> 0 + return APInt(BitWidth, 0); + if (lhsWords < rhsWords || this->ult(RHS)) // X % Y ===> X, iff X < Y return *this; - } else if (*this == RHS) { + if (*this == RHS) // X % X == 0; return APInt(BitWidth, 0); - } else if (lhsWords == 1) { + if (lhsWords == 1) // All high words are zero, just use native remainder - return APInt(BitWidth, pVal[0] % RHS.pVal[0]); - } + return APInt(BitWidth, U.pVal[0] % RHS.U.pVal[0]); + + // We have to compute it the hard way. Invoke the Knuth divide algorithm. + APInt Remainder(BitWidth, 0); + divide(U.pVal, lhsWords, RHS.U.pVal, rhsWords, nullptr, Remainder.U.pVal); + return Remainder; +} + +uint64_t APInt::urem(uint64_t RHS) const { + assert(RHS != 0 && "Remainder by zero?"); + + if (isSingleWord()) + return U.VAL % RHS; + + // Get some facts about the LHS + unsigned lhsWords = getNumWords(getActiveBits()); + + // Check the degenerate cases + if (lhsWords == 0) + // 0 % Y ===> 0 + return 0; + if (RHS == 1) + // X % 1 ===> 0 + return 0; + if (this->ult(RHS)) + // X % Y ===> X, iff X < Y + return getZExtValue(); + if (*this == RHS) + // X % X == 0; + return 0; + if (lhsWords == 1) + // All high words are zero, just use native remainder + return U.pVal[0] % RHS; // We have to compute it the hard way. Invoke the Knuth divide algorithm. - APInt Remainder(1,0); - divide(*this, lhsWords, RHS, rhsWords, nullptr, &Remainder); + uint64_t Remainder; + divide(U.pVal, lhsWords, &RHS, 1, nullptr, &Remainder); return Remainder; } @@ -1910,25 +1690,37 @@ APInt APInt::srem(const APInt &RHS) const { return this->urem(RHS); } +int64_t APInt::srem(int64_t RHS) const { + if (isNegative()) { + if (RHS < 0) + return -((-(*this)).urem(-RHS)); + return -((-(*this)).urem(RHS)); + } + if (RHS < 0) + return this->urem(-RHS); + return this->urem(RHS); +} + void APInt::udivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, APInt &Remainder) { assert(LHS.BitWidth == RHS.BitWidth && "Bit widths must be the same"); + unsigned BitWidth = LHS.BitWidth; // First, deal with the easy case if (LHS.isSingleWord()) { - assert(RHS.VAL != 0 && "Divide by zero?"); - uint64_t QuotVal = LHS.VAL / RHS.VAL; - uint64_t RemVal = LHS.VAL % RHS.VAL; - Quotient = APInt(LHS.BitWidth, QuotVal); - Remainder = APInt(LHS.BitWidth, RemVal); + assert(RHS.U.VAL != 0 && "Divide by zero?"); + uint64_t QuotVal = LHS.U.VAL / RHS.U.VAL; + uint64_t RemVal = LHS.U.VAL % RHS.U.VAL; + Quotient = APInt(BitWidth, QuotVal); + Remainder = APInt(BitWidth, RemVal); return; } // Get some size facts about the dividend and divisor - unsigned lhsBits = LHS.getActiveBits(); - unsigned lhsWords = !lhsBits ? 0 : (APInt::whichWord(lhsBits - 1) + 1); + unsigned lhsWords = getNumWords(LHS.getActiveBits()); unsigned rhsBits = RHS.getActiveBits(); - unsigned rhsWords = !rhsBits ? 0 : (APInt::whichWord(rhsBits - 1) + 1); + unsigned rhsWords = getNumWords(rhsBits); + assert(rhsWords && "Performing divrem operation by zero ???"); // Check the degenerate cases if (lhsWords == 0) { @@ -1937,6 +1729,11 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS, return; } + if (rhsBits == 1) { + Quotient = LHS; // X / 1 ===> X + Remainder = 0; // X % 1 ===> 0 + } + if (lhsWords < rhsWords || LHS.ult(RHS)) { Remainder = LHS; // X % Y ===> X, iff X < Y Quotient = 0; // X / Y ===> 0, iff X < Y @@ -1949,17 +1746,90 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS, return; } - if (lhsWords == 1 && rhsWords == 1) { + // Make sure there is enough space to hold the results. + // NOTE: This assumes that reallocate won't affect any bits if it doesn't + // change the size. This is necessary if Quotient or Remainder is aliased + // with LHS or RHS. + Quotient.reallocate(BitWidth); + Remainder.reallocate(BitWidth); + + if (lhsWords == 1) { // rhsWords is 1 if lhsWords is 1. + // There is only one word to consider so use the native versions. + uint64_t lhsValue = LHS.U.pVal[0]; + uint64_t rhsValue = RHS.U.pVal[0]; + Quotient = lhsValue / rhsValue; + Remainder = lhsValue % rhsValue; + return; + } + + // Okay, lets do it the long way + divide(LHS.U.pVal, lhsWords, RHS.U.pVal, rhsWords, Quotient.U.pVal, + Remainder.U.pVal); + // Clear the rest of the Quotient and Remainder. + std::memset(Quotient.U.pVal + lhsWords, 0, + (getNumWords(BitWidth) - lhsWords) * APINT_WORD_SIZE); + std::memset(Remainder.U.pVal + rhsWords, 0, + (getNumWords(BitWidth) - rhsWords) * APINT_WORD_SIZE); +} + +void APInt::udivrem(const APInt &LHS, uint64_t RHS, APInt &Quotient, + uint64_t &Remainder) { + assert(RHS != 0 && "Divide by zero?"); + unsigned BitWidth = LHS.BitWidth; + + // First, deal with the easy case + if (LHS.isSingleWord()) { + uint64_t QuotVal = LHS.U.VAL / RHS; + Remainder = LHS.U.VAL % RHS; + Quotient = APInt(BitWidth, QuotVal); + return; + } + + // Get some size facts about the dividend and divisor + unsigned lhsWords = getNumWords(LHS.getActiveBits()); + + // Check the degenerate cases + if (lhsWords == 0) { + Quotient = 0; // 0 / Y ===> 0 + Remainder = 0; // 0 % Y ===> 0 + return; + } + + if (RHS == 1) { + Quotient = LHS; // X / 1 ===> X + Remainder = 0; // X % 1 ===> 0 + } + + if (LHS.ult(RHS)) { + Remainder = LHS.getZExtValue(); // X % Y ===> X, iff X < Y + Quotient = 0; // X / Y ===> 0, iff X < Y + return; + } + + if (LHS == RHS) { + Quotient = 1; // X / X ===> 1 + Remainder = 0; // X % X ===> 0; + return; + } + + // Make sure there is enough space to hold the results. + // NOTE: This assumes that reallocate won't affect any bits if it doesn't + // change the size. This is necessary if Quotient is aliased with LHS. + Quotient.reallocate(BitWidth); + + if (lhsWords == 1) { // rhsWords is 1 if lhsWords is 1. // There is only one word to consider so use the native versions. - uint64_t lhsValue = LHS.isSingleWord() ? LHS.VAL : LHS.pVal[0]; - uint64_t rhsValue = RHS.isSingleWord() ? RHS.VAL : RHS.pVal[0]; - Quotient = APInt(LHS.getBitWidth(), lhsValue / rhsValue); - Remainder = APInt(LHS.getBitWidth(), lhsValue % rhsValue); + uint64_t lhsValue = LHS.U.pVal[0]; + Quotient = lhsValue / RHS; + Remainder = lhsValue % RHS; return; } // Okay, lets do it the long way - divide(LHS, lhsWords, RHS, rhsWords, &Quotient, &Remainder); + divide(LHS.U.pVal, lhsWords, &RHS, 1, Quotient.U.pVal, &Remainder); + // Clear the rest of the Quotient. + std::memset(Quotient.U.pVal + lhsWords, 0, + (getNumWords(BitWidth) - lhsWords) * APINT_WORD_SIZE); } void APInt::sdivrem(const APInt &LHS, const APInt &RHS, @@ -1969,17 +1839,37 @@ void APInt::sdivrem(const APInt &LHS, const APInt &RHS, APInt::udivrem(-LHS, -RHS, Quotient, Remainder); else { APInt::udivrem(-LHS, RHS, Quotient, Remainder); - Quotient = -Quotient; + Quotient.negate(); } - Remainder = -Remainder; + Remainder.negate(); } else if (RHS.isNegative()) { APInt::udivrem(LHS, -RHS, Quotient, Remainder); - Quotient = -Quotient; + Quotient.negate(); } else { APInt::udivrem(LHS, RHS, Quotient, Remainder); } } +void APInt::sdivrem(const APInt &LHS, int64_t RHS, + APInt &Quotient, int64_t &Remainder) { + uint64_t R = Remainder; + if (LHS.isNegative()) { + if (RHS < 0) + APInt::udivrem(-LHS, -RHS, Quotient, R); + else { + APInt::udivrem(-LHS, RHS, Quotient, R); + Quotient.negate(); + } + R = -R; + } else if (RHS < 0) { + APInt::udivrem(LHS, -RHS, Quotient, R); + Quotient.negate(); + } else { + APInt::udivrem(LHS, RHS, Quotient, R); + } + Remainder = R; +} + APInt APInt::sadd_ov(const APInt &RHS, bool &Overflow) const { APInt Res = *this+RHS; Overflow = isNonNegative() == RHS.isNonNegative() && @@ -2014,7 +1904,7 @@ APInt APInt::sdiv_ov(const APInt &RHS, bool &Overflow) const { APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const { APInt Res = *this * RHS; - + if (*this != 0 && RHS != 0) Overflow = Res.sdiv(RHS) != *this || Res.sdiv(*this) != RHS; else @@ -2041,7 +1931,7 @@ APInt APInt::sshl_ov(const APInt &ShAmt, bool &Overflow) const { Overflow = ShAmt.uge(countLeadingZeros()); else Overflow = ShAmt.uge(countLeadingOnes()); - + return *this << ShAmt; } @@ -2061,7 +1951,7 @@ APInt APInt::ushl_ov(const APInt &ShAmt, bool &Overflow) const { void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { // Check our assumptions here assert(!str.empty() && "Invalid string length"); - assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || + assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || radix == 36) && "Radix should be 2, 8, 10, 16, or 36!"); @@ -2079,18 +1969,15 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { assert((((slen-1)*64)/22 <= numbits || radix != 10) && "Insufficient bit width"); - // Allocate memory - if (!isSingleWord()) - pVal = getClearedMemory(getNumWords()); + // Allocate memory if needed + if (isSingleWord()) + U.VAL = 0; + else + U.pVal = getClearedMemory(getNumWords()); // Figure out if we can shift instead of multiply unsigned shift = (radix == 16 ? 4 : radix == 8 ? 3 : radix == 2 ? 1 : 0); - // Set up an APInt for the digit to add outside the loop so we don't - // constantly construct/destruct it. - APInt apdigit(getBitWidth(), 0); - APInt apradix(getBitWidth(), radix); - // Enter digit traversal loop for (StringRef::iterator e = str.end(); p != e; ++p) { unsigned digit = getDigit(*p, radix); @@ -2101,26 +1988,20 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { if (shift) *this <<= shift; else - *this *= apradix; + *this *= radix; } // Add in the digit we just interpreted - if (apdigit.isSingleWord()) - apdigit.VAL = digit; - else - apdigit.pVal[0] = digit; - *this += apdigit; + *this += digit; } // If its negative, put it in two's complement form - if (isNeg) { - --(*this); - this->flipAllBits(); - } + if (isNeg) + this->negate(); } void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, bool Signed, bool formatAsCLiteral) const { - assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 || + assert((Radix == 10 || Radix == 8 || Radix == 16 || Radix == 2 || Radix == 36) && "Radix should be 2, 8, 10, 16, or 36!"); @@ -2159,7 +2040,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, if (isSingleWord()) { char Buffer[65]; - char *BufPtr = Buffer+65; + char *BufPtr = std::end(Buffer); uint64_t N; if (!Signed) { @@ -2183,7 +2064,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, *--BufPtr = Digits[N % Radix]; N /= Radix; } - Str.append(BufPtr, Buffer+65); + Str.append(BufPtr, std::end(Buffer)); return; } @@ -2193,8 +2074,7 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, // They want to print the signed version and it is a negative value // Flip the bits and add one to turn it into the equivalent positive // value and put a '-' in the result. - Tmp.flipAllBits(); - ++Tmp; + Tmp.negate(); Str.push_back('-'); } @@ -2208,28 +2088,23 @@ void APInt::toString(SmallVectorImpl<char> &Str, unsigned Radix, // For the 2, 8 and 16 bit cases, we can just shift instead of divide // because the number of bits per digit (1, 3 and 4 respectively) divides - // equaly. We just shift until the value is zero. + // equally. We just shift until the value is zero. if (Radix == 2 || Radix == 8 || Radix == 16) { // Just shift tmp right for each digit width until it becomes zero unsigned ShiftAmt = (Radix == 16 ? 4 : (Radix == 8 ? 3 : 1)); unsigned MaskAmt = Radix - 1; - while (Tmp != 0) { + while (Tmp.getBoolValue()) { unsigned Digit = unsigned(Tmp.getRawData()[0]) & MaskAmt; Str.push_back(Digits[Digit]); - Tmp = Tmp.lshr(ShiftAmt); + Tmp.lshrInPlace(ShiftAmt); } } else { - APInt divisor(Radix == 10? 4 : 8, Radix); - while (Tmp != 0) { - APInt APdigit(1, 0); - APInt tmp2(Tmp.getBitWidth(), 0); - divide(Tmp, Tmp.getNumWords(), divisor, divisor.getNumWords(), &tmp2, - &APdigit); - unsigned Digit = (unsigned)APdigit.getZExtValue(); + while (Tmp.getBoolValue()) { + uint64_t Digit; + udivrem(Tmp, Radix, Tmp, Digit); assert(Digit < Radix && "divide failed"); Str.push_back(Digits[Digit]); - Tmp = tmp2; } } @@ -2245,14 +2120,15 @@ std::string APInt::toString(unsigned Radix = 10, bool Signed = true) const { return S.str(); } - +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void APInt::dump() const { SmallString<40> S, U; this->toStringUnsigned(U); this->toStringSigned(S); dbgs() << "APInt(" << BitWidth << "b, " - << U << "u " << S << "s)"; + << U << "u " << S << "s)\n"; } +#endif void APInt::print(raw_ostream &OS, bool isSigned) const { SmallString<40> S; @@ -2265,83 +2141,60 @@ void APInt::print(raw_ostream &OS, bool isSigned) const { // Assumed by lowHalf, highHalf, partMSB and partLSB. A fairly safe // and unrestricting assumption. -static_assert(integerPartWidth % 2 == 0, "Part width must be divisible by 2!"); +static_assert(APInt::APINT_BITS_PER_WORD % 2 == 0, + "Part width must be divisible by 2!"); /* Some handy functions local to this file. */ -namespace { - /* Returns the integer part with the least significant BITS set. - BITS cannot be zero. */ - static inline integerPart - lowBitMask(unsigned int bits) - { - assert(bits != 0 && bits <= integerPartWidth); +/* Returns the integer part with the least significant BITS set. + BITS cannot be zero. */ +static inline APInt::WordType lowBitMask(unsigned bits) { + assert(bits != 0 && bits <= APInt::APINT_BITS_PER_WORD); - return ~(integerPart) 0 >> (integerPartWidth - bits); - } + return ~(APInt::WordType) 0 >> (APInt::APINT_BITS_PER_WORD - bits); +} - /* Returns the value of the lower half of PART. */ - static inline integerPart - lowHalf(integerPart part) - { - return part & lowBitMask(integerPartWidth / 2); - } +/* Returns the value of the lower half of PART. */ +static inline APInt::WordType lowHalf(APInt::WordType part) { + return part & lowBitMask(APInt::APINT_BITS_PER_WORD / 2); +} - /* Returns the value of the upper half of PART. */ - static inline integerPart - highHalf(integerPart part) - { - return part >> (integerPartWidth / 2); - } +/* Returns the value of the upper half of PART. */ +static inline APInt::WordType highHalf(APInt::WordType part) { + return part >> (APInt::APINT_BITS_PER_WORD / 2); +} - /* Returns the bit number of the most significant set bit of a part. - If the input number has no bits set -1U is returned. */ - static unsigned int - partMSB(integerPart value) - { - return findLastSet(value, ZB_Max); - } +/* Returns the bit number of the most significant set bit of a part. + If the input number has no bits set -1U is returned. */ +static unsigned partMSB(APInt::WordType value) { + return findLastSet(value, ZB_Max); +} - /* Returns the bit number of the least significant set bit of a - part. If the input number has no bits set -1U is returned. */ - static unsigned int - partLSB(integerPart value) - { - return findFirstSet(value, ZB_Max); - } +/* Returns the bit number of the least significant set bit of a + part. If the input number has no bits set -1U is returned. */ +static unsigned partLSB(APInt::WordType value) { + return findFirstSet(value, ZB_Max); } /* Sets the least significant part of a bignum to the input value, and zeroes out higher parts. */ -void -APInt::tcSet(integerPart *dst, integerPart part, unsigned int parts) -{ - unsigned int i; - +void APInt::tcSet(WordType *dst, WordType part, unsigned parts) { assert(parts > 0); dst[0] = part; - for (i = 1; i < parts; i++) + for (unsigned i = 1; i < parts; i++) dst[i] = 0; } /* Assign one bignum to another. */ -void -APInt::tcAssign(integerPart *dst, const integerPart *src, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) +void APInt::tcAssign(WordType *dst, const WordType *src, unsigned parts) { + for (unsigned i = 0; i < parts; i++) dst[i] = src[i]; } /* Returns true if a bignum is zero, false otherwise. */ -bool -APInt::tcIsZero(const integerPart *src, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) +bool APInt::tcIsZero(const WordType *src, unsigned parts) { + for (unsigned i = 0; i < parts; i++) if (src[i]) return false; @@ -2349,41 +2202,29 @@ APInt::tcIsZero(const integerPart *src, unsigned int parts) } /* Extract the given bit of a bignum; returns 0 or 1. */ -int -APInt::tcExtractBit(const integerPart *parts, unsigned int bit) -{ - return (parts[bit / integerPartWidth] & - ((integerPart) 1 << bit % integerPartWidth)) != 0; +int APInt::tcExtractBit(const WordType *parts, unsigned bit) { + return (parts[whichWord(bit)] & maskBit(bit)) != 0; } /* Set the given bit of a bignum. */ -void -APInt::tcSetBit(integerPart *parts, unsigned int bit) -{ - parts[bit / integerPartWidth] |= (integerPart) 1 << (bit % integerPartWidth); +void APInt::tcSetBit(WordType *parts, unsigned bit) { + parts[whichWord(bit)] |= maskBit(bit); } /* Clears the given bit of a bignum. */ -void -APInt::tcClearBit(integerPart *parts, unsigned int bit) -{ - parts[bit / integerPartWidth] &= - ~((integerPart) 1 << (bit % integerPartWidth)); +void APInt::tcClearBit(WordType *parts, unsigned bit) { + parts[whichWord(bit)] &= ~maskBit(bit); } /* Returns the bit number of the least significant set bit of a number. If the input number has no bits set -1U is returned. */ -unsigned int -APInt::tcLSB(const integerPart *parts, unsigned int n) -{ - unsigned int i, lsb; - - for (i = 0; i < n; i++) { - if (parts[i] != 0) { - lsb = partLSB(parts[i]); +unsigned APInt::tcLSB(const WordType *parts, unsigned n) { + for (unsigned i = 0; i < n; i++) { + if (parts[i] != 0) { + unsigned lsb = partLSB(parts[i]); - return lsb + i * integerPartWidth; - } + return lsb + i * APINT_BITS_PER_WORD; + } } return -1U; @@ -2391,18 +2232,14 @@ APInt::tcLSB(const integerPart *parts, unsigned int n) /* Returns the bit number of the most significant set bit of a number. If the input number has no bits set -1U is returned. */ -unsigned int -APInt::tcMSB(const integerPart *parts, unsigned int n) -{ - unsigned int msb; - +unsigned APInt::tcMSB(const WordType *parts, unsigned n) { do { --n; if (parts[n] != 0) { - msb = partMSB(parts[n]); + unsigned msb = partMSB(parts[n]); - return msb + n * integerPartWidth; + return msb + n * APINT_BITS_PER_WORD; } } while (n); @@ -2414,31 +2251,28 @@ APInt::tcMSB(const integerPart *parts, unsigned int n) the least significant bit of DST. All high bits above srcBITS in DST are zero-filled. */ void -APInt::tcExtract(integerPart *dst, unsigned int dstCount,const integerPart *src, - unsigned int srcBits, unsigned int srcLSB) -{ - unsigned int firstSrcPart, dstParts, shift, n; - - dstParts = (srcBits + integerPartWidth - 1) / integerPartWidth; +APInt::tcExtract(WordType *dst, unsigned dstCount, const WordType *src, + unsigned srcBits, unsigned srcLSB) { + unsigned dstParts = (srcBits + APINT_BITS_PER_WORD - 1) / APINT_BITS_PER_WORD; assert(dstParts <= dstCount); - firstSrcPart = srcLSB / integerPartWidth; + unsigned firstSrcPart = srcLSB / APINT_BITS_PER_WORD; tcAssign (dst, src + firstSrcPart, dstParts); - shift = srcLSB % integerPartWidth; + unsigned shift = srcLSB % APINT_BITS_PER_WORD; tcShiftRight (dst, dstParts, shift); - /* We now have (dstParts * integerPartWidth - shift) bits from SRC + /* We now have (dstParts * APINT_BITS_PER_WORD - shift) bits from SRC in DST. If this is less that srcBits, append the rest, else clear the high bits. */ - n = dstParts * integerPartWidth - shift; + unsigned n = dstParts * APINT_BITS_PER_WORD - shift; if (n < srcBits) { - integerPart mask = lowBitMask (srcBits - n); + WordType mask = lowBitMask (srcBits - n); dst[dstParts - 1] |= ((src[firstSrcPart + dstParts] & mask) - << n % integerPartWidth); + << n % APINT_BITS_PER_WORD); } else if (n > srcBits) { - if (srcBits % integerPartWidth) - dst[dstParts - 1] &= lowBitMask (srcBits % integerPartWidth); + if (srcBits % APINT_BITS_PER_WORD) + dst[dstParts - 1] &= lowBitMask (srcBits % APINT_BITS_PER_WORD); } /* Clear high parts. */ @@ -2447,18 +2281,12 @@ APInt::tcExtract(integerPart *dst, unsigned int dstCount,const integerPart *src, } /* DST += RHS + C where C is zero or one. Returns the carry flag. */ -integerPart -APInt::tcAdd(integerPart *dst, const integerPart *rhs, - integerPart c, unsigned int parts) -{ - unsigned int i; - +APInt::WordType APInt::tcAdd(WordType *dst, const WordType *rhs, + WordType c, unsigned parts) { assert(c <= 1); - for (i = 0; i < parts; i++) { - integerPart l; - - l = dst[i]; + for (unsigned i = 0; i < parts; i++) { + WordType l = dst[i]; if (c) { dst[i] += rhs[i] + 1; c = (dst[i] <= l); @@ -2471,19 +2299,29 @@ APInt::tcAdd(integerPart *dst, const integerPart *rhs, return c; } -/* DST -= RHS + C where C is zero or one. Returns the carry flag. */ -integerPart -APInt::tcSubtract(integerPart *dst, const integerPart *rhs, - integerPart c, unsigned int parts) -{ - unsigned int i; +/// This function adds a single "word" integer, src, to the multiple +/// "word" integer array, dst[]. dst[] is modified to reflect the addition and +/// 1 is returned if there is a carry out, otherwise 0 is returned. +/// @returns the carry of the addition. +APInt::WordType APInt::tcAddPart(WordType *dst, WordType src, + unsigned parts) { + for (unsigned i = 0; i < parts; ++i) { + dst[i] += src; + if (dst[i] >= src) + return 0; // No need to carry so exit early. + src = 1; // Carry one to next digit. + } - assert(c <= 1); + return 1; +} - for (i = 0; i < parts; i++) { - integerPart l; +/* DST -= RHS + C where C is zero or one. Returns the carry flag. */ +APInt::WordType APInt::tcSubtract(WordType *dst, const WordType *rhs, + WordType c, unsigned parts) { + assert(c <= 1); - l = dst[i]; + for (unsigned i = 0; i < parts; i++) { + WordType l = dst[i]; if (c) { dst[i] -= rhs[i] + 1; c = (dst[i] >= l); @@ -2496,10 +2334,28 @@ APInt::tcSubtract(integerPart *dst, const integerPart *rhs, return c; } +/// This function subtracts a single "word" (64-bit word), src, from +/// the multi-word integer array, dst[], propagating the borrowed 1 value until +/// no further borrowing is needed or it runs out of "words" in dst. The result +/// is 1 if "borrowing" exhausted the digits in dst, or 0 if dst was not +/// exhausted. In other words, if src > dst then this function returns 1, +/// otherwise 0. +/// @returns the borrow out of the subtraction +APInt::WordType APInt::tcSubtractPart(WordType *dst, WordType src, + unsigned parts) { + for (unsigned i = 0; i < parts; ++i) { + WordType Dst = dst[i]; + dst[i] -= src; + if (src <= Dst) + return 0; // No need to borrow so exit early. + src = 1; // We have to "borrow 1" from next "word" + } + + return 1; +} + /* Negate a bignum in-place. */ -void -APInt::tcNegate(integerPart *dst, unsigned int parts) -{ +void APInt::tcNegate(WordType *dst, unsigned parts) { tcComplement(dst, parts); tcIncrement(dst, parts); } @@ -2515,23 +2371,19 @@ APInt::tcNegate(integerPart *dst, unsigned int parts) DSTPARTS parts of the result, and if all of the omitted higher parts were zero return zero, otherwise overflow occurred and return one. */ -int -APInt::tcMultiplyPart(integerPart *dst, const integerPart *src, - integerPart multiplier, integerPart carry, - unsigned int srcParts, unsigned int dstParts, - bool add) -{ - unsigned int i, n; - +int APInt::tcMultiplyPart(WordType *dst, const WordType *src, + WordType multiplier, WordType carry, + unsigned srcParts, unsigned dstParts, + bool add) { /* Otherwise our writes of DST kill our later reads of SRC. */ assert(dst <= src || dst >= src + srcParts); assert(dstParts <= srcParts + 1); /* N loops; minimum of dstParts and srcParts. */ - n = dstParts < srcParts ? dstParts: srcParts; + unsigned n = std::min(dstParts, srcParts); - for (i = 0; i < n; i++) { - integerPart low, mid, high, srcPart; + for (unsigned i = 0; i < n; i++) { + WordType low, mid, high, srcPart; /* [ LOW, HIGH ] = MULTIPLIER * SRC[i] + DST[i] + CARRY. @@ -2543,7 +2395,7 @@ APInt::tcMultiplyPart(integerPart *dst, const integerPart *src, srcPart = src[i]; - if (multiplier == 0 || srcPart == 0) { + if (multiplier == 0 || srcPart == 0) { low = carry; high = 0; } else { @@ -2552,14 +2404,14 @@ APInt::tcMultiplyPart(integerPart *dst, const integerPart *src, mid = lowHalf(srcPart) * highHalf(multiplier); high += highHalf(mid); - mid <<= integerPartWidth / 2; + mid <<= APINT_BITS_PER_WORD / 2; if (low + mid < low) high++; low += mid; mid = highHalf(srcPart) * lowHalf(multiplier); high += highHalf(mid); - mid <<= integerPartWidth / 2; + mid <<= APINT_BITS_PER_WORD / 2; if (low + mid < low) high++; low += mid; @@ -2581,78 +2433,62 @@ APInt::tcMultiplyPart(integerPart *dst, const integerPart *src, carry = high; } - if (i < dstParts) { + if (srcParts < dstParts) { /* Full multiplication, there is no overflow. */ - assert(i + 1 == dstParts); - dst[i] = carry; - return 0; - } else { - /* We overflowed if there is carry. */ - if (carry) - return 1; - - /* We would overflow if any significant unwritten parts would be - non-zero. This is true if any remaining src parts are non-zero - and the multiplier is non-zero. */ - if (multiplier) - for (; i < srcParts; i++) - if (src[i]) - return 1; - - /* We fitted in the narrow destination. */ + assert(srcParts + 1 == dstParts); + dst[srcParts] = carry; return 0; } + + /* We overflowed if there is carry. */ + if (carry) + return 1; + + /* We would overflow if any significant unwritten parts would be + non-zero. This is true if any remaining src parts are non-zero + and the multiplier is non-zero. */ + if (multiplier) + for (unsigned i = dstParts; i < srcParts; i++) + if (src[i]) + return 1; + + /* We fitted in the narrow destination. */ + return 0; } /* DST = LHS * RHS, where DST has the same width as the operands and is filled with the least significant parts of the result. Returns one if overflow occurred, otherwise zero. DST must be disjoint from both operands. */ -int -APInt::tcMultiply(integerPart *dst, const integerPart *lhs, - const integerPart *rhs, unsigned int parts) -{ - unsigned int i; - int overflow; - +int APInt::tcMultiply(WordType *dst, const WordType *lhs, + const WordType *rhs, unsigned parts) { assert(dst != lhs && dst != rhs); - overflow = 0; + int overflow = 0; tcSet(dst, 0, parts); - for (i = 0; i < parts; i++) + for (unsigned i = 0; i < parts; i++) overflow |= tcMultiplyPart(&dst[i], lhs, rhs[i], 0, parts, parts - i, true); return overflow; } -/* DST = LHS * RHS, where DST has width the sum of the widths of the - operands. No overflow occurs. DST must be disjoint from both - operands. Returns the number of parts required to hold the - result. */ -unsigned int -APInt::tcFullMultiply(integerPart *dst, const integerPart *lhs, - const integerPart *rhs, unsigned int lhsParts, - unsigned int rhsParts) -{ +/// DST = LHS * RHS, where DST has width the sum of the widths of the +/// operands. No overflow occurs. DST must be disjoint from both operands. +void APInt::tcFullMultiply(WordType *dst, const WordType *lhs, + const WordType *rhs, unsigned lhsParts, + unsigned rhsParts) { /* Put the narrower number on the LHS for less loops below. */ - if (lhsParts > rhsParts) { + if (lhsParts > rhsParts) return tcFullMultiply (dst, rhs, lhs, rhsParts, lhsParts); - } else { - unsigned int n; - - assert(dst != lhs && dst != rhs); - tcSet(dst, 0, rhsParts); - - for (n = 0; n < lhsParts; n++) - tcMultiplyPart(&dst[n], rhs, lhs[n], 0, rhsParts, rhsParts + 1, true); + assert(dst != lhs && dst != rhs); - n = lhsParts + rhsParts; + tcSet(dst, 0, rhsParts); - return n - (dst[n - 1] == 0); - } + for (unsigned i = 0; i < lhsParts; i++) + tcMultiplyPart(&dst[i], rhs, lhs[i], 0, rhsParts, rhsParts + 1, true); } /* If RHS is zero LHS and REMAINDER are left unchanged, return one. @@ -2665,23 +2501,18 @@ APInt::tcFullMultiply(integerPart *dst, const integerPart *lhs, use by the routine; its contents need not be initialized and are destroyed. LHS, REMAINDER and SCRATCH must be distinct. */ -int -APInt::tcDivide(integerPart *lhs, const integerPart *rhs, - integerPart *remainder, integerPart *srhs, - unsigned int parts) -{ - unsigned int n, shiftCount; - integerPart mask; - +int APInt::tcDivide(WordType *lhs, const WordType *rhs, + WordType *remainder, WordType *srhs, + unsigned parts) { assert(lhs != remainder && lhs != srhs && remainder != srhs); - shiftCount = tcMSB(rhs, parts) + 1; + unsigned shiftCount = tcMSB(rhs, parts) + 1; if (shiftCount == 0) return true; - shiftCount = parts * integerPartWidth - shiftCount; - n = shiftCount / integerPartWidth; - mask = (integerPart) 1 << (shiftCount % integerPartWidth); + shiftCount = parts * APINT_BITS_PER_WORD - shiftCount; + unsigned n = shiftCount / APINT_BITS_PER_WORD; + WordType mask = (WordType) 1 << (shiftCount % APINT_BITS_PER_WORD); tcAssign(srhs, rhs, parts); tcShiftLeft(srhs, parts, shiftCount); @@ -2691,196 +2522,127 @@ APInt::tcDivide(integerPart *lhs, const integerPart *rhs, /* Loop, subtracting SRHS if REMAINDER is greater and adding that to the total. */ for (;;) { - int compare; - - compare = tcCompare(remainder, srhs, parts); - if (compare >= 0) { - tcSubtract(remainder, srhs, 0, parts); - lhs[n] |= mask; - } + int compare = tcCompare(remainder, srhs, parts); + if (compare >= 0) { + tcSubtract(remainder, srhs, 0, parts); + lhs[n] |= mask; + } - if (shiftCount == 0) - break; - shiftCount--; - tcShiftRight(srhs, parts, 1); - if ((mask >>= 1) == 0) { - mask = (integerPart) 1 << (integerPartWidth - 1); - n--; - } + if (shiftCount == 0) + break; + shiftCount--; + tcShiftRight(srhs, parts, 1); + if ((mask >>= 1) == 0) { + mask = (WordType) 1 << (APINT_BITS_PER_WORD - 1); + n--; + } } return false; } -/* Shift a bignum left COUNT bits in-place. Shifted in bits are zero. - There are no restrictions on COUNT. */ -void -APInt::tcShiftLeft(integerPart *dst, unsigned int parts, unsigned int count) -{ - if (count) { - unsigned int jump, shift; - - /* Jump is the inter-part jump; shift is is intra-part shift. */ - jump = count / integerPartWidth; - shift = count % integerPartWidth; - - while (parts > jump) { - integerPart part; - - parts--; - - /* dst[i] comes from the two parts src[i - jump] and, if we have - an intra-part shift, src[i - jump - 1]. */ - part = dst[parts - jump]; - if (shift) { - part <<= shift; - if (parts >= jump + 1) - part |= dst[parts - jump - 1] >> (integerPartWidth - shift); - } +/// Shift a bignum left Cound bits in-place. Shifted in bits are zero. There are +/// no restrictions on Count. +void APInt::tcShiftLeft(WordType *Dst, unsigned Words, unsigned Count) { + // Don't bother performing a no-op shift. + if (!Count) + return; - dst[parts] = part; - } + // WordShift is the inter-part shift; BitShift is the intra-part shift. + unsigned WordShift = std::min(Count / APINT_BITS_PER_WORD, Words); + unsigned BitShift = Count % APINT_BITS_PER_WORD; - while (parts > 0) - dst[--parts] = 0; + // Fastpath for moving by whole words. + if (BitShift == 0) { + std::memmove(Dst + WordShift, Dst, (Words - WordShift) * APINT_WORD_SIZE); + } else { + while (Words-- > WordShift) { + Dst[Words] = Dst[Words - WordShift] << BitShift; + if (Words > WordShift) + Dst[Words] |= + Dst[Words - WordShift - 1] >> (APINT_BITS_PER_WORD - BitShift); + } } + + // Fill in the remainder with 0s. + std::memset(Dst, 0, WordShift * APINT_WORD_SIZE); } -/* Shift a bignum right COUNT bits in-place. Shifted in bits are - zero. There are no restrictions on COUNT. */ -void -APInt::tcShiftRight(integerPart *dst, unsigned int parts, unsigned int count) -{ - if (count) { - unsigned int i, jump, shift; - - /* Jump is the inter-part jump; shift is is intra-part shift. */ - jump = count / integerPartWidth; - shift = count % integerPartWidth; - - /* Perform the shift. This leaves the most significant COUNT bits - of the result at zero. */ - for (i = 0; i < parts; i++) { - integerPart part; - - if (i + jump >= parts) { - part = 0; - } else { - part = dst[i + jump]; - if (shift) { - part >>= shift; - if (i + jump + 1 < parts) - part |= dst[i + jump + 1] << (integerPartWidth - shift); - } - } +/// Shift a bignum right Count bits in-place. Shifted in bits are zero. There +/// are no restrictions on Count. +void APInt::tcShiftRight(WordType *Dst, unsigned Words, unsigned Count) { + // Don't bother performing a no-op shift. + if (!Count) + return; + + // WordShift is the inter-part shift; BitShift is the intra-part shift. + unsigned WordShift = std::min(Count / APINT_BITS_PER_WORD, Words); + unsigned BitShift = Count % APINT_BITS_PER_WORD; - dst[i] = part; + unsigned WordsToMove = Words - WordShift; + // Fastpath for moving by whole words. + if (BitShift == 0) { + std::memmove(Dst, Dst + WordShift, WordsToMove * APINT_WORD_SIZE); + } else { + for (unsigned i = 0; i != WordsToMove; ++i) { + Dst[i] = Dst[i + WordShift] >> BitShift; + if (i + 1 != WordsToMove) + Dst[i] |= Dst[i + WordShift + 1] << (APINT_BITS_PER_WORD - BitShift); } } + + // Fill in the remainder with 0s. + std::memset(Dst + WordsToMove, 0, WordShift * APINT_WORD_SIZE); } /* Bitwise and of two bignums. */ -void -APInt::tcAnd(integerPart *dst, const integerPart *rhs, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) +void APInt::tcAnd(WordType *dst, const WordType *rhs, unsigned parts) { + for (unsigned i = 0; i < parts; i++) dst[i] &= rhs[i]; } /* Bitwise inclusive or of two bignums. */ -void -APInt::tcOr(integerPart *dst, const integerPart *rhs, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) +void APInt::tcOr(WordType *dst, const WordType *rhs, unsigned parts) { + for (unsigned i = 0; i < parts; i++) dst[i] |= rhs[i]; } /* Bitwise exclusive or of two bignums. */ -void -APInt::tcXor(integerPart *dst, const integerPart *rhs, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) +void APInt::tcXor(WordType *dst, const WordType *rhs, unsigned parts) { + for (unsigned i = 0; i < parts; i++) dst[i] ^= rhs[i]; } /* Complement a bignum in-place. */ -void -APInt::tcComplement(integerPart *dst, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) +void APInt::tcComplement(WordType *dst, unsigned parts) { + for (unsigned i = 0; i < parts; i++) dst[i] = ~dst[i]; } /* Comparison (unsigned) of two bignums. */ -int -APInt::tcCompare(const integerPart *lhs, const integerPart *rhs, - unsigned int parts) -{ +int APInt::tcCompare(const WordType *lhs, const WordType *rhs, + unsigned parts) { while (parts) { - parts--; - if (lhs[parts] == rhs[parts]) - continue; - - if (lhs[parts] > rhs[parts]) - return 1; - else - return -1; - } + parts--; + if (lhs[parts] != rhs[parts]) + return (lhs[parts] > rhs[parts]) ? 1 : -1; + } return 0; } -/* Increment a bignum in-place, return the carry flag. */ -integerPart -APInt::tcIncrement(integerPart *dst, unsigned int parts) -{ - unsigned int i; - - for (i = 0; i < parts; i++) - if (++dst[i] != 0) - break; - - return i == parts; -} - -/* Decrement a bignum in-place, return the borrow flag. */ -integerPart -APInt::tcDecrement(integerPart *dst, unsigned int parts) { - for (unsigned int i = 0; i < parts; i++) { - // If the current word is non-zero, then the decrement has no effect on the - // higher-order words of the integer and no borrow can occur. Exit early. - if (dst[i]--) - return 0; - } - // If every word was zero, then there is a borrow. - return 1; -} - - /* Set the least significant BITS bits of a bignum, clear the rest. */ -void -APInt::tcSetLeastSignificantBits(integerPart *dst, unsigned int parts, - unsigned int bits) -{ - unsigned int i; - - i = 0; - while (bits > integerPartWidth) { - dst[i++] = ~(integerPart) 0; - bits -= integerPartWidth; +void APInt::tcSetLeastSignificantBits(WordType *dst, unsigned parts, + unsigned bits) { + unsigned i = 0; + while (bits > APINT_BITS_PER_WORD) { + dst[i++] = ~(WordType) 0; + bits -= APINT_BITS_PER_WORD; } if (bits) - dst[i++] = ~(integerPart) 0 >> (integerPartWidth - bits); + dst[i++] = ~(WordType) 0 >> (APINT_BITS_PER_WORD - bits); while (i < parts) dst[i++] = 0; diff --git a/contrib/llvm/lib/Support/ARMAttributeParser.cpp b/contrib/llvm/lib/Support/ARMAttributeParser.cpp new file mode 100644 index 0000000..a9a0c1d --- /dev/null +++ b/contrib/llvm/lib/Support/ARMAttributeParser.cpp @@ -0,0 +1,708 @@ +//===--- ARMAttributeParser.cpp - ARM Attribute Information Printer -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.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(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 Length; + uint64_t Value = decodeULEB128(Data + Offset, &Length); + Offset = Offset + Length; + 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); + } +} + +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[] = { + "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" + }; + + uint64_t Value = ParseInteger(Data, Offset); + StringRef ValueDesc = + (Value < array_lengthof(Strings)) ? Strings[Value] : nullptr; + PrintAttribute(Tag, Value, ValueDesc); +} + +void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + uint64_t Encoded = ParseInteger(Data, Offset); + + 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; + } + + PrintAttribute(Tag, Encoded, Profile); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, + uint32_t &Offset) { + static const char *const 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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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" + }; + + uint64_t Value = ParseInteger(Data, Offset); + + 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"); + else + Description = "Invalid"; + + PrintAttribute(Tag, Value, Description); +} + +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" + }; + + uint64_t Value = ParseInteger(Data, Offset); + + 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"; + + PrintAttribute(Tag, Value, Description); +} + +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); +} + +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); +} + +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); +} + +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); +} + +void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, + const uint8_t *Data, + uint32_t &Offset) { + static const char *const 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) { + case 0: + SW->printString("Description", StringRef("No Specific Requirements")); + break; + case 1: + SW->printString("Description", StringRef("AEABI Conformant")); + break; + default: + SW->printString("Description", StringRef("AEABI Non-Conformant")); + break; + } + } +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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 Length; + uint64_t Value = decodeULEB128(Data + Offset, &Length); + Offset = Offset + Length; + if (Value == 0) + break; + IndexList.push_back(Value); + } +} + +void ARMAttributeParser::ParseAttributeList(const uint8_t *Data, + uint32_t &Offset, uint32_t Length) { + while (Offset < Length) { + unsigned Length; + uint64_t Tag = decodeULEB128(Data + Offset, &Length); + Offset += Length; + + bool Handled = false; + for (unsigned AHI = 0, AHE = array_lengthof(DisplayRoutines); + AHI != AHE && !Handled; ++AHI) { + if (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"; + 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" << 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) { + size_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(); + } + + ParseSubsection(Section.data() + Offset, SectionLength); + Offset = Offset + SectionLength; + + if (SW) { + SW->unindent(); + SW->startLine() << "}\n"; + } + } +} +} + diff --git a/contrib/llvm/lib/Support/ARMBuildAttrs.cpp b/contrib/llvm/lib/Support/ARMBuildAttrs.cpp index 134ef8b..8f18e9e 100644 --- a/contrib/llvm/lib/Support/ARMBuildAttrs.cpp +++ b/contrib/llvm/lib/Support/ARMBuildAttrs.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ARMBuildAttributes.h" using namespace llvm; diff --git a/contrib/llvm/lib/Support/Atomic.cpp b/contrib/llvm/lib/Support/Atomic.cpp index 80550e2..55910c4 100644 --- a/contrib/llvm/lib/Support/Atomic.cpp +++ b/contrib/llvm/lib/Support/Atomic.cpp @@ -18,6 +18,8 @@ using namespace llvm; #if defined(_MSC_VER) #include <Intrin.h> + +// We must include windows.h after Intrin.h. #include <windows.h> #undef MemoryFence #endif diff --git a/contrib/llvm/lib/Support/BinaryStreamError.cpp b/contrib/llvm/lib/Support/BinaryStreamError.cpp new file mode 100644 index 0000000..60f5e21 --- /dev/null +++ b/contrib/llvm/lib/Support/BinaryStreamError.cpp @@ -0,0 +1,56 @@ +//===- BinaryStreamError.cpp - Error extensions for streams -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +char BinaryStreamError::ID = 0; + +BinaryStreamError::BinaryStreamError(stream_error_code C) + : BinaryStreamError(C, "") {} + +BinaryStreamError::BinaryStreamError(StringRef Context) + : BinaryStreamError(stream_error_code::unspecified, Context) {} + +BinaryStreamError::BinaryStreamError(stream_error_code C, StringRef Context) + : Code(C) { + ErrMsg = "Stream Error: "; + switch (C) { + case stream_error_code::unspecified: + ErrMsg += "An unspecified error has occurred."; + break; + case stream_error_code::stream_too_short: + ErrMsg += "The stream is too short to perform the requested operation."; + break; + case stream_error_code::invalid_array_size: + ErrMsg += "The buffer size is not a multiple of the array element size."; + break; + case stream_error_code::invalid_offset: + ErrMsg += "The specified offset is invalid for the current stream."; + break; + case stream_error_code::filesystem_error: + ErrMsg += "An I/O error occurred on the file system."; + break; + } + + if (!Context.empty()) { + ErrMsg += " "; + ErrMsg += Context; + } +} + +void BinaryStreamError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +StringRef BinaryStreamError::getErrorMessage() const { return ErrMsg; } + +std::error_code BinaryStreamError::convertToErrorCode() const { + return inconvertibleErrorCode(); +} diff --git a/contrib/llvm/lib/Support/BinaryStreamReader.cpp b/contrib/llvm/lib/Support/BinaryStreamReader.cpp new file mode 100644 index 0000000..e00527f --- /dev/null +++ b/contrib/llvm/lib/Support/BinaryStreamReader.cpp @@ -0,0 +1,149 @@ +//===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamReader.h" + +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/BinaryStreamRef.h" + +using namespace llvm; +using endianness = llvm::support::endianness; + +BinaryStreamReader::BinaryStreamReader(BinaryStreamRef Ref) : Stream(Ref) {} + +BinaryStreamReader::BinaryStreamReader(BinaryStream &Stream) : Stream(Stream) {} + +BinaryStreamReader::BinaryStreamReader(ArrayRef<uint8_t> Data, + endianness Endian) + : Stream(Data, Endian) {} + +BinaryStreamReader::BinaryStreamReader(StringRef Data, endianness Endian) + : Stream(Data, Endian) {} + +Error BinaryStreamReader::readLongestContiguousChunk( + ArrayRef<uint8_t> &Buffer) { + if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) { + if (auto EC = Stream.readBytes(Offset, Size, Buffer)) + return EC; + Offset += Size; + return Error::success(); +} + +Error BinaryStreamReader::readCString(StringRef &Dest) { + uint32_t OriginalOffset = getOffset(); + uint32_t FoundOffset = 0; + while (true) { + uint32_t ThisOffset = getOffset(); + ArrayRef<uint8_t> Buffer; + if (auto EC = readLongestContiguousChunk(Buffer)) + return EC; + StringRef S(reinterpret_cast<const char *>(Buffer.begin()), Buffer.size()); + size_t Pos = S.find_first_of('\0'); + if (LLVM_LIKELY(Pos != StringRef::npos)) { + FoundOffset = Pos + ThisOffset; + break; + } + } + assert(FoundOffset >= OriginalOffset); + + setOffset(OriginalOffset); + size_t Length = FoundOffset - OriginalOffset; + + if (auto EC = readFixedString(Dest, Length)) + return EC; + + // Now set the offset back to after the null terminator. + setOffset(FoundOffset + 1); + return Error::success(); +} + +Error BinaryStreamReader::readWideString(ArrayRef<UTF16> &Dest) { + uint32_t Length = 0; + uint32_t OriginalOffset = getOffset(); + const UTF16 *C; + while (true) { + if (auto EC = readObject(C)) + return EC; + if (*C == 0x0000) + break; + ++Length; + } + uint32_t NewOffset = getOffset(); + setOffset(OriginalOffset); + + if (auto EC = readArray(Dest, Length)) + return EC; + setOffset(NewOffset); + return Error::success(); +} + +Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) { + ArrayRef<uint8_t> Bytes; + if (auto EC = readBytes(Bytes, Length)) + return EC; + Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size()); + return Error::success(); +} + +Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) { + return readStreamRef(Ref, bytesRemaining()); +} + +Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) { + if (bytesRemaining() < Length) + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); + Ref = Stream.slice(Offset, Length); + Offset += Length; + return Error::success(); +} + +Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Stream, + uint32_t Size) { + Stream.Offset = getOffset(); + return readStreamRef(Stream.StreamData, Size); +} + +Error BinaryStreamReader::skip(uint32_t Amount) { + if (Amount > bytesRemaining()) + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); + Offset += Amount; + return Error::success(); +} + +Error BinaryStreamReader::padToAlignment(uint32_t Align) { + uint32_t NewOffset = alignTo(Offset, Align); + return skip(NewOffset - Offset); +} + +uint8_t BinaryStreamReader::peek() const { + ArrayRef<uint8_t> Buffer; + auto EC = Stream.readBytes(Offset, 1, Buffer); + assert(!EC && "Cannot peek an empty buffer!"); + llvm::consumeError(std::move(EC)); + return Buffer[0]; +} + +std::pair<BinaryStreamReader, BinaryStreamReader> +BinaryStreamReader::split(uint32_t Off) const { + assert(getLength() >= Off); + + BinaryStreamRef First = Stream.drop_front(Offset); + + BinaryStreamRef Second = First.drop_front(Off); + First = First.keep_front(Off); + BinaryStreamReader W1{First}; + BinaryStreamReader W2{Second}; + return std::make_pair(W1, W2); +}
\ No newline at end of file diff --git a/contrib/llvm/lib/Support/BinaryStreamRef.cpp b/contrib/llvm/lib/Support/BinaryStreamRef.cpp new file mode 100644 index 0000000..fe9a817 --- /dev/null +++ b/contrib/llvm/lib/Support/BinaryStreamRef.cpp @@ -0,0 +1,137 @@ +//===- BinaryStreamRef.cpp - ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryByteStream.h" + +using namespace llvm; +using namespace llvm::support; + +namespace { + +class ArrayRefImpl : public BinaryStream { +public: + ArrayRefImpl(ArrayRef<uint8_t> Data, endianness Endian) : BBS(Data, Endian) {} + + llvm::support::endianness getEndian() const override { + return BBS.getEndian(); + } + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return BBS.readBytes(Offset, Size, Buffer); + } + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return BBS.readLongestContiguousChunk(Offset, Buffer); + } + uint32_t getLength() override { return BBS.getLength(); } + +private: + BinaryByteStream BBS; +}; + +class MutableArrayRefImpl : public WritableBinaryStream { +public: + MutableArrayRefImpl(MutableArrayRef<uint8_t> Data, endianness Endian) + : BBS(Data, Endian) {} + + // Inherited via WritableBinaryStream + llvm::support::endianness getEndian() const override { + return BBS.getEndian(); + } + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return BBS.readBytes(Offset, Size, Buffer); + } + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return BBS.readLongestContiguousChunk(Offset, Buffer); + } + uint32_t getLength() override { return BBS.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override { + return BBS.writeBytes(Offset, Data); + } + Error commit() override { return BBS.commit(); } + +private: + MutableBinaryByteStream BBS; +}; +} + +BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream) + : BinaryStreamRef(Stream, 0, Stream.getLength()) {} +BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, + uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} +BinaryStreamRef::BinaryStreamRef(ArrayRef<uint8_t> Data, endianness Endian) + : BinaryStreamRefBase(std::make_shared<ArrayRefImpl>(Data, Endian), 0, + Data.size()) {} +BinaryStreamRef::BinaryStreamRef(StringRef Data, endianness Endian) + : BinaryStreamRef(makeArrayRef(Data.bytes_begin(), Data.bytes_end()), + Endian) {} + +BinaryStreamRef::BinaryStreamRef(const BinaryStreamRef &Other) + : BinaryStreamRefBase(Other) {} + +Error BinaryStreamRef::readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const { + if (auto EC = checkOffset(Offset, Size)) + return EC; + return BorrowedImpl->readBytes(ViewOffset + Offset, Size, Buffer); +} + +Error BinaryStreamRef::readLongestContiguousChunk( + uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { + if (auto EC = checkOffset(Offset, 1)) + return EC; + + if (auto EC = + BorrowedImpl->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) + return EC; + // This StreamRef might refer to a smaller window over a larger stream. In + // that case we will have read out more bytes than we should return, because + // we should not read past the end of the current view. + uint32_t MaxLength = Length - Offset; + if (Buffer.size() > MaxLength) + Buffer = Buffer.slice(0, MaxLength); + return Error::success(); +} + +WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream) + : WritableBinaryStreamRef(Stream, 0, Stream.getLength()) {} + +WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream, + uint32_t Offset, + uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} + +WritableBinaryStreamRef::WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data, + endianness Endian) + : BinaryStreamRefBase(std::make_shared<MutableArrayRefImpl>(Data, Endian), + 0, Data.size()) {} + +WritableBinaryStreamRef::WritableBinaryStreamRef( + const WritableBinaryStreamRef &Other) + : BinaryStreamRefBase(Other) {} + +Error WritableBinaryStreamRef::writeBytes(uint32_t Offset, + ArrayRef<uint8_t> Data) const { + if (auto EC = checkOffset(Offset, Data.size())) + return EC; + + return BorrowedImpl->writeBytes(ViewOffset + Offset, Data); +} + +WritableBinaryStreamRef::operator BinaryStreamRef() const { + return BinaryStreamRef(*BorrowedImpl, ViewOffset, Length); +} + +/// \brief For buffered streams, commits changes to the backing store. +Error WritableBinaryStreamRef::commit() { return BorrowedImpl->commit(); } diff --git a/contrib/llvm/lib/Support/BinaryStreamWriter.cpp b/contrib/llvm/lib/Support/BinaryStreamWriter.cpp new file mode 100644 index 0000000..c427651 --- /dev/null +++ b/contrib/llvm/lib/Support/BinaryStreamWriter.cpp @@ -0,0 +1,90 @@ +//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamWriter.h" + +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" + +using namespace llvm; + +BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef Ref) + : Stream(Ref) {} + +BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStream &Stream) + : Stream(Stream) {} + +BinaryStreamWriter::BinaryStreamWriter(MutableArrayRef<uint8_t> Data, + llvm::support::endianness Endian) + : Stream(Data, Endian) {} + +Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { + if (auto EC = Stream.writeBytes(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error BinaryStreamWriter::writeCString(StringRef Str) { + if (auto EC = writeFixedString(Str)) + return EC; + if (auto EC = writeObject('\0')) + return EC; + + return Error::success(); +} + +Error BinaryStreamWriter::writeFixedString(StringRef Str) { + return writeBytes(ArrayRef<uint8_t>(Str.bytes_begin(), Str.bytes_end())); +} + +Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) { + return writeStreamRef(Ref, Ref.getLength()); +} + +Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) { + BinaryStreamReader SrcReader(Ref.slice(0, Length)); + // This is a bit tricky. If we just call readBytes, we are requiring that it + // return us the entire stream as a contiguous buffer. There is no guarantee + // this can be satisfied by returning a reference straight from the buffer, as + // an implementation may not store all data in a single contiguous buffer. So + // we iterate over each contiguous chunk, writing each one in succession. + while (SrcReader.bytesRemaining() > 0) { + ArrayRef<uint8_t> Chunk; + if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) + return EC; + if (auto EC = writeBytes(Chunk)) + return EC; + } + return Error::success(); +} + +std::pair<BinaryStreamWriter, BinaryStreamWriter> +BinaryStreamWriter::split(uint32_t Off) const { + assert(getLength() >= Off); + + WritableBinaryStreamRef First = Stream.drop_front(Offset); + + WritableBinaryStreamRef Second = First.drop_front(Off); + First = First.keep_front(Off); + BinaryStreamWriter W1{First}; + BinaryStreamWriter W2{Second}; + return std::make_pair(W1, W2); +} + +Error BinaryStreamWriter::padToAlignment(uint32_t Align) { + uint32_t NewOffset = alignTo(Offset, Align); + if (NewOffset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::stream_too_short); + while (Offset < NewOffset) + if (auto EC = writeInteger('\0')) + return EC; + return Error::success(); +} diff --git a/contrib/llvm/lib/Support/BranchProbability.cpp b/contrib/llvm/lib/Support/BranchProbability.cpp index 1c41659..44ad110 100644 --- a/contrib/llvm/lib/Support/BranchProbability.cpp +++ b/contrib/llvm/lib/Support/BranchProbability.cpp @@ -32,7 +32,9 @@ raw_ostream &BranchProbability::print(raw_ostream &OS) const { Percent); } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void BranchProbability::dump() const { print(dbgs()) << '\n'; } +#endif BranchProbability::BranchProbability(uint32_t Numerator, uint32_t Denominator) { assert(Denominator > 0 && "Denominator cannot be 0!"); diff --git a/contrib/llvm/lib/Support/CachePruning.cpp b/contrib/llvm/lib/Support/CachePruning.cpp index 3831625..60d0964 100644 --- a/contrib/llvm/lib/Support/CachePruning.cpp +++ b/contrib/llvm/lib/Support/CachePruning.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -33,8 +34,96 @@ static void writeTimestampFile(StringRef TimestampFile) { raw_fd_ostream Out(TimestampFile.str(), EC, sys::fs::F_None); } +static Expected<std::chrono::seconds> parseDuration(StringRef Duration) { + if (Duration.empty()) + return make_error<StringError>("Duration must not be empty", + inconvertibleErrorCode()); + + StringRef NumStr = Duration.slice(0, Duration.size()-1); + uint64_t Num; + if (NumStr.getAsInteger(0, Num)) + return make_error<StringError>("'" + NumStr + "' not an integer", + inconvertibleErrorCode()); + + switch (Duration.back()) { + case 's': + return std::chrono::seconds(Num); + case 'm': + return std::chrono::minutes(Num); + case 'h': + return std::chrono::hours(Num); + default: + return make_error<StringError>("'" + Duration + + "' must end with one of 's', 'm' or 'h'", + inconvertibleErrorCode()); + } +} + +Expected<CachePruningPolicy> +llvm::parseCachePruningPolicy(StringRef PolicyStr) { + CachePruningPolicy Policy; + std::pair<StringRef, StringRef> P = {"", PolicyStr}; + while (!P.second.empty()) { + P = P.second.split(':'); + + StringRef Key, Value; + std::tie(Key, Value) = P.first.split('='); + if (Key == "prune_interval") { + auto DurationOrErr = parseDuration(Value); + if (!DurationOrErr) + return DurationOrErr.takeError(); + Policy.Interval = *DurationOrErr; + } else if (Key == "prune_after") { + auto DurationOrErr = parseDuration(Value); + if (!DurationOrErr) + return DurationOrErr.takeError(); + Policy.Expiration = *DurationOrErr; + } else if (Key == "cache_size") { + if (Value.back() != '%') + return make_error<StringError>("'" + Value + "' must be a percentage", + inconvertibleErrorCode()); + StringRef SizeStr = Value.drop_back(); + uint64_t Size; + if (SizeStr.getAsInteger(0, Size)) + return make_error<StringError>("'" + SizeStr + "' not an integer", + inconvertibleErrorCode()); + if (Size > 100) + return make_error<StringError>("'" + SizeStr + + "' must be between 0 and 100", + inconvertibleErrorCode()); + Policy.MaxSizePercentageOfAvailableSpace = Size; + } else if (Key == "cache_size_bytes") { + uint64_t Mult = 1; + switch (tolower(Value.back())) { + case 'k': + Mult = 1024; + Value = Value.drop_back(); + break; + case 'm': + Mult = 1024 * 1024; + Value = Value.drop_back(); + break; + case 'g': + Mult = 1024 * 1024 * 1024; + Value = Value.drop_back(); + break; + } + uint64_t Size; + if (Value.getAsInteger(0, Size)) + return make_error<StringError>("'" + Value + "' not an integer", + inconvertibleErrorCode()); + Policy.MaxSizeBytes = Size * Mult; + } else { + return make_error<StringError>("Unknown key: '" + Key + "'", + inconvertibleErrorCode()); + } + } + + return Policy; +} + /// Prune the cache of files that haven't been accessed in a long time. -bool CachePruning::prune() { +bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { using namespace std::chrono; if (Path.empty()) @@ -47,7 +136,12 @@ bool CachePruning::prune() { if (!isPathDir) return false; - if (Expiration == seconds(0) && PercentageOfAvailableSpace == 0) { + Policy.MaxSizePercentageOfAvailableSpace = + std::min(Policy.MaxSizePercentageOfAvailableSpace, 100u); + + if (Policy.Expiration == seconds(0) && + Policy.MaxSizePercentageOfAvailableSpace == 0 && + Policy.MaxSizeBytes == 0) { DEBUG(dbgs() << "No pruning settings set, exit early\n"); // Nothing will be pruned, early exit return false; @@ -67,12 +161,12 @@ bool CachePruning::prune() { return false; } } else { - if (Interval == seconds(0)) { + if (Policy.Interval == seconds(0)) { // Check whether the time stamp is older than our pruning interval. // If not, do nothing. const auto TimeStampModTime = FileStatus.getLastModificationTime(); auto TimeStampAge = CurrentTime - TimeStampModTime; - if (TimeStampAge <= Interval) { + if (TimeStampAge <= Policy.Interval) { DEBUG(dbgs() << "Timestamp file too recent (" << duration_cast<seconds>(TimeStampAge).count() << "s old), do not prune.\n"); @@ -85,7 +179,8 @@ bool CachePruning::prune() { writeTimestampFile(TimestampFile); } - bool ShouldComputeSize = (PercentageOfAvailableSpace > 0); + bool ShouldComputeSize = + (Policy.MaxSizePercentageOfAvailableSpace > 0 || Policy.MaxSizeBytes > 0); // Keep track of space std::set<std::pair<uint64_t, std::string>> FileSizes; @@ -108,8 +203,11 @@ bool CachePruning::prune() { // Walk all of the files within this directory. for (sys::fs::directory_iterator File(CachePathNative, EC), FileEnd; File != FileEnd && !EC; File.increment(EC)) { - // Do not touch the timestamp. - if (File->path() == TimestampFile) + // Ignore any files not beginning with the string "llvmcache-". This + // includes the timestamp file as well as any files created by the user. + // This acts as a safeguard against data loss if the user specifies the + // wrong directory as their cache directory. + if (!sys::path::filename(File->path()).startswith("llvmcache-")) continue; // Look at this file. If we can't stat it, there's nothing interesting @@ -122,7 +220,7 @@ bool CachePruning::prune() { // If the file hasn't been used recently enough, delete it const auto FileAccessTime = FileStatus.getLastAccessedTime(); auto FileAge = CurrentTime - FileAccessTime; - if (FileAge > Expiration) { + if (FileAge > Policy.Expiration) { DEBUG(dbgs() << "Remove " << File->path() << " (" << duration_cast<seconds>(FileAge).count() << "s old)\n"); sys::fs::remove(File->path()); @@ -141,12 +239,22 @@ bool CachePruning::prune() { } sys::fs::space_info SpaceInfo = ErrOrSpaceInfo.get(); auto AvailableSpace = TotalSize + SpaceInfo.free; - auto FileAndSize = FileSizes.rbegin(); + + if (Policy.MaxSizePercentageOfAvailableSpace == 0) + Policy.MaxSizePercentageOfAvailableSpace = 100; + if (Policy.MaxSizeBytes == 0) + Policy.MaxSizeBytes = AvailableSpace; + auto TotalSizeTarget = std::min<uint64_t>( + AvailableSpace * Policy.MaxSizePercentageOfAvailableSpace / 100ull, + Policy.MaxSizeBytes); + DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace) - << "% target is: " << PercentageOfAvailableSpace << "\n"); + << "% target is: " << Policy.MaxSizePercentageOfAvailableSpace + << "%, " << Policy.MaxSizeBytes << " bytes\n"); + + auto FileAndSize = FileSizes.rbegin(); // Remove the oldest accessed files first, till we get below the threshold - while (((100 * TotalSize) / AvailableSpace) > PercentageOfAvailableSpace && - FileAndSize != FileSizes.rend()) { + while (TotalSize > TotalSizeTarget && FileAndSize != FileSizes.rend()) { // Remove the file. sys::fs::remove(FileAndSize->second); // Update size diff --git a/contrib/llvm/lib/Support/Chrono.cpp b/contrib/llvm/lib/Support/Chrono.cpp index cdadbd8..daccaf1 100644 --- a/contrib/llvm/lib/Support/Chrono.cpp +++ b/contrib/llvm/lib/Support/Chrono.cpp @@ -16,6 +16,13 @@ namespace llvm { using namespace sys; +const char llvm::detail::unit<std::ratio<3600>>::value[] = "h"; +const char llvm::detail::unit<std::ratio<60>>::value[] = "m"; +const char llvm::detail::unit<std::ratio<1>>::value[] = "s"; +const char llvm::detail::unit<std::milli>::value[] = "ms"; +const char llvm::detail::unit<std::micro>::value[] = "us"; +const char llvm::detail::unit<std::nano>::value[] = "ns"; + static inline struct tm getStructTM(TimePoint<> TP) { struct tm Storage; std::time_t OurTime = toTimeT(TP); diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index 3889902..8eeb685 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" @@ -123,7 +124,7 @@ public: void ResetAllOptionOccurrences(); bool ParseCommandLineOptions(int argc, const char *const *argv, - StringRef Overview, bool IgnoreErrors); + StringRef Overview, raw_ostream *Errs = nullptr); void addLiteralOption(Option &Opt, SubCommand *SC, StringRef Name) { if (Opt.hasArgStr()) @@ -1013,9 +1014,9 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, } bool cl::ParseCommandLineOptions(int argc, const char *const *argv, - StringRef Overview, bool IgnoreErrors) { + StringRef Overview, raw_ostream *Errs) { return GlobalParser->ParseCommandLineOptions(argc, argv, Overview, - IgnoreErrors); + Errs); } void CommandLineParser::ResetAllOptionOccurrences() { @@ -1030,7 +1031,7 @@ void CommandLineParser::ResetAllOptionOccurrences() { bool CommandLineParser::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, - bool IgnoreErrors) { + raw_ostream *Errs) { assert(hasOptions() && "No options specified!"); // Expand response files. @@ -1045,6 +1046,9 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, ProgramName = sys::path::filename(StringRef(argv[0])); ProgramOverview = Overview; + bool IgnoreErrors = Errs; + if (!Errs) + Errs = &errs(); bool ErrorParsing = false; // Check out the positional arguments to collect information about them. @@ -1097,15 +1101,14 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // not specified after an option that eats all extra arguments, or this // one will never get any! // - if (!IgnoreErrors) { + if (!IgnoreErrors) Opt->error("error - option can never match, because " "another positional argument will match an " "unbounded number of values, and this option" " does not require a value!"); - errs() << ProgramName << ": CommandLine Error: Option '" - << Opt->ArgStr << "' is all messed up!\n"; - errs() << PositionalOpts.size(); - } + *Errs << ProgramName << ": CommandLine Error: Option '" << Opt->ArgStr + << "' is all messed up!\n"; + *Errs << PositionalOpts.size(); ErrorParsing = true; } UnboundedFound |= EatsUnboundedNumberOfValues(Opt); @@ -1200,15 +1203,13 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, if (!Handler) { if (SinkOpts.empty()) { - if (!IgnoreErrors) { - errs() << ProgramName << ": Unknown command line argument '" - << argv[i] << "'. Try: '" << argv[0] << " -help'\n"; - - if (NearestHandler) { - // If we know a near match, report it as well. - errs() << ProgramName << ": Did you mean '-" << NearestHandlerString - << "'?\n"; - } + *Errs << ProgramName << ": Unknown command line argument '" << argv[i] + << "'. Try: '" << argv[0] << " -help'\n"; + + if (NearestHandler) { + // If we know a near match, report it as well. + *Errs << ProgramName << ": Did you mean '-" << NearestHandlerString + << "'?\n"; } ErrorParsing = true; @@ -1231,22 +1232,18 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // Check and handle positional arguments now... if (NumPositionalRequired > PositionalVals.size()) { - if (!IgnoreErrors) { - errs() << ProgramName + *Errs << ProgramName << ": Not enough positional command line arguments specified!\n" << "Must specify at least " << NumPositionalRequired << " positional argument" << (NumPositionalRequired > 1 ? "s" : "") - << ": See: " << argv[0] << " - help\n"; - } + << ": See: " << argv[0] << " -help\n"; ErrorParsing = true; } else if (!HasUnlimitedPositionals && PositionalVals.size() > PositionalOpts.size()) { - if (!IgnoreErrors) { - errs() << ProgramName << ": Too many positional arguments specified!\n" - << "Can specify at most " << PositionalOpts.size() - << " positional arguments: See: " << argv[0] << " -help\n"; - } + *Errs << ProgramName << ": Too many positional arguments specified!\n" + << "Can specify at most " << PositionalOpts.size() + << " positional arguments: See: " << argv[0] << " -help\n"; ErrorParsing = true; } else if (!ConsumeAfterOpt) { @@ -1404,8 +1401,8 @@ static StringRef getValueStr(const Option &O, StringRef DefaultMsg) { // Return the width of the option tag for printing... size_t alias::getOptionWidth() const { return ArgStr.size() + 6; } -static void printHelpStr(StringRef HelpStr, size_t Indent, - size_t FirstLineIndentedBy) { +void Option::printHelpStr(StringRef HelpStr, size_t Indent, + size_t FirstLineIndentedBy) { std::pair<StringRef, StringRef> Split = HelpStr.split('\n'); outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n"; while (!Split.second.empty()) { @@ -1448,7 +1445,7 @@ void basic_parser_impl::printOptionInfo(const Option &O, if (!ValName.empty()) outs() << "=<" << getValueStr(O, ValName) << '>'; - printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O)); + Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O)); } void basic_parser_impl::printOptionName(const Option &O, @@ -1526,13 +1523,9 @@ bool parser<unsigned long long>::parse(Option &O, StringRef ArgName, // parser<double>/parser<float> implementation // static bool parseDouble(Option &O, StringRef Arg, double &Value) { - SmallString<32> TmpStr(Arg.begin(), Arg.end()); - const char *ArgStart = TmpStr.c_str(); - char *End; - Value = strtod(ArgStart, &End); - if (*End != 0) - return O.error("'" + Arg + "' value invalid for floating point argument!"); - return false; + if (to_float(Arg, Value)) + return false; + return O.error("'" + Arg + "' value invalid for floating point argument!"); } bool parser<double>::parse(Option &O, StringRef ArgName, StringRef Arg, @@ -1587,7 +1580,7 @@ void generic_parser_base::printOptionInfo(const Option &O, size_t GlobalWidth) const { if (O.hasArgStr()) { outs() << " -" << O.ArgStr; - printHelpStr(O.HelpStr, GlobalWidth, O.ArgStr.size() + 6); + Option::printHelpStr(O.HelpStr, GlobalWidth, O.ArgStr.size() + 6); for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { size_t NumSpaces = GlobalWidth - getOption(i).size() - 8; @@ -1600,7 +1593,7 @@ void generic_parser_base::printOptionInfo(const Option &O, for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { auto Option = getOption(i); outs() << " -" << Option; - printHelpStr(getDescription(i), GlobalWidth, Option.size() + 8); + Option::printHelpStr(getDescription(i), GlobalWidth, Option.size() + 8); } } } @@ -1856,10 +1849,11 @@ public: // Helper function for printOptions(). // It shall return a negative value if A's name should be lexicographically - // ordered before B's name. It returns a value greater equal zero otherwise. + // ordered before B's name. It returns a value greater than zero if B's name + // should be ordered before A's name, and it returns 0 otherwise. static int OptionCategoryCompare(OptionCategory *const *A, OptionCategory *const *B) { - return (*A)->getName() == (*B)->getName(); + return (*A)->getName().compare((*B)->getName()); } // Make sure we inherit our base class's operator=() @@ -2072,12 +2066,15 @@ public: #ifndef NDEBUG OS << " with assertions"; #endif +#if LLVM_VERSION_PRINTER_SHOW_HOST_TARGET_INFO std::string CPU = sys::getHostCPUName(); if (CPU == "generic") CPU = "(unknown)"; OS << ".\n" << " Default target: " << sys::getDefaultTargetTriple() << '\n' - << " Host CPU: " << CPU << '\n'; + << " Host CPU: " << CPU; +#endif + OS << '\n'; } void operator=(bool OptionWasSpecified) { if (!OptionWasSpecified) @@ -2182,5 +2179,6 @@ void cl::ResetAllOptionOccurrences() { void LLVMParseCommandLineOptions(int argc, const char *const *argv, const char *Overview) { - llvm::cl::ParseCommandLineOptions(argc, argv, StringRef(Overview), true); + llvm::cl::ParseCommandLineOptions(argc, argv, StringRef(Overview), + &llvm::nulls()); } diff --git a/contrib/llvm/lib/Support/Compression.cpp b/contrib/llvm/lib/Support/Compression.cpp index 5d55646..c279d10 100644 --- a/contrib/llvm/lib/Support/Compression.cpp +++ b/contrib/llvm/lib/Support/Compression.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H #include <zlib.h> @@ -24,6 +25,10 @@ using namespace llvm; #if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ +static Error createError(StringRef Err) { + return make_error<StringError>(Err, inconvertibleErrorCode()); +} + static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) { switch (Level) { case zlib::NoCompression: return 0; @@ -34,53 +39,59 @@ static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) { llvm_unreachable("Invalid zlib::CompressionLevel!"); } -static zlib::Status encodeZlibReturnValue(int ReturnValue) { - switch (ReturnValue) { - case Z_OK: return zlib::StatusOK; - case Z_MEM_ERROR: return zlib::StatusOutOfMemory; - case Z_BUF_ERROR: return zlib::StatusBufferTooShort; - case Z_STREAM_ERROR: return zlib::StatusInvalidArg; - case Z_DATA_ERROR: return zlib::StatusInvalidData; - default: llvm_unreachable("unknown zlib return status!"); +static StringRef convertZlibCodeToString(int Code) { + switch (Code) { + case Z_MEM_ERROR: + return "zlib error: Z_MEM_ERROR"; + case Z_BUF_ERROR: + return "zlib error: Z_BUF_ERROR"; + case Z_STREAM_ERROR: + return "zlib error: Z_STREAM_ERROR"; + case Z_DATA_ERROR: + return "zlib error: Z_DATA_ERROR"; + case Z_OK: + default: + llvm_unreachable("unknown or unexpected zlib status code"); } } bool zlib::isAvailable() { return true; } -zlib::Status zlib::compress(StringRef InputBuffer, - SmallVectorImpl<char> &CompressedBuffer, - CompressionLevel Level) { + +Error zlib::compress(StringRef InputBuffer, + SmallVectorImpl<char> &CompressedBuffer, + CompressionLevel Level) { unsigned long CompressedSize = ::compressBound(InputBuffer.size()); CompressedBuffer.resize(CompressedSize); int CLevel = encodeZlibCompressionLevel(Level); - Status Res = encodeZlibReturnValue(::compress2( - (Bytef *)CompressedBuffer.data(), &CompressedSize, - (const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel)); + int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize, + (const Bytef *)InputBuffer.data(), InputBuffer.size(), + CLevel); // Tell MemorySanitizer that zlib output buffer is fully initialized. // This avoids a false report when running LLVM with uninstrumented ZLib. __msan_unpoison(CompressedBuffer.data(), CompressedSize); CompressedBuffer.resize(CompressedSize); - return Res; + return Res ? createError(convertZlibCodeToString(Res)) : Error::success(); } -zlib::Status zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer, - size_t &UncompressedSize) { - Status Res = encodeZlibReturnValue( +Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer, + size_t &UncompressedSize) { + int Res = ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, - (const Bytef *)InputBuffer.data(), InputBuffer.size())); + (const Bytef *)InputBuffer.data(), InputBuffer.size()); // Tell MemorySanitizer that zlib output buffer is fully initialized. // This avoids a false report when running LLVM with uninstrumented ZLib. __msan_unpoison(UncompressedBuffer, UncompressedSize); - return Res; + return Res ? createError(convertZlibCodeToString(Res)) : Error::success(); } -zlib::Status zlib::uncompress(StringRef InputBuffer, - SmallVectorImpl<char> &UncompressedBuffer, - size_t UncompressedSize) { +Error zlib::uncompress(StringRef InputBuffer, + SmallVectorImpl<char> &UncompressedBuffer, + size_t UncompressedSize) { UncompressedBuffer.resize(UncompressedSize); - Status Res = + Error E = uncompress(InputBuffer, UncompressedBuffer.data(), UncompressedSize); UncompressedBuffer.resize(UncompressedSize); - return Res; + return E; } uint32_t zlib::crc32(StringRef Buffer) { @@ -89,19 +100,19 @@ uint32_t zlib::crc32(StringRef Buffer) { #else bool zlib::isAvailable() { return false; } -zlib::Status zlib::compress(StringRef InputBuffer, - SmallVectorImpl<char> &CompressedBuffer, - CompressionLevel Level) { - return zlib::StatusUnsupported; +Error zlib::compress(StringRef InputBuffer, + SmallVectorImpl<char> &CompressedBuffer, + CompressionLevel Level) { + llvm_unreachable("zlib::compress is unavailable"); } -zlib::Status zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer, - size_t &UncompressedSize) { - return zlib::StatusUnsupported; +Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer, + size_t &UncompressedSize) { + llvm_unreachable("zlib::uncompress is unavailable"); } -zlib::Status zlib::uncompress(StringRef InputBuffer, - SmallVectorImpl<char> &UncompressedBuffer, - size_t UncompressedSize) { - return zlib::StatusUnsupported; +Error zlib::uncompress(StringRef InputBuffer, + SmallVectorImpl<char> &UncompressedBuffer, + size_t UncompressedSize) { + llvm_unreachable("zlib::uncompress is unavailable"); } uint32_t zlib::crc32(StringRef Buffer) { llvm_unreachable("zlib::crc32 is unavailable"); diff --git a/contrib/llvm/lib/Support/ConvertUTF.cpp b/contrib/llvm/lib/Support/ConvertUTF.cpp index 39fd218..e56854a 100644 --- a/contrib/llvm/lib/Support/ConvertUTF.cpp +++ b/contrib/llvm/lib/Support/ConvertUTF.cpp @@ -46,13 +46,40 @@ ------------------------------------------------------------------------ */ - #include "llvm/Support/ConvertUTF.h" #ifdef CVTUTF_DEBUG #include <stdio.h> #endif #include <assert.h> +/* + * This code extensively uses fall-through switches. + * Keep the compiler from warning about that. + */ +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wimplicit-fallthrough") +# define ConvertUTF_DISABLE_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"") +# define ConvertUTF_RESTORE_WARNINGS \ + _Pragma("clang diagnostic pop") +# endif +#elif defined(__GNUC__) && __GNUC__ > 6 +# define ConvertUTF_DISABLE_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") +# define ConvertUTF_RESTORE_WARNINGS \ + _Pragma("GCC diagnostic pop") +#endif +#ifndef ConvertUTF_DISABLE_WARNINGS +# define ConvertUTF_DISABLE_WARNINGS +#endif +#ifndef ConvertUTF_RESTORE_WARNINGS +# define ConvertUTF_RESTORE_WARNINGS +#endif + +ConvertUTF_DISABLE_WARNINGS + namespace llvm { static const int halfShift = 10; /* used for shifting by 10 bits */ @@ -708,3 +735,5 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, --------------------------------------------------------------------- */ } // namespace llvm + +ConvertUTF_RESTORE_WARNINGS diff --git a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp index 217cedb..6cb4f63 100644 --- a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp +++ b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/ConvertUTF.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SwapByteOrder.h" #include <string> diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp index 98865f5..bd38dd8 100644 --- a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp @@ -78,6 +78,9 @@ static bool gCrashRecoveryEnabled = false; static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContext>> tlIsRecoveringFromCrash; +static void installExceptionOrSignalHandlers(); +static void uninstallExceptionOrSignalHandlers(); + CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} CrashRecoveryContext::~CrashRecoveryContext() { @@ -113,6 +116,23 @@ CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { return CRCI->CRC; } +void CrashRecoveryContext::Enable() { + sys::ScopedLock L(*gCrashRecoveryContextMutex); + // FIXME: Shouldn't this be a refcount or something? + if (gCrashRecoveryEnabled) + return; + gCrashRecoveryEnabled = true; + installExceptionOrSignalHandlers(); +} + +void CrashRecoveryContext::Disable() { + sys::ScopedLock L(*gCrashRecoveryContextMutex); + if (!gCrashRecoveryEnabled) + return; + gCrashRecoveryEnabled = false; + uninstallExceptionOrSignalHandlers(); +} + void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) { if (!cleanup) @@ -140,30 +160,70 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { delete cleanup; } -#ifdef LLVM_ON_WIN32 +#if defined(_MSC_VER) +// 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 +// internal exception handling of other libraries on that thread. SEH works +// exactly as you would expect normal exception handling to work: it only +// catches exceptions if they would bubble out from the stack frame with __try / +// __except. -#include "Windows/WindowsSupport.h" +static void installExceptionOrSignalHandlers() {} +static void uninstallExceptionOrSignalHandlers() {} -// On Windows, we can make use of vectored exception handling to -// catch most crashing situations. Note that this does mean -// we will be alerted of exceptions *before* structured exception -// handling has the opportunity to catch it. But that isn't likely -// to cause problems because nowhere in the project is SEH being -// used. +bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { + if (!gCrashRecoveryEnabled) { + Fn(); + return true; + } + + bool Result = true; + __try { + Fn(); + } __except (1) { // Catch any exception. + Result = false; + } + return Result; +} + +#else // !_MSC_VER + +#if defined(LLVM_ON_WIN32) +// This is a non-MSVC compiler, probably mingw gcc or clang without +// -fms-extensions. Use vectored exception handling (VEH). +// +// On Windows, we can make use of vectored exception handling to catch most +// crashing situations. Note that this does mean we will be alerted of +// exceptions *before* structured exception handling has the opportunity to +// catch it. Unfortunately, this causes problems in practice with other code +// running on threads with LLVM crash recovery contexts, so we would like to +// eventually move away from VEH. // -// Vectored exception handling is built on top of SEH, and so it -// works on a per-thread basis. +// Vectored works on a per-thread basis, which is an advantage over +// SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have +// any native support for chaining exception handlers, but VEH allows more than +// one. // // The vectored exception handler functionality was added in Windows // XP, so if support for older versions of Windows is required, // it will have to be added. -// -// If we want to support as far back as Win2k, we could use the -// SetUnhandledExceptionFilter API, but there's a risk of that -// being entirely overwritten (it's not a chain). + +#include "Windows/WindowsSupport.h" static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { + // DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported + // compilers and platforms, so we define it manually. + constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL; + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) + { + case DBG_PRINTEXCEPTION_C: + case DbgPrintExceptionWideC: + case 0x406D1388: // set debugger thread name + return EXCEPTION_CONTINUE_EXECUTION; + } + // Lookup the current thread local recovery object. const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); @@ -192,14 +252,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) // non-NULL, valid VEH handles, or NULL. static sys::ThreadLocal<const void> sCurrentExceptionHandle; -void CrashRecoveryContext::Enable() { - sys::ScopedLock L(*gCrashRecoveryContextMutex); - - if (gCrashRecoveryEnabled) - return; - - gCrashRecoveryEnabled = true; - +static void installExceptionOrSignalHandlers() { // We can set up vectored exception handling now. We will install our // handler as the front of the list, though there's no assurances that // it will remain at the front (another call could install itself before @@ -208,14 +261,7 @@ void CrashRecoveryContext::Enable() { sCurrentExceptionHandle.set(handle); } -void CrashRecoveryContext::Disable() { - sys::ScopedLock L(*gCrashRecoveryContextMutex); - - if (!gCrashRecoveryEnabled) - return; - - gCrashRecoveryEnabled = false; - +static void uninstallExceptionOrSignalHandlers() { PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get()); if (currentHandle) { // Now we can remove the vectored exception handler from the chain @@ -226,7 +272,7 @@ void CrashRecoveryContext::Disable() { } } -#else +#else // !LLVM_ON_WIN32 // Generic POSIX implementation. // @@ -278,14 +324,7 @@ static void CrashRecoverySignalHandler(int Signal) { const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); } -void CrashRecoveryContext::Enable() { - sys::ScopedLock L(*gCrashRecoveryContextMutex); - - if (gCrashRecoveryEnabled) - return; - - gCrashRecoveryEnabled = true; - +static void installExceptionOrSignalHandlers() { // Setup the signal handler. struct sigaction Handler; Handler.sa_handler = CrashRecoverySignalHandler; @@ -297,20 +336,13 @@ void CrashRecoveryContext::Enable() { } } -void CrashRecoveryContext::Disable() { - sys::ScopedLock L(*gCrashRecoveryContextMutex); - - if (!gCrashRecoveryEnabled) - return; - - gCrashRecoveryEnabled = false; - +static void uninstallExceptionOrSignalHandlers() { // Restore the previous signal handlers. for (unsigned i = 0; i != NumSignals; ++i) sigaction(Signals[i], &PrevActions[i], nullptr); } -#endif +#endif // !LLVM_ON_WIN32 bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { // If crash recovery is disabled, do nothing. @@ -328,6 +360,8 @@ bool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { return true; } +#endif // !_MSC_VER + void CrashRecoveryContext::HandleCrash() { CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; assert(CRCI && "Crash recovery context never initialized!"); diff --git a/contrib/llvm/lib/Support/DataExtractor.cpp b/contrib/llvm/lib/Support/DataExtractor.cpp index 5d6d60a..0199b30 100644 --- a/contrib/llvm/lib/Support/DataExtractor.cpp +++ b/contrib/llvm/lib/Support/DataExtractor.cpp @@ -68,6 +68,13 @@ uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, Data.data()); } +uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const { + uint24_t ExtractedVal = + getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data()); + // The 3 bytes are in the correct byte order for the host. + return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); +} + uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data()); } @@ -128,6 +135,16 @@ const char *DataExtractor::getCStr(uint32_t *offset_ptr) const { return nullptr; } +StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const { + uint32_t Start = *OffsetPtr; + StringRef::size_type Pos = Data.find('\0', Start); + if (Pos != StringRef::npos) { + *OffsetPtr = Pos + 1; + return StringRef(Data.data() + Start, Pos - Start); + } + return StringRef(); +} + uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { uint64_t result = 0; if (Data.empty()) diff --git a/contrib/llvm/lib/Support/DebugCounter.cpp b/contrib/llvm/lib/Support/DebugCounter.cpp new file mode 100644 index 0000000..1d46de0 --- /dev/null +++ b/contrib/llvm/lib/Support/DebugCounter.cpp @@ -0,0 +1,114 @@ +#include "llvm/Support/DebugCounter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Options.h" + +using namespace llvm; + +namespace { +// This class overrides the default list implementation of printing so we +// can pretty print the list of debug counter options. This type of +// dynamic option is pretty rare (basically this and pass lists). +class DebugCounterList : public cl::list<std::string, DebugCounter> { +private: + using Base = cl::list<std::string, DebugCounter>; + +public: + template <class... Mods> + explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {} + +private: + void printOptionInfo(size_t GlobalWidth) const override { + // This is a variant of from generic_parser_base::printOptionInfo. Sadly, + // it's not easy to make it more usable. We could get it to print these as + // options if we were a cl::opt and registered them, but lists don't have + // options, nor does the parser for std::string. The other mechanisms for + // options are global and would pollute the global namespace with our + // counters. Rather than go that route, we have just overridden the + // printing, which only a few things call anyway. + outs() << " -" << ArgStr; + // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for + // width, so we do the same. + Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6); + const auto &CounterInstance = DebugCounter::instance(); + for (auto Name : CounterInstance) { + const auto Info = + CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name)); + size_t NumSpaces = GlobalWidth - Info.first.size() - 8; + outs() << " =" << Info.first; + outs().indent(NumSpaces) << " - " << Info.second << '\n'; + } + } +}; +} // namespace + +// Create our command line option. +static DebugCounterList DebugCounterOption( + "debug-counter", + cl::desc("Comma separated list of debug counter skip and count"), + cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance())); + +static ManagedStatic<DebugCounter> DC; + +DebugCounter &DebugCounter::instance() { return *DC; } + +// This is called by the command line parser when it sees a value for the +// debug-counter option defined above. +void DebugCounter::push_back(const std::string &Val) { + if (Val.empty()) + return; + // The strings should come in as counter=value + auto CounterPair = StringRef(Val).split('='); + if (CounterPair.second.empty()) { + errs() << "DebugCounter Error: " << Val << " does not have an = in it\n"; + return; + } + // Now we have counter=value. + // First, process value. + long CounterVal; + if (CounterPair.second.getAsInteger(0, CounterVal)) { + errs() << "DebugCounter Error: " << CounterPair.second + << " is not a number\n"; + return; + } + // Now we need to see if this is the skip or the count, remove the suffix, and + // add it to the counter values. + if (CounterPair.first.endswith("-skip")) { + auto CounterName = CounterPair.first.drop_back(5); + unsigned CounterID = RegisteredCounters.idFor(CounterName); + if (!CounterID) { + errs() << "DebugCounter Error: " << CounterName + << " is not a registered counter\n"; + return; + } + + auto Res = Counters.insert({CounterID, {0, -1}}); + Res.first->second.first = CounterVal; + } else if (CounterPair.first.endswith("-count")) { + auto CounterName = CounterPair.first.drop_back(6); + unsigned CounterID = RegisteredCounters.idFor(CounterName); + if (!CounterID) { + errs() << "DebugCounter Error: " << CounterName + << " is not a registered counter\n"; + return; + } + + auto Res = Counters.insert({CounterID, {0, -1}}); + Res.first->second.second = CounterVal; + } else { + errs() << "DebugCounter Error: " << CounterPair.first + << " does not end with -skip or -count\n"; + } +} + +void DebugCounter::print(raw_ostream &OS) const { + OS << "Counters and values:\n"; + for (const auto &KV : Counters) + OS << left_justify(RegisteredCounters[KV.first], 32) << ": {" + << KV.second.first << "," << KV.second.second << "}\n"; +} + +LLVM_DUMP_METHOD void DebugCounter::dump() const { + print(dbgs()); +} diff --git a/contrib/llvm/lib/Support/Dwarf.cpp b/contrib/llvm/lib/Support/Dwarf.cpp deleted file mode 100644 index 8950e8c..0000000 --- a/contrib/llvm/lib/Support/Dwarf.cpp +++ /dev/null @@ -1,385 +0,0 @@ -//===-- llvm/Support/Dwarf.cpp - Dwarf Framework ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains support for generic dwarf information. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Dwarf.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm; -using namespace dwarf; - -StringRef llvm::dwarf::TagString(unsigned Tag) { - switch (Tag) { - default: - return StringRef(); -#define HANDLE_DW_TAG(ID, NAME) \ - case DW_TAG_##NAME: \ - return "DW_TAG_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -unsigned llvm::dwarf::getTag(StringRef TagString) { - return StringSwitch<unsigned>(TagString) -#define HANDLE_DW_TAG(ID, NAME) .Case("DW_TAG_" #NAME, DW_TAG_##NAME) -#include "llvm/Support/Dwarf.def" - .Default(DW_TAG_invalid); -} - -StringRef llvm::dwarf::ChildrenString(unsigned Children) { - switch (Children) { - case DW_CHILDREN_no: return "DW_CHILDREN_no"; - case DW_CHILDREN_yes: return "DW_CHILDREN_yes"; - } - return StringRef(); -} - -StringRef llvm::dwarf::AttributeString(unsigned Attribute) { - switch (Attribute) { - default: - return StringRef(); -#define HANDLE_DW_AT(ID, NAME) \ - case DW_AT_##NAME: \ - return "DW_AT_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -StringRef llvm::dwarf::FormEncodingString(unsigned Encoding) { - switch (Encoding) { - default: - return StringRef(); -#define HANDLE_DW_FORM(ID, NAME) \ - case DW_FORM_##NAME: \ - return "DW_FORM_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) { - switch (Encoding) { - default: - return StringRef(); -#define HANDLE_DW_OP(ID, NAME) \ - case DW_OP_##NAME: \ - return "DW_OP_" #NAME; -#include "llvm/Support/Dwarf.def" - case DW_OP_LLVM_fragment: - return "DW_OP_LLVM_fragment"; - } -} - -unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) { - return StringSwitch<unsigned>(OperationEncodingString) -#define HANDLE_DW_OP(ID, NAME) .Case("DW_OP_" #NAME, DW_OP_##NAME) -#include "llvm/Support/Dwarf.def" - .Case("DW_OP_LLVM_fragment", DW_OP_LLVM_fragment) - .Default(0); -} - -StringRef llvm::dwarf::AttributeEncodingString(unsigned Encoding) { - switch (Encoding) { - default: - return StringRef(); -#define HANDLE_DW_ATE(ID, NAME) \ - case DW_ATE_##NAME: \ - return "DW_ATE_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -unsigned llvm::dwarf::getAttributeEncoding(StringRef EncodingString) { - return StringSwitch<unsigned>(EncodingString) -#define HANDLE_DW_ATE(ID, NAME) .Case("DW_ATE_" #NAME, DW_ATE_##NAME) -#include "llvm/Support/Dwarf.def" - .Default(0); -} - -StringRef llvm::dwarf::DecimalSignString(unsigned Sign) { - switch (Sign) { - case DW_DS_unsigned: return "DW_DS_unsigned"; - case DW_DS_leading_overpunch: return "DW_DS_leading_overpunch"; - case DW_DS_trailing_overpunch: return "DW_DS_trailing_overpunch"; - case DW_DS_leading_separate: return "DW_DS_leading_separate"; - case DW_DS_trailing_separate: return "DW_DS_trailing_separate"; - } - return StringRef(); -} - -StringRef llvm::dwarf::EndianityString(unsigned Endian) { - switch (Endian) { - case DW_END_default: return "DW_END_default"; - case DW_END_big: return "DW_END_big"; - case DW_END_little: return "DW_END_little"; - case DW_END_lo_user: return "DW_END_lo_user"; - case DW_END_hi_user: return "DW_END_hi_user"; - } - return StringRef(); -} - -StringRef llvm::dwarf::AccessibilityString(unsigned Access) { - switch (Access) { - // Accessibility codes - case DW_ACCESS_public: return "DW_ACCESS_public"; - case DW_ACCESS_protected: return "DW_ACCESS_protected"; - case DW_ACCESS_private: return "DW_ACCESS_private"; - } - return StringRef(); -} - -StringRef llvm::dwarf::VisibilityString(unsigned Visibility) { - switch (Visibility) { - case DW_VIS_local: return "DW_VIS_local"; - case DW_VIS_exported: return "DW_VIS_exported"; - case DW_VIS_qualified: return "DW_VIS_qualified"; - } - return StringRef(); -} - -StringRef llvm::dwarf::VirtualityString(unsigned Virtuality) { - switch (Virtuality) { - default: - return StringRef(); -#define HANDLE_DW_VIRTUALITY(ID, NAME) \ - case DW_VIRTUALITY_##NAME: \ - return "DW_VIRTUALITY_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -unsigned llvm::dwarf::getVirtuality(StringRef VirtualityString) { - return StringSwitch<unsigned>(VirtualityString) -#define HANDLE_DW_VIRTUALITY(ID, NAME) \ - .Case("DW_VIRTUALITY_" #NAME, DW_VIRTUALITY_##NAME) -#include "llvm/Support/Dwarf.def" - .Default(DW_VIRTUALITY_invalid); -} - -StringRef llvm::dwarf::LanguageString(unsigned Language) { - switch (Language) { - default: - return StringRef(); -#define HANDLE_DW_LANG(ID, NAME) \ - case DW_LANG_##NAME: \ - return "DW_LANG_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -unsigned llvm::dwarf::getLanguage(StringRef LanguageString) { - return StringSwitch<unsigned>(LanguageString) -#define HANDLE_DW_LANG(ID, NAME) .Case("DW_LANG_" #NAME, DW_LANG_##NAME) -#include "llvm/Support/Dwarf.def" - .Default(0); -} - -StringRef llvm::dwarf::CaseString(unsigned Case) { - switch (Case) { - case DW_ID_case_sensitive: return "DW_ID_case_sensitive"; - case DW_ID_up_case: return "DW_ID_up_case"; - case DW_ID_down_case: return "DW_ID_down_case"; - case DW_ID_case_insensitive: return "DW_ID_case_insensitive"; - } - return StringRef(); -} - -StringRef llvm::dwarf::ConventionString(unsigned CC) { - switch (CC) { - default: - return StringRef(); -#define HANDLE_DW_CC(ID, NAME) \ - case DW_CC_##NAME: \ - return "DW_CC_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -unsigned llvm::dwarf::getCallingConvention(StringRef CCString) { - return StringSwitch<unsigned>(CCString) -#define HANDLE_DW_CC(ID, NAME) .Case("DW_CC_" #NAME, DW_CC_##NAME) -#include "llvm/Support/Dwarf.def" - .Default(0); -} - -StringRef llvm::dwarf::InlineCodeString(unsigned Code) { - switch (Code) { - case DW_INL_not_inlined: return "DW_INL_not_inlined"; - case DW_INL_inlined: return "DW_INL_inlined"; - case DW_INL_declared_not_inlined: return "DW_INL_declared_not_inlined"; - case DW_INL_declared_inlined: return "DW_INL_declared_inlined"; - } - return StringRef(); -} - -StringRef llvm::dwarf::ArrayOrderString(unsigned Order) { - switch (Order) { - case DW_ORD_row_major: return "DW_ORD_row_major"; - case DW_ORD_col_major: return "DW_ORD_col_major"; - } - return StringRef(); -} - -StringRef llvm::dwarf::DiscriminantString(unsigned Discriminant) { - switch (Discriminant) { - case DW_DSC_label: return "DW_DSC_label"; - case DW_DSC_range: return "DW_DSC_range"; - } - return StringRef(); -} - -StringRef llvm::dwarf::LNStandardString(unsigned Standard) { - switch (Standard) { - default: - return StringRef(); -#define HANDLE_DW_LNS(ID, NAME) \ - case DW_LNS_##NAME: \ - return "DW_LNS_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -StringRef llvm::dwarf::LNExtendedString(unsigned Encoding) { - switch (Encoding) { - default: - return StringRef(); -#define HANDLE_DW_LNE(ID, NAME) \ - case DW_LNE_##NAME: \ - return "DW_LNE_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -StringRef llvm::dwarf::MacinfoString(unsigned Encoding) { - switch (Encoding) { - // Macinfo Type Encodings - case DW_MACINFO_define: return "DW_MACINFO_define"; - case DW_MACINFO_undef: return "DW_MACINFO_undef"; - case DW_MACINFO_start_file: return "DW_MACINFO_start_file"; - case DW_MACINFO_end_file: return "DW_MACINFO_end_file"; - case DW_MACINFO_vendor_ext: return "DW_MACINFO_vendor_ext"; - case DW_MACINFO_invalid: return "DW_MACINFO_invalid"; - } - return StringRef(); -} - -unsigned llvm::dwarf::getMacinfo(StringRef MacinfoString) { - return StringSwitch<unsigned>(MacinfoString) - .Case("DW_MACINFO_define", DW_MACINFO_define) - .Case("DW_MACINFO_undef", DW_MACINFO_undef) - .Case("DW_MACINFO_start_file", DW_MACINFO_start_file) - .Case("DW_MACINFO_end_file", DW_MACINFO_end_file) - .Case("DW_MACINFO_vendor_ext", DW_MACINFO_vendor_ext) - .Default(DW_MACINFO_invalid); -} - -StringRef llvm::dwarf::CallFrameString(unsigned Encoding) { - switch (Encoding) { - default: - return StringRef(); -#define HANDLE_DW_CFA(ID, NAME) \ - case DW_CFA_##NAME: \ - return "DW_CFA_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -StringRef llvm::dwarf::ApplePropertyString(unsigned Prop) { - switch (Prop) { - default: - return StringRef(); -#define HANDLE_DW_APPLE_PROPERTY(ID, NAME) \ - case DW_APPLE_PROPERTY_##NAME: \ - return "DW_APPLE_PROPERTY_" #NAME; -#include "llvm/Support/Dwarf.def" - } -} - -StringRef llvm::dwarf::AtomTypeString(unsigned AT) { - switch (AT) { - case dwarf::DW_ATOM_null: - return "DW_ATOM_null"; - case dwarf::DW_ATOM_die_offset: - return "DW_ATOM_die_offset"; - case DW_ATOM_cu_offset: - return "DW_ATOM_cu_offset"; - case DW_ATOM_die_tag: - return "DW_ATOM_die_tag"; - case DW_ATOM_type_flags: - return "DW_ATOM_type_flags"; - } - return StringRef(); -} - -StringRef llvm::dwarf::GDBIndexEntryKindString(GDBIndexEntryKind Kind) { - switch (Kind) { - case GIEK_NONE: - return "NONE"; - case GIEK_TYPE: - return "TYPE"; - case GIEK_VARIABLE: - return "VARIABLE"; - case GIEK_FUNCTION: - return "FUNCTION"; - case GIEK_OTHER: - return "OTHER"; - case GIEK_UNUSED5: - return "UNUSED5"; - case GIEK_UNUSED6: - return "UNUSED6"; - case GIEK_UNUSED7: - return "UNUSED7"; - } - llvm_unreachable("Unknown GDBIndexEntryKind value"); -} - -StringRef -llvm::dwarf::GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage) { - switch (Linkage) { - case GIEL_EXTERNAL: - return "EXTERNAL"; - case GIEL_STATIC: - return "STATIC"; - } - llvm_unreachable("Unknown GDBIndexEntryLinkage value"); -} - -StringRef llvm::dwarf::AttributeValueString(uint16_t Attr, unsigned Val) { - switch (Attr) { - case DW_AT_accessibility: - return AccessibilityString(Val); - case DW_AT_virtuality: - return VirtualityString(Val); - case DW_AT_language: - return LanguageString(Val); - case DW_AT_encoding: - return AttributeEncodingString(Val); - case DW_AT_decimal_sign: - return DecimalSignString(Val); - case DW_AT_endianity: - return EndianityString(Val); - case DW_AT_visibility: - return VisibilityString(Val); - case DW_AT_identifier_case: - return CaseString(Val); - case DW_AT_calling_convention: - return ConventionString(Val); - case DW_AT_inline: - return InlineCodeString(Val); - case DW_AT_ordering: - return ArrayOrderString(Val); - case DW_AT_discr_value: - return DiscriminantString(Val); - } - - return StringRef(); -} diff --git a/contrib/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm/lib/Support/DynamicLibrary.cpp index ced21e4..d842211 100644 --- a/contrib/llvm/lib/Support/DynamicLibrary.cpp +++ b/contrib/llvm/lib/Support/DynamicLibrary.cpp @@ -9,173 +9,201 @@ // // This file implements the operating system DynamicLibrary concept. // -// FIXME: This file leaks ExplicitSymbols and OpenedHandles! -// //===----------------------------------------------------------------------===// #include "llvm/Support/DynamicLibrary.h" #include "llvm-c/Support.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/Config/config.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include <cstdio> #include <cstring> +#include <vector> -// Collection of symbol name/value pairs to be searched prior to any libraries. -static llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols; -static llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex; - -void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName, - void *symbolValue) { - SmartScopedLock<true> lock(*SymbolsMutex); - (*ExplicitSymbols)[symbolName] = symbolValue; -} - -char llvm::sys::DynamicLibrary::Invalid = 0; - -#ifdef LLVM_ON_WIN32 - -#include "Windows/DynamicLibrary.inc" - -#else - -#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) -#include <dlfcn.h> using namespace llvm; using namespace llvm::sys; -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// +// All methods for HandleSet should be used holding SymbolsMutex. +class DynamicLibrary::HandleSet { + typedef std::vector<void *> HandleList; + HandleList Handles; + void *Process; -static DenseSet<void *> *OpenedHandles = nullptr; +public: + static void *DLOpen(const char *Filename, std::string *Err); + static void DLClose(void *Handle); + static void *DLSym(void *Handle, const char *Symbol); -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, - std::string *errMsg) { - SmartScopedLock<true> lock(*SymbolsMutex); + HandleSet() : Process(nullptr) {} + ~HandleSet(); - void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL); - if (!handle) { - if (errMsg) *errMsg = dlerror(); - return DynamicLibrary(); + HandleList::iterator Find(void *Handle) { + return std::find(Handles.begin(), Handles.end(), Handle); } -#ifdef __CYGWIN__ - // Cygwin searches symbols only in the main - // with the handle of dlopen(NULL, RTLD_GLOBAL). - if (!filename) - handle = RTLD_DEFAULT; + bool Contains(void *Handle) { + return Handle == Process || Find(Handle) != Handles.end(); + } + + bool AddLibrary(void *Handle, bool IsProcess = false, bool CanClose = true) { +#ifdef LLVM_ON_WIN32 + assert((Handle == this ? IsProcess : !IsProcess) && "Bad Handle."); #endif - if (!OpenedHandles) - OpenedHandles = new DenseSet<void *>(); + if (LLVM_LIKELY(!IsProcess)) { + if (Find(Handle) != Handles.end()) { + if (CanClose) + DLClose(Handle); + return false; + } + Handles.push_back(Handle); + } else { +#ifndef LLVM_ON_WIN32 + if (Process) { + if (CanClose) + DLClose(Process); + if (Process == Handle) + return false; + } +#endif + Process = Handle; + } + return true; + } - // If we've already loaded this library, dlclose() the handle in order to - // keep the internal refcount at +1. - if (!OpenedHandles->insert(handle).second) - dlclose(handle); + void *LibLookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { + if (Order & SO_LoadOrder) { + for (void *Handle : Handles) { + if (void *Ptr = DLSym(Handle, Symbol)) + return Ptr; + } + } else { + for (void *Handle : llvm::reverse(Handles)) { + if (void *Ptr = DLSym(Handle, Symbol)) + return Ptr; + } + } + return nullptr; + } - return DynamicLibrary(handle); -} + void *Lookup(const char *Symbol, DynamicLibrary::SearchOrdering Order) { + assert(!((Order & SO_LoadedFirst) && (Order & SO_LoadedLast)) && + "Invalid Ordering"); -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { - if (!isValid()) + if (!Process || (Order & SO_LoadedFirst)) { + if (void *Ptr = LibLookup(Symbol, Order)) + return Ptr; + } + if (Process) { + // Use OS facilities to search the current binary and all loaded libs. + if (void *Ptr = DLSym(Process, Symbol)) + return Ptr; + + // Search any libs that might have been skipped because of RTLD_LOCAL. + if (Order & SO_LoadedLast) { + if (void *Ptr = LibLookup(Symbol, Order)) + return Ptr; + } + } return nullptr; - return dlsym(Data, symbolName); + } +}; + +namespace { +// Collection of symbol name/value pairs to be searched prior to any libraries. +static llvm::ManagedStatic<llvm::StringMap<void *>> ExplicitSymbols; +// Collection of known library handles. +static llvm::ManagedStatic<DynamicLibrary::HandleSet> OpenedHandles; +// Lock for ExplicitSymbols and OpenedHandles. +static llvm::ManagedStatic<llvm::sys::SmartMutex<true>> SymbolsMutex; } -#else +#ifdef LLVM_ON_WIN32 -using namespace llvm; -using namespace llvm::sys; +#include "Windows/DynamicLibrary.inc" -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, - std::string *errMsg) { - if (errMsg) *errMsg = "dlopen() not supported on this platform"; - return DynamicLibrary(); -} +#else -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { - return NULL; -} +#include "Unix/DynamicLibrary.inc" #endif +char DynamicLibrary::Invalid; +DynamicLibrary::SearchOrdering DynamicLibrary::SearchOrder = + DynamicLibrary::SO_Linker; + namespace llvm { -void *SearchForAddressOfSpecialSymbol(const char* symbolName); +void *SearchForAddressOfSpecialSymbol(const char *SymbolName) { + return DoSearch(SymbolName); // DynamicLibrary.inc +} } -void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) { +void DynamicLibrary::AddSymbol(StringRef SymbolName, void *SymbolValue) { SmartScopedLock<true> Lock(*SymbolsMutex); + (*ExplicitSymbols)[SymbolName] = SymbolValue; +} - // First check symbols added via AddSymbol(). - if (ExplicitSymbols.isConstructed()) { - StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); +DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, + std::string *Err) { + // Force OpenedHandles to be added into the ManagedStatic list before any + // ManagedStatic can be added from static constructors in HandleSet::DLOpen. + HandleSet& HS = *OpenedHandles; - if (i != ExplicitSymbols->end()) - return i->second; + void *Handle = HandleSet::DLOpen(FileName, Err); + if (Handle != &Invalid) { + SmartScopedLock<true> Lock(*SymbolsMutex); + HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); } -#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) - // Now search the libraries. - if (OpenedHandles) { - for (DenseSet<void *>::iterator I = OpenedHandles->begin(), - E = OpenedHandles->end(); I != E; ++I) { - //lt_ptr ptr = lt_dlsym(*I, symbolName); - void *ptr = dlsym(*I, symbolName); - if (ptr) { - return ptr; - } - } - } -#endif + return DynamicLibrary(Handle); +} - if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) - return Result; +DynamicLibrary DynamicLibrary::addPermanentLibrary(void *Handle, + std::string *Err) { + SmartScopedLock<true> Lock(*SymbolsMutex); + // If we've already loaded this library, tell the caller. + if (!OpenedHandles->AddLibrary(Handle, /*IsProcess*/false, /*CanClose*/false)) + *Err = "Library already loaded"; -// This macro returns the address of a well-known, explicit symbol -#define EXPLICIT_SYMBOL(SYM) \ - if (!strcmp(symbolName, #SYM)) return &SYM + return DynamicLibrary(Handle); +} -// On linux we have a weird situation. The stderr/out/in symbols are both -// macros and global variables because of standards requirements. So, we -// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. -#if defined(__linux__) and !defined(__ANDROID__) - { - EXPLICIT_SYMBOL(stderr); - EXPLICIT_SYMBOL(stdout); - EXPLICIT_SYMBOL(stdin); - } -#else - // For everything else, we want to check to make sure the symbol isn't defined - // as a macro before using EXPLICIT_SYMBOL. +void *DynamicLibrary::getAddressOfSymbol(const char *SymbolName) { + if (!isValid()) + return nullptr; + return HandleSet::DLSym(Data, SymbolName); +} + +void *DynamicLibrary::SearchForAddressOfSymbol(const char *SymbolName) { { -#ifndef stdin - EXPLICIT_SYMBOL(stdin); -#endif -#ifndef stdout - EXPLICIT_SYMBOL(stdout); -#endif -#ifndef stderr - EXPLICIT_SYMBOL(stderr); -#endif + SmartScopedLock<true> Lock(*SymbolsMutex); + + // First check symbols added via AddSymbol(). + if (ExplicitSymbols.isConstructed()) { + StringMap<void *>::iterator i = ExplicitSymbols->find(SymbolName); + + if (i != ExplicitSymbols->end()) + return i->second; + } + + // Now search the libraries. + if (OpenedHandles.isConstructed()) { + if (void *Ptr = OpenedHandles->Lookup(SymbolName, SearchOrder)) + return Ptr; + } } -#endif -#undef EXPLICIT_SYMBOL - return nullptr; + return llvm::SearchForAddressOfSpecialSymbol(SymbolName); } -#endif // LLVM_ON_WIN32 - //===----------------------------------------------------------------------===// // C API. //===----------------------------------------------------------------------===// -LLVMBool LLVMLoadLibraryPermanently(const char* Filename) { +LLVMBool LLVMLoadLibraryPermanently(const char *Filename) { return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename); } @@ -186,4 +214,3 @@ void *LLVMSearchForAddressOfSymbol(const char *symbolName) { void LLVMAddSymbol(const char *symbolName, void *symbolValue) { return llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolValue); } - diff --git a/contrib/llvm/lib/Support/Errno.cpp b/contrib/llvm/lib/Support/Errno.cpp index 3ba2a12..10be9b3 100644 --- a/contrib/llvm/lib/Support/Errno.cpp +++ b/contrib/llvm/lib/Support/Errno.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Errno.h" -#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/raw_ostream.h" #include <string.h> diff --git a/contrib/llvm/lib/Support/Error.cpp b/contrib/llvm/lib/Support/Error.cpp index 4730c0b..bb02c03 100644 --- a/contrib/llvm/lib/Support/Error.cpp +++ b/contrib/llvm/lib/Support/Error.cpp @@ -13,7 +13,6 @@ #include "llvm/Support/ManagedStatic.h" #include <system_error> - using namespace llvm; namespace { diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp index a7d3a18..fb8ae4c 100644 --- a/contrib/llvm/lib/Support/ErrorHandling.cpp +++ b/contrib/llvm/lib/Support/ErrorHandling.cpp @@ -20,15 +20,14 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/MutexGuard.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" #include "llvm/Support/WindowsError.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdlib> +#include <mutex> +#include <new> #if defined(HAVE_UNISTD_H) # include <unistd.h> @@ -43,18 +42,39 @@ using namespace llvm; static fatal_error_handler_t ErrorHandler = nullptr; static void *ErrorHandlerUserData = nullptr; -static ManagedStatic<sys::Mutex> ErrorHandlerMutex; +static fatal_error_handler_t BadAllocErrorHandler = nullptr; +static void *BadAllocErrorHandlerUserData = nullptr; + +#if LLVM_ENABLE_THREADS == 1 +// Mutexes to synchronize installing error handlers and calling error handlers. +// Do not use ManagedStatic, or that may allocate memory while attempting to +// report an OOM. +// +// This usage of std::mutex has to be conditionalized behind ifdefs because +// of this script: +// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh +// That script attempts to statically link the LLVM symbolizer library with the +// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it +// cuts out the threading portions of the hermetic copy of libc++ that it +// builds. We can remove these ifdefs if that script goes away. +static std::mutex ErrorHandlerMutex; +static std::mutex BadAllocErrorHandlerMutex; +#endif void llvm::install_fatal_error_handler(fatal_error_handler_t handler, void *user_data) { - llvm::MutexGuard Lock(*ErrorHandlerMutex); +#if LLVM_ENABLE_THREADS == 1 + std::lock_guard<std::mutex> Lock(ErrorHandlerMutex); +#endif assert(!ErrorHandler && "Error handler already registered!\n"); ErrorHandler = handler; ErrorHandlerUserData = user_data; } void llvm::remove_fatal_error_handler() { - llvm::MutexGuard Lock(*ErrorHandlerMutex); +#if LLVM_ENABLE_THREADS == 1 + std::lock_guard<std::mutex> Lock(ErrorHandlerMutex); +#endif ErrorHandler = nullptr; ErrorHandlerUserData = nullptr; } @@ -77,7 +97,9 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) { { // Only acquire the mutex while reading the handler, so as not to invoke a // user-supplied callback under a lock. - llvm::MutexGuard Lock(*ErrorHandlerMutex); +#if LLVM_ENABLE_THREADS == 1 + std::lock_guard<std::mutex> Lock(ErrorHandlerMutex); +#endif handler = ErrorHandler; handlerData = ErrorHandlerUserData; } @@ -104,6 +126,55 @@ void llvm::report_fatal_error(const Twine &Reason, bool GenCrashDiag) { exit(1); } +void llvm::install_bad_alloc_error_handler(fatal_error_handler_t handler, + void *user_data) { +#if LLVM_ENABLE_THREADS == 1 + std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex); +#endif + assert(!ErrorHandler && "Bad alloc error handler already registered!\n"); + BadAllocErrorHandler = handler; + BadAllocErrorHandlerUserData = user_data; +} + +void llvm::remove_bad_alloc_error_handler() { +#if LLVM_ENABLE_THREADS == 1 + std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex); +#endif + BadAllocErrorHandler = nullptr; + BadAllocErrorHandlerUserData = nullptr; +} + +void llvm::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) { + fatal_error_handler_t Handler = nullptr; + void *HandlerData = nullptr; + { + // Only acquire the mutex while reading the handler, so as not to invoke a + // user-supplied callback under a lock. +#if LLVM_ENABLE_THREADS == 1 + std::lock_guard<std::mutex> Lock(BadAllocErrorHandlerMutex); +#endif + Handler = BadAllocErrorHandler; + HandlerData = BadAllocErrorHandlerUserData; + } + + if (Handler) { + Handler(HandlerData, Reason, GenCrashDiag); + llvm_unreachable("bad alloc handler should not return"); + } + +#ifdef LLVM_ENABLE_EXCEPTIONS + // If exceptions are enabled, make OOM in malloc look like OOM in new. + throw std::bad_alloc(); +#else + // Don't call the normal error handler. It may allocate memory. Directly write + // an OOM to stderr and abort. + char OOMMessage[] = "LLVM ERROR: out of memory\n"; + ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage)); + (void)written; + abort(); +#endif +} + void llvm::llvm_unreachable_internal(const char *msg, const char *file, unsigned line) { // This code intentionally doesn't call the ErrorHandler callback, because diff --git a/contrib/llvm/lib/Support/FileOutputBuffer.cpp b/contrib/llvm/lib/Support/FileOutputBuffer.cpp index 57e5a8d..731740d 100644 --- a/contrib/llvm/lib/Support/FileOutputBuffer.cpp +++ b/contrib/llvm/lib/Support/FileOutputBuffer.cpp @@ -57,6 +57,8 @@ FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) { // FIXME: In posix, you use the access() call to check this. } break; + case sys::fs::file_type::directory_file: + return errc::is_a_directory; default: if (EC) return EC; diff --git a/contrib/llvm/lib/Support/FoldingSet.cpp b/contrib/llvm/lib/Support/FoldingSet.cpp index c9bca7f..4496d06 100644 --- a/contrib/llvm/lib/Support/FoldingSet.cpp +++ b/contrib/llvm/lib/Support/FoldingSet.cpp @@ -26,7 +26,7 @@ using namespace llvm; // FoldingSetNodeIDRef Implementation /// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, -/// used to lookup the node in the FoldingSetImpl. +/// used to lookup the node in the FoldingSetBase. unsigned FoldingSetNodeIDRef::ComputeHash() const { return static_cast<unsigned>(hash_combine_range(Data, Data+Size)); } @@ -142,7 +142,7 @@ void FoldingSetNodeID::AddNodeID(const FoldingSetNodeID &ID) { } /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used to -/// lookup the node in the FoldingSetImpl. +/// lookup the node in the FoldingSetBase. unsigned FoldingSetNodeID::ComputeHash() const { return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash(); } @@ -180,7 +180,7 @@ FoldingSetNodeID::Intern(BumpPtrAllocator &Allocator) const { } //===----------------------------------------------------------------------===// -/// Helper functions for FoldingSetImpl. +/// Helper functions for FoldingSetBase. /// GetNextPtr - In order to save space, each bucket is a /// singly-linked-list. In order to make deletion more efficient, we make @@ -188,12 +188,12 @@ FoldingSetNodeID::Intern(BumpPtrAllocator &Allocator) const { /// The problem with this is that the start of the hash buckets are not /// Nodes. If NextInBucketPtr is a bucket pointer, this method returns null: /// use GetBucketPtr when this happens. -static FoldingSetImpl::Node *GetNextPtr(void *NextInBucketPtr) { +static FoldingSetBase::Node *GetNextPtr(void *NextInBucketPtr) { // The low bit is set if this is the pointer back to the bucket. if (reinterpret_cast<intptr_t>(NextInBucketPtr) & 1) return nullptr; - return static_cast<FoldingSetImpl::Node*>(NextInBucketPtr); + return static_cast<FoldingSetBase::Node*>(NextInBucketPtr); } @@ -221,11 +221,11 @@ static void **AllocateBuckets(unsigned NumBuckets) { } //===----------------------------------------------------------------------===// -// FoldingSetImpl Implementation +// FoldingSetBase Implementation -void FoldingSetImpl::anchor() {} +void FoldingSetBase::anchor() {} -FoldingSetImpl::FoldingSetImpl(unsigned Log2InitSize) { +FoldingSetBase::FoldingSetBase(unsigned Log2InitSize) { assert(5 < Log2InitSize && Log2InitSize < 32 && "Initial hash table size out of range"); NumBuckets = 1 << Log2InitSize; @@ -233,14 +233,14 @@ FoldingSetImpl::FoldingSetImpl(unsigned Log2InitSize) { NumNodes = 0; } -FoldingSetImpl::FoldingSetImpl(FoldingSetImpl &&Arg) +FoldingSetBase::FoldingSetBase(FoldingSetBase &&Arg) : Buckets(Arg.Buckets), NumBuckets(Arg.NumBuckets), NumNodes(Arg.NumNodes) { Arg.Buckets = nullptr; Arg.NumBuckets = 0; Arg.NumNodes = 0; } -FoldingSetImpl &FoldingSetImpl::operator=(FoldingSetImpl &&RHS) { +FoldingSetBase &FoldingSetBase::operator=(FoldingSetBase &&RHS) { free(Buckets); // This may be null if the set is in a moved-from state. Buckets = RHS.Buckets; NumBuckets = RHS.NumBuckets; @@ -251,11 +251,11 @@ FoldingSetImpl &FoldingSetImpl::operator=(FoldingSetImpl &&RHS) { return *this; } -FoldingSetImpl::~FoldingSetImpl() { +FoldingSetBase::~FoldingSetBase() { free(Buckets); } -void FoldingSetImpl::clear() { +void FoldingSetBase::clear() { // Set all but the last bucket to null pointers. memset(Buckets, 0, NumBuckets*sizeof(void*)); @@ -266,7 +266,7 @@ void FoldingSetImpl::clear() { NumNodes = 0; } -void FoldingSetImpl::GrowBucketCount(unsigned NewBucketCount) { +void FoldingSetBase::GrowBucketCount(unsigned NewBucketCount) { assert((NewBucketCount > NumBuckets) && "Can't shrink a folding set with GrowBucketCount"); assert(isPowerOf2_32(NewBucketCount) && "Bad bucket count!"); void **OldBuckets = Buckets; @@ -300,11 +300,11 @@ void FoldingSetImpl::GrowBucketCount(unsigned NewBucketCount) { /// GrowHashTable - Double the size of the hash table and rehash everything. /// -void FoldingSetImpl::GrowHashTable() { +void FoldingSetBase::GrowHashTable() { GrowBucketCount(NumBuckets * 2); } -void FoldingSetImpl::reserve(unsigned EltCount) { +void FoldingSetBase::reserve(unsigned EltCount) { // This will give us somewhere between EltCount / 2 and // EltCount buckets. This puts us in the load factor // range of 1.0 - 2.0. @@ -316,9 +316,9 @@ void FoldingSetImpl::reserve(unsigned EltCount) { /// FindNodeOrInsertPos - Look up the node specified by ID. If it exists, /// return it. If not, return the insertion token that will make insertion /// faster. -FoldingSetImpl::Node -*FoldingSetImpl::FindNodeOrInsertPos(const FoldingSetNodeID &ID, - void *&InsertPos) { +FoldingSetBase::Node * +FoldingSetBase::FindNodeOrInsertPos(const FoldingSetNodeID &ID, + void *&InsertPos) { unsigned IDHash = ID.ComputeHash(); void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets); void *Probe = *Bucket; @@ -342,7 +342,7 @@ FoldingSetImpl::Node /// 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 FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { +void FoldingSetBase::InsertNode(Node *N, void *InsertPos) { assert(!N->getNextInBucket()); // Do we need to grow the hashtable? if (NumNodes+1 > capacity()) { @@ -371,7 +371,7 @@ void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { /// RemoveNode - Remove a node from the folding set, returning true if one was /// removed or false if the node was not in the folding set. -bool FoldingSetImpl::RemoveNode(Node *N) { +bool FoldingSetBase::RemoveNode(Node *N) { // Because each bucket is a circular list, we don't need to compute N's hash // to remove it. void *Ptr = N->getNextInBucket(); @@ -412,7 +412,7 @@ bool FoldingSetImpl::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. -FoldingSetImpl::Node *FoldingSetImpl::GetOrInsertNode(FoldingSetImpl::Node *N) { +FoldingSetBase::Node *FoldingSetBase::GetOrInsertNode(FoldingSetBase::Node *N) { FoldingSetNodeID ID; GetNodeProfile(N, ID); void *IP; diff --git a/contrib/llvm/lib/Support/FormattedStream.cpp b/contrib/llvm/lib/Support/FormattedStream.cpp index 2ed71c7..a9f4409 100644 --- a/contrib/llvm/lib/Support/FormattedStream.cpp +++ b/contrib/llvm/lib/Support/FormattedStream.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -32,6 +32,7 @@ static void UpdatePosition(std::pair<unsigned, unsigned> &Position, const char * switch (*Ptr) { case '\n': Line += 1; + LLVM_FALLTHROUGH; case '\r': Column = 0; break; diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp index d0e1d50..e04bd8b 100644 --- a/contrib/llvm/lib/Support/GraphWriter.cpp +++ b/contrib/llvm/lib/Support/GraphWriter.cpp @@ -1,4 +1,4 @@ -//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===// +//===- GraphWriter.cpp - Implements GraphWriter support routines ----------===// // // The LLVM Compiler Infrastructure // @@ -12,10 +12,22 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/GraphWriter.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <system_error> +#include <string> +#include <vector> + using namespace llvm; static cl::opt<bool> ViewBackground("view-background", cl::Hidden, @@ -43,6 +55,7 @@ std::string llvm::DOT::EscapeString(const std::string &Label) { Str.erase(Str.begin()+i); continue; default: break; } + LLVM_FALLTHROUGH; case '{': case '}': case '<': case '>': case '|': case '"': @@ -98,8 +111,10 @@ static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args, } namespace { + struct GraphSession { std::string LogBuffer; + bool TryFindProgram(StringRef Names, std::string &ProgramPath) { raw_string_ostream Log(LogBuffer); SmallVector<StringRef, 8> parts; @@ -114,7 +129,8 @@ struct GraphSession { return false; } }; -} // namespace + +} // end anonymous namespace static const char *getProgramName(GraphProgram::Name program) { switch (program) { diff --git a/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp index d1b4041..5cf0316 100644 --- a/contrib/llvm/lib/Support/Host.cpp +++ b/contrib/llvm/lib/Support/Host.cpp @@ -52,25 +52,220 @@ using namespace llvm; -#if defined(__linux__) -static ssize_t LLVM_ATTRIBUTE_UNUSED readCpuInfo(void *Buf, size_t Size) { - // Note: We cannot mmap /proc/cpuinfo here and then process the resulting - // memory buffer because the 'file' has 0 size (it can be read from only - // as a stream). - - int FD; - std::error_code EC = sys::fs::openFileForRead("/proc/cpuinfo", FD); - if (EC) { - DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << EC.message() << "\n"); - return -1; +static std::unique_ptr<llvm::MemoryBuffer> + LLVM_ATTRIBUTE_UNUSED getProcCpuinfoContent() { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo"); + if (std::error_code EC = Text.getError()) { + llvm::errs() << "Can't read " + << "/proc/cpuinfo: " << EC.message() << "\n"; + return nullptr; } - int Ret = read(FD, Buf, Size); - int CloseStatus = close(FD); - if (CloseStatus) - return -1; - return Ret; + return std::move(*Text); +} + +StringRef sys::detail::getHostCPUNameForPowerPC( + const StringRef &ProcCpuinfoContent) { + // Access to the Processor Version Register (PVR) on PowerPC is privileged, + // and so we must use an operating-system interface to determine the current + // processor type. On Linux, this is exposed through the /proc/cpuinfo file. + const char *generic = "generic"; + + // The cpu line is second (after the 'processor: 0' line), so if this + // buffer is too small then something has changed (or is wrong). + StringRef::const_iterator CPUInfoStart = ProcCpuinfoContent.begin(); + StringRef::const_iterator CPUInfoEnd = ProcCpuinfoContent.end(); + + StringRef::const_iterator CIP = CPUInfoStart; + + StringRef::const_iterator CPUStart = 0; + size_t CPULen = 0; + + // We need to find the first line which starts with cpu, spaces, and a colon. + // After the colon, there may be some additional spaces and then the cpu type. + while (CIP < CPUInfoEnd && CPUStart == 0) { + if (CIP < CPUInfoEnd && *CIP == '\n') + ++CIP; + + if (CIP < CPUInfoEnd && *CIP == 'c') { + ++CIP; + if (CIP < CPUInfoEnd && *CIP == 'p') { + ++CIP; + if (CIP < CPUInfoEnd && *CIP == 'u') { + ++CIP; + while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) + ++CIP; + + if (CIP < CPUInfoEnd && *CIP == ':') { + ++CIP; + while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) + ++CIP; + + if (CIP < CPUInfoEnd) { + CPUStart = CIP; + while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && + *CIP != ',' && *CIP != '\n')) + ++CIP; + CPULen = CIP - CPUStart; + } + } + } + } + } + + if (CPUStart == 0) + while (CIP < CPUInfoEnd && *CIP != '\n') + ++CIP; + } + + if (CPUStart == 0) + return generic; + + return StringSwitch<const char *>(StringRef(CPUStart, CPULen)) + .Case("604e", "604e") + .Case("604", "604") + .Case("7400", "7400") + .Case("7410", "7400") + .Case("7447", "7400") + .Case("7455", "7450") + .Case("G4", "g4") + .Case("POWER4", "970") + .Case("PPC970FX", "970") + .Case("PPC970MP", "970") + .Case("G5", "g5") + .Case("POWER5", "g5") + .Case("A2", "a2") + .Case("POWER6", "pwr6") + .Case("POWER7", "pwr7") + .Case("POWER8", "pwr8") + .Case("POWER8E", "pwr8") + .Case("POWER8NVL", "pwr8") + .Case("POWER9", "pwr9") + .Default(generic); +} + +StringRef sys::detail::getHostCPUNameForARM( + const StringRef &ProcCpuinfoContent) { + // The cpuid register on arm is not accessible from user space. On Linux, + // it is exposed through the /proc/cpuinfo file. + + // Read 32 lines from /proc/cpuinfo, which should contain the CPU part line + // in all cases. + SmallVector<StringRef, 32> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for the CPU implementer line. + StringRef Implementer; + StringRef Hardware; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("CPU implementer")) + Implementer = Lines[I].substr(15).ltrim("\t :"); + if (Lines[I].startswith("Hardware")) + Hardware = Lines[I].substr(8).ltrim("\t :"); + } + + if (Implementer == "0x41") { // ARM Ltd. + // MSM8992/8994 may give cpu part for the core that the kernel is running on, + // which is undeterministic and wrong. Always return cortex-a53 for these SoC. + if (Hardware.endswith("MSM8994") || Hardware.endswith("MSM8996")) + return "cortex-a53"; + + + // Look for the CPU part line. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("CPU part")) + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) + .Case("0x926", "arm926ej-s") + .Case("0xb02", "mpcore") + .Case("0xb36", "arm1136j-s") + .Case("0xb56", "arm1156t2-s") + .Case("0xb76", "arm1176jz-s") + .Case("0xc08", "cortex-a8") + .Case("0xc09", "cortex-a9") + .Case("0xc0f", "cortex-a15") + .Case("0xc20", "cortex-m0") + .Case("0xc23", "cortex-m3") + .Case("0xc24", "cortex-m4") + .Case("0xd04", "cortex-a35") + .Case("0xd03", "cortex-a53") + .Case("0xd07", "cortex-a57") + .Case("0xd08", "cortex-a72") + .Case("0xd09", "cortex-a73") + .Default("generic"); + } + + if (Implementer == "0x51") // Qualcomm Technologies, Inc. + // Look for the CPU part line. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("CPU part")) + // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The + // values correspond to the "Part number" in the CP15/c0 register. The + // contents are specified in the various processor manuals. + return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) + .Case("0x06f", "krait") // APQ8064 + .Case("0x201", "kryo") + .Case("0x205", "kryo") + .Default("generic"); + + return "generic"; +} + +StringRef sys::detail::getHostCPUNameForS390x( + const StringRef &ProcCpuinfoContent) { + // STIDP is a privileged operation, so use /proc/cpuinfo instead. + + // The "processor 0:" line comes after a fair amount of other information, + // including a cache breakdown, but this should be plenty. + SmallVector<StringRef, 32> Lines; + ProcCpuinfoContent.split(Lines, "\n"); + + // Look for the CPU features. + SmallVector<StringRef, 32> CPUFeatures; + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("features")) { + size_t Pos = Lines[I].find(":"); + if (Pos != StringRef::npos) { + Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' '); + break; + } + } + + // We need to check for the presence of vector support independently of + // the machine type, since we may only use the vector register set when + // supported by the kernel (and hypervisor). + bool HaveVectorSupport = false; + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + if (CPUFeatures[I] == "vx") + HaveVectorSupport = true; + } + + // Now check the processor machine type. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) { + if (Lines[I].startswith("processor ")) { + size_t Pos = Lines[I].find("machine = "); + if (Pos != StringRef::npos) { + Pos += sizeof("machine = ") - 1; + unsigned int Id; + if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { + if (Id >= 3906 && HaveVectorSupport) + return "z14"; + if (Id >= 2964 && HaveVectorSupport) + return "z13"; + if (Id >= 2827) + return "zEC12"; + if (Id >= 2817) + return "z196"; + } + } + break; + } + } + + return "generic"; } -#endif #if defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64__) || defined(_M_X64) @@ -88,11 +283,17 @@ enum ProcessorVendors { }; enum ProcessorTypes { - INTEL_ATOM = 1, + INTEL_BONNELL = 1, INTEL_CORE2, INTEL_COREI7, AMDFAM10H, AMDFAM15H, + INTEL_SILVERMONT, + INTEL_KNL, + AMD_BTVER1, + AMD_BTVER2, + AMDFAM17H, + // Entries below this are not in libgcc/compiler-rt. INTEL_i386, INTEL_i486, INTEL_PENTIUM, @@ -102,16 +303,13 @@ enum ProcessorTypes { INTEL_PENTIUM_IV, INTEL_PENTIUM_M, INTEL_CORE_DUO, - INTEL_XEONPHI, INTEL_X86_64, INTEL_NOCONA, INTEL_PRESCOTT, AMD_i486, AMDPENTIUM, AMDATHLON, - AMDFAM14H, - AMDFAM16H, - AMDFAM17H, + INTEL_GOLDMONT, CPU_TYPE_MAX }; @@ -124,33 +322,26 @@ enum ProcessorSubtypes { AMDFAM10H_ISTANBUL, AMDFAM15H_BDVER1, AMDFAM15H_BDVER2, - INTEL_PENTIUM_MMX, - INTEL_CORE2_65, - INTEL_CORE2_45, + AMDFAM15H_BDVER3, + AMDFAM15H_BDVER4, + AMDFAM17H_ZNVER1, INTEL_COREI7_IVYBRIDGE, INTEL_COREI7_HASWELL, INTEL_COREI7_BROADWELL, INTEL_COREI7_SKYLAKE, INTEL_COREI7_SKYLAKE_AVX512, - INTEL_ATOM_BONNELL, - INTEL_ATOM_SILVERMONT, - INTEL_KNIGHTS_LANDING, + // Entries below this are not in libgcc/compiler-rt. + INTEL_PENTIUM_MMX, + INTEL_CORE2_65, + INTEL_CORE2_45, AMDPENTIUM_K6, AMDPENTIUM_K62, AMDPENTIUM_K63, AMDPENTIUM_GEODE, - AMDATHLON_TBIRD, - AMDATHLON_MP, + AMDATHLON_CLASSIC, AMDATHLON_XP, + AMDATHLON_K8, AMDATHLON_K8SSE3, - AMDATHLON_OPTERON, - AMDATHLON_FX, - AMDATHLON_64, - AMD_BTVER1, - AMD_BTVER2, - AMDFAM15H_BDVER3, - AMDFAM15H_BDVER4, - AMDFAM17H_ZNVER1, CPU_SUBTYPE_MAX }; @@ -166,9 +357,28 @@ enum ProcessorFeatures { FEATURE_SSE4_2, FEATURE_AVX, FEATURE_AVX2, - FEATURE_AVX512, - FEATURE_AVX512SAVE, - FEATURE_MOVBE, + FEATURE_SSE4_A, + FEATURE_FMA4, + FEATURE_XOP, + FEATURE_FMA, + FEATURE_AVX512F, + FEATURE_BMI, + FEATURE_BMI2, + FEATURE_AES, + FEATURE_PCLMUL, + FEATURE_AVX512VL, + FEATURE_AVX512BW, + FEATURE_AVX512DQ, + FEATURE_AVX512CD, + FEATURE_AVX512ER, + FEATURE_AVX512PF, + FEATURE_AVX512VBMI, + FEATURE_AVX512IFMA, + FEATURE_AVX5124VNNIW, + FEATURE_AVX5124FMAPS, + FEATURE_AVX512VPOPCNTDQ, + // Only one bit free left in the first 32 features. + FEATURE_MOVBE = 32, FEATURE_ADX, FEATURE_EM64T }; @@ -212,7 +422,6 @@ static bool isCpuIdSupported() { /// the specified arguments. If we can't run cpuid on the host, return true. static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) #if defined(__GNUC__) || defined(__clang__) #if defined(__x86_64__) // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. @@ -222,14 +431,16 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, "xchgq\t%%rbx, %%rsi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value)); + return false; #elif defined(__i386__) __asm__("movl\t%%ebx, %%esi\n\t" "cpuid\n\t" "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value)); + return false; #else - assert(0 && "This method is defined only for x86."); + return true; #endif #elif defined(_MSC_VER) // The MSVC intrinsic is portable across x86 and x64. @@ -239,7 +450,6 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, *rEBX = registers[1]; *rECX = registers[2]; *rEDX = registers[3]; -#endif return false; #else return true; @@ -252,55 +462,40 @@ static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX, static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX, unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) -#if defined(__x86_64__) || defined(_M_X64) #if defined(__GNUC__) || defined(__clang__) - // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. +#if defined(__x86_64__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually. // FIXME: should we save this for Clang? __asm__("movq\t%%rbx, %%rsi\n\t" "cpuid\n\t" "xchgq\t%%rbx, %%rsi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); -#elif defined(_MSC_VER) - int registers[4]; - __cpuidex(registers, value, subleaf); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; -#endif -#elif defined(__i386__) || defined(_M_IX86) -#if defined(__GNUC__) || defined(__clang__) + return false; +#elif defined(__i386__) __asm__("movl\t%%ebx, %%esi\n\t" "cpuid\n\t" "xchgl\t%%ebx, %%esi\n\t" : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX) : "a"(value), "c"(subleaf)); -#elif defined(_MSC_VER) - __asm { - mov eax,value - mov ecx,subleaf - cpuid - mov esi,rEAX - mov dword ptr [esi],eax - mov esi,rEBX - mov dword ptr [esi],ebx - mov esi,rECX - mov dword ptr [esi],ecx - mov esi,rEDX - mov dword ptr [esi],edx - } -#endif + return false; #else - assert(0 && "This method is defined only for x86."); + return true; #endif +#elif defined(_MSC_VER) + int registers[4]; + __cpuidex(registers, value, subleaf); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; return false; #else return true; #endif } +// Read control register 0 (XCR0). Used to detect features such as AVX. static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) { #if defined(__GNUC__) || defined(__clang__) // Check xgetbv; this uses a .byte sequence instead of the instruction @@ -332,9 +527,10 @@ static void detectX86FamilyModel(unsigned EAX, unsigned *Family, } static void -getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, - unsigned int Brand_id, unsigned int Features, - unsigned *Type, unsigned *Subtype) { +getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, + unsigned Brand_id, unsigned Features, + unsigned Features2, unsigned *Type, + unsigned *Subtype) { if (Brand_id != 0) return; switch (Family) { @@ -487,12 +683,7 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, // Skylake Xeon: case 0x55: *Type = INTEL_COREI7; - // Check that we really have AVX512 - if (Features & (1 << FEATURE_AVX512)) { - *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" - } else { - *Subtype = INTEL_COREI7_SKYLAKE; // "skylake" - } + *Subtype = INTEL_COREI7_SKYLAKE_AVX512; // "skylake-avx512" break; case 0x1c: // Most 45 nm Intel Atom processors @@ -500,8 +691,7 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, case 0x27: // 32 nm Atom Medfield case 0x35: // 32 nm Atom Midview case 0x36: // 32 nm Atom Midview - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_BONNELL; + *Type = INTEL_BONNELL; break; // "bonnell" // Atom Silvermont codes from the Intel software optimization guide. @@ -511,22 +701,23 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, case 0x5a: case 0x5d: case 0x4c: // really airmont - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_SILVERMONT; + *Type = INTEL_SILVERMONT; break; // "silvermont" - + // Goldmont: + case 0x5c: + case 0x5f: + *Type = INTEL_GOLDMONT; + break; // "goldmont" case 0x57: - *Type = INTEL_XEONPHI; // knl - *Subtype = INTEL_KNIGHTS_LANDING; + *Type = INTEL_KNL; // knl break; default: // Unknown family 6 CPU, try to guess. - if (Features & (1 << FEATURE_AVX512)) { - *Type = INTEL_XEONPHI; // knl - *Subtype = INTEL_KNIGHTS_LANDING; + if (Features & (1 << FEATURE_AVX512F)) { + *Type = INTEL_KNL; // knl break; } - if (Features & (1 << FEATURE_ADX)) { + if (Features2 & (1 << (FEATURE_ADX - 32))) { *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_BROADWELL; break; @@ -542,9 +733,8 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, break; } if (Features & (1 << FEATURE_SSE4_2)) { - if (Features & (1 << FEATURE_MOVBE)) { - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_SILVERMONT; + if (Features2 & (1 << (FEATURE_MOVBE - 32))) { + *Type = INTEL_SILVERMONT; } else { *Type = INTEL_COREI7; *Subtype = INTEL_COREI7_NEHALEM; @@ -557,16 +747,15 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, break; } if (Features & (1 << FEATURE_SSSE3)) { - if (Features & (1 << FEATURE_MOVBE)) { - *Type = INTEL_ATOM; - *Subtype = INTEL_ATOM_BONNELL; // "bonnell" + if (Features2 & (1 << (FEATURE_MOVBE - 32))) { + *Type = INTEL_BONNELL; // "bonnell" } else { *Type = INTEL_CORE2; // "core2" *Subtype = INTEL_CORE2_65; } break; } - if (Features & (1 << FEATURE_EM64T)) { + if (Features2 & (1 << (FEATURE_EM64T - 32))) { *Type = INTEL_X86_64; break; // x86-64 } @@ -597,8 +786,8 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron // processor, and Mobile Intel Celeron processor. All processors // are model 02h and manufactured using the 0.13 micron process. - *Type = - ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); + *Type = ((Features2 & (1 << (FEATURE_EM64T - 32))) ? INTEL_X86_64 + : INTEL_PENTIUM_IV); break; case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D @@ -612,13 +801,13 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, // Extreme Edition, Intel Xeon processor, Intel Xeon processor // MP, Intel Celeron D processor. All processors are model 06h // and manufactured using the 65 nm process. - *Type = - ((Features & (1 << FEATURE_EM64T)) ? INTEL_NOCONA : INTEL_PRESCOTT); + *Type = ((Features2 & (1 << (FEATURE_EM64T - 32))) ? INTEL_NOCONA + : INTEL_PRESCOTT); break; default: - *Type = - ((Features & (1 << FEATURE_EM64T)) ? INTEL_X86_64 : INTEL_PENTIUM_IV); + *Type = ((Features2 & (1 << (FEATURE_EM64T - 32))) ? INTEL_X86_64 + : INTEL_PENTIUM_IV); break; } break; @@ -628,10 +817,8 @@ getIntelProcessorTypeAndSubtype(unsigned int Family, unsigned int Model, } } -static void getAMDProcessorTypeAndSubtype(unsigned int Family, - unsigned int Model, - unsigned int Features, - unsigned *Type, +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 @@ -661,38 +848,20 @@ static void getAMDProcessorTypeAndSubtype(unsigned int Family, break; case 6: *Type = AMDATHLON; - switch (Model) { - case 4: - *Subtype = AMDATHLON_TBIRD; - break; // "athlon-tbird" - case 6: - case 7: - case 8: - *Subtype = AMDATHLON_MP; - break; // "athlon-mp" - case 10: + if (Features & (1 << FEATURE_SSE)) { *Subtype = AMDATHLON_XP; break; // "athlon-xp" } - break; + *Subtype = AMDATHLON_CLASSIC; + break; // "athlon" case 15: *Type = AMDATHLON; if (Features & (1 << FEATURE_SSE3)) { *Subtype = AMDATHLON_K8SSE3; break; // "k8-sse3" } - switch (Model) { - case 1: - *Subtype = AMDATHLON_OPTERON; - break; // "opteron" - case 5: - *Subtype = AMDATHLON_FX; - break; // "athlon-fx"; also opteron - default: - *Subtype = AMDATHLON_64; - break; // "athlon64" - } - break; + *Subtype = AMDATHLON_K8; + break; // "k8" case 16: *Type = AMDFAM10H; // "amdfam10" switch (Model) { @@ -708,19 +877,13 @@ static void getAMDProcessorTypeAndSubtype(unsigned int Family, } break; case 20: - *Type = AMDFAM14H; - *Subtype = AMD_BTVER1; + *Type = AMD_BTVER1; break; // "btver1"; case 21: *Type = AMDFAM15H; - if (!(Features & - (1 << FEATURE_AVX))) { // If no AVX support, provide a sane fallback. - *Subtype = AMD_BTVER1; - break; // "btver1" - } - if (Model >= 0x50 && Model <= 0x6f) { + if (Model >= 0x60 && Model <= 0x7f) { *Subtype = AMDFAM15H_BDVER4; - break; // "bdver4"; 50h-6Fh: Excavator + break; // "bdver4"; 60h-7Fh: Excavator } if (Model >= 0x30 && Model <= 0x3f) { *Subtype = AMDFAM15H_BDVER3; @@ -736,39 +899,52 @@ static void getAMDProcessorTypeAndSubtype(unsigned int Family, } break; case 22: - *Type = AMDFAM16H; - if (!(Features & - (1 << FEATURE_AVX))) { // If no AVX support provide a sane fallback. - *Subtype = AMD_BTVER1; - break; // "btver1"; - } - *Subtype = AMD_BTVER2; + *Type = AMD_BTVER2; break; // "btver2" case 23: *Type = AMDFAM17H; - if (Features & (1 << FEATURE_ADX)) { - *Subtype = AMDFAM17H_ZNVER1; - break; // "znver1" - } - *Subtype = AMD_BTVER1; + *Subtype = AMDFAM17H_ZNVER1; break; default: break; // "generic" } } -static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, - unsigned MaxLeaf) { +static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, + unsigned *FeaturesOut, + unsigned *Features2Out) { unsigned Features = 0; - unsigned int EAX, EBX; - Features |= (((EDX >> 23) & 1) << FEATURE_MMX); - Features |= (((EDX >> 25) & 1) << FEATURE_SSE); - Features |= (((EDX >> 26) & 1) << FEATURE_SSE2); - Features |= (((ECX >> 0) & 1) << FEATURE_SSE3); - Features |= (((ECX >> 9) & 1) << FEATURE_SSSE3); - Features |= (((ECX >> 19) & 1) << FEATURE_SSE4_1); - Features |= (((ECX >> 20) & 1) << FEATURE_SSE4_2); - Features |= (((ECX >> 22) & 1) << FEATURE_MOVBE); + unsigned Features2 = 0; + unsigned EAX, EBX; + + if ((EDX >> 15) & 1) + Features |= 1 << FEATURE_CMOV; + if ((EDX >> 23) & 1) + Features |= 1 << FEATURE_MMX; + if ((EDX >> 25) & 1) + Features |= 1 << FEATURE_SSE; + if ((EDX >> 26) & 1) + Features |= 1 << FEATURE_SSE2; + + if ((ECX >> 0) & 1) + Features |= 1 << FEATURE_SSE3; + if ((ECX >> 1) & 1) + Features |= 1 << FEATURE_PCLMUL; + if ((ECX >> 9) & 1) + Features |= 1 << FEATURE_SSSE3; + if ((ECX >> 12) & 1) + Features |= 1 << FEATURE_FMA; + if ((ECX >> 19) & 1) + Features |= 1 << FEATURE_SSE4_1; + if ((ECX >> 20) & 1) + Features |= 1 << FEATURE_SSE4_2; + if ((ECX >> 23) & 1) + Features |= 1 << FEATURE_POPCNT; + if ((ECX >> 25) & 1) + Features |= 1 << FEATURE_AES; + + if ((ECX >> 22) & 1) + Features2 |= 1 << (FEATURE_MOVBE - 32); // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV // indicates that the AVX registers will be saved and restored on context @@ -777,20 +953,65 @@ static unsigned getAvailableFeatures(unsigned int ECX, unsigned int EDX, bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) && ((EAX & 0x6) == 0x6); bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0); + + if (HasAVX) + Features |= 1 << FEATURE_AVX; + bool HasLeaf7 = MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); - bool HasADX = HasLeaf7 && ((EBX >> 19) & 1); - bool HasAVX2 = HasAVX && HasLeaf7 && (EBX & 0x20); - bool HasAVX512 = HasLeaf7 && HasAVX512Save && ((EBX >> 16) & 1); - Features |= (HasAVX << FEATURE_AVX); - Features |= (HasAVX2 << FEATURE_AVX2); - Features |= (HasAVX512 << FEATURE_AVX512); - Features |= (HasAVX512Save << FEATURE_AVX512SAVE); - Features |= (HasADX << FEATURE_ADX); - - getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - Features |= (((EDX >> 29) & 0x1) << FEATURE_EM64T); - return Features; + + if (HasLeaf7 && ((EBX >> 3) & 1)) + Features |= 1 << FEATURE_BMI; + if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) + Features |= 1 << FEATURE_AVX2; + if (HasLeaf7 && ((EBX >> 9) & 1)) + Features |= 1 << FEATURE_BMI2; + if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512F; + if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512DQ; + if (HasLeaf7 && ((EBX >> 19) & 1)) + Features2 |= 1 << (FEATURE_ADX - 32); + if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512IFMA; + if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512PF; + if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512ER; + if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512CD; + if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512BW; + if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512VL; + + if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512VBMI; + if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX512VPOPCNTDQ; + + if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX5124VNNIW; + if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save) + Features |= 1 << FEATURE_AVX5124FMAPS; + + unsigned MaxExtLevel; + getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX); + + bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 && + !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + if (HasExtLeaf1 && ((ECX >> 6) & 1)) + Features |= 1 << FEATURE_SSE4_A; + if (HasExtLeaf1 && ((ECX >> 11) & 1)) + Features |= 1 << FEATURE_XOP; + if (HasExtLeaf1 && ((ECX >> 16) & 1)) + Features |= 1 << FEATURE_FMA4; + + if (HasExtLeaf1 && ((EDX >> 29) & 1)) + Features2 |= 1 << (FEATURE_EM64T - 32); + + *FeaturesOut = Features; + *Features2Out = Features2; } StringRef sys::getHostCPUName() { @@ -805,23 +1026,22 @@ StringRef sys::getHostCPUName() { if(!isCpuIdSupported()) return "generic"; #endif - if (getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX)) - return "generic"; - if (getX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) + 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; + unsigned Features = 0, Features2 = 0; detectX86FamilyModel(EAX, &Family, &Model); - Features = getAvailableFeatures(ECX, EDX, MaxLeaf); + getAvailableFeatures(ECX, EDX, MaxLeaf, &Features, &Features2); unsigned Type; unsigned Subtype; if (Vendor == SIG_INTEL) { - getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, &Type, - &Subtype); + getIntelProcessorTypeAndSubtype(Family, Model, Brand_id, Features, + Features2, &Type, &Subtype); switch (Type) { case INTEL_i386: return "i386"; @@ -850,7 +1070,7 @@ StringRef sys::getHostCPUName() { case INTEL_CORE2_45: return "penryn"; default: - return "core2"; + llvm_unreachable("Unexpected subtype!"); } case INTEL_COREI7: switch (Subtype) { @@ -871,19 +1091,16 @@ StringRef sys::getHostCPUName() { case INTEL_COREI7_SKYLAKE_AVX512: return "skylake-avx512"; default: - return "corei7"; - } - case INTEL_ATOM: - switch (Subtype) { - case INTEL_ATOM_BONNELL: - return "bonnell"; - case INTEL_ATOM_SILVERMONT: - return "silvermont"; - default: - return "atom"; + llvm_unreachable("Unexpected subtype!"); } - case INTEL_XEONPHI: - return "knl"; /*update for more variants added*/ + case INTEL_BONNELL: + return "bonnell"; + case INTEL_SILVERMONT: + return "silvermont"; + case INTEL_GOLDMONT: + return "goldmont"; + case INTEL_KNL: + return "knl"; case INTEL_X86_64: return "x86-64"; case INTEL_NOCONA: @@ -891,7 +1108,7 @@ StringRef sys::getHostCPUName() { case INTEL_PRESCOTT: return "prescott"; default: - return "generic"; + break; } } else if (Vendor == SIG_AMD) { getAMDProcessorTypeAndSubtype(Family, Model, Features, &Type, &Subtype); @@ -913,31 +1130,24 @@ StringRef sys::getHostCPUName() { } case AMDATHLON: switch (Subtype) { - case AMDATHLON_TBIRD: - return "athlon-tbird"; - case AMDATHLON_MP: - return "athlon-mp"; + case AMDATHLON_CLASSIC: + return "athlon"; case AMDATHLON_XP: return "athlon-xp"; + case AMDATHLON_K8: + return "k8"; case AMDATHLON_K8SSE3: return "k8-sse3"; - case AMDATHLON_OPTERON: - return "opteron"; - case AMDATHLON_FX: - return "athlon-fx"; - case AMDATHLON_64: - return "athlon64"; default: - return "athlon"; + llvm_unreachable("Unexpected subtype!"); } case AMDFAM10H: - if(Subtype == AMDFAM10H_BARCELONA) - return "barcelona"; return "amdfam10"; - case AMDFAM14H: + case AMD_BTVER1: return "btver1"; case AMDFAM15H: switch (Subtype) { + default: // There are gaps in the subtype detection. case AMDFAM15H_BDVER1: return "bdver1"; case AMDFAM15H_BDVER2: @@ -946,31 +1156,13 @@ StringRef sys::getHostCPUName() { return "bdver3"; case AMDFAM15H_BDVER4: return "bdver4"; - case AMD_BTVER1: - return "btver1"; - default: - return "amdfam15"; - } - case AMDFAM16H: - switch (Subtype) { - case AMD_BTVER1: - return "btver1"; - case AMD_BTVER2: - return "btver2"; - default: - return "amdfam16"; } + case AMD_BTVER2: + return "btver2"; case AMDFAM17H: - switch (Subtype) { - case AMD_BTVER1: - return "btver1"; - case AMDFAM17H_ZNVER1: - return "znver1"; - default: - return "amdfam17"; - } + return "znver1"; default: - return "generic"; + break; } } return "generic"; @@ -1020,201 +1212,21 @@ StringRef sys::getHostCPUName() { } #elif defined(__linux__) && (defined(__ppc__) || defined(__powerpc__)) StringRef sys::getHostCPUName() { - // Access to the Processor Version Register (PVR) on PowerPC is privileged, - // and so we must use an operating-system interface to determine the current - // processor type. On Linux, this is exposed through the /proc/cpuinfo file. - const char *generic = "generic"; - - // The cpu line is second (after the 'processor: 0' line), so if this - // buffer is too small then something has changed (or is wrong). - char buffer[1024]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) - return generic; - - const char *CPUInfoStart = buffer; - const char *CPUInfoEnd = buffer + CPUInfoSize; - - const char *CIP = CPUInfoStart; - - const char *CPUStart = 0; - size_t CPULen = 0; - - // We need to find the first line which starts with cpu, spaces, and a colon. - // After the colon, there may be some additional spaces and then the cpu type. - while (CIP < CPUInfoEnd && CPUStart == 0) { - if (CIP < CPUInfoEnd && *CIP == '\n') - ++CIP; - - if (CIP < CPUInfoEnd && *CIP == 'c') { - ++CIP; - if (CIP < CPUInfoEnd && *CIP == 'p') { - ++CIP; - if (CIP < CPUInfoEnd && *CIP == 'u') { - ++CIP; - while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) - ++CIP; - - if (CIP < CPUInfoEnd && *CIP == ':') { - ++CIP; - while (CIP < CPUInfoEnd && (*CIP == ' ' || *CIP == '\t')) - ++CIP; - - if (CIP < CPUInfoEnd) { - CPUStart = CIP; - while (CIP < CPUInfoEnd && (*CIP != ' ' && *CIP != '\t' && - *CIP != ',' && *CIP != '\n')) - ++CIP; - CPULen = CIP - CPUStart; - } - } - } - } - } - - if (CPUStart == 0) - while (CIP < CPUInfoEnd && *CIP != '\n') - ++CIP; - } - - if (CPUStart == 0) - return generic; - - return StringSwitch<const char *>(StringRef(CPUStart, CPULen)) - .Case("604e", "604e") - .Case("604", "604") - .Case("7400", "7400") - .Case("7410", "7400") - .Case("7447", "7400") - .Case("7455", "7450") - .Case("G4", "g4") - .Case("POWER4", "970") - .Case("PPC970FX", "970") - .Case("PPC970MP", "970") - .Case("G5", "g5") - .Case("POWER5", "g5") - .Case("A2", "a2") - .Case("POWER6", "pwr6") - .Case("POWER7", "pwr7") - .Case("POWER8", "pwr8") - .Case("POWER8E", "pwr8") - .Case("POWER8NVL", "pwr8") - .Case("POWER9", "pwr9") - .Default(generic); + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + const StringRef& Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForPowerPC(Content); } -#elif defined(__linux__) && defined(__arm__) +#elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) StringRef sys::getHostCPUName() { - // The cpuid register on arm is not accessible from user space. On Linux, - // it is exposed through the /proc/cpuinfo file. - - // Read 1024 bytes from /proc/cpuinfo, which should contain the CPU part line - // in all cases. - char buffer[1024]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) - return "generic"; - - StringRef Str(buffer, CPUInfoSize); - - SmallVector<StringRef, 32> Lines; - Str.split(Lines, "\n"); - - // Look for the CPU implementer line. - StringRef Implementer; - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU implementer")) - Implementer = Lines[I].substr(15).ltrim("\t :"); - - if (Implementer == "0x41") // ARM Ltd. - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x926", "arm926ej-s") - .Case("0xb02", "mpcore") - .Case("0xb36", "arm1136j-s") - .Case("0xb56", "arm1156t2-s") - .Case("0xb76", "arm1176jz-s") - .Case("0xc08", "cortex-a8") - .Case("0xc09", "cortex-a9") - .Case("0xc0f", "cortex-a15") - .Case("0xc20", "cortex-m0") - .Case("0xc23", "cortex-m3") - .Case("0xc24", "cortex-m4") - .Default("generic"); - - if (Implementer == "0x51") // Qualcomm Technologies, Inc. - // Look for the CPU part line. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("CPU part")) - // The CPU part is a 3 digit hexadecimal number with a 0x prefix. The - // values correspond to the "Part number" in the CP15/c0 register. The - // contents are specified in the various processor manuals. - return StringSwitch<const char *>(Lines[I].substr(8).ltrim("\t :")) - .Case("0x06f", "krait") // APQ8064 - .Default("generic"); - - return "generic"; + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + const StringRef& Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForARM(Content); } #elif defined(__linux__) && defined(__s390x__) StringRef sys::getHostCPUName() { - // STIDP is a privileged operation, so use /proc/cpuinfo instead. - - // The "processor 0:" line comes after a fair amount of other information, - // including a cache breakdown, but this should be plenty. - char buffer[2048]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) - return "generic"; - - StringRef Str(buffer, CPUInfoSize); - SmallVector<StringRef, 32> Lines; - Str.split(Lines, "\n"); - - // Look for the CPU features. - SmallVector<StringRef, 32> CPUFeatures; - for (unsigned I = 0, E = Lines.size(); I != E; ++I) - if (Lines[I].startswith("features")) { - size_t Pos = Lines[I].find(":"); - if (Pos != StringRef::npos) { - Lines[I].drop_front(Pos + 1).split(CPUFeatures, ' '); - break; - } - } - - // We need to check for the presence of vector support independently of - // the machine type, since we may only use the vector register set when - // supported by the kernel (and hypervisor). - bool HaveVectorSupport = false; - for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { - if (CPUFeatures[I] == "vx") - HaveVectorSupport = true; - } - - // Now check the processor machine type. - for (unsigned I = 0, E = Lines.size(); I != E; ++I) { - if (Lines[I].startswith("processor ")) { - size_t Pos = Lines[I].find("machine = "); - if (Pos != StringRef::npos) { - Pos += sizeof("machine = ") - 1; - unsigned int Id; - if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { - if (Id >= 2964 && HaveVectorSupport) - return "z13"; - if (Id >= 2827) - return "zEC12"; - if (Id >= 2817) - return "z196"; - } - } - break; - } - } - - return "generic"; + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + const StringRef& Content = P ? P->getBuffer() : ""; + return detail::getHostCPUNameForS390x(Content); } #else StringRef sys::getHostCPUName() { return "generic"; } @@ -1232,6 +1244,7 @@ static int computeHostNumPhysicalCores() { if (std::error_code EC = Text.getError()) { llvm::errs() << "Can't read " << "/proc/cpuinfo: " << EC.message() << "\n"; + return -1; } SmallVector<StringRef, 8> strs; (*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, @@ -1349,10 +1362,15 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["sse4a"] = HasExtLeaf1 && ((ECX >> 6) & 1); Features["prfchw"] = HasExtLeaf1 && ((ECX >> 8) & 1); Features["xop"] = HasExtLeaf1 && ((ECX >> 11) & 1) && HasAVXSave; + Features["lwp"] = HasExtLeaf1 && ((ECX >> 15) & 1); Features["fma4"] = HasExtLeaf1 && ((ECX >> 16) & 1) && HasAVXSave; Features["tbm"] = HasExtLeaf1 && ((ECX >> 21) & 1); Features["mwaitx"] = HasExtLeaf1 && ((ECX >> 29) & 1); + bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 && + !getX86CpuIDAndInfoEx(0x80000008,0x0, &EAX, &EBX, &ECX, &EDX); + Features["clzero"] = HasExtLeaf8 && ((EBX >> 0) & 1); + bool HasLeaf7 = MaxLevel >= 7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX); @@ -1362,14 +1380,10 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["fsgsbase"] = HasLeaf7 && ((EBX >> 0) & 1); Features["sgx"] = HasLeaf7 && ((EBX >> 2) & 1); Features["bmi"] = HasLeaf7 && ((EBX >> 3) & 1); - Features["hle"] = HasLeaf7 && ((EBX >> 4) & 1); Features["bmi2"] = HasLeaf7 && ((EBX >> 8) & 1); - Features["invpcid"] = HasLeaf7 && ((EBX >> 10) & 1); Features["rtm"] = HasLeaf7 && ((EBX >> 11) & 1); Features["rdseed"] = HasLeaf7 && ((EBX >> 18) & 1); Features["adx"] = HasLeaf7 && ((EBX >> 19) & 1); - Features["smap"] = HasLeaf7 && ((EBX >> 20) & 1); - Features["pcommit"] = HasLeaf7 && ((EBX >> 22) & 1); Features["clflushopt"] = HasLeaf7 && ((EBX >> 23) & 1); Features["clwb"] = HasLeaf7 && ((EBX >> 24) & 1); Features["sha"] = HasLeaf7 && ((EBX >> 29) & 1); @@ -1386,6 +1400,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { Features["prefetchwt1"] = HasLeaf7 && (ECX & 1); Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save; + Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save; // Enable protection keys Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1); @@ -1401,17 +1416,12 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { } #elif defined(__linux__) && (defined(__arm__) || defined(__aarch64__)) bool sys::getHostCPUFeatures(StringMap<bool> &Features) { - // Read 1024 bytes from /proc/cpuinfo, which should contain the Features line - // in all cases. - char buffer[1024]; - ssize_t CPUInfoSize = readCpuInfo(buffer, sizeof(buffer)); - if (CPUInfoSize == -1) + std::unique_ptr<llvm::MemoryBuffer> P = getProcCpuinfoContent(); + if (!P) return false; - StringRef Str(buffer, CPUInfoSize); - SmallVector<StringRef, 32> Lines; - Str.split(Lines, "\n"); + P->getBuffer().split(Lines, "\n"); SmallVector<StringRef, 32> CPUFeatures; @@ -1475,7 +1485,8 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) { return false; } #endif std::string sys::getProcessTriple() { - Triple PT(Triple::normalize(LLVM_HOST_TRIPLE)); + std::string TargetTripleString = updateTripleOSVersion(LLVM_HOST_TRIPLE); + Triple PT(Triple::normalize(TargetTripleString)); if (sizeof(void *) == 8 && PT.isArch32Bit()) PT = PT.get64BitArchVariant(); diff --git a/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp index 444aaa3..3ee3af7 100644 --- a/contrib/llvm/lib/Support/LockFileManager.cpp +++ b/contrib/llvm/lib/Support/LockFileManager.cpp @@ -15,15 +15,15 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include <cerrno> #include <ctime> #include <memory> -#include <tuple> -#include <system_error> #include <sys/stat.h> #include <sys/types.h> +#include <system_error> +#include <tuple> #if LLVM_ON_WIN32 #include <windows.h> #endif @@ -304,9 +304,9 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() { Interval.tv_sec = 0; Interval.tv_nsec = 1000000; #endif - // Don't wait more than five minutes per iteration. Total timeout for the file - // to appear is ~8.5 mins. - const unsigned MaxSeconds = 5*60; + // Don't wait more than 40s per iteration. Total timeout for the file + // to appear is ~1.5 minutes. + const unsigned MaxSeconds = 40; do { // Sleep for the designated interval, to allow the owning process time to // finish up and remove the lock file. diff --git a/contrib/llvm/lib/Support/LowLevelType.cpp b/contrib/llvm/lib/Support/LowLevelType.cpp new file mode 100644 index 0000000..0ee3f1d --- /dev/null +++ b/contrib/llvm/lib/Support/LowLevelType.cpp @@ -0,0 +1,56 @@ +//===-- llvm/Support/LowLevelType.cpp -------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file implements the more header-heavy bits of the LLT class to +/// avoid polluting users' namespaces. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/LowLevelTypeImpl.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +LLT::LLT(MVT VT) { + if (VT.isVector()) { + init(/*isPointer=*/false, VT.getVectorNumElements() > 1, + VT.getVectorNumElements(), VT.getVectorElementType().getSizeInBits(), + /*AddressSpace=*/0); + } else if (VT.isValid()) { + // Aggregates are no different from real scalars as far as GlobalISel is + // concerned. + assert(VT.getSizeInBits() != 0 && "invalid zero-sized type"); + init(/*isPointer=*/false, /*isVector=*/false, /*NumElements=*/0, + VT.getSizeInBits(), /*AddressSpace=*/0); + } else { + IsPointer = false; + IsVector = false; + RawData = 0; + } +} + +void LLT::print(raw_ostream &OS) const { + if (isVector()) + OS << "<" << getNumElements() << " x " << getElementType() << ">"; + else if (isPointer()) + OS << "p" << getAddressSpace(); + else if (isValid()) { + assert(isScalar() && "unexpected type"); + OS << "s" << getScalarSizeInBits(); + } else + llvm_unreachable("trying to print an invalid type"); +} + +const constexpr LLT::BitFieldInfo LLT::ScalarSizeFieldInfo; +const constexpr LLT::BitFieldInfo LLT::PointerSizeFieldInfo; +const constexpr LLT::BitFieldInfo LLT::PointerAddressSpaceFieldInfo; +const constexpr LLT::BitFieldInfo LLT::VectorElementsFieldInfo; +const constexpr LLT::BitFieldInfo LLT::VectorSizeFieldInfo; +const constexpr LLT::BitFieldInfo LLT::PointerVectorElementsFieldInfo; +const constexpr LLT::BitFieldInfo LLT::PointerVectorSizeFieldInfo; +const constexpr LLT::BitFieldInfo LLT::PointerVectorAddressSpaceFieldInfo; diff --git a/contrib/llvm/lib/Support/MD5.cpp b/contrib/llvm/lib/Support/MD5.cpp index 942571e..545a64c 100644 --- a/contrib/llvm/lib/Support/MD5.cpp +++ b/contrib/llvm/lib/Support/MD5.cpp @@ -37,10 +37,14 @@ * compile-time configuration. */ +#include "llvm/Support/MD5.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" -#include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" +#include <array> +#include <cstdint> #include <cstring> // The basic MD5 functions. @@ -68,7 +72,7 @@ ((MD5_u32plus) ptr[(n) * 4 + 3] << 24)) #define GET(n) (block[(n)]) -namespace llvm { +using namespace llvm; /// \brief This processes one or more 64-byte data blocks, but does NOT update ///the bit counters. There are no alignment requirements. @@ -179,9 +183,7 @@ const uint8_t *MD5::body(ArrayRef<uint8_t> Data) { return ptr; } -MD5::MD5() - : a(0x67452301), b(0xefcdab89), c(0x98badcfe), d(0x10325476), hi(0), lo(0) { -} +MD5::MD5() = default; /// Incrementally add the bytes in \p Data to the hash. void MD5::update(ArrayRef<uint8_t> Data) { @@ -259,10 +261,16 @@ void MD5::final(MD5Result &Result) { support::endian::write32le(&Result[12], d); } -void MD5::stringifyResult(MD5Result &Result, SmallString<32> &Str) { +SmallString<32> MD5::MD5Result::digest() const { + SmallString<32> Str; raw_svector_ostream Res(Str); for (int i = 0; i < 16; ++i) - Res << format("%.2x", Result[i]); + Res << format("%.2x", Bytes[i]); + return Str; +} + +void MD5::stringifyResult(MD5Result &Result, SmallString<32> &Str) { + Str = Result.digest(); } std::array<uint8_t, 16> MD5::hash(ArrayRef<uint8_t> Data) { @@ -271,8 +279,5 @@ std::array<uint8_t, 16> MD5::hash(ArrayRef<uint8_t> Data) { MD5::MD5Result Res; Hash.final(Res); - std::array<uint8_t, 16> Arr; - memcpy(Arr.data(), Res, sizeof(Res)); - return Arr; -} + return Res; } diff --git a/contrib/llvm/lib/Support/ManagedStatic.cpp b/contrib/llvm/lib/Support/ManagedStatic.cpp index 7dd3131..fb7cd07 100644 --- a/contrib/llvm/lib/Support/ManagedStatic.cpp +++ b/contrib/llvm/lib/Support/ManagedStatic.cpp @@ -21,7 +21,7 @@ using namespace llvm; static const ManagedStaticBase *StaticList = nullptr; static sys::Mutex *ManagedStaticMutex = nullptr; -LLVM_DEFINE_ONCE_FLAG(mutex_init_flag); +static llvm::once_flag mutex_init_flag; static void initializeMutex() { ManagedStaticMutex = new sys::Mutex(); diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp index a3a18c9..85e782b 100644 --- a/contrib/llvm/lib/Support/MemoryBuffer.cpp +++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp @@ -103,7 +103,7 @@ public: static ErrorOr<std::unique_ptr<MemoryBuffer>> getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, - uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize); + uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile); std::unique_ptr<MemoryBuffer> MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, @@ -178,8 +178,8 @@ MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize, ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, - uint64_t Offset) { - return getFileAux(FilePath, -1, MapSize, Offset, false, false); + uint64_t Offset, bool IsVolatile) { + return getFileAux(FilePath, -1, MapSize, Offset, false, IsVolatile); } @@ -240,11 +240,9 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) { // Read into Buffer until we hit EOF. do { Buffer.reserve(Buffer.size() + ChunkSize); - ReadBytes = read(FD, Buffer.end(), ChunkSize); - if (ReadBytes == -1) { - if (errno == EINTR) continue; + ReadBytes = sys::RetryAfterSignal(-1, read, FD, Buffer.end(), ChunkSize); + if (ReadBytes == -1) return std::error_code(errno, std::generic_category()); - } Buffer.set_size(Buffer.size() + ReadBytes); } while (ReadBytes != 0); @@ -254,19 +252,19 @@ getMemoryBufferForStream(int FD, const Twine &BufferName) { ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, - bool RequiresNullTerminator, bool IsVolatileSize) { + bool RequiresNullTerminator, bool IsVolatile) { return getFileAux(Filename, FileSize, FileSize, 0, - RequiresNullTerminator, IsVolatileSize); + RequiresNullTerminator, IsVolatile); } static ErrorOr<std::unique_ptr<MemoryBuffer>> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, - bool IsVolatileSize); + bool IsVolatile); static ErrorOr<std::unique_ptr<MemoryBuffer>> getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, - uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize) { + uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { int FD; std::error_code EC = sys::fs::openFileForRead(Filename, FD); if (EC) @@ -274,7 +272,7 @@ getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset, - RequiresNullTerminator, IsVolatileSize); + RequiresNullTerminator, IsVolatile); close(FD); return Ret; } @@ -285,11 +283,11 @@ static bool shouldUseMmap(int FD, off_t Offset, bool RequiresNullTerminator, int PageSize, - bool IsVolatileSize) { + bool IsVolatile) { // 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 (IsVolatileSize) + if (IsVolatile) return false; // We don't use mmap for small files because this can severely fragment our @@ -300,7 +298,6 @@ static bool shouldUseMmap(int FD, if (!RequiresNullTerminator) return true; - // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. // FIXME: this chunk of code is duplicated, but it avoids a fstat when @@ -338,7 +335,7 @@ static bool shouldUseMmap(int FD, static ErrorOr<std::unique_ptr<MemoryBuffer>> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, - bool IsVolatileSize) { + bool IsVolatile) { static int PageSize = sys::Process::getPageSize(); // Default is to map the full file. @@ -365,7 +362,7 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, } if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, - PageSize, IsVolatileSize)) { + PageSize, IsVolatile)) { std::error_code EC; std::unique_ptr<MemoryBuffer> Result( new (NamedBufferAlloc(Filename)) @@ -392,13 +389,12 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, while (BytesLeft) { #ifdef HAVE_PREAD - ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); + ssize_t NumRead = sys::RetryAfterSignal(-1, ::pread, FD, BufPtr, BytesLeft, + MapSize - BytesLeft + Offset); #else - ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); + ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, BufPtr, BytesLeft); #endif if (NumRead == -1) { - if (errno == EINTR) - continue; // Error while reading. return std::error_code(errno, std::generic_category()); } @@ -415,17 +411,16 @@ getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, - bool RequiresNullTerminator, bool IsVolatileSize) { + bool RequiresNullTerminator, bool IsVolatile) { return getOpenFileImpl(FD, Filename, FileSize, FileSize, 0, - RequiresNullTerminator, IsVolatileSize); + RequiresNullTerminator, IsVolatile); } ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize, - int64_t Offset) { + int64_t Offset, bool IsVolatile) { assert(MapSize != uint64_t(-1)); - return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, - /*IsVolatileSize*/ false); + return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, IsVolatile); } ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { diff --git a/contrib/llvm/lib/Support/Mutex.cpp b/contrib/llvm/lib/Support/Mutex.cpp index c8d3844..b1d5e7c 100644 --- a/contrib/llvm/lib/Support/Mutex.cpp +++ b/contrib/llvm/lib/Support/Mutex.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Config/config.h" //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only TRULY operating system @@ -47,6 +48,10 @@ MutexImpl::MutexImpl( bool recursive) // Declare the pthread_mutex data structures pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t))); + + if (mutex == nullptr) + report_bad_alloc_error("Mutex allocation failed"); + pthread_mutexattr_t attr; // Initialize the mutex attributes diff --git a/contrib/llvm/lib/Support/Parallel.cpp b/contrib/llvm/lib/Support/Parallel.cpp new file mode 100644 index 0000000..ab2cfde --- /dev/null +++ b/contrib/llvm/lib/Support/Parallel.cpp @@ -0,0 +1,138 @@ +//===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Parallel.h" +#include "llvm/Config/llvm-config.h" + +#include <atomic> +#include <stack> +#include <thread> + +using namespace llvm; + +namespace { + +/// \brief An abstract class that takes closures and runs them asynchronously. +class Executor { +public: + virtual ~Executor() = default; + virtual void add(std::function<void()> func) = 0; + + static Executor *getDefaultExecutor(); +}; + +#if !LLVM_ENABLE_THREADS +class SyncExecutor : public Executor { +public: + virtual void add(std::function<void()> F) { F(); } +}; + +Executor *Executor::getDefaultExecutor() { + static SyncExecutor Exec; + return &Exec; +} + +#elif defined(_MSC_VER) +/// \brief An Executor that runs tasks via ConcRT. +class ConcRTExecutor : public Executor { + struct Taskish { + Taskish(std::function<void()> Task) : Task(Task) {} + + std::function<void()> Task; + + static void run(void *P) { + Taskish *Self = static_cast<Taskish *>(P); + Self->Task(); + concurrency::Free(Self); + } + }; + +public: + virtual void add(std::function<void()> F) { + Concurrency::CurrentScheduler::ScheduleTask( + Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F)); + } +}; + +Executor *Executor::getDefaultExecutor() { + static ConcRTExecutor exec; + return &exec; +} + +#else +/// \brief An implementation of an Executor that runs closures on a thread pool +/// in filo order. +class ThreadPoolExecutor : public Executor { +public: + explicit ThreadPoolExecutor( + unsigned ThreadCount = std::thread::hardware_concurrency()) + : Done(ThreadCount) { + // Spawn all but one of the threads in another thread as spawning threads + // can take a while. + std::thread([&, ThreadCount] { + for (size_t i = 1; i < ThreadCount; ++i) { + std::thread([=] { work(); }).detach(); + } + work(); + }).detach(); + } + + ~ThreadPoolExecutor() override { + std::unique_lock<std::mutex> Lock(Mutex); + Stop = true; + Lock.unlock(); + Cond.notify_all(); + // Wait for ~Latch. + } + + void add(std::function<void()> F) override { + std::unique_lock<std::mutex> Lock(Mutex); + WorkStack.push(F); + Lock.unlock(); + Cond.notify_one(); + } + +private: + void work() { + while (true) { + std::unique_lock<std::mutex> Lock(Mutex); + Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); }); + if (Stop) + break; + auto Task = WorkStack.top(); + WorkStack.pop(); + Lock.unlock(); + Task(); + } + Done.dec(); + } + + std::atomic<bool> Stop{false}; + std::stack<std::function<void()>> WorkStack; + std::mutex Mutex; + std::condition_variable Cond; + parallel::detail::Latch Done; +}; + +Executor *Executor::getDefaultExecutor() { + static ThreadPoolExecutor exec; + return &exec; +} +#endif +} + +#if LLVM_ENABLE_THREADS +void parallel::detail::TaskGroup::spawn(std::function<void()> F) { + L.inc(); + Executor::getDefaultExecutor()->add([&, F] { + F(); + L.dec(); + }); +} +#endif diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp index 4bb035e..ea59ba6 100644 --- a/contrib/llvm/lib/Support/Path.cpp +++ b/contrib/llvm/lib/Support/Path.cpp @@ -11,13 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/COFF.h" -#include "llvm/Support/MachO.h" +#include "llvm/Support/Path.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include <cctype> #include <cstring> @@ -34,16 +33,29 @@ using namespace llvm::support::endian; namespace { using llvm::StringRef; using llvm::sys::path::is_separator; + using llvm::sys::path::Style; + inline Style real_style(Style style) { #ifdef LLVM_ON_WIN32 - const char *separators = "\\/"; - const char preferred_separator = '\\'; + return (style == Style::posix) ? Style::posix : Style::windows; #else - const char separators = '/'; - const char preferred_separator = '/'; + return (style == Style::windows) ? Style::windows : Style::posix; #endif + } + + inline const char *separators(Style style) { + if (real_style(style) == Style::windows) + return "\\/"; + return "/"; + } + + inline char preferred_separator(Style style) { + if (real_style(style) == Style::windows) + return '\\'; + return '/'; + } - StringRef find_first_component(StringRef path) { + StringRef find_first_component(StringRef path, Style style) { // Look for this first component in the following order. // * empty (in this case we return an empty string) // * either C: or {//,\\}net. @@ -53,96 +65,85 @@ namespace { if (path.empty()) return path; -#ifdef LLVM_ON_WIN32 - // C: - if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) && - path[1] == ':') - return path.substr(0, 2); -#endif + if (real_style(style) == Style::windows) { + // C: + if (path.size() >= 2 && + std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':') + return path.substr(0, 2); + } // //net - if ((path.size() > 2) && - is_separator(path[0]) && - path[0] == path[1] && - !is_separator(path[2])) { + if ((path.size() > 2) && is_separator(path[0], style) && + path[0] == path[1] && !is_separator(path[2], style)) { // Find the next directory separator. - size_t end = path.find_first_of(separators, 2); + size_t end = path.find_first_of(separators(style), 2); return path.substr(0, end); } // {/,\} - if (is_separator(path[0])) + if (is_separator(path[0], style)) return path.substr(0, 1); // * {file,directory}name - size_t end = path.find_first_of(separators); + size_t end = path.find_first_of(separators(style)); return path.substr(0, end); } - size_t filename_pos(StringRef str) { - if (str.size() == 2 && - is_separator(str[0]) && - str[0] == str[1]) + size_t filename_pos(StringRef str, Style style) { + if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1]) return 0; - if (str.size() > 0 && is_separator(str[str.size() - 1])) + if (str.size() > 0 && is_separator(str[str.size() - 1], style)) return str.size() - 1; - size_t pos = str.find_last_of(separators, str.size() - 1); + size_t pos = str.find_last_of(separators(style), str.size() - 1); -#ifdef LLVM_ON_WIN32 - if (pos == StringRef::npos) - pos = str.find_last_of(':', str.size() - 2); -#endif + if (real_style(style) == Style::windows) { + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); + } - if (pos == StringRef::npos || - (pos == 1 && is_separator(str[0]))) + if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style))) return 0; return pos + 1; } - size_t root_dir_start(StringRef str) { + size_t root_dir_start(StringRef str, Style style) { // case "c:/" -#ifdef LLVM_ON_WIN32 - if (str.size() > 2 && - str[1] == ':' && - is_separator(str[2])) - return 2; -#endif + if (real_style(style) == Style::windows) { + if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style)) + return 2; + } // case "//" - if (str.size() == 2 && - is_separator(str[0]) && - str[0] == str[1]) + if (str.size() == 2 && is_separator(str[0], style) && str[0] == str[1]) return StringRef::npos; // case "//net" - if (str.size() > 3 && - is_separator(str[0]) && - str[0] == str[1] && - !is_separator(str[2])) { - return str.find_first_of(separators, 2); + if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] && + !is_separator(str[2], style)) { + return str.find_first_of(separators(style), 2); } // case "/" - if (str.size() > 0 && is_separator(str[0])) + if (str.size() > 0 && is_separator(str[0], style)) return 0; return StringRef::npos; } - size_t parent_path_end(StringRef path) { - size_t end_pos = filename_pos(path); + size_t parent_path_end(StringRef path, Style style) { + size_t end_pos = filename_pos(path, style); - bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + bool filename_was_sep = + path.size() > 0 && is_separator(path[end_pos], style); // Skip separators except for root dir. - size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); + size_t root_dir_pos = root_dir_start(path.substr(0, end_pos), style); - while(end_pos > 0 && - (end_pos - 1) != root_dir_pos && - is_separator(path[end_pos - 1])) + while (end_pos > 0 && (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1], style)) --end_pos; if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) @@ -230,11 +231,12 @@ namespace llvm { namespace sys { namespace path { -const_iterator begin(StringRef path) { +const_iterator begin(StringRef path, Style style) { const_iterator i; i.Path = path; - i.Component = find_first_component(path); + i.Component = find_first_component(path, style); i.Position = 0; + i.S = style; return i; } @@ -259,27 +261,21 @@ const_iterator &const_iterator::operator++() { // Both POSIX and Windows treat paths that begin with exactly two separators // specially. - bool was_net = Component.size() > 2 && - is_separator(Component[0]) && - Component[1] == Component[0] && - !is_separator(Component[2]); + bool was_net = Component.size() > 2 && is_separator(Component[0], S) && + Component[1] == Component[0] && !is_separator(Component[2], S); // Handle separators. - if (is_separator(Path[Position])) { + if (is_separator(Path[Position], S)) { // Root dir. - if (was_net -#ifdef LLVM_ON_WIN32 + if (was_net || // c:/ - || Component.endswith(":") -#endif - ) { + (real_style(S) == Style::windows && Component.endswith(":"))) { Component = Path.substr(Position, 1); return *this; } // Skip extra separators. - while (Position != Path.size() && - is_separator(Path[Position])) { + while (Position != Path.size() && is_separator(Path[Position], S)) { ++Position; } @@ -292,7 +288,7 @@ const_iterator &const_iterator::operator++() { } // Find next component. - size_t end_pos = Path.find_first_of(separators, Position); + size_t end_pos = Path.find_first_of(separators(S), Position); Component = Path.slice(Position, end_pos); return *this; @@ -306,10 +302,11 @@ ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { return Position - RHS.Position; } -reverse_iterator rbegin(StringRef Path) { +reverse_iterator rbegin(StringRef Path, Style style) { reverse_iterator I; I.Path = Path; I.Position = Path.size(); + I.S = style; return ++I; } @@ -324,10 +321,9 @@ reverse_iterator rend(StringRef Path) { reverse_iterator &reverse_iterator::operator++() { // If we're at the end and the previous char was a '/', return '.' unless // we are the root path. - size_t root_dir_pos = root_dir_start(Path); - if (Position == Path.size() && - Path.size() > root_dir_pos + 1 && - is_separator(Path[Position - 1])) { + size_t root_dir_pos = root_dir_start(Path, S); + if (Position == Path.size() && Path.size() > root_dir_pos + 1 && + is_separator(Path[Position - 1], S)) { --Position; Component = "."; return *this; @@ -336,13 +332,12 @@ reverse_iterator &reverse_iterator::operator++() { // Skip separators unless it's the root directory. size_t end_pos = Position; - while(end_pos > 0 && - (end_pos - 1) != root_dir_pos && - is_separator(Path[end_pos - 1])) + while (end_pos > 0 && (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1], S)) --end_pos; // Find next separator. - size_t start_pos = filename_pos(Path.substr(0, end_pos)); + size_t start_pos = filename_pos(Path.substr(0, end_pos), S); Component = Path.slice(start_pos, end_pos); Position = start_pos; return *this; @@ -357,21 +352,15 @@ ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const { return Position - RHS.Position; } -StringRef root_path(StringRef path) { - const_iterator b = begin(path), - pos = b, - e = end(path); +StringRef root_path(StringRef path, Style style) { + const_iterator b = begin(path, style), pos = b, e = end(path); if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif + bool has_net = + b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0]; + bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); if (has_net || has_drive) { - if ((++pos != e) && is_separator((*pos)[0])) { + if ((++pos != e) && is_separator((*pos)[0], style)) { // {C:/,//net/}, so get the first two components. return path.substr(0, b->size() + pos->size()); } else { @@ -381,7 +370,7 @@ StringRef root_path(StringRef path) { } // POSIX style root directory. - if (is_separator((*b)[0])) { + if (is_separator((*b)[0], style)) { return *b; } } @@ -389,17 +378,12 @@ StringRef root_path(StringRef path) { return StringRef(); } -StringRef root_name(StringRef path) { - const_iterator b = begin(path), - e = end(path); +StringRef root_name(StringRef path, Style style) { + const_iterator b = begin(path, style), e = end(path); if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif + bool has_net = + b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0]; + bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); if (has_net || has_drive) { // just {C:,//net}, return the first component. @@ -411,27 +395,21 @@ StringRef root_name(StringRef path) { return StringRef(); } -StringRef root_directory(StringRef path) { - const_iterator b = begin(path), - pos = b, - e = end(path); +StringRef root_directory(StringRef path, Style style) { + const_iterator b = begin(path, style), pos = b, e = end(path); if (b != e) { - bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; - bool has_drive = -#ifdef LLVM_ON_WIN32 - b->endswith(":"); -#else - false; -#endif + bool has_net = + b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0]; + bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); if ((has_net || has_drive) && // {C:,//net}, skip to the next component. - (++pos != e) && is_separator((*pos)[0])) { + (++pos != e) && is_separator((*pos)[0], style)) { return *pos; } // POSIX style root directory. - if (!has_net && is_separator((*b)[0])) { + if (!has_net && is_separator((*b)[0], style)) { return *b; } } @@ -440,15 +418,13 @@ StringRef root_directory(StringRef path) { return StringRef(); } -StringRef relative_path(StringRef path) { - StringRef root = root_path(path); +StringRef relative_path(StringRef path, Style style) { + StringRef root = root_path(path, style); return path.substr(root.size()); } -void append(SmallVectorImpl<char> &path, const Twine &a, - const Twine &b, - const Twine &c, - const Twine &d) { +void append(SmallVectorImpl<char> &path, Style style, const Twine &a, + const Twine &b, const Twine &c, const Twine &d) { SmallString<32> a_storage; SmallString<32> b_storage; SmallString<32> c_storage; @@ -461,13 +437,15 @@ void append(SmallVectorImpl<char> &path, const Twine &a, if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); for (auto &component : components) { - bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); - bool component_has_sep = !component.empty() && is_separator(component[0]); - bool is_root_name = has_root_name(component); + bool path_has_sep = + !path.empty() && is_separator(path[path.size() - 1], style); + bool component_has_sep = + !component.empty() && is_separator(component[0], style); + bool is_root_name = has_root_name(component, style); if (path_has_sep) { // Strip separators from beginning of component. - size_t loc = component.find_first_not_of(separators); + size_t loc = component.find_first_not_of(separators(style)); StringRef c = component.substr(loc); // Append it. @@ -477,41 +455,47 @@ void append(SmallVectorImpl<char> &path, const Twine &a, if (!component_has_sep && !(path.empty() || is_root_name)) { // Add a separator. - path.push_back(preferred_separator); + path.push_back(preferred_separator(style)); } path.append(component.begin(), component.end()); } } -void append(SmallVectorImpl<char> &path, - const_iterator begin, const_iterator end) { +void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b, + const Twine &c, const Twine &d) { + append(path, Style::native, a, b, c, d); +} + +void append(SmallVectorImpl<char> &path, const_iterator begin, + const_iterator end, Style style) { for (; begin != end; ++begin) - path::append(path, *begin); + path::append(path, style, *begin); } -StringRef parent_path(StringRef path) { - size_t end_pos = parent_path_end(path); +StringRef parent_path(StringRef path, Style style) { + size_t end_pos = parent_path_end(path, style); if (end_pos == StringRef::npos) return StringRef(); else return path.substr(0, end_pos); } -void remove_filename(SmallVectorImpl<char> &path) { - size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); +void remove_filename(SmallVectorImpl<char> &path, Style style) { + size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style); if (end_pos != StringRef::npos) path.set_size(end_pos); } -void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { +void replace_extension(SmallVectorImpl<char> &path, const Twine &extension, + Style style) { StringRef p(path.begin(), path.size()); SmallString<32> ext_storage; StringRef ext = extension.toStringRef(ext_storage); // Erase existing extension. size_t pos = p.find_last_of('.'); - if (pos != StringRef::npos && pos >= filename_pos(p)) + if (pos != StringRef::npos && pos >= filename_pos(p, style)) path.set_size(pos); // Append '.' if needed. @@ -523,8 +507,8 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) { } void replace_path_prefix(SmallVectorImpl<char> &Path, - const StringRef &OldPrefix, - const StringRef &NewPrefix) { + const StringRef &OldPrefix, const StringRef &NewPrefix, + Style style) { if (OldPrefix.empty() && NewPrefix.empty()) return; @@ -540,53 +524,58 @@ void replace_path_prefix(SmallVectorImpl<char> &Path, StringRef RelPath = OrigPath.substr(OldPrefix.size()); SmallString<256> NewPath; - path::append(NewPath, NewPrefix); - path::append(NewPath, RelPath); + path::append(NewPath, style, NewPrefix); + path::append(NewPath, style, RelPath); Path.swap(NewPath); } -void native(const Twine &path, SmallVectorImpl<char> &result) { +void native(const Twine &path, SmallVectorImpl<char> &result, Style style) { assert((!path.isSingleStringRef() || path.getSingleStringRef().data() != result.data()) && "path and result are not allowed to overlap!"); // Clear result. result.clear(); path.toVector(result); - native(result); + native(result, style); } -void native(SmallVectorImpl<char> &Path) { -#ifdef LLVM_ON_WIN32 - std::replace(Path.begin(), Path.end(), '/', '\\'); -#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 = '/'; +void native(SmallVectorImpl<char> &Path, Style style) { + if (Path.empty()) + return; + if (real_style(style) == Style::windows) { + std::replace(Path.begin(), Path.end(), '/', '\\'); + if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) { + SmallString<128> PathHome; + home_directory(PathHome); + PathHome.append(Path.begin() + 1, Path.end()); + 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 = '/'; + } } } -#endif } -std::string convert_to_slash(StringRef path) { -#ifdef LLVM_ON_WIN32 +std::string convert_to_slash(StringRef path, Style style) { + if (real_style(style) != Style::windows) + return path; + std::string s = path.str(); std::replace(s.begin(), s.end(), '\\', '/'); return s; -#else - return path; -#endif } -StringRef filename(StringRef path) { - return *rbegin(path); -} +StringRef filename(StringRef path, Style style) { return *rbegin(path, style); } -StringRef stem(StringRef path) { - StringRef fname = filename(path); +StringRef stem(StringRef path, Style style) { + StringRef fname = filename(path, style); size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return fname; @@ -598,8 +587,8 @@ StringRef stem(StringRef path) { return fname.substr(0, pos); } -StringRef extension(StringRef path) { - StringRef fname = filename(path); +StringRef extension(StringRef path, Style style) { + StringRef fname = filename(path, style); size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return StringRef(); @@ -611,110 +600,109 @@ StringRef extension(StringRef path) { return fname.substr(pos); } -bool is_separator(char value) { - switch(value) { -#ifdef LLVM_ON_WIN32 - case '\\': // fall through -#endif - case '/': return true; - default: return false; - } +bool is_separator(char value, Style style) { + if (value == '/') + return true; + if (real_style(style) == Style::windows) + return value == '\\'; + return false; } -static const char preferred_separator_string[] = { preferred_separator, '\0' }; - -StringRef get_separator() { - return preferred_separator_string; +StringRef get_separator(Style style) { + if (real_style(style) == Style::windows) + return "\\"; + return "/"; } -bool has_root_name(const Twine &path) { +bool has_root_name(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !root_name(p).empty(); + return !root_name(p, style).empty(); } -bool has_root_directory(const Twine &path) { +bool has_root_directory(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !root_directory(p).empty(); + return !root_directory(p, style).empty(); } -bool has_root_path(const Twine &path) { +bool has_root_path(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !root_path(p).empty(); + return !root_path(p, style).empty(); } -bool has_relative_path(const Twine &path) { +bool has_relative_path(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !relative_path(p).empty(); + return !relative_path(p, style).empty(); } -bool has_filename(const Twine &path) { +bool has_filename(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !filename(p).empty(); + return !filename(p, style).empty(); } -bool has_parent_path(const Twine &path) { +bool has_parent_path(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !parent_path(p).empty(); + return !parent_path(p, style).empty(); } -bool has_stem(const Twine &path) { +bool has_stem(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !stem(p).empty(); + return !stem(p, style).empty(); } -bool has_extension(const Twine &path) { +bool has_extension(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - return !extension(p).empty(); + return !extension(p, style).empty(); } -bool is_absolute(const Twine &path) { +bool is_absolute(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); - bool rootDir = has_root_directory(p), -#ifdef LLVM_ON_WIN32 - rootName = has_root_name(p); -#else - rootName = true; -#endif + bool rootDir = has_root_directory(p, style); + bool rootName = + (real_style(style) != Style::windows) || has_root_name(p, style); return rootDir && rootName; } -bool is_relative(const Twine &path) { return !is_absolute(path); } +bool is_relative(const Twine &path, Style style) { + return !is_absolute(path, style); +} -StringRef remove_leading_dotslash(StringRef Path) { +StringRef remove_leading_dotslash(StringRef Path, Style style) { // Remove leading "./" (or ".//" or "././" etc.) - while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) { + while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) { Path = Path.substr(2); - while (Path.size() > 0 && is_separator(Path[0])) + while (Path.size() > 0 && is_separator(Path[0], style)) Path = Path.substr(1); } return Path; } -static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) { +static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot, + Style style) { SmallVector<StringRef, 16> components; // Skip the root path, then look for traversal in the components. - StringRef rel = path::relative_path(path); - for (StringRef C : llvm::make_range(path::begin(rel), path::end(rel))) { + 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. @@ -723,22 +711,23 @@ static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) { components.pop_back(); continue; } - if (path::is_absolute(path)) + if (path::is_absolute(path, style)) continue; } components.push_back(C); } - SmallString<256> buffer = path::root_path(path); + SmallString<256> buffer = path::root_path(path, style); for (StringRef C : components) - path::append(buffer, C); + path::append(buffer, style, C); return buffer; } -bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot) { +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); + SmallString<256> result = remove_dots(p, remove_dot_dot, style); if (result == path) return false; @@ -776,7 +765,7 @@ createTemporaryFile(const Twine &Model, int &ResultFD, llvm::SmallVectorImpl<char> &ResultPath, FSEntity Type) { SmallString<128> Storage; StringRef P = Model.toNullTerminatedStringRef(Storage); - assert(P.find_first_of(separators) == StringRef::npos && + assert(P.find_first_of(separators(Style::native)) == StringRef::npos && "Model must be a simple filename."); // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. return createUniqueEntity(P.begin(), ResultFD, ResultPath, @@ -818,12 +807,9 @@ static std::error_code make_absolute(const Twine ¤t_directory, bool use_current_directory) { StringRef p(path.data(), path.size()); - bool rootDirectory = path::has_root_directory(p), -#ifdef LLVM_ON_WIN32 - rootName = path::has_root_name(p); -#else - rootName = true; -#endif + bool rootDirectory = path::has_root_directory(p); + bool rootName = + (real_style(Style::native) != Style::windows) || path::has_root_name(p); // Already absolute. if (rootName && rootDirectory) @@ -937,6 +923,36 @@ std::error_code copy_file(const Twine &From, const Twine &To) { return std::error_code(); } +ErrorOr<MD5::MD5Result> md5_contents(int FD) { + MD5 Hash; + + constexpr size_t BufSize = 4096; + std::vector<uint8_t> Buf(BufSize); + int BytesRead = 0; + for (;;) { + BytesRead = read(FD, Buf.data(), BufSize); + if (BytesRead <= 0) + break; + Hash.update(makeArrayRef(Buf.data(), BytesRead)); + } + + if (BytesRead < 0) + return std::error_code(errno, std::generic_category()); + MD5::MD5Result Result; + Hash.final(Result); + return Result; +} + +ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path) { + int FD; + if (auto EC = openFileForRead(Path, FD)) + return EC; + + auto Result = md5_contents(FD); + close(FD); + return Result; +} + bool exists(file_status status) { return status_known(status) && status.type() != file_type::file_not_found; } @@ -945,6 +961,13 @@ bool status_known(file_status s) { return s.type() != file_type::status_error; } +file_type get_file_type(const Twine &Path, bool Follow) { + file_status st; + if (status(Path, st, Follow)) + return file_type::status_error; + return st.type(); +} + bool is_directory(file_status status) { return status.type() == file_type::directory_file; } @@ -969,6 +992,18 @@ std::error_code is_regular_file(const Twine &path, bool &result) { return std::error_code(); } +bool is_symlink_file(file_status status) { + return status.type() == file_type::symlink_file; +} + +std::error_code is_symlink_file(const Twine &path, bool &result) { + file_status st; + if (std::error_code ec = status(path, st, false)) + return ec; + result = is_symlink_file(st); + return std::error_code(); +} + bool is_other(file_status status) { return exists(status) && !is_regular_file(status) && @@ -990,179 +1025,16 @@ void directory_entry::replace_filename(const Twine &filename, file_status st) { Status = st; } -template <size_t N> -static bool startswith(StringRef Magic, const char (&S)[N]) { - return Magic.startswith(StringRef(S, N - 1)); -} - -/// @brief Identify the magic in magic. -file_magic identify_magic(StringRef Magic) { - if (Magic.size() < 4) - return file_magic::unknown; - switch ((unsigned char)Magic[0]) { - case 0x00: { - // COFF bigobj, CL.exe's LTO object file, or short import library file - if (startswith(Magic, "\0\0\xFF\xFF")) { - size_t MinSize = offsetof(COFF::BigObjHeader, UUID) + sizeof(COFF::BigObjMagic); - if (Magic.size() < MinSize) - return file_magic::coff_import_library; - - const char *Start = Magic.data() + offsetof(COFF::BigObjHeader, UUID); - if (memcmp(Start, COFF::BigObjMagic, sizeof(COFF::BigObjMagic)) == 0) - return file_magic::coff_object; - if (memcmp(Start, COFF::ClGlObjMagic, sizeof(COFF::BigObjMagic)) == 0) - return file_magic::coff_cl_gl_object; - return file_magic::coff_import_library; - } - // Windows resource file - if (startswith(Magic, "\0\0\0\0\x20\0\0\0\xFF")) - return file_magic::windows_resource; - // 0x0000 = COFF unknown machine type - if (Magic[1] == 0) - return file_magic::coff_object; - if (startswith(Magic, "\0asm")) - return file_magic::wasm_object; - break; - } - case 0xDE: // 0x0B17C0DE = BC wraper - if (startswith(Magic, "\xDE\xC0\x17\x0B")) - return file_magic::bitcode; - break; - case 'B': - if (startswith(Magic, "BC\xC0\xDE")) - return file_magic::bitcode; - break; - case '!': - if (startswith(Magic, "!<arch>\n") || startswith(Magic, "!<thin>\n")) - return file_magic::archive; - break; - - case '\177': - if (startswith(Magic, "\177ELF") && Magic.size() >= 18) { - bool Data2MSB = Magic[5] == 2; - unsigned high = Data2MSB ? 16 : 17; - unsigned low = Data2MSB ? 17 : 16; - if (Magic[high] == 0) { - switch (Magic[low]) { - default: return file_magic::elf; - case 1: return file_magic::elf_relocatable; - case 2: return file_magic::elf_executable; - case 3: return file_magic::elf_shared_object; - case 4: return file_magic::elf_core; - } - } - // It's still some type of ELF file. - return file_magic::elf; - } - break; - - case 0xCA: - if (startswith(Magic, "\xCA\xFE\xBA\xBE") || - startswith(Magic, "\xCA\xFE\xBA\xBF")) { - // This is complicated by an overlap with Java class files. - // See the Mach-O section in /usr/share/file/magic for details. - if (Magic.size() >= 8 && Magic[7] < 43) - return file_magic::macho_universal_binary; - } - break; - - // The two magic numbers for mach-o are: - // 0xfeedface - 32-bit mach-o - // 0xfeedfacf - 64-bit mach-o - case 0xFE: - case 0xCE: - case 0xCF: { - uint16_t type = 0; - if (startswith(Magic, "\xFE\xED\xFA\xCE") || - startswith(Magic, "\xFE\xED\xFA\xCF")) { - /* Native endian */ - size_t MinSize; - if (Magic[3] == char(0xCE)) - MinSize = sizeof(MachO::mach_header); - else - MinSize = sizeof(MachO::mach_header_64); - if (Magic.size() >= MinSize) - type = Magic[12] << 24 | Magic[13] << 12 | Magic[14] << 8 | Magic[15]; - } else if (startswith(Magic, "\xCE\xFA\xED\xFE") || - startswith(Magic, "\xCF\xFA\xED\xFE")) { - /* Reverse endian */ - size_t MinSize; - if (Magic[0] == char(0xCE)) - MinSize = sizeof(MachO::mach_header); - else - MinSize = sizeof(MachO::mach_header_64); - if (Magic.size() >= MinSize) - type = Magic[15] << 24 | Magic[14] << 12 |Magic[13] << 8 | Magic[12]; - } - switch (type) { - default: break; - case 1: return file_magic::macho_object; - case 2: return file_magic::macho_executable; - case 3: return file_magic::macho_fixed_virtual_memory_shared_lib; - case 4: return file_magic::macho_core; - case 5: return file_magic::macho_preload_executable; - case 6: return file_magic::macho_dynamically_linked_shared_lib; - case 7: return file_magic::macho_dynamic_linker; - case 8: return file_magic::macho_bundle; - case 9: return file_magic::macho_dynamically_linked_shared_lib_stub; - case 10: return file_magic::macho_dsym_companion; - case 11: return file_magic::macho_kext_bundle; - } - break; - } - case 0xF0: // PowerPC Windows - case 0x83: // Alpha 32-bit - case 0x84: // Alpha 64-bit - case 0x66: // MPS R4000 Windows - case 0x50: // mc68K - case 0x4c: // 80386 Windows - case 0xc4: // ARMNT Windows - if (Magic[1] == 0x01) - return file_magic::coff_object; - - case 0x90: // PA-RISC Windows - case 0x68: // mc68K Windows - if (Magic[1] == 0x02) - return file_magic::coff_object; - break; - - case 'M': // Possible MS-DOS stub on Windows PE file - if (startswith(Magic, "MZ")) { - uint32_t off = read32le(Magic.data() + 0x3c); - // PE/COFF file, either EXE or DLL. - if (off < Magic.size() && - memcmp(Magic.data()+off, COFF::PEMagic, sizeof(COFF::PEMagic)) == 0) - return file_magic::pecoff_executable; - } - break; - - case 0x64: // x86-64 Windows. - if (Magic[1] == char(0x86)) - return file_magic::coff_object; - break; - - default: - break; - } - return file_magic::unknown; +std::error_code directory_entry::status(file_status &result) const { + return fs::status(Path, result, FollowSymlinks); } -std::error_code identify_magic(const Twine &Path, file_magic &Result) { - int FD; - if (std::error_code EC = openFileForRead(Path, FD)) +ErrorOr<perms> getPermissions(const Twine &Path) { + file_status Status; + if (std::error_code EC = status(Path, Status)) return EC; - char Buffer[32]; - int Length = read(FD, Buffer, sizeof(Buffer)); - if (close(FD) != 0 || Length < 0) - return std::error_code(errno, std::generic_category()); - - Result = identify_magic(StringRef(Buffer, Length)); - return std::error_code(); -} - -std::error_code directory_entry::status(file_status &result) const { - return fs::status(Path, result); + return Status.permissions(); } } // end namespace fs diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp index 5b079ff..a18e9cc 100644 --- a/contrib/llvm/lib/Support/PrettyStackTrace.cpp +++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp @@ -15,13 +15,14 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm-c/ErrorHandling.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/Compiler.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" #include <cstdarg> +#include <cstdio> #include <tuple> #ifdef HAVE_CRASHREPORTERCLIENT_H diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp index 290c30f..caec993 100644 --- a/contrib/llvm/lib/Support/Process.cpp +++ b/contrib/llvm/lib/Support/Process.cpp @@ -11,11 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/Process.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" #include "llvm/Support/Program.h" using namespace llvm; diff --git a/contrib/llvm/lib/Support/RWMutex.cpp b/contrib/llvm/lib/Support/RWMutex.cpp index 3b6309c..83c6d1d 100644 --- a/contrib/llvm/lib/Support/RWMutex.cpp +++ b/contrib/llvm/lib/Support/RWMutex.cpp @@ -11,9 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Config/config.h" #include "llvm/Support/RWMutex.h" -#include <cstring> +#include "llvm/Config/config.h" //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only TRULY operating system @@ -22,29 +21,31 @@ #if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 // Define all methods as no-ops if threading is explicitly disabled -namespace llvm { + +using namespace llvm; using namespace sys; -RWMutexImpl::RWMutexImpl() { } -RWMutexImpl::~RWMutexImpl() { } + +RWMutexImpl::RWMutexImpl() = default; +RWMutexImpl::~RWMutexImpl() = default; + bool RWMutexImpl::reader_acquire() { return true; } bool RWMutexImpl::reader_release() { return true; } bool RWMutexImpl::writer_acquire() { return true; } bool RWMutexImpl::writer_release() { return true; } -} + #else #if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT) #include <cassert> +#include <cstdlib> #include <pthread.h> -#include <stdlib.h> -namespace llvm { +using namespace llvm; using namespace sys; // Construct a RWMutex using pthread calls RWMutexImpl::RWMutexImpl() - : data_(nullptr) { // Declare the pthread_rwlock data structures pthread_rwlock_t* rwlock = @@ -113,8 +114,6 @@ RWMutexImpl::writer_release() return errorcode == 0; } -} - #elif defined(LLVM_ON_UNIX) #include "Unix/RWMutex.inc" #elif defined( LLVM_ON_WIN32) diff --git a/contrib/llvm/lib/Support/Regex.cpp b/contrib/llvm/lib/Support/Regex.cpp index 68ba79e..b1087fd 100644 --- a/contrib/llvm/lib/Support/Regex.cpp +++ b/contrib/llvm/lib/Support/Regex.cpp @@ -48,7 +48,7 @@ Regex::~Regex() { } } -bool Regex::isValid(std::string &Error) { +bool Regex::isValid(std::string &Error) const { if (!error) return true; diff --git a/contrib/llvm/lib/Support/SHA1.cpp b/contrib/llvm/lib/Support/SHA1.cpp index 0eefd99..20f41c5 100644 --- a/contrib/llvm/lib/Support/SHA1.cpp +++ b/contrib/llvm/lib/Support/SHA1.cpp @@ -15,9 +15,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/Host.h" #include "llvm/Support/SHA1.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Host.h" using namespace llvm; #include <stdint.h> diff --git a/contrib/llvm/lib/Support/ScopedPrinter.cpp b/contrib/llvm/lib/Support/ScopedPrinter.cpp index d8ee1ef..537ff62 100644 --- a/contrib/llvm/lib/Support/ScopedPrinter.cpp +++ b/contrib/llvm/lib/Support/ScopedPrinter.cpp @@ -21,7 +21,8 @@ const std::string to_hexString(uint64_t Value, bool UpperCase) { } void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str, - ArrayRef<uint8_t> Data, bool Block) { + ArrayRef<uint8_t> Data, bool Block, + uint32_t StartOffset) { if (Data.size() > 16) Block = true; @@ -31,7 +32,8 @@ void ScopedPrinter::printBinaryImpl(StringRef Label, StringRef Str, OS << ": " << Str; OS << " (\n"; if (!Data.empty()) - OS << format_bytes_with_ascii(Data, 0, 16, 4, (IndentLevel + 1) * 2, true) + OS << format_bytes_with_ascii(Data, StartOffset, 16, 4, + (IndentLevel + 1) * 2, true) << "\n"; startLine() << ")\n"; } else { diff --git a/contrib/llvm/lib/Support/SearchForAddressOfSpecialSymbol.cpp b/contrib/llvm/lib/Support/SearchForAddressOfSpecialSymbol.cpp deleted file mode 100644 index 55f3320..0000000 --- a/contrib/llvm/lib/Support/SearchForAddressOfSpecialSymbol.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file pulls the addresses of certain symbols out of the linker. It must -// include as few header files as possible because it declares the symbols as -// void*, which would conflict with the actual symbol type if any header -// declared it. -// -//===----------------------------------------------------------------------===// - -#include <string.h> - -// Must declare the symbols in the global namespace. -static void *DoSearch(const char* symbolName) { -#define EXPLICIT_SYMBOL(SYM) \ - extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM - - // If this is darwin, it has some funky issues, try to solve them here. Some - // important symbols are marked 'private external' which doesn't allow - // SearchForAddressOfSymbol to find them. As such, we special case them here, - // there is only a small handful of them. - -#ifdef __APPLE__ - { - // __eprintf is sometimes used for assert() handling on x86. - // - // FIXME: Currently disabled when using Clang, as we don't always have our - // runtime support libraries available. -#ifndef __clang__ -#ifdef __i386__ - EXPLICIT_SYMBOL(__eprintf); -#endif -#endif - } -#endif - -#ifdef __CYGWIN__ - { - EXPLICIT_SYMBOL(_alloca); - EXPLICIT_SYMBOL(__main); - } -#endif - -#undef EXPLICIT_SYMBOL - return nullptr; -} - -namespace llvm { -void *SearchForAddressOfSpecialSymbol(const char* symbolName) { - return DoSearch(symbolName); -} -} // namespace llvm diff --git a/contrib/llvm/lib/Support/Signals.cpp b/contrib/llvm/lib/Support/Signals.cpp index e5e38f5..256a22d 100644 --- a/contrib/llvm/lib/Support/Signals.cpp +++ b/contrib/llvm/lib/Support/Signals.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/Signals.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" @@ -23,19 +24,23 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Program.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Options.h" #include <vector> -namespace llvm { -using namespace sys; - //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only TRULY operating system //=== independent code. //===----------------------------------------------------------------------===// +using namespace llvm; + +static cl::opt<bool> + DisableSymbolication("disable-symbolication", + cl::desc("Disable symbolizing crash backtraces."), + cl::init(false), cl::Hidden); + static ManagedStatic<std::vector<std::pair<void (*)(void *), void *>>> CallBacksToRun; void sys::RunSignalHandlers() { @@ -45,9 +50,6 @@ void sys::RunSignalHandlers() { I.first(I.second); CallBacksToRun->clear(); } -} - -using namespace llvm; static bool findModulesAndOffsets(void **StackTrace, int Depth, const char **Modules, intptr_t *Offsets, @@ -71,6 +73,9 @@ static bool printSymbolizedStackTrace(StringRef Argv0, static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, int Depth, llvm::raw_ostream &OS) { + if (DisableSymbolication) + return false; + // Don't recursively invoke the llvm-symbolizer binary. if (Argv0.find("llvm-symbolizer") != std::string::npos) return false; diff --git a/contrib/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm/lib/Support/SourceMgr.cpp index 4cb9b2f..b0609d4 100644 --- a/contrib/llvm/lib/Support/SourceMgr.cpp +++ b/contrib/llvm/lib/Support/SourceMgr.cpp @@ -14,33 +14,44 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SourceMgr.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/Locale.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SMLoc.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <memory> +#include <string> +#include <utility> + using namespace llvm; static const size_t TabStop = 8; namespace { + struct LineNoCacheTy { const char *LastQuery; unsigned LastQueryBufferID; unsigned LineNoOfQuery; }; -} + +} // end anonymous namespace static LineNoCacheTy *getCache(void *Ptr) { return (LineNoCacheTy*)Ptr; } - SourceMgr::~SourceMgr() { - // Delete the line # cache if allocated. - if (LineNoCacheTy *Cache = getCache(LineNoCache)) - delete Cache; + delete getCache(LineNoCache); } unsigned SourceMgr::AddIncludeFile(const std::string &Filename, @@ -132,12 +143,10 @@ void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; } - SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind, 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. SmallVector<std::pair<unsigned, unsigned>, 4> ColRanges; @@ -223,7 +232,7 @@ void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc, void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, ArrayRef<SMRange> Ranges, ArrayRef<SMFixIt> FixIts, bool ShowColors) const { - PrintMessage(llvm::errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors); + PrintMessage(errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors); } //===----------------------------------------------------------------------===// @@ -233,7 +242,7 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind, 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<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()), @@ -286,7 +295,7 @@ static void buildFixItLine(std::string &CaretLine, std::string &FixItLine, // FIXME: This assertion is intended to catch unintended use of multibyte // characters in fixits. If we decide to do this, we'll have to track // separate byte widths for the source and fixit lines. - assert((size_t)llvm::sys::locale::columnWidth(I->getText()) == + assert((size_t)sys::locale::columnWidth(I->getText()) == I->getText().size()); // This relies on one byte per column in our fixit hints. diff --git a/contrib/llvm/lib/Support/SpecialCaseList.cpp b/contrib/llvm/lib/Support/SpecialCaseList.cpp index df524b3..05886ea 100644 --- a/contrib/llvm/lib/Support/SpecialCaseList.cpp +++ b/contrib/llvm/lib/Support/SpecialCaseList.cpp @@ -15,12 +15,12 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SpecialCaseList.h" -#include "llvm/Support/TrigramIndex.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/TrigramIndex.h" #include <string> #include <system_error> #include <utility> diff --git a/contrib/llvm/lib/Support/Statistic.cpp b/contrib/llvm/lib/Support/Statistic.cpp index 0c50dfd..72ca228 100644 --- a/contrib/llvm/lib/Support/Statistic.cpp +++ b/contrib/llvm/lib/Support/Statistic.cpp @@ -30,8 +30,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstring> using namespace llvm; diff --git a/contrib/llvm/lib/Support/StringExtras.cpp b/contrib/llvm/lib/Support/StringExtras.cpp index 3e2420f..b2f42df 100644 --- a/contrib/llvm/lib/Support/StringExtras.cpp +++ b/contrib/llvm/lib/Support/StringExtras.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallVector.h" using namespace llvm; /// StrInStrNoCase - Portable version of strcasestr. Locates the first diff --git a/contrib/llvm/lib/Support/StringRef.cpp b/contrib/llvm/lib/Support/StringRef.cpp index d81250e..9b7cc1c 100644 --- a/contrib/llvm/lib/Support/StringRef.cpp +++ b/contrib/llvm/lib/Support/StringRef.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/edit_distance.h" @@ -595,6 +596,18 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { return false; } +bool StringRef::getAsDouble(double &Result, bool AllowInexact) const { + APFloat F(0.0); + APFloat::opStatus Status = + F.convertFromString(*this, APFloat::rmNearestTiesToEven); + if (Status != APFloat::opOK) { + if (!AllowInexact || Status != APFloat::opInexact) + return true; + } + + Result = F.convertToDouble(); + return false; +} // Implementation of StringRef hashing. hash_code llvm::hash_value(StringRef S) { diff --git a/contrib/llvm/lib/Support/TargetParser.cpp b/contrib/llvm/lib/Support/TargetParser.cpp index 42fab67..e8ef1d2 100644 --- a/contrib/llvm/lib/Support/TargetParser.cpp +++ b/contrib/llvm/lib/Support/TargetParser.cpp @@ -210,7 +210,7 @@ bool llvm::ARM::getHWDivFeatures(unsigned HWDivKind, else Features.push_back("-hwdiv-arm"); - if (HWDivKind & ARM::AEK_HWDIV) + if (HWDivKind & ARM::AEK_HWDIVTHUMB) Features.push_back("+hwdiv"); else Features.push_back("-hwdiv"); @@ -422,8 +422,10 @@ unsigned llvm::AArch64::getDefaultExtensions(StringRef CPU, unsigned ArchKind) { return AArch64ARCHNames[ArchKind].ArchBaseExtensions; return StringSwitch<unsigned>(CPU) -#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ - .Case(NAME, DEFAULT_EXT) +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \ + .Case(NAME, \ + AArch64ARCHNames[(unsigned)AArch64::ArchKind::ID].ArchBaseExtensions | \ + DEFAULT_EXT) #include "llvm/Support/AArch64TargetParser.def" .Default(AArch64::AEK_INVALID); } @@ -448,6 +450,10 @@ bool llvm::AArch64::getExtensionFeatures(unsigned Extensions, Features.push_back("+spe"); if (Extensions & AArch64::AEK_RAS) Features.push_back("+ras"); + if (Extensions & AArch64::AEK_LSE) + Features.push_back("+lse"); + if (Extensions & AArch64::AEK_SVE) + Features.push_back("+sve"); return true; } @@ -725,6 +731,7 @@ unsigned llvm::ARM::parseArchProfile(StringRef Arch) { case ARM::AK_ARMV8R: return ARM::PK_R; case ARM::AK_ARMV7A: + case ARM::AK_ARMV7VE: case ARM::AK_ARMV7K: case ARM::AK_ARMV8A: case ARM::AK_ARMV8_1A: @@ -761,6 +768,7 @@ unsigned llvm::ARM::parseArchVersion(StringRef Arch) { case ARM::AK_ARMV6M: return 6; case ARM::AK_ARMV7A: + case ARM::AK_ARMV7VE: case ARM::AK_ARMV7R: case ARM::AK_ARMV7M: case ARM::AK_ARMV7S: @@ -778,6 +786,42 @@ unsigned llvm::ARM::parseArchVersion(StringRef Arch) { return 0; } +StringRef llvm::ARM::computeDefaultTargetABI(const Triple &TT, StringRef CPU) { + StringRef ArchName = + CPU.empty() ? TT.getArchName() : ARM::getArchName(ARM::parseCPUArch(CPU)); + + if (TT.isOSBinFormatMachO()) { + if (TT.getEnvironment() == Triple::EABI || + TT.getOS() == Triple::UnknownOS || + llvm::ARM::parseArchProfile(ArchName) == ARM::PK_M) + return "aapcs"; + if (TT.isWatchABI()) + return "aapcs16"; + return "apcs-gnu"; + } else if (TT.isOSWindows()) + // FIXME: this is invalid for WindowsCE. + return "aapcs"; + + // Select the default based on the platform. + switch (TT.getEnvironment()) { + case Triple::Android: + case Triple::GNUEABI: + case Triple::GNUEABIHF: + case Triple::MuslEABI: + case Triple::MuslEABIHF: + return "aapcs-linux"; + case Triple::EABIHF: + case Triple::EABI: + return "aapcs"; + default: + if (TT.isOSNetBSD()) + return "apcs-gnu"; + if (TT.isOSOpenBSD()) + return "aapcs-linux"; + return "aapcs"; + } +} + StringRef llvm::AArch64::getCanonicalArchName(StringRef Arch) { return ARM::getCanonicalArchName(Arch); } diff --git a/contrib/llvm/lib/Support/ThreadLocal.cpp b/contrib/llvm/lib/Support/ThreadLocal.cpp index 9da1603..9a75c02 100644 --- a/contrib/llvm/lib/Support/ThreadLocal.cpp +++ b/contrib/llvm/lib/Support/ThreadLocal.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Support/ThreadLocal.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/ThreadLocal.h" //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only TRULY operating system diff --git a/contrib/llvm/lib/Support/ThreadPool.cpp b/contrib/llvm/lib/Support/ThreadPool.cpp index db03a4d..22b7550 100644 --- a/contrib/llvm/lib/Support/ThreadPool.cpp +++ b/contrib/llvm/lib/Support/ThreadPool.cpp @@ -53,11 +53,7 @@ ThreadPool::ThreadPool(unsigned ThreadCount) Tasks.pop(); } // Run the task we just grabbed -#ifndef _MSC_VER Task(); -#else - Task(/* unused */ false); -#endif { // Adjust `ActiveThreads`, in case someone waits on ThreadPool::wait() @@ -82,7 +78,7 @@ void ThreadPool::wait() { [&] { return !ActiveThreads && Tasks.empty(); }); } -std::shared_future<ThreadPool::VoidTy> ThreadPool::asyncImpl(TaskTy Task) { +std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) { /// Wrap the Task in a packaged_task to return a future object. PackagedTaskTy PackagedTask(std::move(Task)); auto Future = PackagedTask.get_future(); @@ -128,25 +124,16 @@ void ThreadPool::wait() { while (!Tasks.empty()) { auto Task = std::move(Tasks.front()); Tasks.pop(); -#ifndef _MSC_VER - Task(); -#else - Task(/* unused */ false); -#endif + Task(); } } -std::shared_future<ThreadPool::VoidTy> ThreadPool::asyncImpl(TaskTy Task) { -#ifndef _MSC_VER +std::shared_future<void> ThreadPool::asyncImpl(TaskTy Task) { // Get a Future with launch::deferred execution using std::async auto Future = std::async(std::launch::deferred, std::move(Task)).share(); // Wrap the future so that both ThreadPool::wait() can operate and the // returned future can be sync'ed on. PackagedTaskTy PackagedTask([Future]() { Future.get(); }); -#else - auto Future = std::async(std::launch::deferred, std::move(Task), false).share(); - PackagedTaskTy PackagedTask([Future](bool) -> bool { Future.get(); return false; }); -#endif Tasks.push(std::move(PackagedTask)); return Future; } diff --git a/contrib/llvm/lib/Support/Threading.cpp b/contrib/llvm/lib/Support/Threading.cpp index 760f9e2..6a10b98 100644 --- a/contrib/llvm/lib/Support/Threading.cpp +++ b/contrib/llvm/lib/Support/Threading.cpp @@ -14,14 +14,20 @@ #include "llvm/Support/Threading.h" #include "llvm/Config/config.h" -#include "llvm/Support/Atomic.h" #include "llvm/Support/Host.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/thread.h" + #include <cassert> +#include <errno.h> +#include <stdlib.h> +#include <string.h> using namespace llvm; +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + bool llvm::llvm_is_multithreaded() { #if LLVM_ENABLE_THREADS != 0 return true; @@ -30,100 +36,47 @@ bool llvm::llvm_is_multithreaded() { #endif } -#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) -#include <pthread.h> - -struct ThreadInfo { - void (*UserFn)(void *); - void *UserData; -}; -static void *ExecuteOnThread_Dispatch(void *Arg) { - ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); - TI->UserFn(TI->UserData); - return nullptr; -} - -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, +#if LLVM_ENABLE_THREADS == 0 || \ + (!defined(LLVM_ON_WIN32) && !defined(HAVE_PTHREAD_H)) +// Support for non-Win32, non-pthread implementation. +void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, unsigned RequestedStackSize) { - ThreadInfo Info = { Fn, UserData }; - pthread_attr_t Attr; - pthread_t Thread; - - // Construct the attributes object. - if (::pthread_attr_init(&Attr) != 0) - return; - - // Set the requested stack size, if given. - if (RequestedStackSize != 0) { - if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) - goto error; - } - - // Construct and execute the thread. - if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) - goto error; - - // Wait for the thread and clean up. - ::pthread_join(Thread, nullptr); - - error: - ::pthread_attr_destroy(&Attr); + (void)RequestedStackSize; + Fn(UserData); } -#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) -#include "Windows/WindowsSupport.h" -#include <process.h> -// Windows will at times define MemoryFence. -#ifdef MemoryFence -#undef MemoryFence -#endif +unsigned llvm::heavyweight_hardware_concurrency() { return 1; } -struct ThreadInfo { - void (*func)(void*); - void *param; -}; +uint64_t llvm::get_threadid() { return 0; } -static unsigned __stdcall ThreadCallback(void *param) { - struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); - info->func(info->param); +uint32_t llvm::get_max_thread_name_length() { return 0; } - return 0; -} +void llvm::set_thread_name(const Twine &Name) {} -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - struct ThreadInfo param = { Fn, UserData }; - - HANDLE hThread = (HANDLE)::_beginthreadex(NULL, - RequestedStackSize, ThreadCallback, - ¶m, 0, NULL); +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); } - if (hThread) { - // We actually don't care whether the wait succeeds or fails, in - // the same way we don't care whether the pthread_join call succeeds - // or fails. There's not much we could do if this were to fail. But - // on success, this call will wait until the thread finishes executing - // before returning. - (void)::WaitForSingleObject(hThread, INFINITE); - ::CloseHandle(hThread); - } -} #else -// Support for non-Win32, non-pthread implementation. -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - (void) RequestedStackSize; - Fn(UserData); -} - -#endif +#include <thread> unsigned llvm::heavyweight_hardware_concurrency() { -#if !LLVM_ENABLE_THREADS - return 1; -#endif + // 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 thread::hardware_concurrency(); + return std::thread::hardware_concurrency(); return NumPhysical; } + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Threading.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Threading.inc" +#endif + +#endif diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp index fbd73d0..3386f26 100644 --- a/contrib/llvm/lib/Support/Timer.cpp +++ b/contrib/llvm/lib/Support/Timer.cpp @@ -20,8 +20,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; // This ugly hack is brought to you courtesy of constructor/destructor ordering @@ -72,23 +72,15 @@ std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() { return llvm::make_unique<raw_fd_ostream>(2, false); // stderr. } - -static TimerGroup *DefaultTimerGroup = nullptr; -static TimerGroup *getDefaultTimerGroup() { - TimerGroup *tmp = DefaultTimerGroup; - sys::MemoryFence(); - if (tmp) return tmp; - - sys::SmartScopedLock<true> Lock(*TimerLock); - tmp = DefaultTimerGroup; - if (!tmp) { - tmp = new TimerGroup("misc", "Miscellaneous Ungrouped Timers"); - sys::MemoryFence(); - DefaultTimerGroup = tmp; +namespace { +struct CreateDefaultTimerGroup { + static void *call() { + return new TimerGroup("misc", "Miscellaneous Ungrouped Timers"); } - - return tmp; -} +}; +} // namespace +static ManagedStatic<TimerGroup, CreateDefaultTimerGroup> DefaultTimerGroup; +static TimerGroup *getDefaultTimerGroup() { return &*DefaultTimerGroup; } //===----------------------------------------------------------------------===// // Timer Implementation @@ -309,7 +301,7 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // If this is not an collection of ungrouped times, print the total time. // Ungrouped timers don't really make sense to add up. We still print the // TOTAL line to make the percentages make sense. - if (this != DefaultTimerGroup) + if (this != getDefaultTimerGroup()) OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n", Total.getProcessTime(), Total.getWallTime()); OS << '\n'; diff --git a/contrib/llvm/lib/Support/TrigramIndex.cpp b/contrib/llvm/lib/Support/TrigramIndex.cpp index 85ab528..721763c 100644 --- a/contrib/llvm/lib/Support/TrigramIndex.cpp +++ b/contrib/llvm/lib/Support/TrigramIndex.cpp @@ -18,9 +18,9 @@ #include "llvm/Support/TrigramIndex.h" #include "llvm/ADT/SmallVector.h" -#include <unordered_map> #include <set> #include <string> +#include <unordered_map> using namespace llvm; diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp index 6783b40..2687a67 100644 --- a/contrib/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -12,8 +12,8 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/TargetParser.h" #include "llvm/Support/Host.h" +#include "llvm/Support/TargetParser.h" #include <cstring> using namespace llvm; @@ -34,6 +34,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case mips64: return "mips64"; case mips64el: return "mips64el"; case msp430: return "msp430"; + case nios2: return "nios2"; case ppc64: return "powerpc64"; case ppc64le: return "powerpc64le"; case ppc: return "powerpc"; @@ -98,6 +99,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case mips64: case mips64el: return "mips"; + case nios2: return "nios2"; + case hexagon: return "hexagon"; case amdgcn: return "amdgcn"; @@ -161,6 +164,7 @@ StringRef Triple::getVendorTypeName(VendorType Kind) { case Myriad: return "myriad"; case AMD: return "amd"; case Mesa: return "mesa"; + case SUSE: return "suse"; } llvm_unreachable("Invalid VendorType!"); @@ -170,6 +174,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { switch (Kind) { case UnknownOS: return "unknown"; + case Ananas: return "ananas"; case CloudABI: return "cloudabi"; case Darwin: return "darwin"; case DragonFly: return "dragonfly"; @@ -261,6 +266,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("mips64", mips64) .Case("mips64el", mips64el) .Case("msp430", msp430) + .Case("nios2", nios2) .Case("ppc64", ppc64) .Case("ppc32", ppc) .Case("ppc", ppc) @@ -383,6 +389,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Cases("mipsel", "mipsallegrexel", Triple::mipsel) .Cases("mips64", "mips64eb", Triple::mips64) .Case("mips64el", Triple::mips64el) + .Case("nios2", Triple::nios2) .Case("r600", Triple::r600) .Case("amdgcn", Triple::amdgcn) .Case("riscv32", Triple::riscv32) @@ -443,11 +450,13 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("myriad", Triple::Myriad) .Case("amd", Triple::AMD) .Case("mesa", Triple::Mesa) + .Case("suse", Triple::SUSE) .Default(Triple::UnknownVendor); } static Triple::OSType parseOS(StringRef OSName) { return StringSwitch<Triple::OSType>(OSName) + .StartsWith("ananas", Triple::Ananas) .StartsWith("cloudabi", Triple::CloudABI) .StartsWith("darwin", Triple::Darwin) .StartsWith("dragonfly", Triple::DragonFly) @@ -457,7 +466,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("kfreebsd", Triple::KFreeBSD) .StartsWith("linux", Triple::Linux) .StartsWith("lv2", Triple::Lv2) - .StartsWith("macosx", Triple::MacOSX) + .StartsWith("macos", Triple::MacOSX) .StartsWith("netbsd", Triple::NetBSD) .StartsWith("openbsd", Triple::OpenBSD) .StartsWith("solaris", Triple::Solaris) @@ -510,6 +519,7 @@ static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { .EndsWith("coff", Triple::COFF) .EndsWith("elf", Triple::ELF) .EndsWith("macho", Triple::MachO) + .EndsWith("wasm", Triple::Wasm) .Default(Triple::UnknownObjectFormat); } @@ -550,6 +560,8 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { case ARM::AK_ARMV7A: case ARM::AK_ARMV7R: return Triple::ARMSubArch_v7; + case ARM::AK_ARMV7VE: + return Triple::ARMSubArch_v7ve; case ARM::AK_ARMV7K: return Triple::ARMSubArch_v7k; case ARM::AK_ARMV7M: @@ -581,6 +593,7 @@ static StringRef getObjectFormatTypeName(Triple::ObjectFormatType Kind) { case Triple::COFF: return "coff"; case Triple::ELF: return "elf"; case Triple::MachO: return "macho"; + case Triple::Wasm: return "wasm"; } llvm_unreachable("unknown object format type"); } @@ -619,6 +632,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::mips64el: case Triple::mipsel: case Triple::msp430: + case Triple::nios2: case Triple::nvptx: case Triple::nvptx64: case Triple::ppc64le: @@ -865,6 +879,10 @@ std::string Triple::normalize(StringRef Str) { } } + // SUSE uses "gnueabi" to mean "gnueabihf" + if (Vendor == Triple::SUSE && Environment == llvm::Triple::GNUEABI) + Components[3] = "gnueabihf"; + if (OS == Triple::Win32) { Components.resize(4); Components[2] = "windows"; @@ -978,6 +996,8 @@ void Triple::getOSVersion(unsigned &Major, unsigned &Minor, StringRef OSTypeName = getOSTypeName(getOS()); if (OSName.startswith(OSTypeName)) OSName = OSName.substr(OSTypeName.size()); + else if (getOS() == MacOSX) + OSName.consume_front("macos"); parseVersionFromName(OSName, Major, Minor, Micro); } @@ -1152,6 +1172,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::le32: case llvm::Triple::mips: case llvm::Triple::mipsel: + case llvm::Triple::nios2: case llvm::Triple::nvptx: case llvm::Triple::ppc: case llvm::Triple::r600: @@ -1235,6 +1256,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::le32: case Triple::mips: case Triple::mipsel: + case Triple::nios2: case Triple::nvptx: case Triple::ppc: case Triple::r600: @@ -1282,6 +1304,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::kalimba: case Triple::lanai: case Triple::msp430: + case Triple::nios2: case Triple::r600: case Triple::tce: case Triple::tcele: @@ -1353,6 +1376,7 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::le32: case Triple::le64: case Triple::msp430: + case Triple::nios2: case Triple::nvptx64: case Triple::nvptx: case Triple::r600: @@ -1439,6 +1463,7 @@ bool Triple::isLittleEndian() const { case Triple::mips64el: case Triple::mipsel: case Triple::msp430: + case Triple::nios2: case Triple::nvptx64: case Triple::nvptx: case Triple::ppc64le: @@ -1464,6 +1489,39 @@ bool Triple::isLittleEndian() const { } } +bool Triple::isCompatibleWith(const Triple &Other) const { + // ARM and Thumb triples are compatible, if subarch, vendor and OS match. + if ((getArch() == Triple::thumb && Other.getArch() == Triple::arm) || + (getArch() == Triple::arm && Other.getArch() == Triple::thumb) || + (getArch() == Triple::thumbeb && Other.getArch() == Triple::armeb) || + (getArch() == Triple::armeb && Other.getArch() == Triple::thumbeb)) { + if (getVendor() == Triple::Apple) + return getSubArch() == Other.getSubArch() && + getVendor() == Other.getVendor() && getOS() == Other.getOS(); + else + return getSubArch() == Other.getSubArch() && + getVendor() == Other.getVendor() && getOS() == Other.getOS() && + getEnvironment() == Other.getEnvironment() && + getObjectFormat() == Other.getObjectFormat(); + } + + // If vendor is apple, ignore the version number. + if (getVendor() == Triple::Apple) + return getArch() == Other.getArch() && getSubArch() == Other.getSubArch() && + getVendor() == Other.getVendor() && getOS() == Other.getOS(); + + return *this == Other; +} + +std::string Triple::merge(const Triple &Other) const { + // If vendor is apple, pick the triple with the larger version number. + if (getVendor() == Triple::Apple) + if (Other.isOSVersionLT(*this)) + return str(); + + return Other.str(); +} + StringRef Triple::getARMCPUForArch(StringRef MArch) const { if (MArch.empty()) MArch = getArchName(); @@ -1511,6 +1569,7 @@ StringRef Triple::getARMCPUForArch(StringRef MArch) const { return "strongarm"; } case llvm::Triple::NaCl: + case llvm::Triple::OpenBSD: return "cortex-a8"; default: switch (getEnvironment()) { diff --git a/contrib/llvm/lib/Support/Twine.cpp b/contrib/llvm/lib/Support/Twine.cpp index 465c6e6..d17cd4e 100644 --- a/contrib/llvm/lib/Support/Twine.cpp +++ b/contrib/llvm/lib/Support/Twine.cpp @@ -173,10 +173,12 @@ void Twine::printRepr(raw_ostream &OS) const { OS << ")"; } +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void Twine::dump() const { print(dbgs()); } -void Twine::dumpRepr() const { +LLVM_DUMP_METHOD void Twine::dumpRepr() const { printRepr(dbgs()); } +#endif diff --git a/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc b/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc new file mode 100644 index 0000000..f05103c --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/DynamicLibrary.inc @@ -0,0 +1,135 @@ +//===- Unix/DynamicLibrary.cpp - Unix DL Implementation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the UNIX specific implementation of DynamicLibrary. +// +//===----------------------------------------------------------------------===// + +#if defined(HAVE_DLFCN_H) && defined(HAVE_DLOPEN) +#include <dlfcn.h> + +DynamicLibrary::HandleSet::~HandleSet() { + // Close the libraries in reverse order. + for (void *Handle : llvm::reverse(Handles)) + ::dlclose(Handle); + if (Process) + ::dlclose(Process); + + // llvm_shutdown called, Return to default + DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; +} + +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { + void *Handle = ::dlopen(File, RTLD_LAZY|RTLD_GLOBAL); + if (!Handle) { + if (Err) *Err = ::dlerror(); + return &DynamicLibrary::Invalid; + } + +#ifdef __CYGWIN__ + // Cygwin searches symbols only in the main + // with the handle of dlopen(NULL, RTLD_GLOBAL). + if (!File) + Handle = RTLD_DEFAULT; +#endif + + return Handle; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { + ::dlclose(Handle); +} + +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { + return ::dlsym(Handle, Symbol); +} + +#else // !HAVE_DLOPEN + +DynamicLibrary::HandleSet::~HandleSet() {} + +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { + if (Err) *Err = "dlopen() not supported on this platform"; + return &Invalid; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { +} + +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { + return nullptr; +} + +#endif + +// Must declare the symbols in the global namespace. +static void *DoSearch(const char* SymbolName) { +#define EXPLICIT_SYMBOL(SYM) \ + extern void *SYM; if (!strcmp(SymbolName, #SYM)) return &SYM + + // If this is darwin, it has some funky issues, try to solve them here. Some + // important symbols are marked 'private external' which doesn't allow + // SearchForAddressOfSymbol to find them. As such, we special case them here, + // there is only a small handful of them. + +#ifdef __APPLE__ + { + // __eprintf is sometimes used for assert() handling on x86. + // + // FIXME: Currently disabled when using Clang, as we don't always have our + // runtime support libraries available. +#ifndef __clang__ +#ifdef __i386__ + EXPLICIT_SYMBOL(__eprintf); +#endif +#endif + } +#endif + +#ifdef __CYGWIN__ + { + EXPLICIT_SYMBOL(_alloca); + EXPLICIT_SYMBOL(__main); + } +#endif + +#undef EXPLICIT_SYMBOL + +// This macro returns the address of a well-known, explicit symbol +#define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(SymbolName, #SYM)) return &SYM + +// Under glibc we have a weird situation. The stderr/out/in symbols are both +// macros and global variables because of standards requirements. So, we +// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. +#if defined(__GLIBC__) + { + EXPLICIT_SYMBOL(stderr); + EXPLICIT_SYMBOL(stdout); + EXPLICIT_SYMBOL(stdin); + } +#else + // For everything else, we want to check to make sure the symbol isn't defined + // as a macro before using EXPLICIT_SYMBOL. + { +#ifndef stdin + EXPLICIT_SYMBOL(stdin); +#endif +#ifndef stdout + EXPLICIT_SYMBOL(stdout); +#endif +#ifndef stderr + EXPLICIT_SYMBOL(stderr); +#endif + } +#endif +#undef EXPLICIT_SYMBOL + + return nullptr; +} diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc index 4572171..5580e63 100644 --- a/contrib/llvm/lib/Support/Unix/Host.inc +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -34,16 +34,35 @@ static std::string getOSVersion() { return info.release; } -std::string sys::getDefaultTargetTriple() { - std::string TargetTripleString(LLVM_DEFAULT_TARGET_TRIPLE); - - // On darwin, we want to update the version to match that of the - // target. +static std::string updateTripleOSVersion(std::string TargetTripleString) { + // On darwin, we want to update the version to match that of the target. std::string::size_type DarwinDashIdx = TargetTripleString.find("-darwin"); if (DarwinDashIdx != std::string::npos) { TargetTripleString.resize(DarwinDashIdx + strlen("-darwin")); TargetTripleString += getOSVersion(); + return TargetTripleString; + } + std::string::size_type MacOSDashIdx = TargetTripleString.find("-macos"); + if (MacOSDashIdx != std::string::npos) { + TargetTripleString.resize(MacOSDashIdx); + // Reset the OS to darwin as the OS version from `uname` doesn't use the + // macOS version scheme. + TargetTripleString += "-darwin"; + TargetTripleString += getOSVersion(); } + return TargetTripleString; +} + +std::string sys::getDefaultTargetTriple() { + std::string TargetTripleString = + updateTripleOSVersion(LLVM_DEFAULT_TARGET_TRIPLE); + + // Override the default target with an environment variable named by + // LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + TargetTripleString = EnvTriple; +#endif return Triple::normalize(TargetTripleString); } diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index edbc793..dd39ef9 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -195,6 +195,10 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_EXEC, flags, fd, 0); +#elif defined(__NetBSD__) && defined(PROT_MPROTECT) + void *pa = + ::mmap(start, PageSize * NumPages, + PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC), flags, fd, 0); #else void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, flags, fd, 0); diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc index e0b11aa..45097eb 100644 --- a/contrib/llvm/lib/Support/Unix/Path.inc +++ b/contrib/llvm/lib/Support/Unix/Path.inc @@ -48,6 +48,8 @@ # endif #endif +#include <pwd.h> + #ifdef __APPLE__ #include <mach-o/dyld.h> #include <sys/attr.h> @@ -65,23 +67,41 @@ #endif #include <sys/types.h> -#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) +#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && \ + !defined(__linux__) #include <sys/statvfs.h> #define STATVFS statvfs +#define FSTATVFS fstatvfs #define STATVFS_F_FRSIZE(vfs) vfs.f_frsize #else -#ifdef __OpenBSD__ -#include <sys/param.h> +#if defined(__OpenBSD__) || defined(__FreeBSD__) #include <sys/mount.h> -#elif defined(__ANDROID__) +#include <sys/param.h> +#elif defined(__linux__) +#if defined(HAVE_LINUX_MAGIC_H) +#include <linux/magic.h> +#else +#if defined(HAVE_LINUX_NFS_FS_H) +#include <linux/nfs_fs.h> +#endif +#if defined(HAVE_LINUX_SMB_H) +#include <linux/smb.h> +#endif +#endif #include <sys/vfs.h> #else #include <sys/mount.h> #endif #define STATVFS statfs +#define FSTATVFS fstatfs #define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize) #endif +#if defined(__NetBSD__) +#define STATVFS_F_FLAG(vfs) (vfs).f_flag +#else +#define STATVFS_F_FLAG(vfs) (vfs).f_flags +#endif using namespace llvm; @@ -180,7 +200,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) { if (getprogpath(exe_path, argv0)) return exe_path; } -#elif defined(HAVE_DLFCN_H) +#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR) // Use dladdr to get executable path if available. Dl_info DLInfo; int err = dladdr(MainAddr, &DLInfo); @@ -210,6 +230,10 @@ UniqueID file_status::getUniqueID() const { return UniqueID(fs_st_dev, fs_st_ino); } +uint32_t file_status::getLinkCount() const { + return fs_st_nlinks; +} + ErrorOr<space_info> disk_space(const Twine &Path) { struct STATVFS Vfs; if (::STATVFS(Path.str().c_str(), &Vfs)) @@ -257,6 +281,16 @@ std::error_code current_path(SmallVectorImpl<char> &result) { return std::error_code(); } +std::error_code set_current_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::chdir(p.begin()) == -1) + return std::error_code(errno, std::generic_category()); + + return std::error_code(); +} + std::error_code create_directory(const Twine &path, bool IgnoreExisting, perms Perms) { SmallString<128> path_storage; @@ -325,6 +359,56 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { return std::error_code(); } +static bool is_local_impl(struct STATVFS &Vfs) { +#if defined(__linux__) +#ifndef NFS_SUPER_MAGIC +#define NFS_SUPER_MAGIC 0x6969 +#endif +#ifndef SMB_SUPER_MAGIC +#define SMB_SUPER_MAGIC 0x517B +#endif +#ifndef CIFS_MAGIC_NUMBER +#define CIFS_MAGIC_NUMBER 0xFF534D42 +#endif + switch ((uint32_t)Vfs.f_type) { + case NFS_SUPER_MAGIC: + case SMB_SUPER_MAGIC: + case CIFS_MAGIC_NUMBER: + return false; + default: + return true; + } +#elif defined(__CYGWIN__) + // Cygwin doesn't expose this information; would need to use Win32 API. + return false; +#elif defined(__sun) + // statvfs::f_basetype contains a null-terminated FSType name of the mounted target + StringRef fstype(Vfs.f_basetype); + // NFS is the only non-local fstype?? + return !fstype.equals("nfs"); +#else + return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL); +#endif +} + +std::error_code is_local(const Twine &Path, bool &Result) { + struct STATVFS Vfs; + if (::STATVFS(Path.str().c_str(), &Vfs)) + return std::error_code(errno, std::generic_category()); + + Result = is_local_impl(Vfs); + return std::error_code(); +} + +std::error_code is_local(int FD, bool &Result) { + struct STATVFS Vfs; + if (::FSTATVFS(FD, &Vfs)) + return std::error_code(errno, std::generic_category()); + + Result = is_local_impl(Vfs); + return std::error_code(); +} + std::error_code rename(const Twine &from, const Twine &to) { // Get arguments. SmallString<128> from_storage; @@ -342,14 +426,15 @@ std::error_code resize_file(int FD, uint64_t Size) { #if defined(HAVE_POSIX_FALLOCATE) // If we have posix_fallocate use it. Unlike ftruncate it always allocates // space, so we get an error if the disk is full. - if (int Err = ::posix_fallocate(FD, 0, Size)) - return std::error_code(Err, std::generic_category()); -#else + if (int Err = ::posix_fallocate(FD, 0, Size)) { + if (Err != EOPNOTSUPP) + return std::error_code(Err, std::generic_category()); + } +#endif // Use ftruncate as a fallback. It may or may not allocate space. At least on // OS X with HFS+ it does. if (::ftruncate(FD, Size) == -1) return std::error_code(errno, std::generic_category()); -#endif return std::error_code(); } @@ -405,6 +490,46 @@ std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { return std::error_code(); } +static void expandTildeExpr(SmallVectorImpl<char> &Path) { + StringRef PathStr(Path.begin(), Path.size()); + if (PathStr.empty() || !PathStr.startswith("~")) + return; + + PathStr = PathStr.drop_front(); + StringRef Expr = + PathStr.take_until([](char c) { return path::is_separator(c); }); + StringRef Remainder = PathStr.substr(Expr.size() + 1); + SmallString<128> Storage; + if (Expr.empty()) { + // This is just ~/..., resolve it to the current user's home dir. + if (!path::home_directory(Storage)) { + // For some reason we couldn't get the home directory. Just exit. + return; + } + + // Overwrite the first character and insert the rest. + Path[0] = Storage[0]; + Path.insert(Path.begin() + 1, Storage.begin() + 1, Storage.end()); + return; + } + + // This is a string of the form ~username/, look up this user's entry in the + // password database. + struct passwd *Entry = nullptr; + std::string User = Expr.str(); + Entry = ::getpwnam(User.c_str()); + + if (!Entry) { + // Unable to look up the entry, just return back the original path. + return; + } + + Storage = Remainder; + Path.clear(); + Path.append(Entry->pw_dir, Entry->pw_dir + strlen(Entry->pw_dir)); + llvm::sys::path::append(Path, Storage); +} + static std::error_code fillStatus(int StatRet, const struct stat &Status, file_status &Result) { if (StatRet != 0) { @@ -430,22 +555,23 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status, Type = file_type::fifo_file; else if (S_ISSOCK(Status.st_mode)) Type = file_type::socket_file; + else if (S_ISLNK(Status.st_mode)) + Type = file_type::symlink_file; - perms Perms = static_cast<perms>(Status.st_mode); - Result = - file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime, - Status.st_mtime, Status.st_uid, Status.st_gid, - Status.st_size); + perms Perms = static_cast<perms>(Status.st_mode) & all_perms; + Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink, + Status.st_ino, Status.st_atime, Status.st_mtime, + Status.st_uid, Status.st_gid, Status.st_size); return std::error_code(); } -std::error_code status(const Twine &Path, file_status &Result) { +std::error_code status(const Twine &Path, file_status &Result, bool Follow) { SmallString<128> PathStorage; StringRef P = Path.toNullTerminatedStringRef(PathStorage); struct stat Status; - int StatRet = ::stat(P.begin(), &Status); + int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status); return fillStatus(StatRet, Status, Result); } @@ -455,6 +581,15 @@ std::error_code status(int FD, file_status &Result) { return fillStatus(StatRet, Status, Result); } +std::error_code setPermissions(const Twine &Path, perms Permissions) { + SmallString<128> PathStorage; + StringRef P = Path.toNullTerminatedStringRef(PathStorage); + + if (::chmod(P.begin(), Permissions)) + return std::error_code(errno, std::generic_category()); + return std::error_code(); +} + std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { #if defined(HAVE_FUTIMENS) timespec Times[2]; @@ -481,6 +616,26 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE; int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE); +#if defined(__APPLE__) + //---------------------------------------------------------------------- + // Newer versions of MacOSX have a flag that will allow us to read from + // binaries whose code signature is invalid without crashing by using + // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media + // is mapped we can avoid crashing and return zeroes to any pages we try + // to read if the media becomes unavailable by using the + // MAP_RESILIENT_MEDIA flag. These flags are only usable when mapping + // with PROT_READ, so take care not to specify them otherwise. + //---------------------------------------------------------------------- + if (Mode == readonly) { +#if defined(MAP_RESILIENT_CODESIGN) + flags |= MAP_RESILIENT_CODESIGN; +#endif +#if defined(MAP_RESILIENT_MEDIA) + flags |= MAP_RESILIENT_MEDIA; +#endif + } +#endif // #if defined (__APPLE__) + Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset); if (Mapping == MAP_FAILED) return std::error_code(errno, std::generic_category()); @@ -526,7 +681,8 @@ int mapped_file_region::alignment() { } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, - StringRef path){ + StringRef path, + bool follow_symlinks) { SmallString<128> path_null(path); DIR *directory = ::opendir(path_null.c_str()); if (!directory) @@ -535,7 +691,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, it.IterationHandle = reinterpret_cast<intptr_t>(directory); // Add something for replace_filename to replace. path::append(path_null, "."); - it.CurrentEntry = directory_entry(path_null.str()); + it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks); return directory_iterator_increment(it); } @@ -577,10 +733,17 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD, SmallVectorImpl<char> *RealPath) { SmallString<128> Storage; StringRef P = Name.toNullTerminatedStringRef(Storage); - while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) { - if (errno != EINTR) - return std::error_code(errno, std::generic_category()); - } + int OpenFlags = O_RDONLY; +#ifdef O_CLOEXEC + OpenFlags |= O_CLOEXEC; +#endif + if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags)) < 0) + return std::error_code(errno, std::generic_category()); +#ifndef O_CLOEXEC + int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); + (void)r; + assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); +#endif // Attempt to get the real name of the file, if the user asked if(!RealPath) return std::error_code(); @@ -616,6 +779,10 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, int OpenFlags = O_CREAT; +#ifdef O_CLOEXEC + OpenFlags |= O_CLOEXEC; +#endif + if (Flags & F_RW) OpenFlags |= O_RDWR; else @@ -631,10 +798,13 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD, SmallString<128> Storage; StringRef P = Name.toNullTerminatedStringRef(Storage); - while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) { - if (errno != EINTR) - return std::error_code(errno, std::generic_category()); - } + if ((ResultFD = sys::RetryAfterSignal(-1, open, P.begin(), OpenFlags, Mode)) < 0) + return std::error_code(errno, std::generic_category()); +#ifndef O_CLOEXEC + int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC); + (void)r; + assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed"); +#endif return std::error_code(); } @@ -685,18 +855,85 @@ std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { return std::error_code(); } +template <typename T> +static std::error_code remove_directories_impl(const T &Entry, + bool IgnoreErrors) { + std::error_code EC; + directory_iterator Begin(Entry, EC, false); + directory_iterator End; + while (Begin != End) { + auto &Item = *Begin; + file_status st; + EC = Item.status(st); + if (EC && !IgnoreErrors) + return EC; + + if (is_directory(st)) { + EC = remove_directories_impl(Item, IgnoreErrors); + if (EC && !IgnoreErrors) + return EC; + } + + EC = fs::remove(Item.path(), true); + if (EC && !IgnoreErrors) + return EC; + + Begin.increment(EC); + if (EC && !IgnoreErrors) + return EC; + } + return std::error_code(); +} + +std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { + auto EC = remove_directories_impl(path, IgnoreErrors); + if (EC && !IgnoreErrors) + return EC; + EC = fs::remove(path, true); + if (EC && !IgnoreErrors) + return EC; + return std::error_code(); +} + +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, + bool expand_tilde) { + dest.clear(); + if (path.isTriviallyEmpty()) + return std::error_code(); + + if (expand_tilde) { + SmallString<128> Storage; + path.toVector(Storage); + expandTildeExpr(Storage); + return real_path(Storage, dest, false); + } + + int fd; + std::error_code EC = openFileForRead(path, fd, &dest); + + if (EC) + return EC; + ::close(fd); + return std::error_code(); +} + } // end namespace fs namespace path { bool home_directory(SmallVectorImpl<char> &result) { - if (char *RequestedDir = getenv("HOME")) { - result.clear(); - result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); - return true; + char *RequestedDir = getenv("HOME"); + if (!RequestedDir) { + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir) + RequestedDir = pw->pw_dir; } + if (!RequestedDir) + return false; - return false; + result.clear(); + result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return true; } static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) { diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc index 16f8f5a..2d46620 100644 --- a/contrib/llvm/lib/Support/Unix/Process.inc +++ b/contrib/llvm/lib/Support/Unix/Process.inc @@ -207,13 +207,10 @@ std::error_code Process::FixupStandardFileDescriptors() { for (int StandardFD : StandardFDs) { struct stat st; errno = 0; - while (fstat(StandardFD, &st) < 0) { + if (RetryAfterSignal(-1, fstat, StandardFD, &st) < 0) { assert(errno && "expected errno to be set if fstat failed!"); // fstat should return EBADF if the file descriptor is closed. - if (errno == EBADF) - break; - // retry fstat if we got EINTR, otherwise bubble up the failure. - if (errno != EINTR) + if (errno != EBADF) return std::error_code(errno, std::generic_category()); } // if fstat succeeds, move on to the next FD. @@ -222,11 +219,8 @@ std::error_code Process::FixupStandardFileDescriptors() { assert(errno == EBADF && "expected errno to have EBADF at this point!"); if (NullFD < 0) { - while ((NullFD = open("/dev/null", O_RDWR)) < 0) { - if (errno == EINTR) - continue; + if ((NullFD = RetryAfterSignal(-1, open, "/dev/null", O_RDWR)) < 0) return std::error_code(errno, std::generic_category()); - } } if (NullFD == StandardFD) @@ -347,7 +341,7 @@ static bool terminalHasColors(int fd) { MutexGuard G(*TermColorMutex); int errret = 0; - if (setupterm((char *)nullptr, fd, &errret) != 0) + if (setupterm(nullptr, fd, &errret) != 0) // Regardless of why, if we can't get terminfo, we shouldn't try to print // colors. return false; @@ -369,7 +363,7 @@ static bool terminalHasColors(int fd) { // Now extract the structure allocated by setupterm and free its memory // through a really silly dance. - struct term *termp = set_curterm((struct term *)nullptr); + struct term *termp = set_curterm(nullptr); (void)del_curterm(termp); // Drop any errors here. // Return true if we found a color capabilities for the current terminal. diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index 7d3537e..c866d5b 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -40,9 +40,6 @@ #include <unistd.h> #endif #ifdef HAVE_POSIX_SPAWN -#ifdef __sun__ -#define _RESTRICT_KYWD -#endif #include <spawn.h> #if defined(__APPLE__) @@ -163,16 +160,6 @@ static void SetMemoryLimits (unsigned size) r.rlim_cur = limit; setrlimit (RLIMIT_RSS, &r); #endif -#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. - // Don't set virtual memory limit if built with any Sanitizer. They need 80Tb - // of virtual memory for shadow memory mapping. -#if !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_ADDRESS_SANITIZER_BUILD - // Virtual memory. - getrlimit (RLIMIT_AS, &r); - r.rlim_cur = limit; - setrlimit (RLIMIT_AS, &r); -#endif -#endif #endif } @@ -459,11 +446,22 @@ bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<co size_t ArgLength = Program.size() + 1; for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { - ArgLength += strlen(*I) + 1; + size_t length = strlen(*I); + + // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which + // does not have a constant unlike what the man pages would have you + // believe. Since this limit is pretty high, perform the check + // unconditionally rather than trying to be aggressive and limiting it to + // Linux only. + if (length >= (32 * 4096)) + return false; + + ArgLength += length + 1; if (ArgLength > size_t(HalfArgMax)) { return false; } } + return true; } } diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc index 9752b70..aaf760c 100644 --- a/contrib/llvm/lib/Support/Unix/Signals.inc +++ b/contrib/llvm/lib/Support/Unix/Signals.inc @@ -15,9 +15,9 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Demangle/Demangle.h" -#include "llvm/Support/Format.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Program.h" @@ -25,8 +25,8 @@ #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <string> -#if HAVE_EXECINFO_H -# include <execinfo.h> // For backtrace(). +#ifdef HAVE_BACKTRACE +# include BACKTRACE_HEADER // For backtrace(). #endif #if HAVE_SIGNAL_H #include <signal.h> @@ -59,7 +59,7 @@ using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. -static ManagedStatic<SmartMutex<true> > SignalsMutex; +static ManagedStatic<sys::SmartMutex<true> > SignalsMutex; /// InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = nullptr; @@ -149,11 +149,7 @@ static void CreateSigAltStack() {} #endif static void RegisterHandlers() { - // We need to dereference the signals mutex during handler registration so - // that we force its construction. This is to prevent the first use being - // during handling an actual signal because you can't safely call new in a - // signal handler. - *SignalsMutex; + sys::SmartScopedLock<true> Guard(*SignalsMutex); // If the handlers are already registered, we're done. if (NumRegisteredSignals != 0) return; @@ -223,7 +219,7 @@ static RETSIGTYPE SignalHandler(int Sig) { sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); { - unique_lock<SmartMutex<true>> Guard(*SignalsMutex); + unique_lock<sys::SmartMutex<true>> Guard(*SignalsMutex); RemoveFilesToRemove(); if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig) @@ -412,7 +408,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS)) return; -#if HAVE_DLFCN_H && __GNUG__ && !defined(__CYGWIN__) +#if HAVE_DLFCN_H && HAVE_DLADDR int width = 0; for (int i = 0; i < depth; ++i) { Dl_info dlinfo; @@ -462,7 +458,7 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) { } static void PrintStackTraceSignalHandler(void *) { - PrintStackTrace(llvm::errs()); + sys::PrintStackTrace(llvm::errs()); } void llvm::sys::DisableSystemDialogsOnCrash() {} diff --git a/contrib/llvm/lib/Support/Unix/Threading.inc b/contrib/llvm/lib/Support/Unix/Threading.inc new file mode 100644 index 0000000..267af38 --- /dev/null +++ b/contrib/llvm/lib/Support/Unix/Threading.inc @@ -0,0 +1,215 @@ +//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Unix specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +#if defined(__APPLE__) +#include <mach/mach_init.h> +#include <mach/mach_port.h> +#endif + +#include <pthread.h> + +#if defined(__FreeBSD__) +#include <pthread_np.h> // For pthread_getthreadid_np() +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include <errno.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <unistd.h> +#endif + +#if defined(__NetBSD__) +#include <lwp.h> // For _lwp_self() +#endif + +#if defined(__linux__) +#include <sys/syscall.h> // For syscall codes +#include <unistd.h> // For syscall() +#endif + +namespace { + struct ThreadInfo { + void(*UserFn)(void *); + void *UserData; + }; +} + +static void *ExecuteOnThread_Dispatch(void *Arg) { + ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); + TI->UserFn(TI->UserData); + return nullptr; +} + +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + ThreadInfo Info = { Fn, UserData }; + pthread_attr_t Attr; + pthread_t Thread; + + // Construct the attributes object. + if (::pthread_attr_init(&Attr) != 0) + return; + + // Set the requested stack size, if given. + if (RequestedStackSize != 0) { + if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) + goto error; + } + + // Construct and execute the thread. + if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) + goto error; + + // Wait for the thread and clean up. + ::pthread_join(Thread, nullptr); + +error: + ::pthread_attr_destroy(&Attr); +} + + +uint64_t llvm::get_threadid() { +#if defined(__APPLE__) + // Calling "mach_thread_self()" bumps the reference count on the thread + // port, so we need to deallocate it. mach_task_self() doesn't bump the ref + // count. + thread_port_t Self = mach_thread_self(); + mach_port_deallocate(mach_task_self(), Self); + return Self; +#elif defined(__FreeBSD__) + return uint64_t(pthread_getthreadid_np()); +#elif defined(__NetBSD__) + return uint64_t(_lwp_self()); +#elif defined(__ANDROID__) + return uint64_t(gettid()); +#elif defined(__linux__) + return uint64_t(syscall(SYS_gettid)); +#elif defined(LLVM_ON_WIN32) + return uint64_t(::GetCurrentThreadId()); +#else + return uint64_t(pthread_self()); +#endif +} + + +static constexpr uint32_t get_max_thread_name_length_impl() { +#if defined(__NetBSD__) + return PTHREAD_MAX_NAMELEN_NP; +#elif defined(__APPLE__) + return 64; +#elif defined(__linux__) +#if HAVE_PTHREAD_SETNAME_NP + return 16; +#else + return 0; +#endif +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + return 16; +#else + return 0; +#endif +} + +uint32_t llvm::get_max_thread_name_length() { + return get_max_thread_name_length_impl(); +} + +void llvm::set_thread_name(const Twine &Name) { + // Make sure the input is null terminated. + SmallString<64> Storage; + StringRef NameStr = Name.toNullTerminatedStringRef(Storage); + + // Truncate from the beginning, not the end, if the specified name is too + // long. For one, this ensures that the resulting string is still null + // terminated, but additionally the end of a long thread name will usually + // be more unique than the beginning, since a common pattern is for similar + // threads to share a common prefix. + if (get_max_thread_name_length() > 0) + NameStr = NameStr.take_back(get_max_thread_name_length()); + (void)NameStr; +#if defined(__linux__) +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) +#if HAVE_PTHREAD_SETNAME_NP + ::pthread_setname_np(::pthread_self(), NameStr.data()); +#endif +#endif +#elif defined(__FreeBSD__) + ::pthread_set_name_np(::pthread_self(), NameStr.data()); +#elif defined(__NetBSD__) + ::pthread_setname_np(::pthread_self(), "%s", + const_cast<char *>(NameStr.data())); +#elif defined(__APPLE__) + ::pthread_setname_np(NameStr.data()); +#endif +} + +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { + Name.clear(); + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + int pid = ::getpid(); + uint64_t tid = get_threadid(); + + struct kinfo_proc *kp = nullptr, *nkp; + size_t len = 0; + int error; + int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, + (int)pid }; + + while (1) { + error = sysctl(ctl, 4, kp, &len, nullptr, 0); + if (kp == nullptr || (error != 0 && errno == ENOMEM)) { + // Add extra space in case threads are added before next call. + len += sizeof(*kp) + len / 10; + nkp = (struct kinfo_proc *)realloc(kp, len); + if (nkp == nullptr) { + free(kp); + return; + } + kp = nkp; + continue; + } + if (error != 0) + len = 0; + break; + } + + for (size_t i = 0; i < len / sizeof(*kp); i++) { + if (kp[i].ki_tid == (lwpid_t)tid) { + Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname)); + break; + } + } + free(kp); + return; +#elif defined(__NetBSD__) + constexpr uint32_t len = get_max_thread_name_length_impl(); + char buf[len]; + ::pthread_getname_np(::pthread_self(), buf, len); + + Name.append(buf, buf + strlen(buf)); +#elif defined(__linux__) +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) +#if HAVE_PTHREAD_GETNAME_NP + constexpr uint32_t len = get_max_thread_name_length_impl(); + char Buffer[len]; + if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len)) + Name.append(Buffer, Buffer + strlen(Buffer)); +#endif +#endif +#endif +} diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc index 0506894..083ea90 100644 --- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -12,92 +12,142 @@ //===----------------------------------------------------------------------===// #include "WindowsSupport.h" +#include "llvm/Support/raw_ostream.h" -#ifdef __MINGW32__ - #include <imagehlp.h> -#else - #include <dbghelp.h> -#endif - -#ifdef _MSC_VER - #include <ntverp.h> -#endif - -namespace llvm { -using namespace sys; +#include <psapi.h> //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code. //===----------------------------------------------------------------------===// -typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); -static fpEnumerateLoadedModules fEnumerateLoadedModules; -static DenseSet<HMODULE> *OpenedHandles; -static bool loadDebugHelp(void) { - HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); - if (hLib) { - fEnumerateLoadedModules = (fpEnumerateLoadedModules) - ::GetProcAddress(hLib, "EnumerateLoadedModules64"); - } - return fEnumerateLoadedModules != 0; -} +DynamicLibrary::HandleSet::~HandleSet() { + for (void *Handle : llvm::reverse(Handles)) + FreeLibrary(HMODULE(Handle)); -static BOOL CALLBACK -ELM_Callback(PCSTR ModuleName, DWORD64 ModuleBase, - ULONG ModuleSize, PVOID UserContext) { - OpenedHandles->insert((HMODULE)ModuleBase); - return TRUE; + // 'Process' should not be released on Windows. + assert((!Process || Process==this) && "Bad Handle"); + // llvm_shutdown called, Return to default + DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; } -DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, - std::string *errMsg) { - SmartScopedLock<true> lock(*SymbolsMutex); +void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { + // Create the instance and return it to be the *Process* handle + // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) + if (!File) + return &(*OpenedHandles); - if (!filename) { - // When no file is specified, enumerate all DLLs and EXEs in the process. - if (OpenedHandles == 0) - OpenedHandles = new DenseSet<HMODULE>(); - - if (!fEnumerateLoadedModules) { - if (!loadDebugHelp()) { - assert(false && "These APIs should always be available"); - return DynamicLibrary(); - } - } - - fEnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); - // Dummy library that represents "search all handles". - // This is mostly to ensure that the return value still shows up as "valid". - return DynamicLibrary(&OpenedHandles); - } - - SmallVector<wchar_t, MAX_PATH> filenameUnicode; - if (std::error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) { + SmallVector<wchar_t, MAX_PATH> FileUnicode; + if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { SetLastError(ec.value()); - MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16"); - return DynamicLibrary(); + MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); + return &DynamicLibrary::Invalid; } - - HMODULE a_handle = LoadLibraryW(filenameUnicode.data()); - if (a_handle == 0) { - MakeErrMsg(errMsg, std::string(filename) + ": Can't open"); - return DynamicLibrary(); + HMODULE Handle = LoadLibraryW(FileUnicode.data()); + if (Handle == NULL) { + MakeErrMsg(Err, std::string(File) + ": Can't open"); + return &DynamicLibrary::Invalid; } - if (OpenedHandles == 0) - OpenedHandles = new DenseSet<HMODULE>(); + return reinterpret_cast<void*>(Handle); +} + +static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { + if (!OpenedHandles.isConstructed()) + return nullptr; + DynamicLibrary::HandleSet &Inst = *OpenedHandles; + return Handle == &Inst ? &Inst : nullptr; +} + +void DynamicLibrary::HandleSet::DLClose(void *Handle) { + if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) + HS->Process = nullptr; // Just drop the *Process* handle. + else + FreeLibrary((HMODULE)Handle); +} - // If we've already loaded this library, FreeLibrary() the handle in order to - // keep the internal refcount at +1. - if (!OpenedHandles->insert(a_handle).second) - FreeLibrary(a_handle); +static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { + // EnumProcessModules will fail on Windows 64 while some versions of + // MingW-32 don't have EnumProcessModulesEx. + if ( +#ifdef _WIN64 + !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) +#else + !EnumProcessModules(H, Data, Bytes, &Bytes) +#endif + ) { + std::string Err; + if (MakeErrMsg(&Err, "EnumProcessModules failure")) + llvm::errs() << Err << "\n"; + return false; + } + return true; +} - return DynamicLibrary(a_handle); +void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { + HandleSet* HS = IsOpenedHandlesInstance(Handle); + if (!HS) + return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); + + // Could have done a dlclose on the *Process* handle + if (!HS->Process) + return nullptr; + + // Trials indicate EnumProcessModulesEx is consistantly faster than using + // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. + // + // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx + // |=========|=============|======================================== + // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 + // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 + // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 + // + // * Not including the load time of Dbghelp.dll (~.005 sec) + // + // There's still a case to somehow cache the result of EnumProcessModulesEx + // across invocations, but the complication of doing that properly... + // Possibly using LdrRegisterDllNotification to invalidate the cache? + + DWORD Bytes = 0; + HMODULE Self = HMODULE(GetCurrentProcess()); + if (!GetProcessModules(Self, Bytes)) + return nullptr; + + // Get the most recent list in case any modules added/removed between calls + // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. + // MSDN is pretty clear that if the module list changes during the call to + // EnumProcessModulesEx the results should not be used. + std::vector<HMODULE> Handles; + do { + assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && + "Should have at least one module and be aligned"); + Handles.resize(Bytes / sizeof(HMODULE)); + if (!GetProcessModules(Self, Bytes, Handles.data())) + return nullptr; + } while (Bytes != (Handles.size() * sizeof(HMODULE))); + + // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. + if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) + return (void *) uintptr_t(Ptr); + + if (Handles.size() > 1) { + // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. + // Doing that here is causing real problems for the JIT where msvc.dll + // and ucrt.dll can define the same symbols. The runtime linker will choose + // symbols from ucrt.dll first, but iterating NOT in reverse here would + // mean that the msvc.dll versions would be returned. + + for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { + if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) + return (void *) uintptr_t(Ptr); + } + } + return nullptr; } + // Stack probing routines are in the support library (e.g. libgcc), but we don't // have dynamic linking on windows. Provide a hook. #define EXPLICIT_SYMBOL(SYM) \ @@ -123,38 +173,18 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename, #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 -void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { - SmartScopedLock<true> Lock(*SymbolsMutex); - - // First check symbols added via AddSymbol(). - if (ExplicitSymbols.isConstructed()) { - StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName); - - if (i != ExplicitSymbols->end()) - return i->second; - } - - // Now search the libraries. - if (OpenedHandles) { - for (DenseSet<HMODULE>::iterator I = OpenedHandles->begin(), - E = OpenedHandles->end(); I != E; ++I) { - FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); - if (ptr) { - return (void *)(intptr_t)ptr; - } - } - } +static void *DoSearch(const char *SymbolName) { #define EXPLICIT_SYMBOL(SYM) \ - if (!strcmp(symbolName, #SYM)) \ + if (!strcmp(SymbolName, #SYM)) \ return (void *)&SYM; #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ - if (!strcmp(symbolName, #SYMFROM)) \ + if (!strcmp(SymbolName, #SYMFROM)) \ return (void *)&SYMTO; #ifdef _M_IX86 #define INLINE_DEF_SYMBOL1(TYP, SYM) \ - if (!strcmp(symbolName, #SYM)) \ + if (!strcmp(SymbolName, #SYM)) \ return (void *)&inline_##SYM; #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) #endif @@ -168,15 +198,5 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 - return 0; -} - -void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) { - if (!isValid()) - return NULL; - if (Data == &OpenedHandles) - return SearchForAddressOfSymbol(symbolName); - return (void *)(intptr_t)GetProcAddress((HMODULE)Data, symbolName); -} - + return nullptr; } diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc index fe89fe0..90a6fb3 100644 --- a/contrib/llvm/lib/Support/Windows/Host.inc +++ b/contrib/llvm/lib/Support/Windows/Host.inc @@ -17,6 +17,18 @@ using namespace llvm; +static std::string updateTripleOSVersion(std::string Triple) { + return Triple; +} + std::string sys::getDefaultTargetTriple() { - return Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE); + const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; + + // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + Triple = EnvTriple; +#endif + + return Triple::normalize(Triple); } diff --git a/contrib/llvm/lib/Support/Windows/Mutex.inc b/contrib/llvm/lib/Support/Windows/Mutex.inc index ab79d07..0af145e 100644 --- a/contrib/llvm/lib/Support/Windows/Mutex.inc +++ b/contrib/llvm/lib/Support/Windows/Mutex.inc @@ -20,15 +20,14 @@ #include "llvm/Support/Mutex.h" namespace llvm { -using namespace sys; -MutexImpl::MutexImpl(bool /*recursive*/) +sys::MutexImpl::MutexImpl(bool /*recursive*/) { data_ = new CRITICAL_SECTION; InitializeCriticalSection((LPCRITICAL_SECTION)data_); } -MutexImpl::~MutexImpl() +sys::MutexImpl::~MutexImpl() { DeleteCriticalSection((LPCRITICAL_SECTION)data_); delete (LPCRITICAL_SECTION)data_; @@ -36,21 +35,21 @@ MutexImpl::~MutexImpl() } bool -MutexImpl::acquire() +sys::MutexImpl::acquire() { EnterCriticalSection((LPCRITICAL_SECTION)data_); return true; } bool -MutexImpl::release() +sys::MutexImpl::release() { LeaveCriticalSection((LPCRITICAL_SECTION)data_); return true; } bool -MutexImpl::tryacquire() +sys::MutexImpl::tryacquire() { return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); } diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc index 27b250b..b00d390 100644 --- a/contrib/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm/lib/Support/Windows/Path.inc @@ -26,6 +26,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 <shellapi.h> #include <shlobj.h> #undef max @@ -178,6 +179,10 @@ TimePoint<> file_status::getLastModificationTime() const { return toTimePoint(Time); } +uint32_t file_status::getLinkCount() const { + return NumLinks; +} + std::error_code current_path(SmallVectorImpl<char> &result) { SmallVector<wchar_t, MAX_PATH> cur_path; DWORD len = MAX_PATH; @@ -200,6 +205,18 @@ std::error_code current_path(SmallVectorImpl<char> &result) { return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } +std::error_code set_current_path(const Twine &path) { + // Convert to utf-16. + SmallVector<wchar_t, 128> wide_path; + if (std::error_code ec = widenPath(path, wide_path)) + return ec; + + if (!::SetCurrentDirectoryW(wide_path.begin())) + return mapWindowsError(::GetLastError()); + + return std::error_code(); +} + std::error_code create_directory(const Twine &path, bool IgnoreExisting, perms Perms) { SmallVector<wchar_t, 128> path_utf16; @@ -265,6 +282,80 @@ std::error_code remove(const Twine &path, bool IgnoreNonExisting) { return std::error_code(); } +static std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path, + bool &Result) { + SmallVector<wchar_t, 128> VolumePath; + size_t Len = 128; + while (true) { + VolumePath.resize(Len); + BOOL Success = + ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); + + if (Success) + break; + + DWORD Err = ::GetLastError(); + if (Err != ERROR_INSUFFICIENT_BUFFER) + return mapWindowsError(Err); + + Len *= 2; + } + // If the output buffer has exactly enough space for the path name, but not + // the null terminator, it will leave the output unterminated. Push a null + // terminator onto the end to ensure that this never happens. + VolumePath.push_back(L'\0'); + VolumePath.set_size(wcslen(VolumePath.data())); + const wchar_t *P = VolumePath.data(); + + UINT Type = ::GetDriveTypeW(P); + switch (Type) { + case DRIVE_FIXED: + Result = true; + return std::error_code(); + case DRIVE_REMOTE: + case DRIVE_CDROM: + case DRIVE_RAMDISK: + case DRIVE_REMOVABLE: + Result = false; + return std::error_code(); + default: + return make_error_code(errc::no_such_file_or_directory); + } + llvm_unreachable("Unreachable!"); +} + +std::error_code is_local(const Twine &path, bool &result) { + if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) + return make_error_code(errc::no_such_file_or_directory); + + SmallString<128> Storage; + StringRef P = path.toStringRef(Storage); + + // Convert to utf-16. + SmallVector<wchar_t, 128> WidePath; + if (std::error_code ec = widenPath(P, WidePath)) + return ec; + return is_local_internal(WidePath, result); +} + +std::error_code is_local(int FD, bool &Result) { + SmallVector<wchar_t, 128> FinalPath; + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + + size_t Len = 128; + do { + FinalPath.reserve(Len); + Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(), + FinalPath.capacity() - 1, VOLUME_NAME_NT); + if (Len == 0) + return mapWindowsError(::GetLastError()); + } while (Len > FinalPath.capacity()); + + FinalPath.set_size(Len); + + return is_local_internal(FinalPath, Result); +} + std::error_code rename(const Twine &from, const Twine &to) { // Convert to utf-16. SmallVector<wchar_t, 128> wide_from; @@ -443,13 +534,16 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file : file_type::regular_file; - Result = - file_status(Type, Info.ftLastAccessTime.dwHighDateTime, - Info.ftLastAccessTime.dwLowDateTime, - Info.ftLastWriteTime.dwHighDateTime, - Info.ftLastWriteTime.dwLowDateTime, - Info.dwVolumeSerialNumber, Info.nFileSizeHigh, - Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); + perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + ? (all_read | all_exe) + : all_all; + Result = file_status( + Type, Permissions, Info.nNumberOfLinks, + Info.ftLastAccessTime.dwHighDateTime, + Info.ftLastAccessTime.dwLowDateTime, + Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, + Info.nFileIndexHigh, Info.nFileIndexLow); return std::error_code(); } @@ -465,7 +559,7 @@ handle_status_error: return mapWindowsError(LastError); } -std::error_code status(const Twine &path, file_status &result) { +std::error_code status(const Twine &path, file_status &result, bool Follow) { SmallString<128> path_storage; SmallVector<wchar_t, 128> path_utf16; @@ -482,28 +576,19 @@ std::error_code status(const Twine &path, file_status &result) { if (attr == INVALID_FILE_ATTRIBUTES) return getStatus(INVALID_HANDLE_VALUE, result); + DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; // Handle reparse points. - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), - 0, // Attributes only. - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - if (!h) - return getStatus(INVALID_HANDLE_VALUE, result); - } + if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) + Flags |= FILE_FLAG_OPEN_REPARSE_POINT; ScopedFileHandle h( ::CreateFileW(path_utf16.begin(), 0, // Attributes only. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); - if (!h) - return getStatus(INVALID_HANDLE_VALUE, result); + NULL, OPEN_EXISTING, Flags, 0)); + if (!h) + return getStatus(INVALID_HANDLE_VALUE, result); - return getStatus(h, result); + return getStatus(h, result); } std::error_code status(int FD, file_status &Result) { @@ -511,6 +596,37 @@ std::error_code status(int FD, file_status &Result) { return getStatus(FileHandle, Result); } +std::error_code setPermissions(const Twine &Path, perms Permissions) { + SmallVector<wchar_t, 128> PathUTF16; + if (std::error_code EC = widenPath(Path, PathUTF16)) + return EC; + + DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); + if (Attributes == INVALID_FILE_ATTRIBUTES) + return mapWindowsError(GetLastError()); + + // There are many Windows file attributes that are not to do with the file + // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve + // them. + if (Permissions & all_write) { + Attributes &= ~FILE_ATTRIBUTE_READONLY; + if (Attributes == 0) + // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. + Attributes |= FILE_ATTRIBUTE_NORMAL; + } + else { + Attributes |= FILE_ATTRIBUTE_READONLY; + // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so + // remove it, if it is present. + Attributes &= ~FILE_ATTRIBUTE_NORMAL; + } + + if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) + return mapWindowsError(GetLastError()); + + return std::error_code(); +} + std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { FILETIME FT = toFILETIME(Time); HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); @@ -616,7 +732,8 @@ int mapped_file_region::alignment() { } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, - StringRef path){ + StringRef path, + bool follow_symlinks) { SmallVector<wchar_t, 128> path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) @@ -661,7 +778,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it, it.IterationHandle = intptr_t(FindHandle.take()); SmallString<128> directory_entry_path(path); path::append(directory_entry_path, directory_entry_name_utf8); - it.CurrentEntry = directory_entry(directory_entry_path); + it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks); return std::error_code(); } @@ -701,6 +818,52 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { return std::error_code(); } +static std::error_code realPathFromHandle(HANDLE H, + SmallVectorImpl<char> &RealPath) { + RealPath.clear(); + llvm::SmallVector<wchar_t, MAX_PATH> Buffer; + DWORD CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); + if (CountChars > Buffer.capacity()) { + // The buffer wasn't big enough, try again. In this case the return value + // *does* indicate the size of the null terminator. + Buffer.reserve(CountChars); + CountChars = ::GetFinalPathNameByHandleW( + H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); + } + if (CountChars == 0) + return mapWindowsError(GetLastError()); + + const wchar_t *Data = Buffer.data(); + if (CountChars >= 4) { + if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { + CountChars -= 4; + Data += 4; + } + } + + // Convert the result from UTF-16 to UTF-8. + return UTF16ToUTF8(Data, CountChars, RealPath); +} + +static std::error_code directoryRealPath(const Twine &Name, + SmallVectorImpl<char> &RealPath) { + SmallVector<wchar_t, 128> PathUTF16; + + if (std::error_code EC = widenPath(Name, PathUTF16)) + return EC; + + HANDLE H = + ::CreateFileW(PathUTF16.begin(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (H == INVALID_HANDLE_VALUE) + return mapWindowsError(GetLastError()); + std::error_code EC = realPathFromHandle(H, RealPath); + ::CloseHandle(H); + return EC; +} + std::error_code openFileForRead(const Twine &Name, int &ResultFD, SmallVectorImpl<char> *RealPath) { SmallVector<wchar_t, 128> PathUTF16; @@ -732,20 +895,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD, } // Fetch the real name of the file, if the user asked - if (RealPath) { - RealPath->clear(); - wchar_t RealPathUTF16[MAX_PATH]; - DWORD CountChars = - ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH, - FILE_NAME_NORMALIZED); - if (CountChars > 0 && CountChars < MAX_PATH) { - // Convert the result from UTF-16 to UTF-8. - SmallString<MAX_PATH> RealPathUTF8; - if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8)) - RealPath->append(RealPathUTF8.data(), - RealPathUTF8.data() + strlen(RealPathUTF8.data())); - } - } + if (RealPath) + realPathFromHandle(H, *RealPath); ResultFD = FD; return std::error_code(); @@ -843,6 +994,81 @@ std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath); } + +std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { + // Convert to utf-16. + SmallVector<wchar_t, 128> Path16; + std::error_code EC = widenPath(path, Path16); + if (EC && !IgnoreErrors) + return EC; + + // SHFileOperation() accepts a list of paths, and so must be double null- + // terminated to indicate the end of the list. The buffer is already null + // terminated, but since that null character is not considered part of the + // vector's size, pushing another one will just consume that byte. So we + // need to push 2 null terminators. + Path16.push_back(0); + Path16.push_back(0); + + SHFILEOPSTRUCTW shfos = {}; + shfos.wFunc = FO_DELETE; + shfos.pFrom = Path16.data(); + shfos.fFlags = FOF_NO_UI; + + int result = ::SHFileOperationW(&shfos); + if (result != 0 && !IgnoreErrors) + return mapWindowsError(result); + return std::error_code(); +} + +static void expandTildeExpr(SmallVectorImpl<char> &Path) { + // Path does not begin with a tilde expression. + if (Path.empty() || Path[0] != '~') + return; + + StringRef PathStr(Path.begin(), Path.size()); + PathStr = PathStr.drop_front(); + StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); + + if (!Expr.empty()) { + // This is probably a ~username/ expression. Don't support this on Windows. + return; + } + + SmallString<128> HomeDir; + if (!path::home_directory(HomeDir)) { + // For some reason we couldn't get the home directory. Just exit. + return; + } + + // Overwrite the first character and insert the rest. + Path[0] = HomeDir[0]; + Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); +} + +std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest, + bool expand_tilde) { + dest.clear(); + if (path.isTriviallyEmpty()) + return std::error_code(); + + if (expand_tilde) { + SmallString<128> Storage; + path.toVector(Storage); + expandTildeExpr(Storage); + return real_path(Storage, dest, false); + } + + if (is_directory(path)) + return directoryRealPath(path, dest); + + int fd; + if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest)) + return EC; + ::close(fd); + return std::error_code(); +} + } // end namespace fs namespace path { diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc index 8d646b3..18aef61 100644 --- a/contrib/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm/lib/Support/Windows/Process.inc @@ -47,7 +47,6 @@ #endif using namespace llvm; -using namespace sys; // This function retrieves the page size using GetNativeSystemInfo() and is // present solely so it can be called once to initialize the self_process member diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc index 78fc538..721167d 100644 --- a/contrib/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm/lib/Support/Windows/Program.inc @@ -29,7 +29,6 @@ //===----------------------------------------------------------------------===// namespace llvm { -using namespace sys; ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {} diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc index 2d1d25f..ac60c2f 100644 --- a/contrib/llvm/lib/Support/Windows/RWMutex.inc +++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc @@ -19,7 +19,6 @@ #include "WindowsSupport.h" namespace llvm { -using namespace sys; // Windows has slim read-writer lock support on Vista and higher, so we // will attempt to load the APIs. If they exist, we will use them, and @@ -73,7 +72,7 @@ static bool loadSRW() { return sHasSRW; } -RWMutexImpl::RWMutexImpl() { +sys::RWMutexImpl::RWMutexImpl() { if (loadSRW()) { data_ = calloc(1, sizeof(SRWLOCK)); fpInitializeSRWLock(static_cast<PSRWLOCK>(data_)); @@ -83,14 +82,14 @@ RWMutexImpl::RWMutexImpl() { } } -RWMutexImpl::~RWMutexImpl() { +sys::RWMutexImpl::~RWMutexImpl() { if (!sHasSRW) DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); // Nothing to do in the case of slim reader/writers except free the memory. free(data_); } -bool RWMutexImpl::reader_acquire() { +bool sys::RWMutexImpl::reader_acquire() { if (sHasSRW) { fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_)); } else { @@ -99,7 +98,7 @@ bool RWMutexImpl::reader_acquire() { return true; } -bool RWMutexImpl::reader_release() { +bool sys::RWMutexImpl::reader_release() { if (sHasSRW) { fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_)); } else { @@ -108,7 +107,7 @@ bool RWMutexImpl::reader_release() { return true; } -bool RWMutexImpl::writer_acquire() { +bool sys::RWMutexImpl::writer_acquire() { if (sHasSRW) { fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_)); } else { @@ -117,7 +116,7 @@ bool RWMutexImpl::writer_acquire() { return true; } -bool RWMutexImpl::writer_release() { +bool sys::RWMutexImpl::writer_release() { if (sHasSRW) { fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_)); } else { diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc index f739421..1ef5188 100644 --- a/contrib/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm/lib/Support/Windows/Signals.inc @@ -776,7 +776,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { // the nasty sorts of crashes that aren't 100% reproducible from a set of // inputs (or in the event that the user is unable or unwilling to provide a // reproducible case). - if (!llvm::Process::AreCoreFilesPrevented()) { + if (!llvm::sys::Process::AreCoreFilesPrevented()) { MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; ExceptionInfo.ThreadId = ::GetCurrentThreadId(); ExceptionInfo.ExceptionPointers = ep; diff --git a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc index b9cb8ff..8be1c3e 100644 --- a/contrib/llvm/lib/Support/Windows/ThreadLocal.inc +++ b/contrib/llvm/lib/Support/Windows/ThreadLocal.inc @@ -20,33 +20,32 @@ #include "llvm/Support/ThreadLocal.h" namespace llvm { -using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() : data() { +sys::ThreadLocalImpl::ThreadLocalImpl() : data() { static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); DWORD* tls = reinterpret_cast<DWORD*>(&data); *tls = TlsAlloc(); assert(*tls != TLS_OUT_OF_INDEXES); } -ThreadLocalImpl::~ThreadLocalImpl() { +sys::ThreadLocalImpl::~ThreadLocalImpl() { DWORD* tls = reinterpret_cast<DWORD*>(&data); TlsFree(*tls); } -void *ThreadLocalImpl::getInstance() { +void *sys::ThreadLocalImpl::getInstance() { DWORD* tls = reinterpret_cast<DWORD*>(&data); return TlsGetValue(*tls); } -void ThreadLocalImpl::setInstance(const void* d){ +void sys::ThreadLocalImpl::setInstance(const void* d){ DWORD* tls = reinterpret_cast<DWORD*>(&data); int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); assert(errorcode != 0); (void)errorcode; } -void ThreadLocalImpl::removeInstance() { +void sys::ThreadLocalImpl::removeInstance() { setInstance(0); } diff --git a/contrib/llvm/lib/Support/Windows/Threading.inc b/contrib/llvm/lib/Support/Windows/Threading.inc new file mode 100644 index 0000000..decb488 --- /dev/null +++ b/contrib/llvm/lib/Support/Windows/Threading.inc @@ -0,0 +1,109 @@ +//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" + +#include "Windows/WindowsSupport.h" +#include <process.h> + +// Windows will at times define MemoryFence. +#ifdef MemoryFence +#undef MemoryFence +#endif + +namespace { + struct ThreadInfo { + void(*func)(void*); + void *param; + }; +} + +static unsigned __stdcall ThreadCallback(void *param) { + struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); + info->func(info->param); + + return 0; +} + +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + struct ThreadInfo param = { Fn, UserData }; + + HANDLE hThread = (HANDLE)::_beginthreadex(NULL, + RequestedStackSize, ThreadCallback, + ¶m, 0, NULL); + + if (hThread) { + // We actually don't care whether the wait succeeds or fails, in + // the same way we don't care whether the pthread_join call succeeds + // or fails. There's not much we could do if this were to fail. But + // on success, this call will wait until the thread finishes executing + // before returning. + (void)::WaitForSingleObject(hThread, INFINITE); + ::CloseHandle(hThread); + } +} + +uint64_t llvm::get_threadid() { + return uint64_t(::GetCurrentThreadId()); +} + +uint32_t llvm::get_max_thread_name_length() { return 0; } + +#if defined(_MSC_VER) +static void SetThreadName(DWORD Id, LPCSTR Name) { + constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) + struct THREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to thread name + DWORD dwThreadId; // Thread ID (-1 == current thread) + DWORD dwFlags; // Reserved. Do not use. + }; +#pragma pack(pop) + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = Name; + info.dwThreadId = Id; + info.dwFlags = 0; + + __try { + ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), + (ULONG_PTR *)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + } +} +#endif + +void llvm::set_thread_name(const Twine &Name) { +#if defined(_MSC_VER) + // Make sure the input is null terminated. + SmallString<64> Storage; + StringRef NameStr = Name.toNullTerminatedStringRef(Storage); + SetThreadName(::GetCurrentThreadId(), NameStr.data()); +#endif +} + +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { + // "Name" is not an inherent property of a thread on Windows. In fact, when + // you "set" the name, you are only firing a one-time message to a debugger + // which it interprets as a program setting its threads' name. We may be + // able to get fancy by creating a TLS entry when someone calls + // set_thread_name so that subsequent calls to get_thread_name return this + // value. + Name.clear(); +} diff --git a/contrib/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm/lib/Support/Windows/WindowsSupport.h index c358b99..d4599dc 100644 --- a/contrib/llvm/lib/Support/Windows/WindowsSupport.h +++ b/contrib/llvm/lib/Support/Windows/WindowsSupport.h @@ -45,7 +45,9 @@ #include <string> #include <system_error> #include <windows.h> -#include <wincrypt.h> // Must be included after windows.h + +// Must be included after windows.h +#include <wincrypt.h> /// 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 diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp index c17a6f6..e2f21a5 100644 --- a/contrib/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm/lib/Support/YAMLParser.cpp @@ -1,4 +1,4 @@ -//===--- YAMLParser.cpp - Simple YAML parser ------------------------------===// +//===- YAMLParser.cpp - Simple YAML parser --------------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,16 +12,30 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/YAMLParser.h" +#include "llvm/ADT/AllocatorList.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/ADT/AllocatorList.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <map> +#include <memory> +#include <string> +#include <system_error> +#include <utility> using namespace llvm; using namespace yaml; @@ -37,7 +51,7 @@ enum UnicodeEncodingForm { /// EncodingInfo - Holds the encoding type and length of the byte order mark if /// it exists. Length is in {0, 2, 3, 4}. -typedef std::pair<UnicodeEncodingForm, unsigned> EncodingInfo; +using EncodingInfo = std::pair<UnicodeEncodingForm, unsigned>; /// getUnicodeEncoding - Reads up to the first 4 bytes to determine the Unicode /// encoding form of \a Input. @@ -46,7 +60,7 @@ typedef std::pair<UnicodeEncodingForm, unsigned> EncodingInfo; /// @returns An EncodingInfo indicating the Unicode encoding form of the input /// and how long the byte order mark is if one exists. static EncodingInfo getUnicodeEncoding(StringRef Input) { - if (Input.size() == 0) + if (Input.empty()) return std::make_pair(UEF_Unknown, 0); switch (uint8_t(Input[0])) { @@ -95,8 +109,6 @@ static EncodingInfo getUnicodeEncoding(StringRef Input) { return std::make_pair(UEF_UTF8, 0); } -namespace llvm { -namespace yaml { /// Pin the vtables to this file. void Node::anchor() {} void NullNode::anchor() {} @@ -107,6 +119,9 @@ void MappingNode::anchor() {} void SequenceNode::anchor() {} void AliasNode::anchor() {} +namespace llvm { +namespace yaml { + /// Token - A single YAML token. struct Token { enum TokenKind { @@ -133,7 +148,7 @@ struct Token { TK_Alias, TK_Anchor, TK_Tag - } Kind; + } Kind = TK_Error; /// A string of length 0 or more whose begin() points to the logical location /// of the token in the input. @@ -142,14 +157,16 @@ struct Token { /// The value of a block scalar node. std::string Value; - Token() : Kind(TK_Error) {} + Token() = default; }; -} -} -typedef llvm::BumpPtrList<Token> TokenQueueT; +} // end namespace yaml +} // end namespace llvm + +using TokenQueueT = BumpPtrList<Token>; namespace { + /// @brief This struct is used to track simple keys. /// /// Simple keys are handled by creating an entry in SimpleKeys for each Token @@ -170,12 +187,13 @@ struct SimpleKey { return Tok == Other.Tok; } }; -} + +} // end anonymous namespace /// @brief The Unicode scalar value of a UTF-8 minimal well-formed code unit /// subsequence and the subsequence's length in code units (uint8_t). /// A length of 0 represents an error. -typedef std::pair<uint32_t, unsigned> UTF8Decoded; +using UTF8Decoded = std::pair<uint32_t, unsigned>; static UTF8Decoded decodeUTF8(StringRef Range) { StringRef::iterator Position= Range.begin(); @@ -229,6 +247,7 @@ static UTF8Decoded decodeUTF8(StringRef Range) { namespace llvm { namespace yaml { + /// @brief Scans YAML tokens from a MemoryBuffer. class Scanner { public: @@ -350,7 +369,8 @@ private: /// ns-char. StringRef::iterator skip_ns_char(StringRef::iterator Position); - typedef StringRef::iterator (Scanner::*SkipWhileFunc)(StringRef::iterator); + using SkipWhileFunc = StringRef::iterator (Scanner::*)(StringRef::iterator); + /// @brief Skip minimal well-formed code unit subsequences until Func /// returns its input. /// @@ -655,10 +675,10 @@ bool yaml::dumpTokens(StringRef Input, raw_ostream &OS) { } bool yaml::scanTokens(StringRef Input) { - llvm::SourceMgr SM; - llvm::yaml::Scanner scanner(Input, SM); - for (;;) { - llvm::yaml::Token T = scanner.getNext(); + SourceMgr SM; + Scanner scanner(Input, SM); + while (true) { + Token T = scanner.getNext(); if (T.Kind == Token::TK_StreamEnd) break; else if (T.Kind == Token::TK_Error) @@ -1744,7 +1764,7 @@ Stream::Stream(MemoryBufferRef InputBuffer, SourceMgr &SM, bool ShowColors, std::error_code *EC) : scanner(new Scanner(InputBuffer, SM, ShowColors, EC)), CurrentDoc() {} -Stream::~Stream() {} +Stream::~Stream() = default; bool Stream::failed() { return scanner->failed(); } @@ -1851,8 +1871,6 @@ bool Node::failed() const { return Doc->failed(); } - - StringRef ScalarNode::getValue(SmallVectorImpl<char> &Storage) const { // TODO: Handle newlines properly. We need to remove leading whitespace. if (Value[0] == '"') { // Double quoted. @@ -2116,6 +2134,7 @@ void MappingNode::increment() { break; default: setError("Unexpected token. Expected Key or Block End", T); + LLVM_FALLTHROUGH; case Token::TK_Error: IsAtEnd = true; CurrentEntry = nullptr; @@ -2128,6 +2147,7 @@ void MappingNode::increment() { return increment(); case Token::TK_FlowMappingEnd: getNext(); + LLVM_FALLTHROUGH; case Token::TK_Error: // Set this to end iterator. IsAtEnd = true; @@ -2170,6 +2190,7 @@ void SequenceNode::increment() { default: setError( "Unexpected token. Expected Block Entry or Block End." , T); + LLVM_FALLTHROUGH; case Token::TK_Error: IsAtEnd = true; CurrentEntry = nullptr; @@ -2198,6 +2219,7 @@ void SequenceNode::increment() { return increment(); case Token::TK_FlowSequenceEnd: getNext(); + LLVM_FALLTHROUGH; case Token::TK_Error: // Set this to end iterator. IsAtEnd = true; diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp index 9849b3a..65eda24 100644 --- a/contrib/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm/lib/Support/YAMLTraits.cpp @@ -8,17 +8,27 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/YAMLTraits.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" -#include <cctype> +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstdlib> #include <cstring> +#include <string> +#include <vector> + using namespace llvm; using namespace yaml; @@ -26,11 +36,9 @@ using namespace yaml; // IO //===----------------------------------------------------------------------===// -IO::IO(void *Context) : Ctxt(Context) { -} +IO::IO(void *Context) : Ctxt(Context) {} -IO::~IO() { -} +IO::~IO() = default; void *IO::getContext() { return Ctxt; @@ -46,16 +54,22 @@ void IO::setContext(void *Context) { Input::Input(StringRef InputContent, void *Ctxt, SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt) - : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)), - CurrentNode(nullptr) { + : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)) { if (DiagHandler) SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt); DocIterator = Strm->begin(); } -Input::~Input() { +Input::Input(MemoryBufferRef Input, void *Ctxt, + SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt) + : IO(Ctxt), Strm(new Stream(Input, SrcMgr, false, &EC)) { + if (DiagHandler) + SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt); + DocIterator = Strm->begin(); } +Input::~Input() = default; + std::error_code Input::error() { return EC; } // Pin the vtables to this file. @@ -398,20 +412,9 @@ bool Input::canElideEmptySequence() { //===----------------------------------------------------------------------===// Output::Output(raw_ostream &yout, void *context, int WrapColumn) - : IO(context), - Out(yout), - WrapColumn(WrapColumn), - Column(0), - ColumnAtFlowStart(0), - ColumnAtMapFlowStart(0), - NeedBitValueComma(false), - NeedFlowSequenceComma(false), - EnumerationMatchFound(false), - NeedsNewLine(false) { -} + : IO(context), Out(yout), WrapColumn(WrapColumn) {} -Output::~Output() { -} +Output::~Output() = default; bool Output::outputting() { return true; @@ -462,7 +465,7 @@ std::vector<StringRef> Output::keys() { bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault, bool &UseDefault, void *&) { UseDefault = false; - if (Required || !SameAsDefault) { + if (Required || !SameAsDefault || WriteDefaultValues) { auto State = StateStack.back(); if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) { flowKey(Key); @@ -918,12 +921,9 @@ void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) { - SmallString<32> buff(Scalar.begin(), Scalar.end()); - char *end; - Val = strtod(buff.c_str(), &end); - if (*end != '\0') - return "invalid floating point number"; - return StringRef(); + if (to_float(Scalar, Val)) + return StringRef(); + return "invalid floating point number"; } void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) { @@ -931,12 +931,9 @@ void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) { - SmallString<32> buff(Scalar.begin(), Scalar.end()); - char *end; - Val = strtod(buff.c_str(), &end); - if (*end != '\0') - return "invalid floating point number"; - return StringRef(); + if (to_float(Scalar, Val)) + return StringRef(); + return "invalid floating point number"; } void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) { diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp index d073802..dd58ecc 100644 --- a/contrib/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -326,13 +326,30 @@ raw_ostream &raw_ostream::operator<<(const formatv_object_base &Obj) { } raw_ostream &raw_ostream::operator<<(const FormattedString &FS) { - unsigned Len = FS.Str.size(); - int PadAmount = FS.Width - Len; - if (FS.RightJustify && (PadAmount > 0)) - this->indent(PadAmount); - this->operator<<(FS.Str); - if (!FS.RightJustify && (PadAmount > 0)) + 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"); + } return *this; } @@ -465,8 +482,7 @@ void format_object_base::home() { static int getFD(StringRef Filename, std::error_code &EC, sys::fs::OpenFlags Flags) { // Handle "-" as stdout. Note that when we do this, we consider ourself - // the owner of stdout. This means that we can do things like close the - // file descriptor when we're done and set the "binary" flag globally. + // the owner of stdout and may set the "binary" flag globally based on Flags. if (Filename == "-") { EC = std::error_code(); // If user requested binary then put stdout into binary mode if @@ -497,6 +513,13 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) ShouldClose = false; return; } + // We do not want to close STDOUT as there may have been several uses of it + // such as the case: llc %s -o=- -pass-remarks-output=- -filetype=asm + // which cause multiple closes of STDOUT_FILENO and/or use-after-close of it. + // Using dup() in getFD doesn't work as we end up with original STDOUT_FILENO + // open anyhow. + if (FD <= STDERR_FILENO) + ShouldClose = false; // Get the starting position. off_t loc = ::lseek(FD, 0, SEEK_CUR); @@ -542,7 +565,11 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { pos += Size; #ifndef LLVM_ON_WIN32 +#if defined(__linux__) + bool ShouldWriteInChunks = true; +#else bool ShouldWriteInChunks = false; +#endif #else // Writing a large size of output to Windows console returns ENOMEM. It seems // that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and |