<div dir="ltr">Bots have been broken for a long time now. I'm going to revert this to get the bots green and Richard can re-land...</div><br><div class="gmail_quote"><div dir="ltr">On Sat, Aug 25, 2018 at 4:20 PM via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Richard, your commit is causing a build failure on the PS4 Windows bot. Can you please take a look?<br>
<br>
<a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/19356/steps/build/logs/stdio" rel="noreferrer" target="_blank">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/19356/steps/build/logs/stdio</a><br>
<br>
FAILED: lib/Support/CMakeFiles/LLVMSupport.dir/ItaniumManglingCanonicalizer.cpp.obj <br>
C:\PROGRA~2\MICROS~1.0\VC\bin\cl.exe /nologo /TP -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_FILE_OFFSET_BITS=64 -D_HAS_EXCEPTIONS=0 -D_LARGEFILE_SOURCE -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Ilib\Support -IC:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\lib\Support -Iinclude -IC:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\include /DWIN32 /D_WINDOWS /Zc:inline /Zc:strictStrings /Oi /Zc:rvalueCast /W4 -wd4141 -wd4146 -wd4180 -wd4244 -wd4258 -wd4267 -wd4291 -wd4345 -wd4351 -wd4355 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4800 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4324 -w14062 -we4238 /MD /O2 /Ob2 -UNDEBUG /EHs-c- /GR- /showIncludes /Folib\Support\CMakeFiles\LLVMSupport.dir\ItaniumManglingCanonicalizer.cpp.obj /Fdlib\Support\CMakeFiles\LLVMSupport.dir\LLVMSupport.pdb /FS -c C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\lib\Support\ItaniumManglingCanonicalizer.cpp<br>
C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\lib\Support\ItaniumManglingCanonicalizer.cpp(146): error C2910: '`anonymous-namespace'::FoldingNodeAllocator::getOrCreateNode': cannot be explicitly specialized<br>
<br>
Douglas Yung<br>
<br>
> -----Original Message-----<br>
> From: llvm-commits [mailto:<a href="mailto:llvm-commits-bounces@lists.llvm.org" target="_blank">llvm-commits-bounces@lists.llvm.org</a>] On<br>
> Behalf Of Richard Smith via llvm-commits<br>
> Sent: Friday, August 24, 2018 15:32<br>
> To: <a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
> Subject: [llvm] r340663 - Add data structure to form equivalence<br>
> classes of mangled names.<br>
> <br>
> Author: rsmith<br>
> Date: Fri Aug 24 15:31:51 2018<br>
> New Revision: 340663<br>
> <br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=340663&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=340663&view=rev</a><br>
> Log:<br>
> Add data structure to form equivalence classes of mangled names.<br>
> <br>
> Summary:<br>
> Given a set of equivalent name fragments, this mechanism determines<br>
> whether two<br>
> mangled names are equivalent. The intent is to use this for fuzzy<br>
> matching of<br>
> profile data against the program after certain refactorings are<br>
> performed.<br>
> <br>
> Reviewers: erik.pilkington, dlj<br>
> <br>
> Subscribers: mgorny, llvm-commits<br>
> <br>
> Differential Revision: <a href="https://reviews.llvm.org/D50935" rel="noreferrer" target="_blank">https://reviews.llvm.org/D50935</a><br>
> <br>
> Added:<br>
> llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h<br>
> llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp<br>
> llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp<br>
> Modified:<br>
> llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h<br>
> llvm/trunk/lib/Support/CMakeLists.txt<br>
> llvm/trunk/unittests/Support/CMakeLists.txt<br>
> <br>
> Modified: llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-</a><br>
> project/llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h?rev=340663&r<br>
> 1=340662&r2=340663&view=diff<br>
> =======================================================================<br>
> =======<br>
> --- llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h (original)<br>
> +++ llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h Fri Aug 24<br>
> 15:31:51 2018<br>
> @@ -2160,7 +2160,7 @@ struct Db {<br>
> ASTAllocator.reset();<br>
> }<br>
> <br>
> - template <class T, class... Args> T *make(Args &&... args) {<br>
> + template <class T, class... Args> Node *make(Args &&... args) {<br>
> return ASTAllocator.template<br>
> makeNode<T>(std::forward<Args>(args)...);<br>
> }<br>
> <br>
> @@ -4948,8 +4948,11 @@ template<typename Alloc> Node *Db<Alloc><br>
> // <template-arg> further ahead in the mangled name (currently just<br>
> conversion<br>
> // operator types), then we should only look it up in the right<br>
> context.<br>
> if (PermitForwardTemplateReferences) {<br>
> -<br>
> ForwardTemplateRefs.push_back(make<ForwardTemplateReference>(Index));<br>
> - return ForwardTemplateRefs.back();<br>
> + Node *ForwardRef = make<ForwardTemplateReference>(Index);<br>
> + assert(ForwardRef->getKind() == Node::KForwardTemplateReference);<br>
> + ForwardTemplateRefs.push_back(<br>
> + static_cast<ForwardTemplateReference *>(ForwardRef));<br>
> + return ForwardRef;<br>
> }<br>
> <br>
> if (Index >= TemplateParams.size())<br>
> <br>
> Added: llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-</a><br>
> project/llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h?<br>
> rev=340663&view=auto<br>
> =======================================================================<br>
> =======<br>
> --- llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h<br>
> (added)<br>
> +++ llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h Fri<br>
> Aug 24 15:31:51 2018<br>
> @@ -0,0 +1,87 @@<br>
> +//===--- ItaniumManglingCanonicalizer.h -------------------------*-<br>
> C++ -*-===//<br>
> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is distributed under the University of Illinois Open<br>
> Source<br>
> +// License. See LICENSE.TXT for details.<br>
> +//<br>
> +//===-----------------------------------------------------------------<br>
> -----===//<br>
> +//<br>
> +// This file defines a class for computing equivalence classes of<br>
> mangled names<br>
> +// given a set of equivalences between name fragments.<br>
> +//<br>
> +//===-----------------------------------------------------------------<br>
> -----===//<br>
> +<br>
> +#ifndef LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H<br>
> +#define LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H<br>
> +<br>
> +#include "llvm/ADT/StringRef.h"<br>
> +<br>
> +#include <cstddef><br>
> +<br>
> +namespace llvm {<br>
> +/// Canonicalizer for mangled names.<br>
> +///<br>
> +/// This class allows specifying a list of "equivalent" manglings. For<br>
> example,<br>
> +/// you can specify that Ss is equivalent to<br>
> +/// NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE<br>
> +/// and then manglings that refer to libstdc++'s 'std::string' will be<br>
> +/// considered equivalent to manglings that are the same except that<br>
> they refer<br>
> +/// to libc++'s 'std::string'.<br>
> +///<br>
> +/// This can be used when data (eg, profiling data) is available for a<br>
> version<br>
> +/// of a program built in a different configuration, with<br>
> correspondingly<br>
> +/// different manglings.<br>
> +class ItaniumManglingCanonicalizer {<br>
> +public:<br>
> + ItaniumManglingCanonicalizer();<br>
> + ItaniumManglingCanonicalizer(const ItaniumManglingCanonicalizer &) =<br>
> delete;<br>
> + void operator=(const ItaniumManglingCanonicalizer &) = delete;<br>
> + ~ItaniumManglingCanonicalizer();<br>
> +<br>
> + enum class EquivalenceError {<br>
> + Success,<br>
> +<br>
> + /// Both the equivalent manglings have already been used as<br>
> components of<br>
> + /// some other mangling we've looked at. It's too late to add this<br>
> + /// equivalence.<br>
> + ManglingAlreadyUsed,<br>
> +<br>
> + /// The first equivalent mangling is invalid.<br>
> + InvalidFirstMangling,<br>
> +<br>
> + /// The second equivalent mangling is invalid.<br>
> + InvalidSecondMangling,<br>
> + };<br>
> +<br>
> + enum class FragmentKind {<br>
> + /// The mangling fragment is a <name> (or a predefined<br>
> <substitution>).<br>
> + Name,<br>
> + /// The mangling fragment is a <type>.<br>
> + Type,<br>
> + /// The mangling fragment is an <encoding>.<br>
> + Encoding,<br>
> + };<br>
> +<br>
> + /// Add an equivalence between \p First and \p Second. Both<br>
> manglings must<br>
> + /// live at least as long as the canonicalizer.<br>
> + EquivalenceError addEquivalence(FragmentKind Kind, StringRef First,<br>
> + StringRef Second);<br>
> +<br>
> + using Key = uintptr_t;<br>
> +<br>
> + /// Form a canonical key for the specified mangling. They key will<br>
> be the<br>
> + /// same for all equivalent manglings, and different for any two<br>
> + /// non-equivalent manglings, but is otherwise unspecified.<br>
> + ///<br>
> + /// Returns Key() if (and only if) the mangling is not a valid<br>
> Itanium C++<br>
> + /// ABI mangling.<br>
> + Key canonicalize(StringRef Mangling);<br>
> +<br>
> +private:<br>
> + struct Impl;<br>
> + Impl *P;<br>
> +};<br>
> +} // namespace llvm<br>
> +<br>
> +#endif // LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H<br>
> <br>
> Modified: llvm/trunk/lib/Support/CMakeLists.txt<br>
> URL: <a href="http://llvm.org/viewvc/llvm-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-</a><br>
> project/llvm/trunk/lib/Support/CMakeLists.txt?rev=340663&r1=340662&r2=3<br>
> 40663&view=diff<br>
> =======================================================================<br>
> =======<br>
> --- llvm/trunk/lib/Support/CMakeLists.txt (original)<br>
> +++ llvm/trunk/lib/Support/CMakeLists.txt Fri Aug 24 15:31:51 2018<br>
> @@ -83,6 +83,7 @@ add_llvm_library(LLVMSupport<br>
> InitLLVM.cpp<br>
> IntEqClasses.cpp<br>
> IntervalMap.cpp<br>
> + ItaniumManglingCanonicalizer.cpp<br>
> JamCRC.cpp<br>
> JSON.cpp<br>
> KnownBits.cpp<br>
> <br>
> Added: llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-</a><br>
> project/llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp?rev=340<br>
> 663&view=auto<br>
> =======================================================================<br>
> =======<br>
> --- llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp (added)<br>
> +++ llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp Fri Aug 24<br>
> 15:31:51 2018<br>
> @@ -0,0 +1,307 @@<br>
> +//===----------------- ItaniumManglingCanonicalizer.cpp --------------<br>
> -----===//<br>
> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of<br>
> Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===-----------------------------------------------------------------<br>
> -----===//<br>
> +<br>
> +#include "llvm/Support/ItaniumManglingCanonicalizer.h"<br>
> +<br>
> +#include "llvm/ADT/FoldingSet.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> +#include "llvm/Demangle/ItaniumDemangle.h"<br>
> +#include "llvm/Support/Allocator.h"<br>
> +<br>
> +#include "llvm/ADT/DenseMap.h"<br>
> +#include "llvm/ADT/FoldingSet.h"<br>
> +#include "llvm/ADT/StringRef.h"<br>
> +<br>
> +using namespace llvm;<br>
> +using llvm::itanium_demangle::ForwardTemplateReference;<br>
> +using llvm::itanium_demangle::Node;<br>
> +using llvm::itanium_demangle::NodeKind;<br>
> +<br>
> +namespace {<br>
> +struct FoldingSetNodeIDBuilder {<br>
> + llvm::FoldingSetNodeID &ID;<br>
> + void operator()(const Node *P) { ID.AddPointer(P); }<br>
> + void operator()(StringView Str) {<br>
> + ID.AddString(llvm::StringRef(Str.begin(), Str.size()));<br>
> + }<br>
> + template<typename T><br>
> + typename std::enable_if<std::is_integral<T>::value ||<br>
> + std::is_enum<T>::value>::type<br>
> + operator()(T V) {<br>
> + ID.AddInteger((unsigned long long)V);<br>
> + }<br>
> + void operator()(itanium_demangle::NodeOrString NS) {<br>
> + if (NS.isNode()) {<br>
> + ID.AddInteger(0);<br>
> + (*this)(NS.asNode());<br>
> + } else if (NS.isString()) {<br>
> + ID.AddInteger(1);<br>
> + (*this)(NS.asString());<br>
> + } else {<br>
> + ID.AddInteger(2);<br>
> + }<br>
> + }<br>
> + void operator()(itanium_demangle::NodeArray A) {<br>
> + ID.AddInteger(A.size());<br>
> + for (const Node *N : A)<br>
> + (*this)(N);<br>
> + }<br>
> +};<br>
> +<br>
> +template<typename ...T><br>
> +void profileCtor(llvm::FoldingSetNodeID &ID, Node::Kind K, T ...V) {<br>
> + FoldingSetNodeIDBuilder Builder = {ID};<br>
> + Builder(K);<br>
> + int VisitInOrder[] = {<br>
> + (Builder(V), 0) ...,<br>
> + 0 // Avoid empty array if there are no arguments.<br>
> + };<br>
> + (void)VisitInOrder;<br>
> +}<br>
> +<br>
> +// FIXME: Convert this to a generic lambda when possible.<br>
> +template<typename NodeT> struct ProfileSpecificNode {<br>
> + FoldingSetNodeID &ID;<br>
> + template<typename ...T> void operator()(T ...V) {<br>
> + profileCtor(ID, NodeKind<NodeT>::Kind, V...);<br>
> + }<br>
> +};<br>
> +<br>
> +struct ProfileNode {<br>
> + FoldingSetNodeID &ID;<br>
> + template<typename NodeT> void operator()(const NodeT *N) {<br>
> + N->match(ProfileSpecificNode<NodeT>{ID});<br>
> + }<br>
> +};<br>
> +<br>
> +template<> void ProfileNode::operator()(const ForwardTemplateReference<br>
> *N) {<br>
> + llvm_unreachable("should never canonicalize a<br>
> ForwardTemplateReference");<br>
> +};<br>
> +<br>
> +void profileNode(llvm::FoldingSetNodeID &ID, const Node *N) {<br>
> + N->visit(ProfileNode{ID});<br>
> +}<br>
> +<br>
> +class FoldingNodeAllocator {<br>
> + class alignas(alignof(Node *)) NodeHeader : public<br>
> llvm::FoldingSetNode {<br>
> + public:<br>
> + // 'Node' in this context names the injected-class-name of the<br>
> base class.<br>
> + itanium_demangle::Node *getNode() {<br>
> + return reinterpret_cast<itanium_demangle::Node *>(this + 1);<br>
> + }<br>
> + void Profile(llvm::FoldingSetNodeID &ID) { profileNode(ID,<br>
> getNode()); }<br>
> + };<br>
> +<br>
> + BumpPtrAllocator RawAlloc;<br>
> + llvm::FoldingSet<NodeHeader> Nodes;<br>
> +<br>
> +public:<br>
> + void reset() {}<br>
> +<br>
> + template<typename T, typename ...Args><br>
> + std::pair<Node*, bool> getOrCreateNode(Args &&...As) {<br>
> + llvm::FoldingSetNodeID ID;<br>
> + profileCtor(ID, NodeKind<T>::Kind, As...);<br>
> +<br>
> + void *InsertPos;<br>
> + if (NodeHeader *Existing = Nodes.FindNodeOrInsertPos(ID,<br>
> InsertPos))<br>
> + return {static_cast<T*>(Existing->getNode()), false};<br>
> +<br>
> + static_assert(alignof(T) <= alignof(NodeHeader),<br>
> + "underaligned node header for specific node kind");<br>
> + void *Storage =<br>
> + RawAlloc.Allocate(sizeof(NodeHeader) + sizeof(T),<br>
> alignof(NodeHeader));<br>
> + NodeHeader *New = new (Storage) NodeHeader;<br>
> + T *Result = new (New->getNode()) T(std::forward<Args>(As)...);<br>
> + Nodes.InsertNode(New, InsertPos);<br>
> + return {Result, true};<br>
> + }<br>
> +<br>
> + template<typename T, typename... Args><br>
> + Node *makeNode(Args &&...As) {<br>
> + return getOrCreateNode<T>(std::forward<Args>(As)...).first;<br>
> + }<br>
> +<br>
> + void *allocateNodeArray(size_t sz) {<br>
> + return RawAlloc.Allocate(sizeof(Node *) * sz, alignof(Node *));<br>
> + }<br>
> +};<br>
> +<br>
> +// FIXME: Don't canonicalize forward template references for now,<br>
> because they<br>
> +// contain state (the resolved template node) that's not known at<br>
> their point<br>
> +// of creation.<br>
> +template<><br>
> +std::pair<Node *, bool><br>
> +FoldingNodeAllocator::getOrCreateNode<ForwardTemplateReference>(size_t<br>
> &Index) {<br>
> + return {new (RawAlloc.Allocate(sizeof(ForwardTemplateReference),<br>
> + alignof(ForwardTemplateReference)))<br>
> + ForwardTemplateReference(Index),<br>
> + true};<br>
> +}<br>
> +<br>
> +class CanonicalizerAllocator : public FoldingNodeAllocator {<br>
> + Node *MostRecentlyCreated = nullptr;<br>
> + Node *TrackedNode = nullptr;<br>
> + bool TrackedNodeIsUsed = false;<br>
> + llvm::SmallDenseMap<Node*, Node*, 32> Remappings;<br>
> +<br>
> + template<typename T, typename ...Args> Node *makeNodeSimple(Args<br>
> &&...As) {<br>
> + std::pair<Node *, bool> Result =<br>
> + getOrCreateNode<T>(std::forward<Args>(As)...);<br>
> + if (Result.second) {<br>
> + // Node is new. Make a note of that.<br>
> + MostRecentlyCreated = Result.first;<br>
> + } else {<br>
> + // Node is pre-existing; check if it's in our remapping table.<br>
> + if (auto *N = Remappings.lookup(Result.first)) {<br>
> + Result.first = N;<br>
> + assert(Remappings.find(Result.first) == Remappings.end() &&<br>
> + "should never need multiple remap steps");<br>
> + }<br>
> + if (Result.first == TrackedNode)<br>
> + TrackedNodeIsUsed = true;<br>
> + }<br>
> + return Result.first;<br>
> + }<br>
> +<br>
> + /// Helper to allow makeNode to be partially-specialized on T.<br>
> + template<typename T> struct MakeNodeImpl {<br>
> + CanonicalizerAllocator &Self;<br>
> + template<typename ...Args> Node *make(Args &&...As) {<br>
> + return Self.makeNodeSimple<T>(std::forward<Args>(As)...);<br>
> + }<br>
> + };<br>
> +<br>
> +public:<br>
> + template<typename T, typename ...Args> Node *makeNode(Args &&...As)<br>
> {<br>
> + return MakeNodeImpl<T>{*this}.make(std::forward<Args>(As)...);<br>
> + }<br>
> +<br>
> + void reset() { MostRecentlyCreated = nullptr; }<br>
> +<br>
> + void addRemapping(Node *A, Node *B) {<br>
> + // Note, we don't need to check whether B is also remapped,<br>
> because if it<br>
> + // was we would have already remapped it when building it.<br>
> + Remappings.insert(std::make_pair(A, B));<br>
> + }<br>
> +<br>
> + bool isMostRecentlyCreated(Node *N) const { return<br>
> MostRecentlyCreated == N; }<br>
> +<br>
> + void trackUsesOf(Node *N) {<br>
> + TrackedNode = N;<br>
> + TrackedNodeIsUsed = false;<br>
> + }<br>
> + bool trackedNodeIsUsed() const { return TrackedNodeIsUsed; }<br>
> +};<br>
> +<br>
> +/// Convert St3foo to NSt3fooE so that equivalences naming one also<br>
> affect the<br>
> +/// other.<br>
> +template<><br>
> +struct CanonicalizerAllocator::MakeNodeImpl<<br>
> + itanium_demangle::StdQualifiedName> {<br>
> + CanonicalizerAllocator &Self;<br>
> + Node *make(Node *Child) {<br>
> + Node *StdNamespace =<br>
> Self.makeNode<itanium_demangle::NameType>("std");<br>
> + if (!StdNamespace)<br>
> + return nullptr;<br>
> + return Self.makeNode<itanium_demangle::NestedName>(StdNamespace,<br>
> Child);<br>
> + }<br>
> +};<br>
> +<br>
> +// FIXME: Also expand built-in substitutions?<br>
> +<br>
> +using CanonicalizingDemangler =<br>
> itanium_demangle::Db<CanonicalizerAllocator>;<br>
> +}<br>
> +<br>
> +struct ItaniumManglingCanonicalizer::Impl {<br>
> + CanonicalizingDemangler Demangler = {nullptr, nullptr};<br>
> +};<br>
> +<br>
> +ItaniumManglingCanonicalizer::ItaniumManglingCanonicalizer() : P(new<br>
> Impl) {}<br>
> +ItaniumManglingCanonicalizer::~ItaniumManglingCanonicalizer() { delete<br>
> P; }<br>
> +<br>
> +ItaniumManglingCanonicalizer::EquivalenceError<br>
> +ItaniumManglingCanonicalizer::addEquivalence(FragmentKind Kind,<br>
> StringRef First,<br>
> + StringRef Second) {<br>
> + auto &Alloc = P->Demangler.ASTAllocator;<br>
> +<br>
> + auto Parse = [&](StringRef Str) {<br>
> + P->Demangler.reset(Str.begin(), Str.end());<br>
> + Node *N = nullptr;<br>
> + switch (Kind) {<br>
> + // A <name>, with minor extensions to allow arbitrary namespace<br>
> and<br>
> + // template names that can't easily be written as <name>s.<br>
> + case FragmentKind::Name:<br>
> + // Very special case: allow "St" as a shorthand for "3std". It's<br>
> not<br>
> + // valid as a <name> mangling, but is nonetheless the most<br>
> natural<br>
> + // way to name the 'std' namespace.<br>
> + if (Str.size() == 2 && P->Demangler.consumeIf("St"))<br>
> + N = P->Demangler.make<itanium_demangle::NameType>("std");<br>
> + // We permit substitutions to name templates without their<br>
> template<br>
> + // arguments. This mostly just falls out, as almost all template<br>
> names<br>
> + // are valid as <name>s, but we also want to parse<br>
> <substitution>s as<br>
> + // <name>s, even though they're not.<br>
> + else if (Str.startswith("S"))<br>
> + // Parse the substitution and optional following template<br>
> arguments.<br>
> + N = P->Demangler.parseType();<br>
> + else<br>
> + N = P->Demangler.parseName();<br>
> + break;<br>
> +<br>
> + // A <type>.<br>
> + case FragmentKind::Type:<br>
> + N = P->Demangler.parseType();<br>
> + break;<br>
> +<br>
> + // An <encoding>.<br>
> + case FragmentKind::Encoding:<br>
> + N = P->Demangler.parseEncoding();<br>
> + break;<br>
> + }<br>
> +<br>
> + // If we have trailing junk, the mangling is invalid.<br>
> + if (P->Demangler.numLeft() != 0)<br>
> + N = nullptr;<br>
> +<br>
> + // If any node was created after N, then we cannot safely remap it<br>
> because<br>
> + // it might already be in use by another node.<br>
> + return std::make_pair(N, Alloc.isMostRecentlyCreated(N));<br>
> + };<br>
> +<br>
> + Node *FirstNode, *SecondNode;<br>
> + bool FirstIsNew, SecondIsNew;<br>
> +<br>
> + std::tie(FirstNode, FirstIsNew) = Parse(First);<br>
> + if (!FirstNode)<br>
> + return EquivalenceError::InvalidFirstMangling;<br>
> +<br>
> + Alloc.trackUsesOf(FirstNode);<br>
> + std::tie(SecondNode, SecondIsNew) = Parse(Second);<br>
> + if (!SecondNode)<br>
> + return EquivalenceError::InvalidSecondMangling;<br>
> +<br>
> + // If they're already equivalent, there's nothing to do.<br>
> + if (FirstNode == SecondNode)<br>
> + return EquivalenceError::Success;<br>
> +<br>
> + if (FirstIsNew && !Alloc.trackedNodeIsUsed())<br>
> + Alloc.addRemapping(FirstNode, SecondNode);<br>
> + else if (SecondIsNew)<br>
> + Alloc.addRemapping(SecondNode, FirstNode);<br>
> + else<br>
> + return EquivalenceError::ManglingAlreadyUsed;<br>
> +<br>
> + return EquivalenceError::Success;<br>
> +}<br>
> +<br>
> +ItaniumManglingCanonicalizer::Key<br>
> +ItaniumManglingCanonicalizer::canonicalize(StringRef Mangling) {<br>
> + P->Demangler.reset(Mangling.begin(), Mangling.end());<br>
> + return reinterpret_cast<Key>(P->Demangler.parse());<br>
> +}<br>
> <br>
> Modified: llvm/trunk/unittests/Support/CMakeLists.txt<br>
> URL: <a href="http://llvm.org/viewvc/llvm-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-</a><br>
> project/llvm/trunk/unittests/Support/CMakeLists.txt?rev=340663&r1=34066<br>
> 2&r2=340663&view=diff<br>
> =======================================================================<br>
> =======<br>
> --- llvm/trunk/unittests/Support/CMakeLists.txt (original)<br>
> +++ llvm/trunk/unittests/Support/CMakeLists.txt Fri Aug 24 15:31:51<br>
> 2018<br>
> @@ -31,6 +31,7 @@ add_llvm_unittest(SupportTests<br>
> FormatVariadicTest.cpp<br>
> GlobPatternTest.cpp<br>
> Host.cpp<br>
> + ItaniumManglingCanonicalizerTest.cpp<br>
> JSONTest.cpp<br>
> LEB128Test.cpp<br>
> LineIteratorTest.cpp<br>
> <br>
> Added:<br>
> llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-</a><br>
> project/llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.c<br>
> pp?rev=340663&view=auto<br>
> =======================================================================<br>
> =======<br>
> --- llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp<br>
> (added)<br>
> +++ llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp<br>
> Fri Aug 24 15:31:51 2018<br>
> @@ -0,0 +1,315 @@<br>
> +//===-------------- ItaniumManglingCanonicalizerTest.cpp -------------<br>
> -----===//<br>
> +//<br>
> +// The LLVM Compiler Infrastructure<br>
> +//<br>
> +// This file is dual licensed under the MIT and the University of<br>
> Illinois Open<br>
> +// Source Licenses. See LICENSE.TXT for details.<br>
> +//<br>
> +//===-----------------------------------------------------------------<br>
> -----===//<br>
> +<br>
> +#include <cstdlib><br>
> +#include "llvm/Support/ItaniumManglingCanonicalizer.h"<br>
> +#include "gtest/gtest.h"<br>
> +<br>
> +using EquivalenceError =<br>
> llvm::ItaniumManglingCanonicalizer::EquivalenceError;<br>
> +using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind;<br>
> +<br>
> +struct Equivalence {<br>
> + FragmentKind Kind;<br>
> + llvm::StringRef First;<br>
> + llvm::StringRef Second;<br>
> +};<br>
> +<br>
> +// A set of manglings that should all be considered equivalent.<br>
> +using EquivalenceClass = std::initializer_list<llvm::StringRef>;<br>
> +<br>
> +struct Testcase {<br>
> + // A set of equivalences to register.<br>
> + std::initializer_list<Equivalence> Equivalences;<br>
> + // A set of distinct equivalence classes created by registering the<br>
> + // equivalences.<br>
> + std::initializer_list<EquivalenceClass> Classes;<br>
> +};<br>
> +<br>
> +static std::initializer_list<Testcase> Testcases = {<br>
> + // Three different manglings for std::string (old libstdc++, new<br>
> libstdc++,<br>
> + // libc++).<br>
> + {<br>
> + {<br>
> + {FragmentKind::Type, "Ss",<br>
> +<br>
> "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"},<br>
> + {FragmentKind::Type, "Ss",<br>
> + "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},<br>
> + },<br>
> + {<br>
> + {"_Z1fv"},<br>
> + {"_Z1fSs",<br>
> +<br>
> "_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",<br>
> + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},<br>
> + {"_ZNKSs4sizeEv",<br>
> +<br>
> "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv",<br>
> +<br>
> "_ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeE<br>
> v"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Check that substitutions are properly handled.<br>
> + {<br>
> + {<br>
> + // ::X <-> ::N::X<int><br>
> + {FragmentKind::Type, "1X", "N1N1XIiEE"},<br>
> + // ::T<T<int, int>, T<int, int>> <-> T<int><br>
> + {FragmentKind::Type, "1TIS_IiiES0_E", "1TIiE"},<br>
> + // A::B::foo <-> AB::foo<br>
> + {FragmentKind::Name, "N1A1B3fooE", "N2AB3fooE"},<br>
> + },<br>
> + {<br>
> + {"_Z1f1XPS_RS_", "_Z1fN1N1XIiEEPS1_RS1_"},<br>
> + {"_ZN1A1B3fooE1TIS1_IiiES2_EPS3_RS3_",<br>
> "_ZN2AB3fooE1TIiEPS1_RS1_"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Check that nested equivalences are properly handled.<br>
> + {<br>
> + {<br>
> + // std::__1::char_traits == std::__cxx11::char_traits<br>
> + // (Note that this is unused and should make no difference,<br>
> + // but it should not cause us to fail to match up the cases<br>
> + // below.)<br>
> + {FragmentKind::Name,<br>
> + "NSt3__111char_traitsE",<br>
> + "NSt7__cxx1111char_traitsE"},<br>
> + // std::__1::allocator == std::allocator<br>
> + {FragmentKind::Name,<br>
> + "NSt3__19allocatorE",<br>
> + "Sa"}, // "Sa" is not strictly a <name> but we accept it as<br>
> one.<br>
> + // std::__1::vector == std::vector<br>
> + {FragmentKind::Name,<br>
> + "St6vector",<br>
> + "NSt3__16vectorE"},<br>
> + // std::__1::basic_string<<br>
> + // char<br>
> + // std::__1::char_traits<char>,<br>
> + // std::__1::allocator<char>> ==<br>
> + // std::__cxx11::basic_string<<br>
> + // char,<br>
> + // std::char_traits<char>,<br>
> + // std::allocator<char>><br>
> + {FragmentKind::Type,<br>
> +<br>
> "NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",<br>
> + "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},<br>
> + // X<A> <-> X<B><br>
> + {FragmentKind::Type, "1XI1AE", "1XI1BE"},<br>
> + // X <-> Y<br>
> + {FragmentKind::Name, "1X", "1Y"},<br>
> + },<br>
> + {<br>
> + // f(std::string)<br>
> +<br>
> {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",<br>
> + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},<br>
> + // f(std::vector<int>)<br>
> + {"_Z1fSt6vectorIiSaIiEE",<br>
> "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"},<br>
> + // f(X<A>), f(X<B>), f(Y<A>), f(Y<B>)<br>
> + {"_Z1f1XI1AE", "_Z1f1XI1BE", "_Z1f1YI1AE", "_Z1f1YI1BE"},<br>
> + // f(X<C>), f(Y<C>)<br>
> + {"_Z1f1XI1CE", "_Z1f1YI1CE"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Check namespace equivalences.<br>
> + {<br>
> + {<br>
> + // std::__1 == std::__cxx11<br>
> + {FragmentKind::Name, "St3__1", "St7__cxx11"},<br>
> + // std::__1::allocator == std::allocator<br>
> + {FragmentKind::Name, "NSt3__19allocatorE", "Sa"},<br>
> + // std::vector == std::__1::vector<br>
> + {FragmentKind::Name, "St6vector", "NSt3__16vectorE"},<br>
> + // std::__cxx11::char_traits == std::char_traits<br>
> + // (This indirectly means that std::__1::char_traits ==<br>
> std::char_traits,<br>
> + // due to the std::__cxx11 == std::__1 equivalence, which is<br>
> what we rely<br>
> + // on below.)<br>
> + {FragmentKind::Name, "NSt7__cxx1111char_traitsE",<br>
> "St11char_traits"},<br>
> + },<br>
> + {<br>
> + // f(std::foo)<br>
> + {"_Z1fNSt7__cxx113fooE",<br>
> + "_Z1fNSt3__13fooE"},<br>
> + // f(std::string)<br>
> + {"_Z1fNSt7__cxx1111char_traitsIcEE",<br>
> + "_Z1fNSt3__111char_traitsIcEE",<br>
> + "_Z1fSt11char_traitsIcE"},<br>
> + // f(std::string)<br>
> +<br>
> {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",<br>
> + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},<br>
> + // f(std::vector<int>)<br>
> + {"_Z1fSt6vectorIiSaIiEE",<br>
> "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Check namespace equivalences for namespace 'std'. We support<br>
> using 'St'<br>
> + // for this, despite it not technically being a <name>.<br>
> + {<br>
> + {<br>
> + // std::__1 == std<br>
> + {FragmentKind::Name, "St3__1", "St"},<br>
> + // std::__1 == std::__cxx11<br>
> + {FragmentKind::Name, "St3__1", "St7__cxx11"},<br>
> + // FIXME: Should a 'std' equivalence also cover the predefined<br>
> + // substitutions?<br>
> + // std::__1::allocator == std::allocator<br>
> + {FragmentKind::Name, "NSt3__19allocatorE", "Sa"},<br>
> + },<br>
> + {<br>
> + {"_Z1fSt3foo", "_Z1fNSt3__13fooE", "_Z1fNSt7__cxx113fooE"},<br>
> + {"_Z1fNSt3bar3bazE", "_Z1fNSt3__13bar3bazE"},<br>
> + // f(std::string)<br>
> +<br>
> {"_Z1fNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE",<br>
> + "_Z1fNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"},<br>
> + // f(std::vector<int>)<br>
> + {"_Z1fSt6vectorIiSaIiEE",<br>
> "_Z1fNSt3__16vectorIiNS_9allocatorIiEEEE"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Check mutually-recursive equivalences.<br>
> + {<br>
> + {<br>
> + {FragmentKind::Type, "1A", "1B"},<br>
> + {FragmentKind::Type, "1A", "1C"},<br>
> + {FragmentKind::Type, "1D", "1B"},<br>
> + {FragmentKind::Type, "1C", "1E"},<br>
> + },<br>
> + {<br>
> + {"_Z1f1A", "_Z1f1B", "_Z1f1C", "_Z1f1D", "_Z1f1E"},<br>
> + {"_Z1f1F"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Check <encoding>s.<br>
> + {<br>
> + {<br>
> + {FragmentKind::Encoding, "1fv", "1gv"},<br>
> + },<br>
> + {<br>
> + // f(void) -> g(void)<br>
> + {"_Z1fv", "_Z1gv"},<br>
> + // static local 'n' in f(void) -> static local 'n' in g(void)<br>
> + {"_ZZ1fvE1n", "_ZZ1gvE1n"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Corner case: the substitution can appear within its own<br>
> expansion.<br>
> + {<br>
> + {<br>
> + // X <-> Y<X><br>
> + {FragmentKind::Type, "1X", "1YI1XE"},<br>
> + // A<B> <-> B<br>
> + {FragmentKind::Type, "1AI1BE", "1B"},<br>
> + },<br>
> + {<br>
> + // f(X) == f(Y<X>) == f(Y<Y<X>>) == f(Y<Y<Y<X>>>)<br>
> + {"_Z1f1X", "_Z1f1YI1XE", "_Z1f1YIS_I1XEE",<br>
> "_Z1f1YIS_IS_I1XEEE"},<br>
> + // f(B) == f(A<B>) == f(A<A<B>>) == f(A<A<A<B>>>)<br>
> + {"_Z1f1B", "_Z1f1AI1BE", "_Z1f1AIS_I1BEE",<br>
> "_Z1f1AIS_IS_I1BEEE"},<br>
> + }<br>
> + },<br>
> +<br>
> + // Redundant equivalences are accepted (and have no effect).<br>
> + {<br>
> + {<br>
> + {FragmentKind::Name, "3std", "St"},<br>
> + {FragmentKind::Name, "1X", "1Y"},<br>
> + {FragmentKind::Name, "N1X1ZE", "N1Y1ZE"},<br>
> + },<br>
> + {}<br>
> + },<br>
> +<br>
> + // ForwardTemplateReference does not support canonicalization.<br>
> + // FIXME: We should consider ways of fixing this, perhaps by<br>
> eliminating<br>
> + // the ForwardTemplateReference node with a tree transformation.<br>
> + {<br>
> + {<br>
> + // X::operator T() <with T = A> == Y::operator T() <with T = A><br>
> + {FragmentKind::Encoding, "N1XcvT_I1AEEv", "N1YcvT_I1AEEv"},<br>
> + // A == B<br>
> + {FragmentKind::Name, "1A", "1B"},<br>
> + },<br>
> + {<br>
> + // All combinations result in unique equivalence classes.<br>
> + {"_ZN1XcvT_I1AEEv"},<br>
> + {"_ZN1XcvT_I1BEEv"},<br>
> + {"_ZN1YcvT_I1AEEv"},<br>
> + {"_ZN1YcvT_I1BEEv"},<br>
> + // Even giving the same string twice gives a new class.<br>
> + {"_ZN1XcvT_I1AEEv"},<br>
> + }<br>
> + },<br>
> +};<br>
> +<br>
> +TEST(ItaniumManglingCanonicalizerTest, TestTestcases) {<br>
> + for (const auto &Testcase : Testcases) {<br>
> + llvm::ItaniumManglingCanonicalizer Canonicalizer;<br>
> + for (const auto &Equiv : Testcase.Equivalences) {<br>
> + auto Result =<br>
> + Canonicalizer.addEquivalence(Equiv.Kind, Equiv.First,<br>
> Equiv.Second);<br>
> + EXPECT_EQ(Result, EquivalenceError::Success)<br>
> + << "couldn't add equivalence between " << Equiv.First << "<br>
> and "<br>
> + << Equiv.Second;<br>
> + }<br>
> +<br>
> + using CanonKey = llvm::ItaniumManglingCanonicalizer::Key;<br>
> + std::map<CanonKey, llvm::StringRef> Found;<br>
> + for (const auto &Class : Testcase.Classes) {<br>
> + CanonKey ClassKey = {};<br>
> + for (llvm::StringRef Str : Class) {<br>
> + CanonKey ThisKey = Canonicalizer.canonicalize(Str);<br>
> + EXPECT_NE(ThisKey, CanonKey()) << "couldn't canonicalize " <<<br>
> Str;<br>
> + if (ClassKey) {<br>
> + EXPECT_EQ(ThisKey, ClassKey)<br>
> + << Str << " not in the same class as " <<<br>
> *Class.begin();<br>
> + } else {<br>
> + ClassKey = ThisKey;<br>
> + }<br>
> + }<br>
> + EXPECT_TRUE(Found.insert({ClassKey, *Class.begin()}).second)<br>
> + << *Class.begin() << " is in the same class as " <<<br>
> Found[ClassKey];<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +TEST(ItaniumManglingCanonicalizerTest, TestInvalidManglings) {<br>
> + llvm::ItaniumManglingCanonicalizer Canonicalizer;<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "",<br>
> "1X"),<br>
> + EquivalenceError::InvalidFirstMangling);<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1X",<br>
> "1ab"),<br>
> + EquivalenceError::InvalidSecondMangling);<br>
> + EXPECT_EQ(Canonicalizer.canonicalize("_Z3fooE"),<br>
> + llvm::ItaniumManglingCanonicalizer::Key());<br>
> + EXPECT_EQ(Canonicalizer.canonicalize("foo"),<br>
> + llvm::ItaniumManglingCanonicalizer::Key());<br>
> +<br>
> + // A reference to a template parameter ('T_' etc) cannot appear in a<br>
> <name>,<br>
> + // because we don't have template arguments to bind to it. (The<br>
> arguments in<br>
> + // an 'I ... E' construct in the <name> aren't registered as<br>
> + // backreferenceable arguments in this sense, because they're not<br>
> part of<br>
> + // the template argument list of an <encoding>.<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Name,<br>
> "N1XcvT_I1AEE",<br>
> + "1f"),<br>
> + EquivalenceError::InvalidFirstMangling);<br>
> +}<br>
> +<br>
> +TEST(ItaniumManglingCanonicalizerTest, TestBadEquivalenceOrder) {<br>
> + llvm::ItaniumManglingCanonicalizer Canonicalizer;<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "N1P1XE",<br>
> "N1Q1XE"),<br>
> + EquivalenceError::Success);<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1P",<br>
> "1Q"),<br>
> + EquivalenceError::ManglingAlreadyUsed);<br>
> +<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "N1C1XE",<br>
> "N1A1YE"),<br>
> + EquivalenceError::Success);<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1A",<br>
> "1B"),<br>
> + EquivalenceError::Success);<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1C",<br>
> "1D"),<br>
> + EquivalenceError::Success);<br>
> + EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "1B",<br>
> "1D"),<br>
> + EquivalenceError::ManglingAlreadyUsed);<br>
> +}<br>
> <br>
> <br>
> _______________________________________________<br>
> llvm-commits mailing list<br>
> <a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>