[libcxx-commits] [libcxxabi] 569ec18 - [llvm-cxxfilt] Added the option --no-params (#75348)
Dmitry Vasilyev via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 4 08:43:28 PST 2024
Author: Dmitry Vasilyev
Date: 2024-01-04T20:42:51+04:00
New Revision: 569ec185f5dc4a9e4a239948191977ecc2b2b475
URL: https://github.com/llvm/llvm-project/commit/569ec185f5dc4a9e4a239948191977ecc2b2b475
DIFF: https://github.com/llvm/llvm-project/commit/569ec185f5dc4a9e4a239948191977ecc2b2b475.diff
LOG: [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.
Added:
llvm/test/tools/llvm-cxxfilt/no-params.test
Modified:
libcxxabi/src/demangle/ItaniumDemangle.h
llvm/docs/CommandGuide/llvm-cxxfilt.rst
llvm/include/llvm/Demangle/Demangle.h
llvm/include/llvm/Demangle/ItaniumDemangle.h
llvm/lib/Demangle/Demangle.cpp
llvm/lib/Demangle/ItaniumDemangle.cpp
llvm/tools/llvm-cxxfilt/Opts.td
llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
Removed:
################################################################################
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 90f25519fad1c8..5a53a18bcc5fe2 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -2794,7 +2794,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseClassEnumType();
Node *parseQualifiedType();
- Node *parseEncoding();
+ Node *parseEncoding(bool ParseParams = true);
bool parseCallOffset();
Node *parseSpecialName();
@@ -2911,7 +2911,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseDestructorName();
/// Top-level entry point into the parser.
- Node *parse();
+ Node *parse(bool ParseParams = true);
};
const char* parse_discriminator(const char* first, const char* last);
@@ -5405,7 +5405,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
// ::= <data name>
// ::= <special-name>
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
+Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) {
// The template parameters of an encoding are unrelated to those of the
// enclosing context.
SaveTemplateParams SaveTemplateParamsScope(this);
@@ -5431,6 +5431,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
if (IsEndOfEncoding())
return Name;
+ // ParseParams may be false at the top level only, when called from parse().
+ // For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be
+ // false when demangling 3fooILZ3BarEET_f but is always true when demangling
+ // 3Bar.
+ if (!ParseParams) {
+ while (consume())
+ ;
+ return Name;
+ }
+
Node *Attrs = nullptr;
if (consumeIf("Ua9enable_ifI")) {
size_t BeforeArgs = Names.size();
@@ -5895,9 +5905,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parse() {
+Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
if (consumeIf("_Z") || consumeIf("__Z")) {
- Node *Encoding = getDerived().parseEncoding();
+ Node *Encoding = getDerived().parseEncoding(ParseParams);
if (Encoding == nullptr)
return nullptr;
if (look() == '.') {
@@ -5911,7 +5921,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
}
if (consumeIf("___Z") || consumeIf("____Z")) {
- Node *Encoding = getDerived().parseEncoding();
+ Node *Encoding = getDerived().parseEncoding(ParseParams);
if (Encoding == nullptr || !consumeIf("_block_invoke"))
return nullptr;
bool RequireNumber = consumeIf('_');
diff --git a/llvm/docs/CommandGuide/llvm-cxxfilt.rst b/llvm/docs/CommandGuide/llvm-cxxfilt.rst
index 3f7deb1719511b..0933f0b5bed878 100644
--- a/llvm/docs/CommandGuide/llvm-cxxfilt.rst
+++ b/llvm/docs/CommandGuide/llvm-cxxfilt.rst
@@ -48,6 +48,10 @@ OPTIONS
Print a summary of command line options.
+.. option:: --no-params, -p
+
+ Do not demangle function parameters or return types.
+
.. option:: --no-strip-underscore, -n
Do not strip a leading underscore. This is the default for all platforms
diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index 70cfc1418f0c7b..fe129603c0785d 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -32,7 +32,7 @@ enum : int {
/// Returns a non-NULL pointer to a NUL-terminated C style string
/// that should be explicitly freed, if successful. Otherwise, may return
/// nullptr if mangled_name is not a valid mangling or is nullptr.
-char *itaniumDemangle(std::string_view mangled_name);
+char *itaniumDemangle(std::string_view mangled_name, bool ParseParams = true);
enum MSDemangleFlags {
MSDF_None = 0,
@@ -68,7 +68,8 @@ char *dlangDemangle(std::string_view MangledName);
std::string demangle(std::string_view MangledName);
bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result,
- bool CanHaveLeadingDot = true);
+ bool CanHaveLeadingDot = true,
+ bool ParseParams = true);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index e0ff035d47cfb4..06956f47c1f0b5 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -2793,7 +2793,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseClassEnumType();
Node *parseQualifiedType();
- Node *parseEncoding();
+ Node *parseEncoding(bool ParseParams = true);
bool parseCallOffset();
Node *parseSpecialName();
@@ -2910,7 +2910,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseDestructorName();
/// Top-level entry point into the parser.
- Node *parse();
+ Node *parse(bool ParseParams = true);
};
const char* parse_discriminator(const char* first, const char* last);
@@ -5404,7 +5404,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
// ::= <data name>
// ::= <special-name>
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
+Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) {
// The template parameters of an encoding are unrelated to those of the
// enclosing context.
SaveTemplateParams SaveTemplateParamsScope(this);
@@ -5430,6 +5430,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
if (IsEndOfEncoding())
return Name;
+ // ParseParams may be false at the top level only, when called from parse().
+ // For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be
+ // false when demangling 3fooILZ3BarEET_f but is always true when demangling
+ // 3Bar.
+ if (!ParseParams) {
+ while (consume())
+ ;
+ return Name;
+ }
+
Node *Attrs = nullptr;
if (consumeIf("Ua9enable_ifI")) {
size_t BeforeArgs = Names.size();
@@ -5894,9 +5904,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parse() {
+Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
if (consumeIf("_Z") || consumeIf("__Z")) {
- Node *Encoding = getDerived().parseEncoding();
+ Node *Encoding = getDerived().parseEncoding(ParseParams);
if (Encoding == nullptr)
return nullptr;
if (look() == '.') {
@@ -5910,7 +5920,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
}
if (consumeIf("___Z") || consumeIf("____Z")) {
- Node *Encoding = getDerived().parseEncoding();
+ Node *Encoding = getDerived().parseEncoding(ParseParams);
if (Encoding == nullptr || !consumeIf("_block_invoke"))
return nullptr;
bool RequireNumber = consumeIf('_');
diff --git a/llvm/lib/Demangle/Demangle.cpp b/llvm/lib/Demangle/Demangle.cpp
index 83f3cdc88c01ef..117b849d1c7848 100644
--- a/llvm/lib/Demangle/Demangle.cpp
+++ b/llvm/lib/Demangle/Demangle.cpp
@@ -47,7 +47,8 @@ static bool isRustEncoding(std::string_view S) { return starts_with(S, "_R"); }
static bool isDLangEncoding(std::string_view S) { return starts_with(S, "_D"); }
bool llvm::nonMicrosoftDemangle(std::string_view MangledName,
- std::string &Result, bool CanHaveLeadingDot) {
+ std::string &Result, bool CanHaveLeadingDot,
+ bool ParseParams) {
char *Demangled = nullptr;
// Do not consider the dot prefix as part of the demangled symbol name.
@@ -57,7 +58,7 @@ bool llvm::nonMicrosoftDemangle(std::string_view MangledName,
}
if (isItaniumEncoding(MangledName))
- Demangled = itaniumDemangle(MangledName);
+ Demangled = itaniumDemangle(MangledName, ParseParams);
else if (isRustEncoding(MangledName))
Demangled = rustDemangle(MangledName);
else if (isDLangEncoding(MangledName))
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp
index e3f208f0adf8dc..5c21b06a1d0955 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -366,13 +366,13 @@ class DefaultAllocator {
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
-char *llvm::itaniumDemangle(std::string_view MangledName) {
+char *llvm::itaniumDemangle(std::string_view MangledName, bool ParseParams) {
if (MangledName.empty())
return nullptr;
Demangler Parser(MangledName.data(),
MangledName.data() + MangledName.length());
- Node *AST = Parser.parse();
+ Node *AST = Parser.parse(ParseParams);
if (!AST)
return nullptr;
diff --git a/llvm/test/tools/llvm-cxxfilt/no-params.test b/llvm/test/tools/llvm-cxxfilt/no-params.test
new file mode 100644
index 00000000000000..cf1eac27aa02d1
--- /dev/null
+++ b/llvm/test/tools/llvm-cxxfilt/no-params.test
@@ -0,0 +1,34 @@
+RUN: llvm-cxxfilt -n _Z3fooILZ3BarEET_f _Z3fooIPFcfEET_d _ZN1f2baC2ERKNS_2baIT_EE _Z3foov.123 | FileCheck %s --check-prefix=CHECK-PARAMS
+RUN: llvm-cxxfilt -p -n _Z3fooILZ3BarEET_f _Z3fooIPFcfEET_d _ZN1f2baC2ERKNS_2baIT_EE _Z3foov.123 | FileCheck %s --check-prefix=CHECK-NO-PARAMS --match-full-lines
+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
+
+# Check that -p or --no-params flag omits function parameters and the return
+# type.
+
+CHECK-PARAMS: Bar foo<Bar>(float)
+CHECK-NO-PARAMS: foo<Bar>
+
+# Check that only the top-level function is impacted by the switch, and that
+# nested function types in the encoding (e.g. where a function type is being
+# used as a template parameter) still include their parameters.
+#
+# template <typename T> T foo(double);
+# typedef char (*F)(float);
+# F foo<F>(double)
+
+CHECK-PARAMS: char (*foo<char (*)(float)>(double))(float)
+CHECK-NO-PARAMS: foo<char (*)(float)>
+
+# Use an invalid mangled name broken in the function parameters to check how -p
+# or --no-params flag works. If the option is given we should be able to
+# demangle the function name just fine. If it is not given, demangling will fail
+# because of the invalid params.
+
+CHECK-PARAMS: _ZN1f2baC2ERKNS_2baIT_EE
+CHECK-NO-PARAMS: f::ba::ba
+
+# Check that a vendor specific suffix is also omitted when --no-params is
+# specified. This matches c++filt's behaviour.
+
+CHECK-PARAMS: foo() (.123)
+CHECK-NO-PARAMS: foo
diff --git a/llvm/tools/llvm-cxxfilt/Opts.td b/llvm/tools/llvm-cxxfilt/Opts.td
index f652a1a7f88bbd..034cb267aab800 100644
--- a/llvm/tools/llvm-cxxfilt/Opts.td
+++ b/llvm/tools/llvm-cxxfilt/Opts.td
@@ -17,6 +17,7 @@ multiclass Eq<string name, string help> {
def help : FF<"help", "Display this help">;
defm strip_underscore : BB<"strip-underscore", "Strip the leading underscore", "Don't strip the leading underscore">;
def types : FF<"types", "Attempt to demangle types as well as function names">;
+def no_params : FF<"no-params", "Skip function parameters and return types">;
def version : FF<"version", "Display the version">;
defm : Eq<"format", "Specify mangling format. Currently ignored because only 'gnu' is supported">;
@@ -25,4 +26,5 @@ def : F<"s", "Alias for --format">;
def : F<"_", "Alias for --strip-underscore">, Alias<strip_underscore>;
def : F<"h", "Alias for --help">, Alias<help>;
def : F<"n", "Alias for --no-strip-underscore">, Alias<no_strip_underscore>;
+def : F<"p", "Alias for --no-params">, Alias<no_params>;
def : F<"t", "Alias for --types">, Alias<types>;
diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index 4b9d88a650666e..26a1f2f4afebd0 100644
--- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -54,6 +54,7 @@ class CxxfiltOptTable : public opt::GenericOptTable {
};
} // namespace
+static bool ParseParams;
static bool StripUnderscore;
static bool Types;
@@ -74,18 +75,19 @@ static std::string demangle(const std::string &Mangled) {
}
std::string Result;
- if (nonMicrosoftDemangle(DecoratedStr, Result, CanHaveLeadingDot))
+ if (nonMicrosoftDemangle(DecoratedStr, Result, CanHaveLeadingDot,
+ ParseParams))
return Result;
std::string Prefix;
char *Undecorated = nullptr;
if (Types)
- Undecorated = itaniumDemangle(DecoratedStr);
+ Undecorated = itaniumDemangle(DecoratedStr, ParseParams);
if (!Undecorated && starts_with(DecoratedStr, "__imp_")) {
Prefix = "import thunk for ";
- Undecorated = itaniumDemangle(DecoratedStr.substr(6));
+ Undecorated = itaniumDemangle(DecoratedStr.substr(6), ParseParams);
}
Result = Undecorated ? Prefix + Undecorated : Mangled;
@@ -173,6 +175,8 @@ int llvm_cxxfilt_main(int argc, char **argv, const llvm::ToolContext &) {
else
StripUnderscore = Triple(sys::getProcessTriple()).isOSBinFormatMachO();
+ ParseParams = !Args.hasArg(OPT_no_params);
+
Types = Args.hasArg(OPT_types);
std::vector<std::string> Decorated = Args.getAllArgValues(OPT_INPUT);
More information about the libcxx-commits
mailing list