Skip to content

Commit 8a39214

Browse files
authored
[Support] Apply constexpr to getTypeName (#127893)
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.
1 parent bd034ab commit 8a39214

File tree

1 file changed

+52
-38
lines changed

1 file changed

+52
-38
lines changed

llvm/include/llvm/Support/TypeName.h

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,61 +9,75 @@
99
#ifndef LLVM_SUPPORT_TYPENAME_H
1010
#define LLVM_SUPPORT_TYPENAME_H
1111

12+
#include <string_view>
13+
1214
#include "llvm/ADT/StringRef.h"
1315

1416
namespace llvm {
1517

16-
namespace detail {
17-
template <typename DesiredTypeName> inline StringRef getTypeNameImpl() {
18+
/// We provide a function which tries to compute the (demangled) name of a type
19+
/// statically.
20+
///
21+
/// This routine may fail on some platforms or for particularly unusual types.
22+
/// Do not use it for anything other than logging and debugging aids. It isn't
23+
/// portable or dependendable in any real sense.
24+
///
25+
/// The returned StringRef will point into a static storage duration string.
26+
/// However, it may not be null terminated and may be some strangely aligned
27+
/// inner substring of a larger string.
28+
template <typename DesiredTypeName> inline constexpr StringRef getTypeName() {
1829
#if defined(__clang__) || defined(__GNUC__)
19-
StringRef Name = __PRETTY_FUNCTION__;
30+
constexpr std::string_view Name = __PRETTY_FUNCTION__;
2031

21-
StringRef Key = "DesiredTypeName = ";
22-
Name = Name.substr(Name.find(Key));
23-
assert(!Name.empty() && "Unable to find the template parameter!");
24-
Name = Name.drop_front(Key.size());
32+
constexpr std::string_view Key = "DesiredTypeName = ";
33+
constexpr std::string_view TemplateParamsStart = Name.substr(Name.find(Key));
34+
static_assert(!TemplateParamsStart.empty(),
35+
"Unable to find the template parameter!");
36+
constexpr std::string_view SubstitutionKey =
37+
TemplateParamsStart.substr(Key.size());
2538

26-
assert(Name.ends_with("]") && "Name doesn't end in the substitution key!");
27-
return Name.drop_back(1);
39+
// ends_with() is only available in c++20
40+
static_assert(!SubstitutionKey.empty() && SubstitutionKey.back() == ']',
41+
"Name doesn't end in the substitution key!");
42+
return SubstitutionKey.substr(0, SubstitutionKey.size() - 1);
2843
#elif defined(_MSC_VER)
29-
StringRef Name = __FUNCSIG__;
44+
constexpr std::string_view Name = __FUNCSIG__;
3045

31-
StringRef Key = "getTypeNameImpl<";
32-
Name = Name.substr(Name.find(Key));
33-
assert(!Name.empty() && "Unable to find the function name!");
34-
Name = Name.drop_front(Key.size());
46+
constexpr std::string_view Key = "getTypeName<";
47+
constexpr std::string_view GetTypeNameStart = Name.substr(Name.find(Key));
48+
static_assert(!GetTypeNameStart.empty(),
49+
"Unable to find the template parameter!");
50+
constexpr std::string_view SubstitutionKey =
51+
GetTypeNameStart.substr(Key.size());
3552

36-
for (StringRef Prefix : {"class ", "struct ", "union ", "enum "})
37-
if (Name.starts_with(Prefix)) {
38-
Name = Name.drop_front(Prefix.size());
39-
break;
40-
}
53+
// starts_with() only available in c++20
54+
constexpr std::string_view RmPrefixClass =
55+
SubstitutionKey.find("class ") == 0
56+
? SubstitutionKey.substr(sizeof("class ") - 1)
57+
: SubstitutionKey;
58+
constexpr std::string_view RmPrefixStruct =
59+
RmPrefixClass.find("struct ") == 0
60+
? RmPrefixClass.substr(sizeof("struct ") - 1)
61+
: RmPrefixClass;
62+
constexpr std::string_view RmPrefixUnion =
63+
RmPrefixStruct.find("union ") == 0
64+
? RmPrefixStruct.substr(sizeof("union ") - 1)
65+
: RmPrefixStruct;
66+
constexpr std::string_view RmPrefixEnum =
67+
RmPrefixUnion.find("enum ") == 0
68+
? RmPrefixUnion.substr(sizeof("enum ") - 1)
69+
: RmPrefixUnion;
4170

42-
auto AnglePos = Name.rfind('>');
43-
assert(AnglePos != StringRef::npos && "Unable to find the closing '>'!");
44-
return Name.substr(0, AnglePos);
71+
constexpr auto AnglePos = RmPrefixEnum.rfind('>');
72+
static_assert(AnglePos != std::string_view::npos,
73+
"Unable to find the closing '>'!");
74+
return RmPrefixEnum.substr(0, AnglePos);
4575
#else
4676
// No known technique for statically extracting a type name on this compiler.
4777
// We return a string that is unlikely to look like any type in LLVM.
4878
return "UNKNOWN_TYPE";
4979
#endif
5080
}
51-
} // namespace detail
52-
53-
/// We provide a function which tries to compute the (demangled) name of a type
54-
/// statically.
55-
///
56-
/// This routine may fail on some platforms or for particularly unusual types.
57-
/// Do not use it for anything other than logging and debugging aids. It isn't
58-
/// portable or dependendable in any real sense.
59-
///
60-
/// The returned StringRef will point into a static storage duration string.
61-
/// However, it may not be null terminated and may be some strangely aligned
62-
/// inner substring of a larger string.
63-
template <typename DesiredTypeName> inline StringRef getTypeName() {
64-
static StringRef Name = detail::getTypeNameImpl<DesiredTypeName>();
65-
return Name;
66-
}
6781

6882
} // namespace llvm
6983

0 commit comments

Comments
 (0)