Skip to content

Commit 569ec18

Browse files
committed
[llvm-cxxfilt] Added the option --no-params (#75348)
Added -p / --no-params flag to skip demangling function parameters similar to how it is supported by GNU c++filt tool. There are cases when users want to demangle a large number of symbols in bulk, for example, at startup, and do not care about function parameters and overloads at that time. Skipping the demangling of parameter types led to a measurable improvement in performance. Our users reported about 15% speed up with GNU c++filt and we expect similar results with llvm-cxxfilt with this patch.
1 parent 640ef55 commit 569ec18

File tree

9 files changed

+87
-21
lines changed

9 files changed

+87
-21
lines changed

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,7 +2794,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
27942794
Node *parseClassEnumType();
27952795
Node *parseQualifiedType();
27962796

2797-
Node *parseEncoding();
2797+
Node *parseEncoding(bool ParseParams = true);
27982798
bool parseCallOffset();
27992799
Node *parseSpecialName();
28002800

@@ -2911,7 +2911,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
29112911
Node *parseDestructorName();
29122912

29132913
/// Top-level entry point into the parser.
2914-
Node *parse();
2914+
Node *parse(bool ParseParams = true);
29152915
};
29162916

29172917
const char* parse_discriminator(const char* first, const char* last);
@@ -5405,7 +5405,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
54055405
// ::= <data name>
54065406
// ::= <special-name>
54075407
template <typename Derived, typename Alloc>
5408-
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
5408+
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) {
54095409
// The template parameters of an encoding are unrelated to those of the
54105410
// enclosing context.
54115411
SaveTemplateParams SaveTemplateParamsScope(this);
@@ -5431,6 +5431,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
54315431
if (IsEndOfEncoding())
54325432
return Name;
54335433

5434+
// ParseParams may be false at the top level only, when called from parse().
5435+
// For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be
5436+
// false when demangling 3fooILZ3BarEET_f but is always true when demangling
5437+
// 3Bar.
5438+
if (!ParseParams) {
5439+
while (consume())
5440+
;
5441+
return Name;
5442+
}
5443+
54345444
Node *Attrs = nullptr;
54355445
if (consumeIf("Ua9enable_ifI")) {
54365446
size_t BeforeArgs = Names.size();
@@ -5895,9 +5905,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
58955905
// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
58965906
// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
58975907
template <typename Derived, typename Alloc>
5898-
Node *AbstractManglingParser<Derived, Alloc>::parse() {
5908+
Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
58995909
if (consumeIf("_Z") || consumeIf("__Z")) {
5900-
Node *Encoding = getDerived().parseEncoding();
5910+
Node *Encoding = getDerived().parseEncoding(ParseParams);
59015911
if (Encoding == nullptr)
59025912
return nullptr;
59035913
if (look() == '.') {
@@ -5911,7 +5921,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
59115921
}
59125922

59135923
if (consumeIf("___Z") || consumeIf("____Z")) {
5914-
Node *Encoding = getDerived().parseEncoding();
5924+
Node *Encoding = getDerived().parseEncoding(ParseParams);
59155925
if (Encoding == nullptr || !consumeIf("_block_invoke"))
59165926
return nullptr;
59175927
bool RequireNumber = consumeIf('_');

llvm/docs/CommandGuide/llvm-cxxfilt.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ OPTIONS
4848

4949
Print a summary of command line options.
5050

51+
.. option:: --no-params, -p
52+
53+
Do not demangle function parameters or return types.
54+
5155
.. option:: --no-strip-underscore, -n
5256

5357
Do not strip a leading underscore. This is the default for all platforms

llvm/include/llvm/Demangle/Demangle.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ enum : int {
3232
/// Returns a non-NULL pointer to a NUL-terminated C style string
3333
/// that should be explicitly freed, if successful. Otherwise, may return
3434
/// nullptr if mangled_name is not a valid mangling or is nullptr.
35-
char *itaniumDemangle(std::string_view mangled_name);
35+
char *itaniumDemangle(std::string_view mangled_name, bool ParseParams = true);
3636

3737
enum MSDemangleFlags {
3838
MSDF_None = 0,
@@ -68,7 +68,8 @@ char *dlangDemangle(std::string_view MangledName);
6868
std::string demangle(std::string_view MangledName);
6969

7070
bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result,
71-
bool CanHaveLeadingDot = true);
71+
bool CanHaveLeadingDot = true,
72+
bool ParseParams = true);
7273

7374
/// "Partial" demangler. This supports demangling a string into an AST
7475
/// (typically an intermediate stage in itaniumDemangle) and querying certain

llvm/include/llvm/Demangle/ItaniumDemangle.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,7 +2793,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
27932793
Node *parseClassEnumType();
27942794
Node *parseQualifiedType();
27952795

2796-
Node *parseEncoding();
2796+
Node *parseEncoding(bool ParseParams = true);
27972797
bool parseCallOffset();
27982798
Node *parseSpecialName();
27992799

@@ -2910,7 +2910,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
29102910
Node *parseDestructorName();
29112911

29122912
/// Top-level entry point into the parser.
2913-
Node *parse();
2913+
Node *parse(bool ParseParams = true);
29142914
};
29152915

29162916
const char* parse_discriminator(const char* first, const char* last);
@@ -5404,7 +5404,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
54045404
// ::= <data name>
54055405
// ::= <special-name>
54065406
template <typename Derived, typename Alloc>
5407-
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
5407+
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) {
54085408
// The template parameters of an encoding are unrelated to those of the
54095409
// enclosing context.
54105410
SaveTemplateParams SaveTemplateParamsScope(this);
@@ -5430,6 +5430,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
54305430
if (IsEndOfEncoding())
54315431
return Name;
54325432

5433+
// ParseParams may be false at the top level only, when called from parse().
5434+
// For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be
5435+
// false when demangling 3fooILZ3BarEET_f but is always true when demangling
5436+
// 3Bar.
5437+
if (!ParseParams) {
5438+
while (consume())
5439+
;
5440+
return Name;
5441+
}
5442+
54335443
Node *Attrs = nullptr;
54345444
if (consumeIf("Ua9enable_ifI")) {
54355445
size_t BeforeArgs = Names.size();
@@ -5894,9 +5904,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
58945904
// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
58955905
// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
58965906
template <typename Derived, typename Alloc>
5897-
Node *AbstractManglingParser<Derived, Alloc>::parse() {
5907+
Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
58985908
if (consumeIf("_Z") || consumeIf("__Z")) {
5899-
Node *Encoding = getDerived().parseEncoding();
5909+
Node *Encoding = getDerived().parseEncoding(ParseParams);
59005910
if (Encoding == nullptr)
59015911
return nullptr;
59025912
if (look() == '.') {
@@ -5910,7 +5920,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
59105920
}
59115921

59125922
if (consumeIf("___Z") || consumeIf("____Z")) {
5913-
Node *Encoding = getDerived().parseEncoding();
5923+
Node *Encoding = getDerived().parseEncoding(ParseParams);
59145924
if (Encoding == nullptr || !consumeIf("_block_invoke"))
59155925
return nullptr;
59165926
bool RequireNumber = consumeIf('_');

llvm/lib/Demangle/Demangle.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ static bool isRustEncoding(std::string_view S) { return starts_with(S, "_R"); }
4747
static bool isDLangEncoding(std::string_view S) { return starts_with(S, "_D"); }
4848

4949
bool llvm::nonMicrosoftDemangle(std::string_view MangledName,
50-
std::string &Result, bool CanHaveLeadingDot) {
50+
std::string &Result, bool CanHaveLeadingDot,
51+
bool ParseParams) {
5152
char *Demangled = nullptr;
5253

5354
// Do not consider the dot prefix as part of the demangled symbol name.
@@ -57,7 +58,7 @@ bool llvm::nonMicrosoftDemangle(std::string_view MangledName,
5758
}
5859

5960
if (isItaniumEncoding(MangledName))
60-
Demangled = itaniumDemangle(MangledName);
61+
Demangled = itaniumDemangle(MangledName, ParseParams);
6162
else if (isRustEncoding(MangledName))
6263
Demangled = rustDemangle(MangledName);
6364
else if (isDLangEncoding(MangledName))

llvm/lib/Demangle/ItaniumDemangle.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,13 +366,13 @@ class DefaultAllocator {
366366

367367
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
368368

369-
char *llvm::itaniumDemangle(std::string_view MangledName) {
369+
char *llvm::itaniumDemangle(std::string_view MangledName, bool ParseParams) {
370370
if (MangledName.empty())
371371
return nullptr;
372372

373373
Demangler Parser(MangledName.data(),
374374
MangledName.data() + MangledName.length());
375-
Node *AST = Parser.parse();
375+
Node *AST = Parser.parse(ParseParams);
376376
if (!AST)
377377
return nullptr;
378378

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
RUN: llvm-cxxfilt -n _Z3fooILZ3BarEET_f _Z3fooIPFcfEET_d _ZN1f2baC2ERKNS_2baIT_EE _Z3foov.123 | FileCheck %s --check-prefix=CHECK-PARAMS
2+
RUN: llvm-cxxfilt -p -n _Z3fooILZ3BarEET_f _Z3fooIPFcfEET_d _ZN1f2baC2ERKNS_2baIT_EE _Z3foov.123 | FileCheck %s --check-prefix=CHECK-NO-PARAMS --match-full-lines
3+
RUN: llvm-cxxfilt --no-params -n _Z3fooILZ3BarEET_f _Z3fooIPFcfEET_d _ZN1f2baC2ERKNS_2baIT_EE _Z3foov.123 | FileCheck %s --check-prefix=CHECK-NO-PARAMS --match-full-lines
4+
5+
# Check that -p or --no-params flag omits function parameters and the return
6+
# type.
7+
8+
CHECK-PARAMS: Bar foo<Bar>(float)
9+
CHECK-NO-PARAMS: foo<Bar>
10+
11+
# Check that only the top-level function is impacted by the switch, and that
12+
# nested function types in the encoding (e.g. where a function type is being
13+
# used as a template parameter) still include their parameters.
14+
#
15+
# template <typename T> T foo(double);
16+
# typedef char (*F)(float);
17+
# F foo<F>(double)
18+
19+
CHECK-PARAMS: char (*foo<char (*)(float)>(double))(float)
20+
CHECK-NO-PARAMS: foo<char (*)(float)>
21+
22+
# Use an invalid mangled name broken in the function parameters to check how -p
23+
# or --no-params flag works. If the option is given we should be able to
24+
# demangle the function name just fine. If it is not given, demangling will fail
25+
# because of the invalid params.
26+
27+
CHECK-PARAMS: _ZN1f2baC2ERKNS_2baIT_EE
28+
CHECK-NO-PARAMS: f::ba::ba
29+
30+
# Check that a vendor specific suffix is also omitted when --no-params is
31+
# specified. This matches c++filt's behaviour.
32+
33+
CHECK-PARAMS: foo() (.123)
34+
CHECK-NO-PARAMS: foo

llvm/tools/llvm-cxxfilt/Opts.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ multiclass Eq<string name, string help> {
1717
def help : FF<"help", "Display this help">;
1818
defm strip_underscore : BB<"strip-underscore", "Strip the leading underscore", "Don't strip the leading underscore">;
1919
def types : FF<"types", "Attempt to demangle types as well as function names">;
20+
def no_params : FF<"no-params", "Skip function parameters and return types">;
2021
def version : FF<"version", "Display the version">;
2122

2223
defm : Eq<"format", "Specify mangling format. Currently ignored because only 'gnu' is supported">;
@@ -25,4 +26,5 @@ def : F<"s", "Alias for --format">;
2526
def : F<"_", "Alias for --strip-underscore">, Alias<strip_underscore>;
2627
def : F<"h", "Alias for --help">, Alias<help>;
2728
def : F<"n", "Alias for --no-strip-underscore">, Alias<no_strip_underscore>;
29+
def : F<"p", "Alias for --no-params">, Alias<no_params>;
2830
def : F<"t", "Alias for --types">, Alias<types>;

llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class CxxfiltOptTable : public opt::GenericOptTable {
5454
};
5555
} // namespace
5656

57+
static bool ParseParams;
5758
static bool StripUnderscore;
5859
static bool Types;
5960

@@ -74,18 +75,19 @@ static std::string demangle(const std::string &Mangled) {
7475
}
7576

7677
std::string Result;
77-
if (nonMicrosoftDemangle(DecoratedStr, Result, CanHaveLeadingDot))
78+
if (nonMicrosoftDemangle(DecoratedStr, Result, CanHaveLeadingDot,
79+
ParseParams))
7880
return Result;
7981

8082
std::string Prefix;
8183
char *Undecorated = nullptr;
8284

8385
if (Types)
84-
Undecorated = itaniumDemangle(DecoratedStr);
86+
Undecorated = itaniumDemangle(DecoratedStr, ParseParams);
8587

8688
if (!Undecorated && starts_with(DecoratedStr, "__imp_")) {
8789
Prefix = "import thunk for ";
88-
Undecorated = itaniumDemangle(DecoratedStr.substr(6));
90+
Undecorated = itaniumDemangle(DecoratedStr.substr(6), ParseParams);
8991
}
9092

9193
Result = Undecorated ? Prefix + Undecorated : Mangled;
@@ -173,6 +175,8 @@ int llvm_cxxfilt_main(int argc, char **argv, const llvm::ToolContext &) {
173175
else
174176
StripUnderscore = Triple(sys::getProcessTriple()).isOSBinFormatMachO();
175177

178+
ParseParams = !Args.hasArg(OPT_no_params);
179+
176180
Types = Args.hasArg(OPT_types);
177181

178182
std::vector<std::string> Decorated = Args.getAllArgValues(OPT_INPUT);

0 commit comments

Comments
 (0)