[AMDGPU] New AMDGPUInsertSingleUseVDST pass (#72388)
[llvm-project.git] / libcxxabi / src / cxa_demangle.cpp
blobbece33a007fcd3deeb47b59915fc4a50129f3b6a
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 // FIXME: (possibly) incomplete list of features that clang mangles that this
10 // file does not yet support:
11 // - C++ modules TS
13 #include "abort_message.h"
14 #define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)
16 #include "demangle/DemangleConfig.h"
17 #include "demangle/ItaniumDemangle.h"
18 #include "__cxxabi_config.h"
19 #include <cctype>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <exception>
24 #include <functional>
25 #include <numeric>
26 #include <string_view>
27 #include <utility>
29 using namespace itanium_demangle;
31 constexpr const char *itanium_demangle::FloatData<float>::spec;
32 constexpr const char *itanium_demangle::FloatData<double>::spec;
33 constexpr const char *itanium_demangle::FloatData<long double>::spec;
35 // <discriminator> := _ <non-negative number> # when number < 10
36 // := __ <non-negative number> _ # when number >= 10
37 // extension := decimal-digit+ # at the end of string
38 const char *itanium_demangle::parse_discriminator(const char *first,
39 const char *last) {
40 // parse but ignore discriminator
41 if (first != last) {
42 if (*first == '_') {
43 const char *t1 = first + 1;
44 if (t1 != last) {
45 if (std::isdigit(*t1))
46 first = t1 + 1;
47 else if (*t1 == '_') {
48 for (++t1; t1 != last && std::isdigit(*t1); ++t1)
50 if (t1 != last && *t1 == '_')
51 first = t1 + 1;
54 } else if (std::isdigit(*first)) {
55 const char *t1 = first + 1;
56 for (; t1 != last && std::isdigit(*t1); ++t1)
58 if (t1 == last)
59 first = last;
62 return first;
65 #ifndef NDEBUG
66 namespace {
67 struct DumpVisitor {
68 unsigned Depth = 0;
69 bool PendingNewline = false;
71 template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) {
72 return true;
74 static bool wantsNewline(NodeArray A) { return !A.empty(); }
75 static constexpr bool wantsNewline(...) { return false; }
77 template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) {
78 for (bool B : {wantsNewline(Vs)...})
79 if (B)
80 return true;
81 return false;
84 void printStr(const char *S) { fprintf(stderr, "%s", S); }
85 void print(std::string_view SV) {
86 fprintf(stderr, "\"%.*s\"", (int)SV.size(), &*SV.begin());
88 void print(const Node *N) {
89 if (N)
90 N->visit(std::ref(*this));
91 else
92 printStr("<null>");
94 void print(NodeArray A) {
95 ++Depth;
96 printStr("{");
97 bool First = true;
98 for (const Node *N : A) {
99 if (First)
100 print(N);
101 else
102 printWithComma(N);
103 First = false;
105 printStr("}");
106 --Depth;
109 // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
110 void print(bool B) { printStr(B ? "true" : "false"); }
112 template <class T>
113 typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
114 fprintf(stderr, "%llu", (unsigned long long)N);
117 template <class T>
118 typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
119 fprintf(stderr, "%lld", (long long)N);
122 void print(ReferenceKind RK) {
123 switch (RK) {
124 case ReferenceKind::LValue:
125 return printStr("ReferenceKind::LValue");
126 case ReferenceKind::RValue:
127 return printStr("ReferenceKind::RValue");
130 void print(FunctionRefQual RQ) {
131 switch (RQ) {
132 case FunctionRefQual::FrefQualNone:
133 return printStr("FunctionRefQual::FrefQualNone");
134 case FunctionRefQual::FrefQualLValue:
135 return printStr("FunctionRefQual::FrefQualLValue");
136 case FunctionRefQual::FrefQualRValue:
137 return printStr("FunctionRefQual::FrefQualRValue");
140 void print(Qualifiers Qs) {
141 if (!Qs) return printStr("QualNone");
142 struct QualName { Qualifiers Q; const char *Name; } Names[] = {
143 {QualConst, "QualConst"},
144 {QualVolatile, "QualVolatile"},
145 {QualRestrict, "QualRestrict"},
147 for (QualName Name : Names) {
148 if (Qs & Name.Q) {
149 printStr(Name.Name);
150 Qs = Qualifiers(Qs & ~Name.Q);
151 if (Qs) printStr(" | ");
155 void print(SpecialSubKind SSK) {
156 switch (SSK) {
157 case SpecialSubKind::allocator:
158 return printStr("SpecialSubKind::allocator");
159 case SpecialSubKind::basic_string:
160 return printStr("SpecialSubKind::basic_string");
161 case SpecialSubKind::string:
162 return printStr("SpecialSubKind::string");
163 case SpecialSubKind::istream:
164 return printStr("SpecialSubKind::istream");
165 case SpecialSubKind::ostream:
166 return printStr("SpecialSubKind::ostream");
167 case SpecialSubKind::iostream:
168 return printStr("SpecialSubKind::iostream");
171 void print(TemplateParamKind TPK) {
172 switch (TPK) {
173 case TemplateParamKind::Type:
174 return printStr("TemplateParamKind::Type");
175 case TemplateParamKind::NonType:
176 return printStr("TemplateParamKind::NonType");
177 case TemplateParamKind::Template:
178 return printStr("TemplateParamKind::Template");
181 void print(Node::Prec P) {
182 switch (P) {
183 case Node::Prec::Primary:
184 return printStr("Node::Prec::Primary");
185 case Node::Prec::Postfix:
186 return printStr("Node::Prec::Postfix");
187 case Node::Prec::Unary:
188 return printStr("Node::Prec::Unary");
189 case Node::Prec::Cast:
190 return printStr("Node::Prec::Cast");
191 case Node::Prec::PtrMem:
192 return printStr("Node::Prec::PtrMem");
193 case Node::Prec::Multiplicative:
194 return printStr("Node::Prec::Multiplicative");
195 case Node::Prec::Additive:
196 return printStr("Node::Prec::Additive");
197 case Node::Prec::Shift:
198 return printStr("Node::Prec::Shift");
199 case Node::Prec::Spaceship:
200 return printStr("Node::Prec::Spaceship");
201 case Node::Prec::Relational:
202 return printStr("Node::Prec::Relational");
203 case Node::Prec::Equality:
204 return printStr("Node::Prec::Equality");
205 case Node::Prec::And:
206 return printStr("Node::Prec::And");
207 case Node::Prec::Xor:
208 return printStr("Node::Prec::Xor");
209 case Node::Prec::Ior:
210 return printStr("Node::Prec::Ior");
211 case Node::Prec::AndIf:
212 return printStr("Node::Prec::AndIf");
213 case Node::Prec::OrIf:
214 return printStr("Node::Prec::OrIf");
215 case Node::Prec::Conditional:
216 return printStr("Node::Prec::Conditional");
217 case Node::Prec::Assign:
218 return printStr("Node::Prec::Assign");
219 case Node::Prec::Comma:
220 return printStr("Node::Prec::Comma");
221 case Node::Prec::Default:
222 return printStr("Node::Prec::Default");
226 void newLine() {
227 printStr("\n");
228 for (unsigned I = 0; I != Depth; ++I)
229 printStr(" ");
230 PendingNewline = false;
233 template<typename T> void printWithPendingNewline(T V) {
234 print(V);
235 if (wantsNewline(V))
236 PendingNewline = true;
239 template<typename T> void printWithComma(T V) {
240 if (PendingNewline || wantsNewline(V)) {
241 printStr(",");
242 newLine();
243 } else {
244 printStr(", ");
247 printWithPendingNewline(V);
250 struct CtorArgPrinter {
251 DumpVisitor &Visitor;
253 template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) {
254 if (Visitor.anyWantNewline(V, Vs...))
255 Visitor.newLine();
256 Visitor.printWithPendingNewline(V);
257 int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 };
258 (void)PrintInOrder;
262 template<typename NodeT> void operator()(const NodeT *Node) {
263 Depth += 2;
264 fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name());
265 Node->match(CtorArgPrinter{*this});
266 fprintf(stderr, ")");
267 Depth -= 2;
270 void operator()(const ForwardTemplateReference *Node) {
271 Depth += 2;
272 fprintf(stderr, "ForwardTemplateReference(");
273 if (Node->Ref && !Node->Printing) {
274 Node->Printing = true;
275 CtorArgPrinter{*this}(Node->Ref);
276 Node->Printing = false;
277 } else {
278 CtorArgPrinter{*this}(Node->Index);
280 fprintf(stderr, ")");
281 Depth -= 2;
286 void itanium_demangle::Node::dump() const {
287 DumpVisitor V;
288 visit(std::ref(V));
289 V.newLine();
291 #endif
293 namespace {
294 class BumpPointerAllocator {
295 struct BlockMeta {
296 BlockMeta* Next;
297 size_t Current;
300 static constexpr size_t AllocSize = 4096;
301 static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
303 alignas(long double) char InitialBuffer[AllocSize];
304 BlockMeta* BlockList = nullptr;
306 void grow() {
307 char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
308 if (NewMeta == nullptr)
309 std::terminate();
310 BlockList = new (NewMeta) BlockMeta{BlockList, 0};
313 void* allocateMassive(size_t NBytes) {
314 NBytes += sizeof(BlockMeta);
315 BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
316 if (NewMeta == nullptr)
317 std::terminate();
318 BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
319 return static_cast<void*>(NewMeta + 1);
322 public:
323 BumpPointerAllocator()
324 : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}
326 void* allocate(size_t N) {
327 N = (N + 15u) & ~15u;
328 if (N + BlockList->Current >= UsableAllocSize) {
329 if (N > UsableAllocSize)
330 return allocateMassive(N);
331 grow();
333 BlockList->Current += N;
334 return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) +
335 BlockList->Current - N);
338 void reset() {
339 while (BlockList) {
340 BlockMeta* Tmp = BlockList;
341 BlockList = BlockList->Next;
342 if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
343 std::free(Tmp);
345 BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
348 ~BumpPointerAllocator() { reset(); }
351 class DefaultAllocator {
352 BumpPointerAllocator Alloc;
354 public:
355 void reset() { Alloc.reset(); }
357 template<typename T, typename ...Args> T *makeNode(Args &&...args) {
358 return new (Alloc.allocate(sizeof(T)))
359 T(std::forward<Args>(args)...);
362 void *allocateNodeArray(size_t sz) {
363 return Alloc.allocate(sizeof(Node *) * sz);
366 } // unnamed namespace
368 //===----------------------------------------------------------------------===//
369 // Code beyond this point should not be synchronized with LLVM.
370 //===----------------------------------------------------------------------===//
372 using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
374 namespace {
375 enum : int {
376 demangle_invalid_args = -3,
377 demangle_invalid_mangled_name = -2,
378 demangle_memory_alloc_failure = -1,
379 demangle_success = 0,
383 namespace __cxxabiv1 {
384 extern "C" _LIBCXXABI_FUNC_VIS char *
385 __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
386 if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
387 if (Status)
388 *Status = demangle_invalid_args;
389 return nullptr;
392 int InternalStatus = demangle_success;
393 Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
394 Node *AST = Parser.parse();
396 if (AST == nullptr)
397 InternalStatus = demangle_invalid_mangled_name;
398 else {
399 OutputBuffer O(Buf, N);
400 DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");
401 AST->print(O);
402 O += '\0';
403 if (N != nullptr)
404 *N = O.getCurrentPosition();
405 Buf = O.getBuffer();
408 if (Status)
409 *Status = InternalStatus;
410 return InternalStatus == demangle_success ? Buf : nullptr;
412 } // __cxxabiv1