[llvm] [Support] Apply `constexpr` to `getTypeName` (PR #127893)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 19 12:48:49 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: Jordan Rupprecht (rupprecht)
<details>
<summary>Changes</summary>
This is a followup to 003a721c1c9e3a99d6d0c1a6755443b260235537, which we noticed increased binary size a small but noticable amount. The increase seems to be due to code size from each `llvm::getTypeName<T>` wrapper, which adds up if there are a lot of types.
The original motivation was to improve runtime and avoid `getTypeName` being recomputed each time. The implementation is simple enough that we can make it fully constexpr, which addresses the size increase, but also further improves runtime: we directly reference the data instead of jumping through a guard variable to see if we've computed it already.
---
Full diff: https://github.com/llvm/llvm-project/pull/127893.diff
1 Files Affected:
- (modified) llvm/include/llvm/Support/TypeName.h (+52-38)
``````````diff
diff --git a/llvm/include/llvm/Support/TypeName.h b/llvm/include/llvm/Support/TypeName.h
index baa7a691302e3..c50d67dc38635 100644
--- a/llvm/include/llvm/Support/TypeName.h
+++ b/llvm/include/llvm/Support/TypeName.h
@@ -9,61 +9,75 @@
#ifndef LLVM_SUPPORT_TYPENAME_H
#define LLVM_SUPPORT_TYPENAME_H
+#include <string_view>
+
#include "llvm/ADT/StringRef.h"
namespace llvm {
-namespace detail {
-template <typename DesiredTypeName> inline StringRef getTypeNameImpl() {
+/// We provide a function which tries to compute the (demangled) name of a type
+/// statically.
+///
+/// This routine may fail on some platforms or for particularly unusual types.
+/// Do not use it for anything other than logging and debugging aids. It isn't
+/// portable or dependendable in any real sense.
+///
+/// The returned StringRef will point into a static storage duration string.
+/// However, it may not be null terminated and may be some strangely aligned
+/// inner substring of a larger string.
+template <typename DesiredTypeName> inline constexpr StringRef getTypeName() {
#if defined(__clang__) || defined(__GNUC__)
- StringRef Name = __PRETTY_FUNCTION__;
+ constexpr std::string_view Name = __PRETTY_FUNCTION__;
- StringRef Key = "DesiredTypeName = ";
- Name = Name.substr(Name.find(Key));
- assert(!Name.empty() && "Unable to find the template parameter!");
- Name = Name.drop_front(Key.size());
+ constexpr std::string_view Key = "DesiredTypeName = ";
+ constexpr std::string_view TemplateParamsStart = Name.substr(Name.find(Key));
+ static_assert(!TemplateParamsStart.empty(),
+ "Unable to find the template parameter!");
+ constexpr std::string_view SubstitutionKey =
+ TemplateParamsStart.substr(Key.size());
- assert(Name.ends_with("]") && "Name doesn't end in the substitution key!");
- return Name.drop_back(1);
+ // ends_with() is only available in c++20
+ static_assert(!SubstitutionKey.empty() && SubstitutionKey.back() == ']',
+ "Name doesn't end in the substitution key!");
+ return SubstitutionKey.substr(0, SubstitutionKey.size() - 1);
#elif defined(_MSC_VER)
- StringRef Name = __FUNCSIG__;
+ constexpr std::string_view Name = __FUNCSIG__;
- StringRef Key = "getTypeNameImpl<";
- Name = Name.substr(Name.find(Key));
- assert(!Name.empty() && "Unable to find the function name!");
- Name = Name.drop_front(Key.size());
+ constexpr std::string_view Key = "getTypeName<";
+ constexpr std::string_view GetTypeNameStart = Name.substr(Name.find(Key));
+ static_assert(!GetTypeNameStart.empty(),
+ "Unable to find the template parameter!");
+ constexpr std::string_view SubstitutionKey =
+ GetTypeNameStart.substr(Key.size());
- for (StringRef Prefix : {"class ", "struct ", "union ", "enum "})
- if (Name.starts_with(Prefix)) {
- Name = Name.drop_front(Prefix.size());
- break;
- }
+ // starts_with() only available in c++20
+ constexpr std::string_view RmPrefixClass =
+ SubstitutionKey.find("class ") == 0
+ ? SubstitutionKey.substr(sizeof("class ") - 1)
+ : SubstitutionKey;
+ constexpr std::string_view RmPrefixStruct =
+ RmPrefixClass.find("struct ") == 0
+ ? RmPrefixClass.substr(sizeof("struct ") - 1)
+ : RmPrefixClass;
+ constexpr std::string_view RmPrefixUnion =
+ RmPrefixStruct.find("union ") == 0
+ ? RmPrefixStruct.substr(sizeof("union ") - 1)
+ : RmPrefixStruct;
+ constexpr std::string_view RmPrefixEnum =
+ RmPrefixUnion.find("enum ") == 0
+ ? RmPrefixUnion.substr(sizeof("enum ") - 1)
+ : RmPrefixUnion;
- auto AnglePos = Name.rfind('>');
- assert(AnglePos != StringRef::npos && "Unable to find the closing '>'!");
- return Name.substr(0, AnglePos);
+ constexpr auto AnglePos = RmPrefixEnum.rfind('>');
+ static_assert(AnglePos != std::string_view::npos,
+ "Unable to find the closing '>'!");
+ return RmPrefixEnum.substr(0, AnglePos);
#else
// No known technique for statically extracting a type name on this compiler.
// We return a string that is unlikely to look like any type in LLVM.
return "UNKNOWN_TYPE";
#endif
}
-} // namespace detail
-
-/// We provide a function which tries to compute the (demangled) name of a type
-/// statically.
-///
-/// This routine may fail on some platforms or for particularly unusual types.
-/// Do not use it for anything other than logging and debugging aids. It isn't
-/// portable or dependendable in any real sense.
-///
-/// The returned StringRef will point into a static storage duration string.
-/// However, it may not be null terminated and may be some strangely aligned
-/// inner substring of a larger string.
-template <typename DesiredTypeName> inline StringRef getTypeName() {
- static StringRef Name = detail::getTypeNameImpl<DesiredTypeName>();
- return Name;
-}
} // namespace llvm
``````````
</details>
https://github.com/llvm/llvm-project/pull/127893
More information about the llvm-commits
mailing list