mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 19:12:56 +02:00
933a42da48
Summary: This transforms the Itanium demangler into a generic reusable library that can be used to build, traverse, and transform Itanium mangled name trees. This is in preparation for adding a canonicalizing demangler, which cannot live in the Demangle library for layering reasons. In order to keep the diffs simpler, this patch moves more code to the new header than is strictly necessary: in particular, all of the printLeft / printRight implementations can be moved to the implementation file. (And indeed we could make them non-virtual now if we wished, and remove the vptr from Node.) All nodes are now included in the Kind enumeration, rather than omitting some of the Expr nodes, and the three different floating-point literal node types now have distinct Kind values. As a proof of concept for the visitation / matching mechanism, this patch implements a Node dumping facility on top of it, replacing the prior mechanism that produced the pretty-printed output rather than a tree dump. Sample dump output: FunctionEncoding( NameType("int"), NameWithTemplateArgs( NestedName( NameWithTemplateArgs( NameType("A"), TemplateArgs( {NameType("B")})), NameType("f")), TemplateArgs( {NameType("int")})), {}, <null>, QualConst, FunctionRefQual::FrefQualLValue) As a next step, it would make sense to move the LLVM high-level interface to the demangler (the itaniumDemangler function and ItaniumPartialDemangler class) into the Support library, and implement them in terms of the Demangle library. This would allow the libc++abi demangler implementation to be an identical copy of the llvm Demangle library, and would allow the LLVM implementation to reuse LLVM components such as llvm::BumpPtrAllocator, but we'll need to decide how to coordinate that with the MS ABI demangler, so I'm not doing that in this patch. No functionality change intended other than the behavior of dump(). Reviewers: erik.pilkington, zturner, chandlerc, dlj Subscribers: aheejin, llvm-commits Differential Revision: https://reviews.llvm.org/D50930 llvm-svn: 340203
189 lines
4.9 KiB
C++
189 lines
4.9 KiB
C++
//===--- Utility.h ----------------------------------------------*- 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 several utility classes used by the demangle library.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_DEMANGLE_UTILITY_H
|
|
#define LLVM_DEMANGLE_UTILITY_H
|
|
|
|
#include "StringView.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <iterator>
|
|
#include <limits>
|
|
|
|
// Stream that AST nodes write their string representation into after the AST
|
|
// has been parsed.
|
|
class OutputStream {
|
|
char *Buffer;
|
|
size_t CurrentPosition;
|
|
size_t BufferCapacity;
|
|
|
|
// Ensure there is at least n more positions in buffer.
|
|
void grow(size_t N) {
|
|
if (N + CurrentPosition >= BufferCapacity) {
|
|
BufferCapacity *= 2;
|
|
if (BufferCapacity < N + CurrentPosition)
|
|
BufferCapacity = N + CurrentPosition;
|
|
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
|
|
if (Buffer == nullptr)
|
|
std::terminate();
|
|
}
|
|
}
|
|
|
|
void writeUnsigned(uint64_t N, bool isNeg = false) {
|
|
// Handle special case...
|
|
if (N == 0) {
|
|
*this << '0';
|
|
return;
|
|
}
|
|
|
|
char Temp[21];
|
|
char *TempPtr = std::end(Temp);
|
|
|
|
while (N) {
|
|
*--TempPtr = '0' + char(N % 10);
|
|
N /= 10;
|
|
}
|
|
|
|
// Add negative sign...
|
|
if (isNeg)
|
|
*--TempPtr = '-';
|
|
this->operator<<(StringView(TempPtr, std::end(Temp)));
|
|
}
|
|
|
|
public:
|
|
OutputStream(char *StartBuf, size_t Size)
|
|
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
|
|
OutputStream() = default;
|
|
void reset(char *Buffer_, size_t BufferCapacity_) {
|
|
CurrentPosition = 0;
|
|
Buffer = Buffer_;
|
|
BufferCapacity = BufferCapacity_;
|
|
}
|
|
|
|
/// Create an OutputStream from a buffer and a size. If either of these are
|
|
/// null a buffer is allocated.
|
|
static OutputStream create(char *StartBuf, size_t *Size, size_t AllocSize) {
|
|
OutputStream Result;
|
|
|
|
if (!StartBuf || !Size) {
|
|
StartBuf = static_cast<char *>(std::malloc(AllocSize));
|
|
if (StartBuf == nullptr)
|
|
std::terminate();
|
|
Size = &AllocSize;
|
|
}
|
|
|
|
Result.reset(StartBuf, *Size);
|
|
return Result;
|
|
}
|
|
|
|
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
|
|
/// into the pack that we're currently printing.
|
|
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
|
|
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
|
|
|
|
OutputStream &operator+=(StringView R) {
|
|
size_t Size = R.size();
|
|
if (Size == 0)
|
|
return *this;
|
|
grow(Size);
|
|
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
|
|
CurrentPosition += Size;
|
|
return *this;
|
|
}
|
|
|
|
OutputStream &operator+=(char C) {
|
|
grow(1);
|
|
Buffer[CurrentPosition++] = C;
|
|
return *this;
|
|
}
|
|
|
|
OutputStream &operator<<(StringView R) { return (*this += R); }
|
|
|
|
OutputStream &operator<<(char C) { return (*this += C); }
|
|
|
|
OutputStream &operator<<(long long N) {
|
|
if (N < 0)
|
|
writeUnsigned(static_cast<unsigned long long>(-N), true);
|
|
else
|
|
writeUnsigned(static_cast<unsigned long long>(N));
|
|
return *this;
|
|
}
|
|
|
|
OutputStream &operator<<(unsigned long long N) {
|
|
writeUnsigned(N, false);
|
|
return *this;
|
|
}
|
|
|
|
OutputStream &operator<<(long N) {
|
|
return this->operator<<(static_cast<long long>(N));
|
|
}
|
|
|
|
OutputStream &operator<<(unsigned long N) {
|
|
return this->operator<<(static_cast<unsigned long long>(N));
|
|
}
|
|
|
|
OutputStream &operator<<(int N) {
|
|
return this->operator<<(static_cast<long long>(N));
|
|
}
|
|
|
|
OutputStream &operator<<(unsigned int N) {
|
|
return this->operator<<(static_cast<unsigned long long>(N));
|
|
}
|
|
|
|
size_t getCurrentPosition() const { return CurrentPosition; }
|
|
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
|
|
|
char back() const {
|
|
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
|
|
}
|
|
|
|
bool empty() const { return CurrentPosition == 0; }
|
|
|
|
char *getBuffer() { return Buffer; }
|
|
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
|
|
size_t getBufferCapacity() { return BufferCapacity; }
|
|
};
|
|
|
|
template <class T> class SwapAndRestore {
|
|
T &Restore;
|
|
T OriginalValue;
|
|
bool ShouldRestore = true;
|
|
|
|
public:
|
|
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
|
|
|
|
SwapAndRestore(T &Restore_, T NewVal)
|
|
: Restore(Restore_), OriginalValue(Restore) {
|
|
Restore = std::move(NewVal);
|
|
}
|
|
~SwapAndRestore() {
|
|
if (ShouldRestore)
|
|
Restore = std::move(OriginalValue);
|
|
}
|
|
|
|
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
|
|
|
|
void restoreNow(bool Force) {
|
|
if (!Force && !ShouldRestore)
|
|
return;
|
|
|
|
Restore = std::move(OriginalValue);
|
|
ShouldRestore = false;
|
|
}
|
|
|
|
SwapAndRestore(const SwapAndRestore &) = delete;
|
|
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
|
|
};
|
|
|
|
#endif
|