-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Support] Apply constexpr
to getTypeName
#127893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This is a followup to 003a721, 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.
@llvm/pr-subscribers-llvm-support Author: Jordan Rupprecht (rupprecht) ChangesThis is a followup to 003a721, which we noticed increased binary size a small but noticable amount. The increase seems to be due to code size from each The original motivation was to improve runtime and avoid Full diff: https://github.com/llvm/llvm-project/pull/127893.diff 1 Files Affected:
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
|
It seems this broke our sles buildbot. |
It looks like gcc doesn't consider |
Yes, it looks like older versions of gcc don't declare 9.1 seems to be the minimum version that's OK with this patch: https://godbolt.org/z/Y6j6hdeov. All supported clang/msvc versions seem to be OK. |
…128212) Prior to gcc version 9, the `__PRETTY_FUNCTION__` macro was not declared constexpr. In that case, don't declare this as constexpr, and switch the static asserts to runtime asserts. Verified this should work on all supported compilers: https://godbolt.org/z/T77rvPW5z Followup to #127893 / 8a39214
This is a followup to 003a721, 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.