GCC Code Coverage Report


Directory: ../
File: src/irgenerator/NameMangling.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 151 162 93.2%
Functions: 13 13 100.0%
Branches: 152 251 60.6%

Line Branch Exec Source
1 // Copyright (c) 2021-2024 ChilliBits. All rights reserved.
2
3 #include "NameMangling.h"
4
5 #include <exception/CompilerError.h>
6 #include <model/Function.h>
7 #include <model/Interface.h>
8 #include <model/Struct.h>
9 #include <symboltablebuilder/SymbolTableEntry.h>
10 #include <util/CommonUtil.h>
11
12 namespace spice::compiler {
13
14 /**
15 * Mangle a function or procedure.
16 * This should be mostly compatible with the C++ Itanium ABI name mangling scheme.
17 *
18 * @param spiceFunc Input function
19 * @return Mangled name
20 */
21 16174 std::string NameMangling::mangleFunction(const Function &spiceFunc) {
22 // Check if we have a predefined mangled name, specified by e.g. a function attribute
23
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16174 times.
16174 if (!spiceFunc.predefinedMangledName.empty())
24 return spiceFunc.predefinedMangledName;
25
26 // Check if mangling is required
27
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16174 times.
16174 if (!spiceFunc.mangleFunctionName)
28 return spiceFunc.name;
29
30
1/2
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
16174 std::stringstream mangledName;
31
1/2
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
16174 mangledName << "_Z";
32
33 // This type
34
2/2
✓ Branch 0 taken 11664 times.
✓ Branch 1 taken 4510 times.
16174 if (spiceFunc.isMethod()) {
35
1/2
✓ Branch 1 taken 11664 times.
✗ Branch 2 not taken.
11664 mangledName << "N";
36
1/2
✓ Branch 1 taken 11664 times.
✗ Branch 2 not taken.
11664 mangleType(mangledName, spiceFunc.thisType);
37 }
38
39 // Function name
40
1/2
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
16174 const std::string name = spiceFunc.name + spiceFunc.mangleSuffix;
41
2/4
✓ Branch 2 taken 16174 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 16174 times.
✗ Branch 6 not taken.
16174 mangledName << name.length() << name;
42
43 // Template types
44
1/2
✓ Branch 2 taken 16174 times.
✗ Branch 3 not taken.
16174 bool isSelfGeneric = !spiceFunc.templateTypes.empty();
45
2/2
✓ Branch 0 taken 11664 times.
✓ Branch 1 taken 4510 times.
16174 if (spiceFunc.isMethod())
46
1/2
✓ Branch 2 taken 11664 times.
✗ Branch 3 not taken.
11664 isSelfGeneric = spiceFunc.templateTypes.size() > spiceFunc.thisType.getTemplateTypes().size();
47
2/2
✓ Branch 0 taken 829 times.
✓ Branch 1 taken 15345 times.
16174 if (isSelfGeneric) {
48
1/2
✓ Branch 1 taken 829 times.
✗ Branch 2 not taken.
829 mangledName << "I";
49 // Template types themselves
50
2/2
✓ Branch 5 taken 916 times.
✓ Branch 6 taken 829 times.
1745 for (const GenericType &genericTemplateType : spiceFunc.templateTypes) {
51
3/6
✓ Branch 1 taken 916 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 916 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 916 times.
916 assert(spiceFunc.typeMapping.contains(genericTemplateType.getSubType()));
52
2/4
✓ Branch 1 taken 916 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 916 times.
✗ Branch 5 not taken.
916 const QualType &actualType = spiceFunc.typeMapping.at(genericTemplateType.getSubType());
53
1/2
✓ Branch 1 taken 916 times.
✗ Branch 2 not taken.
916 mangleType(mangledName, actualType);
54 }
55
1/2
✓ Branch 1 taken 829 times.
✗ Branch 2 not taken.
829 mangledName << "E";
56
57 // Insert second end marker to end the nested type
58
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 721 times.
829 if (spiceFunc.isMethod())
59
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
108 mangledName << "E";
60
61 // Return type
62
2/2
✓ Branch 0 taken 599 times.
✓ Branch 1 taken 230 times.
829 if (spiceFunc.isFunction())
63
1/2
✓ Branch 1 taken 599 times.
✗ Branch 2 not taken.
599 mangleType(mangledName, spiceFunc.returnType);
64 else
65
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 mangledName << "v";
66
67
2/2
✓ Branch 0 taken 11556 times.
✓ Branch 1 taken 3789 times.
15345 } else if (spiceFunc.isMethod()) {
68
1/2
✓ Branch 1 taken 11556 times.
✗ Branch 2 not taken.
11556 mangledName << "E";
69 }
70
71 // Parameter types
72
2/2
✓ Branch 5 taken 14917 times.
✓ Branch 6 taken 16174 times.
31091 for (const auto &[qualType, isOptional] : spiceFunc.paramList) {
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14917 times.
14917 assert(!isOptional);
74
1/2
✓ Branch 1 taken 14917 times.
✗ Branch 2 not taken.
14917 mangleType(mangledName, qualType);
75 }
76
2/2
✓ Branch 1 taken 5773 times.
✓ Branch 2 taken 10401 times.
16174 if (spiceFunc.paramList.empty())
77
1/2
✓ Branch 1 taken 5773 times.
✗ Branch 2 not taken.
5773 mangledName << "v";
78
79 #ifndef NDEBUG
80 16174 const TypeMapping &typeMapping = spiceFunc.typeMapping;
81
2/4
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16174 times.
✗ Branch 5 not taken.
16174 const bool returnTypeIsFctOrProc = spiceFunc.returnType.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE});
82
2/4
✓ Branch 1 taken 14879 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14879 times.
✗ Branch 5 not taken.
14879 const auto paramPredicate = [](const Param &p) { return p.qualType.getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE}); };
83
1/2
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
16174 const bool paramTypeIsFctOrProc = std::ranges::any_of(spiceFunc.paramList, paramPredicate);
84 5029 const auto templateTypePredicate = [&](const GenericType &t) {
85
4/8
✓ Branch 1 taken 5029 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5029 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5029 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5029 times.
✗ Branch 11 not taken.
5029 return typeMapping.at(t.getSubType()).getBase().isOneOf({TY_FUNCTION, TY_PROCEDURE});
86 16174 };
87
1/2
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
16174 const bool templateTypeIsFctOrProc = std::ranges::any_of(spiceFunc.templateTypes, templateTypePredicate);
88
6/6
✓ Branch 0 taken 16172 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 16102 times.
✓ Branch 3 taken 70 times.
✓ Branch 4 taken 16084 times.
✓ Branch 5 taken 18 times.
16174 if (!returnTypeIsFctOrProc && !paramTypeIsFctOrProc && !templateTypeIsFctOrProc)
89
3/6
✓ Branch 1 taken 16084 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16084 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 16084 times.
16084 assert(CommonUtil::isValidMangledName(mangledName.str()));
90 #endif
91
92
1/2
✓ Branch 1 taken 16174 times.
✗ Branch 2 not taken.
16174 return mangledName.str();
93 16174 }
94
95 /**
96 * Mangle a struct
97 * This should be mostly compatible with the C++ Itanium ABI name mangling scheme.
98 *
99 * @param spiceStruct Input struct
100 * @return Mangled name
101 */
102 1200 std::string NameMangling::mangleStruct(const Struct &spiceStruct) { return "struct." + spiceStruct.name; }
103
104 /**
105 * Mangle an interface
106 *
107 * @param spiceInterface Input interface
108 * @return Mangled name
109 */
110 142 std::string NameMangling::mangleInterface(const Interface &spiceInterface) { return "interface." + spiceInterface.name; }
111
112 /**
113 * Mangle a fully qualified name like e.g. test::s1::calledMethod to 4test2s112calledMethod
114 * This should be mostly compatible with the C++ Itanium ABI name mangling scheme.
115 *
116 * @param out Output string stream
117 * @param name Input name
118 * @param nestedType True if the name is a nested type
119 * @return Mangled name
120 */
121 19407 void NameMangling::mangleName(std::stringstream &out, const std::string &name, bool &nestedType) {
122 19407 std::vector<std::string> fragments;
123
1/2
✓ Branch 1 taken 19407 times.
✗ Branch 2 not taken.
19407 std::istringstream ss(name);
124 19407 std::string token;
125
126
4/6
✓ Branch 1 taken 38814 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38814 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19407 times.
✓ Branch 7 taken 19407 times.
38814 while (std::getline(ss, token, ':')) {
127
1/2
✓ Branch 1 taken 19407 times.
✗ Branch 2 not taken.
19407 std::istringstream subStream(token);
128 19407 std::string subToken;
129
4/6
✓ Branch 1 taken 38814 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38814 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19407 times.
✓ Branch 7 taken 19407 times.
38814 while (std::getline(subStream, subToken, '/')) {
130
1/2
✓ Branch 1 taken 19407 times.
✗ Branch 2 not taken.
19407 fragments.push_back(subToken);
131 }
132 19407 }
133
134 // Start a nested type if needed. The caller needs to emit the end marker.
135
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19407 times.
19407 if (fragments.size() > 1) {
136 out << "N";
137 nestedType = true;
138 }
139
140 // Process each fragment and append it to the result
141
2/2
✓ Branch 4 taken 19407 times.
✓ Branch 5 taken 19407 times.
38814 for (const std::string &fragment : fragments) {
142 19407 int fragmentLength = static_cast<int>(fragment.length());
143
2/4
✓ Branch 2 taken 19407 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 19407 times.
✗ Branch 6 not taken.
19407 out << std::to_string(fragmentLength) << fragment;
144 }
145 19407 }
146
147 /**
148 * Mangle a symbol qualType
149 * This should be mostly compatible with the C++ Itanium ABI name mangling scheme.
150 *
151 * @param out Output string stream
152 * @param qualType Input symbol qualType
153 * @return Mangled name
154 */
155 37511 void NameMangling::mangleType(std::stringstream &out, QualType qualType) { // NOLINT(*-no-recursion)
156 37511 const Type *type = qualType.getType();
157
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 37511 times.
37511 assert(!qualType.hasAnyGenericParts());
158
159 // Unwrap qualType chain
160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 37511 times.
37511 assert(!type->typeChain.empty());
161
2/2
✓ Branch 1 taken 5424 times.
✓ Branch 2 taken 37511 times.
42935 for (size_t i = type->typeChain.size() - 1; i >= 1; i--)
162 5424 mangleTypeChainElement(out, type->typeChain.at(i), false);
163
164 // Specifiers
165
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 37511 times.
37511 assert(qualType.getSpecifiers().isSigned == !qualType.getSpecifiers().isUnsigned);
166 37511 const bool signedness = qualType.getSpecifiers().isSigned;
167
6/6
✓ Branch 1 taken 4309 times.
✓ Branch 2 taken 33202 times.
✓ Branch 4 taken 3198 times.
✓ Branch 5 taken 1111 times.
✓ Branch 6 taken 3198 times.
✓ Branch 7 taken 34313 times.
37511 if (qualType.getSpecifiers().isConst && type->typeChain.size() > 1)
168 3198 out << "K";
169
170 // Base chain element
171 37511 mangleTypeChainElement(out, type->typeChain.front(), signedness);
172 37511 }
173
174 /**
175 * Mangle a type chain element
176 *
177 * @param out Output string stream
178 * @param chainElement Input type chain element
179 * @param signedness Signedness of the type
180 * @return Mangled name
181 */
182 42935 void NameMangling::mangleTypeChainElement(std::stringstream &out, const TypeChainElement &chainElement, bool signedness) {
183
13/15
✓ Branch 0 taken 1330 times.
✓ Branch 1 taken 4094 times.
✓ Branch 2 taken 242 times.
✓ Branch 3 taken 4109 times.
✓ Branch 4 taken 189 times.
✓ Branch 5 taken 2839 times.
✓ Branch 6 taken 1097 times.
✓ Branch 7 taken 1520 times.
✓ Branch 8 taken 7567 times.
✓ Branch 9 taken 446 times.
✓ Branch 10 taken 19407 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10 times.
✓ Branch 13 taken 85 times.
✗ Branch 14 not taken.
42935 switch (chainElement.superType) {
184 1330 case TY_PTR: // fall-through
185 case TY_ARRAY:
186 1330 out << "P";
187 1330 break;
188 4094 case TY_REF:
189 4094 out << "R";
190 4094 break;
191 242 case TY_DOUBLE:
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 assert(signedness && "Unsigned double types are forbidden");
193 242 out << "d";
194 242 break;
195 4109 case TY_INT:
196
2/2
✓ Branch 0 taken 3772 times.
✓ Branch 1 taken 337 times.
4109 out << (signedness ? "i" : "j");
197 4109 break;
198 189 case TY_SHORT:
199
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 23 times.
189 out << (signedness ? "s" : "t");
200 189 break;
201 2839 case TY_LONG:
202
2/2
✓ Branch 0 taken 496 times.
✓ Branch 1 taken 2343 times.
2839 out << (signedness ? "l" : "m");
203 2839 break;
204 1097 case TY_BYTE:
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1097 times.
1097 out << (signedness ? "a" : "h");
206 1097 break;
207 1520 case TY_CHAR:
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1520 times.
1520 out << (signedness ? "c" : "h");
209 1520 break;
210 7567 case TY_STRING:
211 7567 out << "PKc";
212 7567 break;
213 446 case TY_BOOL:
214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 446 times.
446 assert(!signedness && "Signed bool types are forbidden");
215 446 out << "b";
216 446 break;
217 19407 case TY_STRUCT: // fall-through
218 case TY_INTERFACE: {
219 19407 bool nestedType = false;
220
1/2
✓ Branch 1 taken 19407 times.
✗ Branch 2 not taken.
19407 mangleName(out, chainElement.subType, nestedType);
221
2/2
✓ Branch 1 taken 6710 times.
✓ Branch 2 taken 12697 times.
19407 if (!chainElement.templateTypes.empty()) {
222
1/2
✓ Branch 1 taken 6710 times.
✗ Branch 2 not taken.
6710 out << "I";
223
2/2
✓ Branch 5 taken 8254 times.
✓ Branch 6 taken 6710 times.
14964 for (const QualType &templateType : chainElement.templateTypes)
224
1/2
✓ Branch 1 taken 8254 times.
✗ Branch 2 not taken.
8254 mangleType(out, templateType);
225
1/2
✓ Branch 1 taken 6710 times.
✗ Branch 2 not taken.
6710 out << "E";
226 }
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19407 times.
19407 if (nestedType)
228 out << "E";
229 19407 break;
230 }
231 case TY_ENUM: {
232 bool nestedType = false;
233 mangleName(out, chainElement.subType, nestedType);
234 if (nestedType)
235 out << "E";
236 break;
237 }
238 10 case TY_FUNCTION: {
239
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 out << (chainElement.data.hasCaptures ? "PFC" : "PF");
240
2/2
✓ Branch 5 taken 22 times.
✓ Branch 6 taken 10 times.
32 for (const QualType &paramType : chainElement.paramTypes)
241
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 mangleType(out, paramType);
242 10 out << "E";
243 10 break;
244 }
245 85 case TY_PROCEDURE: {
246
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 81 times.
85 out << (chainElement.data.hasCaptures ? "PFCv" : "PFv");
247
2/2
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 85 times.
123 for (size_t i = 1; i < chainElement.paramTypes.size(); i++)
248 38 mangleType(out, chainElement.paramTypes.at(i));
249 85 out << "E";
250 85 break;
251 }
252 default: // GCOV_EXCL_LINE
253 throw CompilerError(INTERNAL_ERROR, "Type " + chainElement.getName(false) + " cannot be mangled"); // GCOV_EXCL_LINE
254 }
255 42935 }
256
257 249 std::string NameMangling::mangleTypeInfoName(const StructBase *structBase) {
258
1/2
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
249 std::stringstream out;
259
1/2
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
249 out << "_ZTS";
260
2/4
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 249 times.
✗ Branch 5 not taken.
249 mangleType(out, structBase->entry->getQualType());
261
1/2
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
498 return out.str();
262 249 }
263
264
2/4
✓ Branch 2 taken 249 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 249 times.
✗ Branch 6 not taken.
249 std::string NameMangling::mangleTypeInfoValue(const std::string &value) { return std::to_string(value.size()) + value; }
265
266 354 std::string NameMangling::mangleTypeInfo(const StructBase *structBase) {
267
1/2
✓ Branch 1 taken 354 times.
✗ Branch 2 not taken.
354 std::stringstream out;
268
1/2
✓ Branch 1 taken 354 times.
✗ Branch 2 not taken.
354 out << "_ZTI";
269
2/4
✓ Branch 1 taken 354 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 354 times.
✗ Branch 5 not taken.
354 mangleType(out, structBase->entry->getQualType());
270
1/2
✓ Branch 1 taken 354 times.
✗ Branch 2 not taken.
708 return out.str();
271 354 }
272
273 498 std::string NameMangling::mangleVTable(const StructBase *structBase) {
274
1/2
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
498 std::stringstream out;
275
1/2
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
498 out << "_ZTV";
276
2/4
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 498 times.
✗ Branch 5 not taken.
498 mangleType(out, structBase->entry->getQualType());
277
1/2
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
996 return out.str();
278 498 }
279
280 213 std::string NameMangling::mangleVTable(const std::string &typeName) {
281
3/6
✓ Branch 2 taken 213 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 213 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 213 times.
✗ Branch 9 not taken.
213 return "_ZTV" + std::to_string(typeName.size()) + typeName;
282 }
283
284 } // namespace spice::compiler
285