[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