[Demangler] Further optimizations for the remangler.

Replace use of `snprintf()` with some custom code (this is around 10x
faster on my machine).

Move a few of the `Node` member functions to the header so they're
inlined.

Optimize the `deepEquals()` function by adding an `isSimilarTo()`
method on `Node`; the checks that were happening in the `deepEquals()`
function could be implemented more efficiently by making use of
details of the internal representation of `Node`.

rdar://125739630
This commit is contained in:
Alastair Houghton
2024-04-05 22:24:06 +01:00
parent 7d72a62ac5
commit 3bd83377a1
3 changed files with 104 additions and 57 deletions

View File

@@ -206,7 +206,8 @@ private:
Kind NodeKind;
enum class PayloadKind : uint8_t {
None, Text, Index, OneChild, TwoChildren, ManyChildren
None = 0, OneChild = 1, TwoChildren = 2,
Text, Index, ManyChildren
};
PayloadKind NodePayloadKind;
@@ -227,6 +228,22 @@ private:
public:
Kind getKind() const { return NodeKind; }
bool isSimilarTo(const Node *other) const {
if (NodeKind != other->NodeKind
|| NodePayloadKind != other->NodePayloadKind)
return false;
switch (NodePayloadKind) {
case PayloadKind::ManyChildren:
return Children.Number == other->Children.Number;
case PayloadKind::Index:
return Index == other->Index;
case PayloadKind::Text:
return Text == other->Text;
default:
return true;
}
}
bool hasText() const { return NodePayloadKind == PayloadKind::Text; }
llvm::StringRef getText() const {
assert(hasText());
@@ -241,13 +258,41 @@ public:
using iterator = const NodePointer *;
size_t getNumChildren() const;
size_t getNumChildren() const {
switch (NodePayloadKind) {
case PayloadKind::OneChild: return 1;
case PayloadKind::TwoChildren: return 2;
case PayloadKind::ManyChildren: return Children.Number;
default: return 0;
}
}
bool hasChildren() const { return getNumChildren() != 0; }
iterator begin() const;
iterator begin() const {
switch (NodePayloadKind) {
case PayloadKind::OneChild:
case PayloadKind::TwoChildren:
return &InlineChildren[0];
case PayloadKind::ManyChildren:
return Children.Nodes;
default:
return nullptr;
}
}
iterator end() const;
iterator end() const {
switch (NodePayloadKind) {
case PayloadKind::OneChild:
return &InlineChildren[1];
case PayloadKind::TwoChildren:
return &InlineChildren[2];
case PayloadKind::ManyChildren:
return Children.Nodes + Children.Number;
default:
return nullptr;
}
}
NodePointer getFirstChild() const {
return getChild(0);

View File

@@ -354,40 +354,6 @@ using namespace Demangle;
// Node member functions //
//////////////////////////////////
size_t Node::getNumChildren() const {
switch (NodePayloadKind) {
case PayloadKind::OneChild: return 1;
case PayloadKind::TwoChildren: return 2;
case PayloadKind::ManyChildren: return Children.Number;
default: return 0;
}
}
Node::iterator Node::begin() const {
switch (NodePayloadKind) {
case PayloadKind::OneChild:
case PayloadKind::TwoChildren:
return &InlineChildren[0];
case PayloadKind::ManyChildren:
return Children.Nodes;
default:
return nullptr;
}
}
Node::iterator Node::end() const {
switch (NodePayloadKind) {
case PayloadKind::OneChild:
return &InlineChildren[1];
case PayloadKind::TwoChildren:
return &InlineChildren[2];
case PayloadKind::ManyChildren:
return Children.Nodes + Children.Number;
default:
return nullptr;
}
}
void Node::addChild(NodePointer Child, NodeFactory &Factory) {
DEMANGLER_ALWAYS_ASSERT(Child, this);
switch (NodePayloadKind) {
@@ -635,6 +601,58 @@ NodePointer NodeFactory::createNode(Node::Kind K, const char *Text) {
int NodeFactory::nestingLevel = 0;
#endif
// Fast integer formatting
namespace {
// Format an unsigned integer into a buffer
template <typename U,
typename std::enable_if<std::is_unsigned<U>::value, bool>::type = true>
size_t int2str(U n, char *buf) {
// The easy case is zero
if (n == 0) {
*buf++ = '0';
*buf++ = '\0';
return 1;
}
// Do the digits one a time (for really high speed we could do these in
// chunks, but that's probably not necessary here.)
char *ptr = buf;
while (n) {
char digit = '0' + (n % 10);
n /= 10;
*ptr++ = digit;
}
size_t len = ptr - buf;
// Terminate the string
*ptr = '\0';
// Now reverse the digits
while (buf < ptr) {
char tmp = *--ptr;
*ptr = *buf;
*buf++ = tmp;
}
return len;
}
// Deal with negative numbers
template <typename S,
typename std::enable_if<std::is_signed<S>::value, bool>::type = true>
size_t int2str(S n, char *buf) {
using U = typename std::make_unsigned<S>::type;
if (n < 0) {
*buf++ = '-';
return int2str(static_cast<U>(-n), buf);
}
return int2str(static_cast<U>(n), buf);
}
} // namespace
//////////////////////////////////
// CharVector member functions //
//////////////////////////////////
@@ -651,7 +669,7 @@ void CharVector::append(int Number, NodeFactory &Factory) {
const int MaxIntPrintSize = 11;
if (NumElems + MaxIntPrintSize > Capacity)
Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxIntPrintSize);
int Length = snprintf(Elems + NumElems, MaxIntPrintSize, "%d", Number);
int Length = int2str(Number, Elems + NumElems);
assert(Length > 0 && Length < MaxIntPrintSize);
NumElems += Length;
}
@@ -660,7 +678,7 @@ void CharVector::append(unsigned long long Number, NodeFactory &Factory) {
const int MaxPrintSize = 21;
if (NumElems + MaxPrintSize > Capacity)
Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxPrintSize);
int Length = snprintf(Elems + NumElems, MaxPrintSize, "%llu", Number);
int Length = int2str(Number, Elems + NumElems);
assert(Length > 0 && Length < MaxPrintSize);
NumElems += Length;
}

View File

@@ -60,23 +60,7 @@ bool SubstitutionEntry::identifierEquals(Node *lhs, Node *rhs) {
}
bool SubstitutionEntry::deepEquals(Node *lhs, Node *rhs) const {
if (lhs->getKind() != rhs->getKind())
return false;
if (lhs->hasIndex()) {
if (!rhs->hasIndex())
return false;
if (lhs->getIndex() != rhs->getIndex())
return false;
} else if (lhs->hasText()) {
if (!rhs->hasText())
return false;
if (lhs->getText() != rhs->getText())
return false;
} else if (rhs->hasIndex() || rhs->hasText()) {
return false;
}
if (lhs->getNumChildren() != rhs->getNumChildren())
if (!lhs->isSimilarTo(rhs))
return false;
for (auto li = lhs->begin(), ri = rhs->begin(), le = lhs->end();