1 #include "CPlusPlusMangle.h"
2
3 #include <map>
4
5 #include "ExternFuncArgument.h"
6 #include "Function.h"
7 #include "IR.h"
8 #include "IROperator.h"
9 #include "Type.h"
10
11 /** \file Support for creating C++ mangled function names from a type signature. */
12
13 /** \note For Itanium C++ ABI, there is a specification here:
14 * https://mentorembedded.github.io/cxx-abi/abi.html
15 * There is also useful info here:
16 * http://www.agner.org/optimize/calling_conventions.pdf
17 */
18
19 namespace Halide {
20
21 namespace Internal {
22
23 namespace {
24
25 // Used in both Windows and Itanium manglers to track pieces of a type name
26 // in both their final form in the output and their canonical substituted form.
27 struct MangledNamePart {
28 std::string full_name;
29 std::string with_substitutions;
30
31 MangledNamePart() = default;
MangledNamePartHalide::Internal::__anon24ed16480111::MangledNamePart32 MangledNamePart(const std::string &mangled)
33 : full_name(mangled), with_substitutions(mangled) {
34 }
MangledNamePartHalide::Internal::__anon24ed16480111::MangledNamePart35 MangledNamePart(const char *mangled)
36 : full_name(mangled), with_substitutions(mangled) {
37 }
38 };
39
non_null_void_star_type()40 Type non_null_void_star_type() {
41 static halide_handle_cplusplus_type t(halide_handle_cplusplus_type(
42 halide_cplusplus_type_name(halide_cplusplus_type_name::Simple, "void"),
43 {}, {}, {halide_handle_cplusplus_type::Pointer}));
44 return Handle(1, &t);
45 }
46
47 } // namespace
48
49 namespace WindowsMangling {
50
51 struct PreviousDeclarations {
52 std::map<std::string, int> prev_types;
53 std::map<std::string, int> prev_names;
54
check_and_enterHalide::Internal::WindowsMangling::PreviousDeclarations55 std::string check_and_enter(std::map<std::string, int> &table, const std::string &name, const std::string &full) {
56 int sub = -1;
57 if (table.size() >= 10) {
58 auto i = table.find(name);
59 if (i != table.end()) {
60 sub = i->second;
61 }
62 } else {
63 auto insert_result = table.insert({name, table.size()});
64 if (!insert_result.second) {
65 sub = insert_result.first->second;
66 }
67 }
68 if (sub != -1) {
69 return std::string(1, (char)('0' + sub));
70 } else {
71 return full;
72 }
73 }
74
check_and_enter_typeHalide::Internal::WindowsMangling::PreviousDeclarations75 std::string check_and_enter_type(const MangledNamePart &mangled) {
76 if (mangled.full_name.size() < 2) {
77 return mangled.full_name;
78 }
79 return check_and_enter(prev_types, mangled.full_name, mangled.with_substitutions);
80 }
81
check_and_enter_nameHalide::Internal::WindowsMangling::PreviousDeclarations82 std::string check_and_enter_name(const std::string &name) {
83 return check_and_enter(prev_names, name, name + "@");
84 }
85 };
86
simple_type_to_mangle_char(const std::string & type_name,const Target & target)87 std::string simple_type_to_mangle_char(const std::string &type_name, const Target &target) {
88 if (type_name == "void") {
89 return "X";
90 } else if (type_name == "bool") {
91 return "_N";
92 } else if (type_name == "char") {
93 return "D";
94 }
95 if (type_name == "int8_t") {
96 return "C";
97 } else if (type_name == "uint8_t") {
98 return "E";
99 } else if (type_name == "int16_t") {
100 return "F";
101 } else if (type_name == "uint16_t") {
102 return "G";
103 } else if (type_name == "int32_t") {
104 return "H";
105 } else if (type_name == "uint32_t") {
106 return "I";
107 } else if (type_name == "int64_t") {
108 return "_J";
109 } else if (type_name == "uint64_t") {
110 return "_K";
111 } else if (type_name == "float") {
112 return "M";
113 } else if (type_name == "double") {
114 return "N";
115 }
116 user_error << "Unknown type name: " << type_name << "\n";
117 return "";
118 }
119
one_qualifier_set(bool is_const,bool is_volatile,bool is_restrict,bool is_pointer_target,const std::string & base_mode)120 std::string one_qualifier_set(bool is_const, bool is_volatile, bool is_restrict, bool is_pointer_target, const std::string &base_mode) {
121 if (is_const && is_volatile) {
122 return (is_pointer_target ? ("S" + base_mode) : "D");
123 } else if (is_const) {
124 return (is_pointer_target ? ("Q" + base_mode) : "B");
125 } else if (is_volatile) {
126 return (is_pointer_target ? ("R" + base_mode) : "C");
127 } else if (is_restrict && is_pointer_target) {
128 return ("P" + base_mode + "I");
129 } else {
130 return (is_pointer_target ? ("P" + base_mode) : "A");
131 }
132 }
133
134 struct QualsState {
135 bool last_is_pointer{false};
136
137 const Type &type;
138 const std::string base_mode;
139 std::string result;
140
141 bool finished{false};
142
QualsStateHalide::Internal::WindowsMangling::QualsState143 QualsState(const Type &type, const std::string &base_mode)
144 : type(type), base_mode(base_mode) {
145 }
146
handle_modifierHalide::Internal::WindowsMangling::QualsState147 void handle_modifier(uint8_t modifier) {
148 bool is_pointer = (modifier & halide_handle_cplusplus_type::Pointer) != 0;
149 bool last_is_const = (modifier & halide_handle_cplusplus_type::Const) != 0;
150 bool last_is_volatile = (modifier & halide_handle_cplusplus_type::Volatile) != 0;
151 bool last_is_restrict = (modifier & halide_handle_cplusplus_type::Restrict) != 0;
152
153 if (finished ||
154 (!is_pointer && !last_is_pointer &&
155 type.handle_type->reference_type == halide_handle_cplusplus_type::NotReference)) {
156 finished = true;
157 return;
158 }
159
160 result = one_qualifier_set(last_is_const, last_is_volatile, last_is_restrict, last_is_pointer, base_mode) + result;
161 if (last_is_pointer && (is_pointer || type.handle_type->reference_type != halide_handle_cplusplus_type::NotReference)) {
162 result = one_qualifier_set(last_is_const, last_is_volatile, last_is_restrict, false, base_mode) + result;
163 }
164
165 last_is_pointer = is_pointer;
166 if (!is_pointer) {
167 finished = true;
168 }
169 }
170
finalHalide::Internal::WindowsMangling::QualsState171 void final() {
172 if (!finished) {
173 handle_modifier(0);
174 }
175 if (last_is_pointer) {
176 result = one_qualifier_set(false, false, false, last_is_pointer, base_mode) + result;
177 }
178
179 if (type.handle_type->reference_type == halide_handle_cplusplus_type::LValueReference) {
180 result = "A" + base_mode + result; // Or is it "R"?
181 } else if (type.handle_type->reference_type == halide_handle_cplusplus_type::RValueReference) {
182 result = "$$Q" + base_mode + result;
183 }
184 }
185
get_resultHalide::Internal::WindowsMangling::QualsState186 const std::string &get_result() const {
187 return result;
188 }
189 };
190
mangle_indirection_and_cvr_quals(const Type & type,const Target & target)191 std::string mangle_indirection_and_cvr_quals(const Type &type, const Target &target) {
192 QualsState state(type, (target.bits == 64) ? "E" : "");
193 for (uint8_t modifier : type.handle_type->cpp_type_modifiers) {
194 state.handle_modifier(modifier);
195 }
196 state.final();
197
198 return state.get_result();
199 }
200
mangle_inner_name(const Type & type,const Target & target,PreviousDeclarations & prev_decls)201 MangledNamePart mangle_inner_name(const Type &type, const Target &target, PreviousDeclarations &prev_decls) {
202 MangledNamePart result("");
203
204 std::string quals = mangle_indirection_and_cvr_quals(type, target);
205 if (type.handle_type->inner_name.cpp_type_type == halide_cplusplus_type_name::Simple) {
206 return quals + simple_type_to_mangle_char(type.handle_type->inner_name.name, target);
207 } else {
208 std::string code;
209 if (type.handle_type->inner_name.cpp_type_type == halide_cplusplus_type_name::Struct) {
210 code = "U";
211 } else if (type.handle_type->inner_name.cpp_type_type == halide_cplusplus_type_name::Class) {
212 code = "V";
213 } else if (type.handle_type->inner_name.cpp_type_type == halide_cplusplus_type_name::Union) {
214 code = "T";
215 } else if (type.handle_type->inner_name.cpp_type_type == halide_cplusplus_type_name::Enum) {
216 code = "W4";
217 }
218 result.full_name = quals + code + type.handle_type->inner_name.name + "@";
219 result.with_substitutions = quals + code + prev_decls.check_and_enter_name(type.handle_type->inner_name.name);
220
221 for (size_t i = type.handle_type->enclosing_types.size(); i > 0; i--) {
222 result.full_name += type.handle_type->enclosing_types[i - 1].name + "@";
223 result.with_substitutions += prev_decls.check_and_enter_name(type.handle_type->enclosing_types[i - 1].name);
224 }
225
226 for (size_t i = type.handle_type->namespaces.size(); i > 0; i--) {
227 result.full_name += type.handle_type->namespaces[i - 1] + "@";
228 result.with_substitutions += prev_decls.check_and_enter_name(type.handle_type->namespaces[i - 1]);
229 }
230
231 result.full_name += "@";
232 result.with_substitutions += "@";
233
234 return result;
235 }
236 }
237
mangle_type(const Type & type,const Target & target,PreviousDeclarations & prev_decls)238 MangledNamePart mangle_type(const Type &type, const Target &target, PreviousDeclarations &prev_decls) {
239 if (type.is_int()) {
240 switch (type.bits()) {
241 case 8:
242 return "C";
243 case 16:
244 return "F";
245 case 32:
246 return "H";
247 case 64:
248 return "_J";
249 }
250 internal_error << "Unexpected integer size: " << type.bits() << ".\n";
251 return "";
252 } else if (type.is_uint()) {
253 switch (type.bits()) {
254 case 1:
255 return "_N";
256 case 8:
257 return "E";
258 case 16:
259 return "G";
260 case 32:
261 return "I";
262 case 64:
263 return "_K";
264 }
265 internal_error << "Unexpected unsigned integer size: " << type.bits() << "\n";
266 return "";
267 } else if (type.is_float()) {
268 if (type.bits() == 32) {
269 return "M";
270 } else if (type.bits() == 64) {
271 return "N";
272 }
273 internal_error << "Unexpected floating-point type size: " << type.bits() << ".\n";
274 return "";
275 } else if (type.is_handle()) {
276 return mangle_inner_name((type.handle_type != nullptr) ? type : non_null_void_star_type(),
277 target, prev_decls);
278 }
279 internal_error << "Unexpected kind of type. Code: " << type.code() << "\n";
280 return "";
281 }
282
cplusplus_function_mangled_name(const std::string & name,const std::vector<std::string> & namespaces,Type return_type,const std::vector<ExternFuncArgument> & args,const Target & target)283 std::string cplusplus_function_mangled_name(const std::string &name, const std::vector<std::string> &namespaces,
284 Type return_type, const std::vector<ExternFuncArgument> &args,
285 const Target &target) {
286 std::string result("\1?");
287
288 PreviousDeclarations prev_decls;
289 result += prev_decls.check_and_enter_name(name);
290
291 for (size_t i = namespaces.size(); i > 0; i--) {
292 result += prev_decls.check_and_enter_name(namespaces[i - 1]);
293 }
294 result += "@";
295
296 result += "YA";
297
298 result += prev_decls.check_and_enter_type(mangle_type(return_type, target, prev_decls));
299
300 if (args.empty()) {
301 result += "X";
302 } else {
303 for (const auto &arg : args) {
304 result += prev_decls.check_and_enter_type(mangle_type(arg.is_expr() ? arg.expr.type() : type_of<struct halide_buffer_t *>(), target, prev_decls));
305 }
306 // I think ending in a 'Z' only happens for nested function types, which never
307 // occurs with Halide, but putting it in anyway per.
308 // http://www.agner.org/optimize/calling_conventions.pdf
309 if (result.back() != 'Z') {
310 result += "@";
311 }
312 }
313 result += "Z";
314
315 return result;
316 }
317
318 } // namespace WindowsMangling
319
320 namespace ItaniumABIMangling {
321
itanium_mangle_id(const std::string & id)322 std::string itanium_mangle_id(const std::string &id) {
323 std::ostringstream oss;
324 oss << id.size() << id;
325 return oss.str();
326 }
327
simple_type_to_mangle_char(const std::string & type_name,const Target & target)328 std::string simple_type_to_mangle_char(const std::string &type_name, const Target &target) {
329 if (type_name == "void") {
330 return "v";
331 } else if (type_name == "bool") {
332 return "b";
333 } else if (type_name == "char") {
334 return "c";
335 }
336 if (type_name == "int8_t") {
337 return "a";
338 } else if (type_name == "uint8_t") {
339 return "h";
340 } else if (type_name == "int16_t") {
341 return "s";
342 } else if (type_name == "uint16_t") {
343 return "t";
344 } else if (type_name == "int32_t") {
345 return "i";
346 } else if (type_name == "uint32_t") {
347 return "j";
348 } else if (type_name == "int64_t") {
349 if (target.os == Target::OSX ||
350 target.os == Target::IOS ||
351 target.bits == 32) {
352 return "x";
353 } else {
354 return "l";
355 }
356 } else if (type_name == "uint64_t") {
357 if (target.os == Target::OSX ||
358 target.os == Target::IOS ||
359 target.bits == 32) {
360 return "y";
361 } else {
362 return "m";
363 }
364 } else if (type_name == "float") {
365 return "f";
366 } else if (type_name == "double") {
367 return "d";
368 }
369 user_error << "Unknown type name: " << type_name << "\n";
370 return "";
371 }
372
373 struct Quals {
374 std::string modifiers;
375 std::string indirections;
376 };
377
378 struct PrevPrefixes {
379 std::map<std::string, int32_t> prev_seen;
380
check_and_enterHalide::Internal::ItaniumABIMangling::PrevPrefixes381 bool check_and_enter(const std::string &prefix, std::string &substitute) {
382 auto place = prev_seen.insert({prefix, prev_seen.size()});
383 if (place.first->second == 0) {
384 substitute = "S_";
385 } else {
386 // Convert to base 36, using digits and upper case letters for each digit.
387 std::string seq_id;
388 int32_t to_encode = place.first->second - 1;
389 do {
390 int least_sig_digit = to_encode % 36;
391 if (least_sig_digit < 10) {
392 seq_id = std::string(1, (char)('0' + least_sig_digit)) + seq_id;
393 } else {
394 seq_id = (char)('A' + (least_sig_digit - 10)) + seq_id;
395 }
396 to_encode /= 36;
397 } while (to_encode > 0);
398 substitute = "S" + seq_id + "_";
399 }
400 return !place.second;
401 }
402
extend_name_partHalide::Internal::ItaniumABIMangling::PrevPrefixes403 bool extend_name_part(MangledNamePart &name_part, const std::string &mangled) {
404 std::string substitute;
405 bool found = check_and_enter(name_part.with_substitutions + mangled, substitute);
406 if (found) {
407 name_part.full_name = substitute;
408 } else {
409 name_part.full_name = name_part.full_name + mangled;
410 }
411 name_part.with_substitutions = substitute;
412 return found;
413 }
414
prepend_name_partHalide::Internal::ItaniumABIMangling::PrevPrefixes415 bool prepend_name_part(const std::string &mangled, MangledNamePart &name_part) {
416 std::string substitute;
417 bool found = check_and_enter(mangled + name_part.with_substitutions, substitute);
418 if (found) {
419 name_part.full_name = substitute;
420 } else {
421 name_part.full_name = mangled + name_part.full_name;
422 }
423 name_part.with_substitutions = substitute;
424 return found;
425 }
426 };
427
apply_indirection_and_cvr_quals(const Type & type,MangledNamePart & name_part,PrevPrefixes & prevs)428 MangledNamePart apply_indirection_and_cvr_quals(const Type &type, MangledNamePart &name_part,
429 PrevPrefixes &prevs) {
430 for (uint8_t modifier : type.handle_type->cpp_type_modifiers) {
431 // Qualifiers on a value type are simply not encoded.
432 // E.g. "int f(const int)" mangles the same as "int f(int)".
433 if (!(modifier & halide_handle_cplusplus_type::Pointer) &&
434 type.handle_type->reference_type == halide_handle_cplusplus_type::NotReference) {
435 break;
436 }
437
438 std::string quals;
439
440 if (modifier & halide_handle_cplusplus_type::Restrict) {
441 quals += "r";
442 }
443 if (modifier & halide_handle_cplusplus_type::Volatile) {
444 quals += "V";
445 }
446 if (modifier & halide_handle_cplusplus_type::Const) {
447 quals += "K";
448 }
449
450 if (!quals.empty()) {
451 prevs.prepend_name_part(quals, name_part);
452 }
453
454 if (modifier & halide_handle_cplusplus_type::Pointer) {
455 prevs.prepend_name_part("P", name_part);
456 } else {
457 break;
458 }
459 }
460
461 if (type.handle_type->reference_type == halide_handle_cplusplus_type::LValueReference) {
462 prevs.prepend_name_part("R", name_part);
463 } else if (type.handle_type->reference_type == halide_handle_cplusplus_type::RValueReference) {
464 prevs.prepend_name_part("O", name_part);
465 }
466
467 return name_part;
468 }
469
mangle_qualified_name(const std::string & name,const std::vector<std::string> & namespaces,const std::vector<halide_cplusplus_type_name> & enclosing_types,bool can_substitute,PrevPrefixes & prevs)470 MangledNamePart mangle_qualified_name(const std::string &name, const std::vector<std::string> &namespaces,
471 const std::vector<halide_cplusplus_type_name> &enclosing_types,
472 bool can_substitute, PrevPrefixes &prevs) {
473 MangledNamePart result;
474
475 // Nested names start with N and then have the enclosing scope names.
476 bool is_directly_in_std = enclosing_types.empty() && (namespaces.size() == 1 && namespaces[0] == "std");
477 bool not_simple = !is_directly_in_std && (!namespaces.empty() || !enclosing_types.empty());
478 std::string substitute;
479 if (is_directly_in_std) {
480 // TODO: more cases here.
481 if (name == "allocator") {
482 return "Sa";
483 } else if (name == "string") { // Not correct, but it does the right thing
484 return "Ss";
485 }
486 result.full_name += "St";
487 result.with_substitutions += "St";
488 } else if (not_simple) {
489 for (const auto &ns : namespaces) {
490 if (ns == "std") {
491 result.full_name += "St";
492 result.with_substitutions += "St";
493 } else {
494 prevs.extend_name_part(result, itanium_mangle_id(ns));
495 }
496 }
497 for (const auto &et : enclosing_types) {
498 prevs.extend_name_part(result, itanium_mangle_id(et.name));
499 }
500 }
501
502 std::string mangled = itanium_mangle_id(name);
503 bool substituted = false;
504 if (can_substitute) {
505 substituted = prevs.extend_name_part(result, mangled);
506 } else {
507 result.full_name += mangled;
508 result.with_substitutions += mangled;
509 }
510 if (not_simple && !substituted) {
511 result.full_name = "N" + result.full_name + "E";
512 }
513
514 return result;
515 }
516
mangle_inner_name(const Type & type,const Target & target,PrevPrefixes & prevs)517 std::string mangle_inner_name(const Type &type, const Target &target, PrevPrefixes &prevs) {
518 if (type.handle_type->inner_name.cpp_type_type == halide_cplusplus_type_name::Simple) {
519 MangledNamePart result = simple_type_to_mangle_char(type.handle_type->inner_name.name, target);
520 return apply_indirection_and_cvr_quals(type, result, prevs).full_name;
521 } else {
522 MangledNamePart mangled = mangle_qualified_name(type.handle_type->inner_name.name, type.handle_type->namespaces,
523 type.handle_type->enclosing_types, true, prevs);
524 return apply_indirection_and_cvr_quals(type, mangled, prevs).full_name;
525 }
526 }
527
mangle_type(const Type & type,const Target & target,PrevPrefixes & prevs)528 std::string mangle_type(const Type &type, const Target &target, PrevPrefixes &prevs) {
529 if (type.is_int()) {
530 switch (type.bits()) {
531 case 8:
532 return "a";
533 case 16:
534 return "s";
535 case 32:
536 return "i";
537 case 64:
538 if (target.os == Target::OSX ||
539 target.os == Target::IOS ||
540 target.bits == 32) {
541 return "x";
542 } else {
543 return "l";
544 }
545 }
546 internal_error << "Unexpected integer size: " << type.bits() << ".\n";
547 return "";
548 } else if (type.is_uint()) {
549 switch (type.bits()) {
550 case 1:
551 return "b";
552 case 8:
553 return "h";
554 case 16:
555 return "t";
556 case 32:
557 return "j";
558 case 64:
559 if (target.os == Target::OSX ||
560 target.os == Target::IOS ||
561 target.bits == 32) {
562 return "y";
563 } else {
564 return "m";
565 }
566 }
567 internal_error << "Unexpected unsigned integer size: " << type.bits() << "\n";
568 return "";
569 } else if (type.is_float()) {
570 if (type.bits() == 32) {
571 return "f";
572 } else if (type.bits() == 64) {
573 return "d";
574 }
575 internal_error << "Unexpected floating-point type size: " << type.bits() << ".\n";
576 return "";
577 } else if (type.is_handle()) {
578 return mangle_inner_name((type.handle_type != nullptr) ? type : non_null_void_star_type(),
579 target, prevs);
580 }
581 internal_error << "Unexpected kind of type. Code: " << type.code() << "\n";
582 return "";
583 }
584
cplusplus_function_mangled_name(const std::string & name,const std::vector<std::string> & namespaces,Type return_type,const std::vector<ExternFuncArgument> & args,const Target & target)585 std::string cplusplus_function_mangled_name(const std::string &name, const std::vector<std::string> &namespaces,
586 Type return_type, const std::vector<ExternFuncArgument> &args,
587 const Target &target) {
588 std::string result("_Z");
589
590 PrevPrefixes prevs;
591 result += mangle_qualified_name(name, namespaces, {}, false, prevs).full_name;
592
593 if (args.empty()) {
594 result += "v";
595 }
596
597 for (const auto &arg : args) {
598 result += mangle_type(arg.is_expr() ? arg.expr.type() : type_of<struct halide_buffer_t *>(), target, prevs);
599 }
600
601 return result;
602 }
603
604 } // namespace ItaniumABIMangling
605
cplusplus_function_mangled_name(const std::string & name,const std::vector<std::string> & namespaces,Type return_type,const std::vector<ExternFuncArgument> & args,const Target & target)606 std::string cplusplus_function_mangled_name(const std::string &name, const std::vector<std::string> &namespaces,
607 Type return_type, const std::vector<ExternFuncArgument> &args,
608 const Target &target) {
609 if (target.os == Target::Windows) {
610 return WindowsMangling::cplusplus_function_mangled_name(name, namespaces, return_type, args, target);
611 } else {
612 return ItaniumABIMangling::cplusplus_function_mangled_name(name, namespaces, return_type, args, target);
613 }
614 }
615
616 // All code below is for tests.
617
618 namespace {
619
620 constexpr int kTestTargetCount = 8;
621
622 struct MangleResult {
623 const char *expected;
624 const char *label;
625 };
626
627 MangleResult ItaniumABIMangling_main[] = {
628 {"_Z13test_functionv", "int32_t test_function(void)"},
629 {"_ZN3foo13test_functionEv", "int32_t foo::test_function(void)"},
630 {"_ZN3foo3bar13test_functionEv", "int32_t foo::bar::test_function(void)"},
631 {"_ZN3foo3bar13test_functionEi", "int32_t foo::test_function(int32_t)"},
632 {"_ZN3foo3bar13test_functionEiP15halide_buffer_t", "int32_t foo::test_function(int32_t, struct halide_buffer_t *)"},
633 {"_ZN14test_namespace14test_namespace13test_functionENS0_15enclosing_class11test_structE",
634 "test_namespace::test_namespace::test_function(test_namespace::test_namespace::enclosing_class::test_struct)"},
635 {"_ZN3foo3bar13test_functionEiP15halide_buffer_tS2_", "foo::bar::test_function(int, halide_buffer_t*, halide_buffer_t*)"},
636 {"_ZN14test_namespace14test_namespace13test_functionEPNS_11test_structEPKS1_", "test_namespace::test_namespace::test_function(test_namespace::test_struct*, test_namespace::test_struct const*)"},
637 {"_ZN14test_namespace14test_namespace13test_functionENS0_15enclosing_class11test_structES2_",
638 "test_namespace::test_namespace::test_function(test_namespace::test_namespace::enclosing_class::test_struct, test_namespace::test_namespace::enclosing_class::test_struct)"},
639 {"_ZSt13test_functionv", "std::test_function()"},
640 {"_ZNSt3foo13test_functionEv", "std::foo::test_function()"},
641 {"_ZSt13test_functionNSt15enclosing_class11test_structE", "std::test_function(std::enclosing_class::test_struct)"},
642 {"_ZN14test_namespace14test_namespace13test_functionEPNS_10test_classE", "test_namespace::test_namespace::test_function(test_namespace::test_class*)"},
643 {"_ZN14test_namespace14test_namespace13test_functionEPNS_10test_unionE", "test_namespace::test_namespace::test_function(test_namespace::test_union*)"},
644 {"_ZN14test_namespace14test_namespace13test_functionEPNS_9test_enumE", "test_namespace::test_namespace::test_function(test_namespace::test_enum*)"},
645 };
646
647 MangleResult win32_expecteds[] = {
648 {"\001?test_function@@YAHXZ", "int32_t test_function(void)"},
649 {"\001?test_function@foo@@YAHXZ", "int32_t foo::test_function(void)"},
650 {"\001?test_function@bar@foo@@YAHXZ", "int32_t foo::bar::test_function(void)"},
651 {"\001?test_function@bar@foo@@YAHH@Z", "int32_t foo::test_function(int32_t)"},
652 {"\001?test_function@bar@foo@@YAHHPAUhalide_buffer_t@@@Z", "int32_t foo::test_function(int32_t, struct halide_buffer_t *)"},
653 {"\001?test_function@test_namespace@1@YAHUtest_struct@enclosing_class@11@@Z",
654 "test_namespace::test_namespace::test_function(test_namespace::test_namespace::enclosing_class::test_struct)"},
655 {"\001?test_function@bar@foo@@YAHHPAUhalide_buffer_t@@0@Z", "foo::bar::test_function(int, halide_buffer_t*, halide_buffer_t*)"},
656 {"\001?test_function@test_namespace@1@YAHPAUtest_struct@1@PBU21@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_struct*, test_namespace::test_struct const*)"},
657 {"\001?test_function@test_namespace@1@YAHUtest_struct@enclosing_class@11@0@Z",
658 "test_namespace::test_namespace::test_function(test_namespace::test_namespace::enclosing_class::test_struct, test_namespace::test_namespace::enclosing_class::test_struct)"},
659 {"\001?test_function@std@@YAHXZ", "std::test_function()"},
660 {"\001?test_function@foo@std@@YAHXZ", "std::foo::test_function()"},
661 {"\001?test_function@std@@YAHUtest_struct@enclosing_class@1@@Z", "std::test_function(std::enclosing_class::test_struct)"},
662 {"\001?test_function@test_namespace@1@YAHPAVtest_class@1@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_class*)"},
663 {"\001?test_function@test_namespace@1@YAHPATtest_union@1@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_union*)"},
664 {"\001?test_function@test_namespace@1@YAHPAVtest_enum@1@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_enum*)"},
665 };
666
667 MangleResult win64_expecteds[] = {
668 {"\001?test_function@@YAHXZ", "int32_t test_function(void)"},
669 {"\001?test_function@foo@@YAHXZ", "int32_t foo::test_function(void)"},
670 {"\001?test_function@bar@foo@@YAHXZ", "int32_t foo::bar::test_function(void)"},
671 {"\001?test_function@bar@foo@@YAHH@Z", "int32_t foo::test_function(int32_t)"},
672 {"\001?test_function@bar@foo@@YAHHPEAUhalide_buffer_t@@@Z", "int32_t foo::test_function(int32_t, struct halide_buffer_t *)"},
673 {"\001?test_function@test_namespace@1@YAHUtest_struct@enclosing_class@11@@Z",
674 "test_namespace::test_namespace::test_function(test_namespace::test_namespace::enclosing_class::test_struct)"},
675 {"\001?test_function@bar@foo@@YAHHPEAUhalide_buffer_t@@0@Z", "foo::bar::test_function(int, halide_buffer_t*, halide_buffer_t*)"},
676 {"\001?test_function@test_namespace@1@YAHPEAUtest_struct@1@PEBU21@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_struct*, test_namespace::test_struct const*)"},
677 {"\001?test_function@test_namespace@1@YAHUtest_struct@enclosing_class@11@0@Z",
678 "test_namespace::test_namespace::test_function(test_namespace::test_namespace::enclosing_class::test_struct, test_namespace::test_namespace::enclosing_class::test_struct)"},
679 {"\001?test_function@std@@YAHXZ", "std::test_function()"},
680 {"\001?test_function@foo@std@@YAHXZ", "std::foo::test_function()"},
681 {"\001?test_function@std@@YAHUtest_struct@enclosing_class@1@@Z", "std::test_function(std::enclosing_class::test_struct)"},
682 {"\001?test_function@test_namespace@1@YAHPEAVtest_class@1@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_class*)"},
683 {"\001?test_function@test_namespace@1@YAHPEATtest_union@1@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_union*)"},
684 {"\001?test_function@test_namespace@1@YAHPEAVtest_enum@1@@Z", "test_namespace::test_namespace::test_function(test_namespace::test_enum*)"},
685 };
686
687 MangleResult all_types_by_target[kTestTargetCount] = {
688 {"_Z13test_functionbahstijxyfd", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long long, unsigned long long, float, double)"},
689 {"_Z13test_functionbahstijlmfd", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, float, double)"},
690 {"_Z13test_functionbahstijxyfd", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long long, unsigned long long, float, double)"},
691 {"_Z13test_functionbahstijxyfd", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, float, double)"},
692 {"_Z13test_functionbahstijxyfd", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long long, unsigned long long, float, double)"},
693 {"_Z13test_functionbahstijxyfd", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, float, double)"},
694 {"\001?test_function@@YAH_NCEFGHI_J_KMN@Z", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long long, unsigned long long, float, double)"},
695 {"\001?test_function@@YAH_NCEFGHI_J_KMN@Z", "test_function(bool, signed char, unsigned char, short, unsigned short, int, unsigned int, long long, unsigned long long, float, double)"},
696 };
697
698 const char *many_type_subs_itanium = "_Z13test_functionPN14test_namespace2s0EPNS_2s1EPNS_2s2EPNS_2s3EPNS_2s4EPNS_2s5EPNS_2s6EPNS_2s7EPNS_2s8EPNS_2s9EPNS_3s10EPNS_3s11EPNS_3s12EPNS_3s13EPNS_3s14EPNS_3s15EPNS_3s16EPNS_3s17EPNS_3s18EPNS_3s19EPNS_3s20EPNS_3s21EPNS_3s22EPNS_3s23EPNS_3s24EPNS_3s25EPNS_3s26EPNS_3s27EPNS_3s28EPNS_3s29EPNS_3s30EPNS_3s31EPNS_3s32EPNS_3s33EPNS_3s34EPNS_3s35EPNS_3s36EPNS_3s37EPNS_3s38EPNS_3s39EPNS_3s40EPNS_3s41EPNS_3s42EPNS_3s43EPNS_3s44EPNS_3s45EPNS_3s46EPNS_3s47EPNS_3s48EPNS_3s49EPNS_3s50EPNS_3s51EPNS_3s52EPNS_3s53EPNS_3s54EPNS_3s55EPNS_3s56EPNS_3s57EPNS_3s58EPNS_3s59EPNS_3s60EPNS_3s61EPNS_3s62EPNS_3s63EPNS_3s64EPNS_3s65EPNS_3s66EPNS_3s67EPNS_3s68EPNS_3s69EPNS_3s70EPNS_3s71EPNS_3s72EPNS_3s73EPNS_3s74EPNS_3s75EPNS_3s76EPNS_3s77EPNS_3s78EPNS_3s79EPNS_3s80EPNS_3s81EPNS_3s82EPNS_3s83EPNS_3s84EPNS_3s85EPNS_3s86EPNS_3s87EPNS_3s88EPNS_3s89EPNS_3s90EPNS_3s91EPNS_3s92EPNS_3s93EPNS_3s94EPNS_3s95EPNS_3s96EPNS_3s97EPNS_3s98EPNS_3s99ES1_S3_S5_S7_S9_SB_SD_SF_SH_SJ_SL_SN_SP_SR_ST_SV_SX_SZ_S11_S13_S15_S17_S19_S1B_S1D_S1F_S1H_S1J_S1L_S1N_S1P_S1R_S1T_S1V_S1X_S1Z_S21_S23_S25_S27_S29_S2B_S2D_S2F_S2H_S2J_S2L_S2N_S2P_S2R_S2T_S2V_S2X_S2Z_S31_S33_S35_S37_S39_S3B_S3D_S3F_S3H_S3J_S3L_S3N_S3P_S3R_S3T_S3V_S3X_S3Z_S41_S43_S45_S47_S49_S4B_S4D_S4F_S4H_S4J_S4L_S4N_S4P_S4R_S4T_S4V_S4X_S4Z_S51_S53_S55_S57_S59_S5B_S5D_S5F_S5H_S5J_";
699
700 const char *many_type_subs_win32 = "\001?test_function@@YAHPAUs0@test_namespace@@PAUs1@2@PAUs2@2@PAUs3@2@PAUs4@2@PAUs5@2@PAUs6@2@PAUs7@2@PAUs8@2@PAUs9@2@PAUs10@2@PAUs11@2@PAUs12@2@PAUs13@2@PAUs14@2@PAUs15@2@PAUs16@2@PAUs17@2@PAUs18@2@PAUs19@2@PAUs20@2@PAUs21@2@PAUs22@2@PAUs23@2@PAUs24@2@PAUs25@2@PAUs26@2@PAUs27@2@PAUs28@2@PAUs29@2@PAUs30@2@PAUs31@2@PAUs32@2@PAUs33@2@PAUs34@2@PAUs35@2@PAUs36@2@PAUs37@2@PAUs38@2@PAUs39@2@PAUs40@2@PAUs41@2@PAUs42@2@PAUs43@2@PAUs44@2@PAUs45@2@PAUs46@2@PAUs47@2@PAUs48@2@PAUs49@2@PAUs50@2@PAUs51@2@PAUs52@2@PAUs53@2@PAUs54@2@PAUs55@2@PAUs56@2@PAUs57@2@PAUs58@2@PAUs59@2@PAUs60@2@PAUs61@2@PAUs62@2@PAUs63@2@PAUs64@2@PAUs65@2@PAUs66@2@PAUs67@2@PAUs68@2@PAUs69@2@PAUs70@2@PAUs71@2@PAUs72@2@PAUs73@2@PAUs74@2@PAUs75@2@PAUs76@2@PAUs77@2@PAUs78@2@PAUs79@2@PAUs80@2@PAUs81@2@PAUs82@2@PAUs83@2@PAUs84@2@PAUs85@2@PAUs86@2@PAUs87@2@PAUs88@2@PAUs89@2@PAUs90@2@PAUs91@2@PAUs92@2@PAUs93@2@PAUs94@2@PAUs95@2@PAUs96@2@PAUs97@2@PAUs98@2@PAUs99@2@0123456789PAUs10@2@PAUs11@2@PAUs12@2@PAUs13@2@PAUs14@2@PAUs15@2@PAUs16@2@PAUs17@2@PAUs18@2@PAUs19@2@PAUs20@2@PAUs21@2@PAUs22@2@PAUs23@2@PAUs24@2@PAUs25@2@PAUs26@2@PAUs27@2@PAUs28@2@PAUs29@2@PAUs30@2@PAUs31@2@PAUs32@2@PAUs33@2@PAUs34@2@PAUs35@2@PAUs36@2@PAUs37@2@PAUs38@2@PAUs39@2@PAUs40@2@PAUs41@2@PAUs42@2@PAUs43@2@PAUs44@2@PAUs45@2@PAUs46@2@PAUs47@2@PAUs48@2@PAUs49@2@PAUs50@2@PAUs51@2@PAUs52@2@PAUs53@2@PAUs54@2@PAUs55@2@PAUs56@2@PAUs57@2@PAUs58@2@PAUs59@2@PAUs60@2@PAUs61@2@PAUs62@2@PAUs63@2@PAUs64@2@PAUs65@2@PAUs66@2@PAUs67@2@PAUs68@2@PAUs69@2@PAUs70@2@PAUs71@2@PAUs72@2@PAUs73@2@PAUs74@2@PAUs75@2@PAUs76@2@PAUs77@2@PAUs78@2@PAUs79@2@PAUs80@2@PAUs81@2@PAUs82@2@PAUs83@2@PAUs84@2@PAUs85@2@PAUs86@2@PAUs87@2@PAUs88@2@PAUs89@2@PAUs90@2@PAUs91@2@PAUs92@2@PAUs93@2@PAUs94@2@PAUs95@2@PAUs96@2@PAUs97@2@PAUs98@2@PAUs99@2@@Z";
701
702 const char *many_type_subs_win64 = "\001?test_function@@YAHPEAUs0@test_namespace@@PEAUs1@2@PEAUs2@2@PEAUs3@2@PEAUs4@2@PEAUs5@2@PEAUs6@2@PEAUs7@2@PEAUs8@2@PEAUs9@2@PEAUs10@2@PEAUs11@2@PEAUs12@2@PEAUs13@2@PEAUs14@2@PEAUs15@2@PEAUs16@2@PEAUs17@2@PEAUs18@2@PEAUs19@2@PEAUs20@2@PEAUs21@2@PEAUs22@2@PEAUs23@2@PEAUs24@2@PEAUs25@2@PEAUs26@2@PEAUs27@2@PEAUs28@2@PEAUs29@2@PEAUs30@2@PEAUs31@2@PEAUs32@2@PEAUs33@2@PEAUs34@2@PEAUs35@2@PEAUs36@2@PEAUs37@2@PEAUs38@2@PEAUs39@2@PEAUs40@2@PEAUs41@2@PEAUs42@2@PEAUs43@2@PEAUs44@2@PEAUs45@2@PEAUs46@2@PEAUs47@2@PEAUs48@2@PEAUs49@2@PEAUs50@2@PEAUs51@2@PEAUs52@2@PEAUs53@2@PEAUs54@2@PEAUs55@2@PEAUs56@2@PEAUs57@2@PEAUs58@2@PEAUs59@2@PEAUs60@2@PEAUs61@2@PEAUs62@2@PEAUs63@2@PEAUs64@2@PEAUs65@2@PEAUs66@2@PEAUs67@2@PEAUs68@2@PEAUs69@2@PEAUs70@2@PEAUs71@2@PEAUs72@2@PEAUs73@2@PEAUs74@2@PEAUs75@2@PEAUs76@2@PEAUs77@2@PEAUs78@2@PEAUs79@2@PEAUs80@2@PEAUs81@2@PEAUs82@2@PEAUs83@2@PEAUs84@2@PEAUs85@2@PEAUs86@2@PEAUs87@2@PEAUs88@2@PEAUs89@2@PEAUs90@2@PEAUs91@2@PEAUs92@2@PEAUs93@2@PEAUs94@2@PEAUs95@2@PEAUs96@2@PEAUs97@2@PEAUs98@2@PEAUs99@2@0123456789PEAUs10@2@PEAUs11@2@PEAUs12@2@PEAUs13@2@PEAUs14@2@PEAUs15@2@PEAUs16@2@PEAUs17@2@PEAUs18@2@PEAUs19@2@PEAUs20@2@PEAUs21@2@PEAUs22@2@PEAUs23@2@PEAUs24@2@PEAUs25@2@PEAUs26@2@PEAUs27@2@PEAUs28@2@PEAUs29@2@PEAUs30@2@PEAUs31@2@PEAUs32@2@PEAUs33@2@PEAUs34@2@PEAUs35@2@PEAUs36@2@PEAUs37@2@PEAUs38@2@PEAUs39@2@PEAUs40@2@PEAUs41@2@PEAUs42@2@PEAUs43@2@PEAUs44@2@PEAUs45@2@PEAUs46@2@PEAUs47@2@PEAUs48@2@PEAUs49@2@PEAUs50@2@PEAUs51@2@PEAUs52@2@PEAUs53@2@PEAUs54@2@PEAUs55@2@PEAUs56@2@PEAUs57@2@PEAUs58@2@PEAUs59@2@PEAUs60@2@PEAUs61@2@PEAUs62@2@PEAUs63@2@PEAUs64@2@PEAUs65@2@PEAUs66@2@PEAUs67@2@PEAUs68@2@PEAUs69@2@PEAUs70@2@PEAUs71@2@PEAUs72@2@PEAUs73@2@PEAUs74@2@PEAUs75@2@PEAUs76@2@PEAUs77@2@PEAUs78@2@PEAUs79@2@PEAUs80@2@PEAUs81@2@PEAUs82@2@PEAUs83@2@PEAUs84@2@PEAUs85@2@PEAUs86@2@PEAUs87@2@PEAUs88@2@PEAUs89@2@PEAUs90@2@PEAUs91@2@PEAUs92@2@PEAUs93@2@PEAUs94@2@PEAUs95@2@PEAUs96@2@PEAUs97@2@PEAUs98@2@PEAUs99@2@@Z";
703
704 MangleResult many_type_subs[kTestTargetCount] = {
705 {many_type_subs_itanium, "The expanded prototype is very long."},
706 {many_type_subs_itanium, "No really, too large to put here."},
707 {many_type_subs_itanium, "wc -l says 4394 characters."},
708 {many_type_subs_itanium, "Feel free to run c++filt if you want to..."},
709 {many_type_subs_itanium, "longity long long"},
710 {many_type_subs_itanium, "It's been a long, long, long..."},
711 {many_type_subs_win32, "Not gonna do it."},
712 {many_type_subs_win64, "Wouldn't be prudent."}};
713
714 const char *many_name_subs_itanium = "_Z13test_functionPN15test_namespace01sEPN15test_namespace11sEPN15test_namespace21sEPN15test_namespace31sEPN15test_namespace41sEPN15test_namespace51sEPN15test_namespace61sEPN15test_namespace71sEPN15test_namespace81sEPN15test_namespace91sEPN16test_namespace101sEPN16test_namespace111sEPN16test_namespace121sEPN16test_namespace131sEPN16test_namespace141sEPN16test_namespace151sEPN16test_namespace161sEPN16test_namespace171sEPN16test_namespace181sEPN16test_namespace191sEPN16test_namespace201sEPN16test_namespace211sEPN16test_namespace221sEPN16test_namespace231sEPN16test_namespace241sES1_S4_S7_SA_SD_SG_SJ_SM_SP_SS_SV_SY_S11_S14_S17_S1A_S1D_S1G_S1J_S1M_S1P_S1S_S1V_S1Y_S21_";
715
716 const char *many_name_subs_win32 = "\001?test_function@@YAHPAUs@test_namespace0@@PAU1test_namespace1@@PAU1test_namespace2@@PAU1test_namespace3@@PAU1test_namespace4@@PAU1test_namespace5@@PAU1test_namespace6@@PAU1test_namespace7@@PAU1test_namespace8@@PAU1test_namespace9@@PAU1test_namespace10@@PAU1test_namespace11@@PAU1test_namespace12@@PAU1test_namespace13@@PAU1test_namespace14@@PAU1test_namespace15@@PAU1test_namespace16@@PAU1test_namespace17@@PAU1test_namespace18@@PAU1test_namespace19@@PAU1test_namespace20@@PAU1test_namespace21@@PAU1test_namespace22@@PAU1test_namespace23@@PAU1test_namespace24@@0123456789PAU1test_namespace10@@PAU1test_namespace11@@PAU1test_namespace12@@PAU1test_namespace13@@PAU1test_namespace14@@PAU1test_namespace15@@PAU1test_namespace16@@PAU1test_namespace17@@PAU1test_namespace18@@PAU1test_namespace19@@PAU1test_namespace20@@PAU1test_namespace21@@PAU1test_namespace22@@PAU1test_namespace23@@PAU1test_namespace24@@@Z";
717
718 const char *many_name_subs_win64 = "\001?test_function@@YAHPEAUs@test_namespace0@@PEAU1test_namespace1@@PEAU1test_namespace2@@PEAU1test_namespace3@@PEAU1test_namespace4@@PEAU1test_namespace5@@PEAU1test_namespace6@@PEAU1test_namespace7@@PEAU1test_namespace8@@PEAU1test_namespace9@@PEAU1test_namespace10@@PEAU1test_namespace11@@PEAU1test_namespace12@@PEAU1test_namespace13@@PEAU1test_namespace14@@PEAU1test_namespace15@@PEAU1test_namespace16@@PEAU1test_namespace17@@PEAU1test_namespace18@@PEAU1test_namespace19@@PEAU1test_namespace20@@PEAU1test_namespace21@@PEAU1test_namespace22@@PEAU1test_namespace23@@PEAU1test_namespace24@@0123456789PEAU1test_namespace10@@PEAU1test_namespace11@@PEAU1test_namespace12@@PEAU1test_namespace13@@PEAU1test_namespace14@@PEAU1test_namespace15@@PEAU1test_namespace16@@PEAU1test_namespace17@@PEAU1test_namespace18@@PEAU1test_namespace19@@PEAU1test_namespace20@@PEAU1test_namespace21@@PEAU1test_namespace22@@PEAU1test_namespace23@@PEAU1test_namespace24@@@Z";
719
720 const char *many_name_subs_proto = "test_function(test_namespace0::s*, test_namespace1::s*, test_namespace2::s*, test_namespace3::s*, test_namespace4::s*, test_namespace5::s*, test_namespace6::s*, test_namespace7::s*, test_namespace8::s*, test_namespace9::s*, test_namespace10::s*, test_namespace11::s*, test_namespace12::s*, test_namespace13::s*, test_namespace14::s*, test_namespace15::s*, test_namespace16::s*, test_namespace17::s*, test_namespace18::s*, test_namespace19::s*, test_namespace20::s*, test_namespace21::s*, test_namespace22::s*, test_namespace23::s*, test_namespace24::s*, test_namespace0::s*, test_namespace1::s*, test_namespace2::s*, test_namespace3::s*, test_namespace4::s*, test_namespace5::s*, test_namespace6::s*, test_namespace7::s*, test_namespace8::s*, test_namespace9::s*, test_namespace10::s*, test_namespace11::s*, test_namespace12::s*, test_namespace13::s*, test_namespace14::s*, test_namespace15::s*, test_namespace16::s*, test_namespace17::s*, test_namespace18::s*, test_namespace19::s*, test_namespace20::s*, test_namespace21::s*, test_namespace22::s*, test_namespace23::s*, test_namespace24::s*)";
721
722 MangleResult many_name_subs[kTestTargetCount] = {
723 {many_name_subs_itanium, many_name_subs_proto},
724 {many_name_subs_itanium, many_name_subs_proto},
725 {many_name_subs_itanium, many_name_subs_proto},
726 {many_name_subs_itanium, many_name_subs_proto},
727 {many_name_subs_itanium, many_name_subs_proto},
728 {many_name_subs_itanium, many_name_subs_proto},
729 {many_name_subs_win32, many_name_subs_proto},
730 {many_name_subs_win64, many_name_subs_proto}};
731
732 MangleResult stacked_indirections[kTestTargetCount] = {
733 {"_Z13test_functionPKiPKS0_PKS2_PKS4_PKS6_PKS8_PKSA_PKSC_", ""},
734 {"_Z13test_functionPKiPKS0_PKS2_PKS4_PKS6_PKS8_PKSA_PKSC_", ""},
735 {"_Z13test_functionPKiPKS0_PKS2_PKS4_PKS6_PKS8_PKSA_PKSC_", ""},
736 {"_Z13test_functionPKiPKS0_PKS2_PKS4_PKS6_PKS8_PKSA_PKSC_", ""},
737 {"_Z13test_functionPKiPKS0_PKS2_PKS4_PKS6_PKS8_PKSA_PKSC_", ""},
738 {"_Z13test_functionPKiPKS0_PKS2_PKS4_PKS6_PKS8_PKSA_PKSC_", ""},
739 {"\001?test_function@@YAHPBHPBQBHPBQBQBHPBQBQBQBHPBQBQBQBQBHPBQBQBQBQBQBHPBQBQBQBQBQBQBHPBQBQBQBQBQBQBQBH@Z", ""},
740 {"\001?test_function@@YAHPEBHPEBQEBHPEBQEBQEBHPEBQEBQEBQEBHPEBQEBQEBQEBQEBHPEBQEBQEBQEBQEBQEBHPEBQEBQEBQEBQEBQEBQEBHPEBQEBQEBQEBQEBQEBQEBQEBH@Z", ""}};
741
742 MangleResult all_mods_itanium[] = {
743 {"_Z13test_function1sRS_OS_", "test_function(s, s&, s&&)"},
744 {"_Z13test_function1sRKS_OS0_", "test_function(s, s const&, s const&&)"},
745 {"_Z13test_function1sRVS_OS0_", "test_function(s, s volatile&, s volatile&&)"},
746 {"_Z13test_function1sRVKS_OS0_", "test_function(s, s const volatile&, s const volatile&&)"},
747 {"_Z13test_function1sRrS_OS0_", "test_function(s, s restrict&, s restrict&&)"},
748 {"_Z13test_function1sRrKS_OS0_", "test_function(s, s const restrict&, s const restrict&&)"},
749 {"_Z13test_function1sRrVS_OS0_", "test_function(s, s volatile restrict&, s volatile restrict&&)"},
750 {"_Z13test_function1sRrVKS_OS0_", "test_function(s, s const volatile restrict&, s const volatile restrict&&)"},
751 {"_Z13test_functionP1sRS0_OS0_", "test_function(s*, s*&, s*&&)"},
752 {"_Z13test_functionPK1sRS1_OS1_", "test_function(s const*, s const*&, s const*&&)"},
753 {"_Z13test_functionPV1sRS1_OS1_", "test_function(s volatile*, s volatile*&, s volatile*&&)"},
754 {"_Z13test_functionPVK1sRS1_OS1_", "test_function(s const volatile*, s const volatile*&, s const volatile*&&)"},
755 {"_Z13test_functionPr1sRS1_OS1_", "test_function(s restrict*, s restrict*&, s restrict*&&)"},
756 {"_Z13test_functionPrK1sRS1_OS1_", "test_function(s const restrict*, s const restrict*&, s const restrict*&&)"},
757 {"_Z13test_functionPrV1sRS1_OS1_", "test_function(s volatile restrict*, s volatile restrict*&, s volatile restrict*&&)"},
758 {"_Z13test_functionPrVK1sRS1_OS1_", "test_function(s const volatile restrict*, s const volatile restrict*&, s const volatile restrict*&&)"}};
759
760 MangleResult all_mods_win32[] = {
761 {"\001?test_function@@YAHUs@@AAU1@$$QAU1@@Z", "test_function(s, s&, s&&)"},
762 {"\001?test_function@@YAHUs@@ABU1@$$QBU1@@Z", "test_function(s, s const&, s const&&)"},
763 {"\001?test_function@@YAHUs@@ACU1@$$QCU1@@Z", "test_function(s, s volatile&, s volatile&&)"},
764 {"\001?test_function@@YAHUs@@ADU1@$$QDU1@@Z", "test_function(s, s const volatile&, s const volatile&&)"},
765 {"\001?test_function@@YAHUs@@AAU1@$$QAU1@@Z", "test_function(s, s restrict&, s restrict&&)"},
766 {"\001?test_function@@YAHUs@@ABU1@$$QBU1@@Z", "test_function(s, s const restrict&, s const restrict&&)"},
767 {"\001?test_function@@YAHUs@@ACU1@$$QCU1@@Z", "test_function(s, s volatile restrict&, s volatile restrict&&)"},
768 {"\001?test_function@@YAHUs@@ADU1@$$QDU1@@Z", "test_function(s, s const volatile restrict&, s const volatile restrict&&)"},
769 {"\001?test_function@@YAHPAUs@@AAPAU1@$$QAPAU1@@Z", "test_function(s*, s*&, s*&&)"},
770 {"\001?test_function@@YAHPBUs@@AAPBU1@$$QAPBU1@@Z", "test_function(s const*, s const*&, s const*&&)"},
771 {"\001?test_function@@YAHPCUs@@AAPCU1@$$QAPCU1@@Z", "test_function(s volatile*, s volatile*&, s volatile*&&)"},
772 {"\001?test_function@@YAHPDUs@@AAPDU1@$$QAPDU1@@Z", "test_function(s const volatile*, s const volatile*&, s const volatile*&&)"},
773 {"\001?test_function@@YAHPAUs@@AAPAU1@$$QAPAU1@@Z", "test_function(s restrict*, s restrict*&, s restrict*&&)"},
774 {"\001?test_function@@YAHPBUs@@AAPBU1@$$QAPBU1@@Z", "test_function(s const restrict*, s const restrict*&, s const restrict*&&)"},
775 {"\001?test_function@@YAHPCUs@@AAPCU1@$$QAPCU1@@Z", "test_function(s volatile restrict*, s volatile restrict*&, s volatile restrict*&&)"},
776 {"\001?test_function@@YAHPDUs@@AAPDU1@$$QAPDU1@@Z", "test_function(s const volatile restrict*, s const volatile restrict*&, s const volatile restrict*&&)"}};
777
778 MangleResult all_mods_win64[] = {
779 {"\001?test_function@@YAHUs@@AEAU1@$$QEAU1@@Z", "test_function(s, s&, s&&)"},
780 {"\001?test_function@@YAHUs@@AEBU1@$$QEBU1@@Z", "test_function(s, s const&, s const&&)"},
781 {"\001?test_function@@YAHUs@@AECU1@$$QECU1@@Z", "test_function(s, s volatile&, s volatile&&)"},
782 {"\001?test_function@@YAHUs@@AEDU1@$$QEDU1@@Z", "test_function(s, s const volatile&, s const volatile&&)"},
783 {"\001?test_function@@YAHUs@@AEAU1@$$QEAU1@@Z", "test_function(s, s restrict&, s restrict&&)"},
784 {"\001?test_function@@YAHUs@@AEBU1@$$QEBU1@@Z", "test_function(s, s const restrict&, s const restrict&&)"},
785 {"\001?test_function@@YAHUs@@AECU1@$$QECU1@@Z", "test_function(s, s volatile restrict&, s volatile restrict&&)"},
786 {"\001?test_function@@YAHUs@@AEDU1@$$QEDU1@@Z", "test_function(s, s const volatile restrict&, s const volatile restrict&&)"},
787 {"\001?test_function@@YAHPEAUs@@AEAPEAU1@$$QEAPEAU1@@Z", "test_function(s*, s*&, s*&&)"},
788 {"\001?test_function@@YAHPEBUs@@AEAPEBU1@$$QEAPEBU1@@Z", "test_function(s const*, s const*&, s const*&&)"},
789 {"\001?test_function@@YAHPECUs@@AEAPECU1@$$QEAPECU1@@Z", "test_function(s volatile*, s volatile*&, s volatile*&&)"},
790 {"\001?test_function@@YAHPEDUs@@AEAPEDU1@$$QEAPEDU1@@Z", "test_function(s const volatile*, s const volatile*&, s const volatile*&&)"},
791 {"\001?test_function@@YAHPEAUs@@AEAPEAU1@$$QEAPEAU1@@Z", "test_function(s restrict*, s restrict*&, s restrict*&&)"},
792 {"\001?test_function@@YAHPEBUs@@AEAPEBU1@$$QEAPEBU1@@Z", "test_function(s const restrict*, s const restrict*&, s const restrict*&&)"},
793 {"\001?test_function@@YAHPECUs@@AEAPECU1@$$QEAPECU1@@Z", "test_function(s volatile restrict*, s volatile restrict*&, s volatile restrict*&&)"},
794 {"\001?test_function@@YAHPEDUs@@AEAPEDU1@$$QEAPEDU1@@Z", "test_function(s const volatile restrict*, s const volatile restrict*&, s const volatile restrict*&&)"},
795 };
796
797 MangleResult two_void_stars_itanium[] = {
798 {"_Z13test_functionPvS_", "test_function(void *, void *)"},
799 };
800
801 MangleResult two_void_stars_win64[] = {
802 {"\001?test_function@@YAHPEAX0@Z", "test_function(void *, void *)"},
803 };
804
805 MangleResult two_void_stars_win32[] = {
806 {"\001?test_function@@YAHPAX0@Z", "test_function(void *, void *)"},
807 };
808
check_result(const MangleResult * expecteds,size_t & expected_index,const Target & target,const std::string & mangled_name)809 void check_result(const MangleResult *expecteds, size_t &expected_index,
810 const Target &target, const std::string &mangled_name) {
811 internal_assert(mangled_name == expecteds[expected_index].expected) << "Mangling for " << expecteds[expected_index].label << " expected\n " << expecteds[expected_index].expected << " got\n " << mangled_name << "\nfor target " << target.to_string();
812 expected_index++;
813 }
814
main_tests(const MangleResult * expecteds,const Target & target)815 void main_tests(const MangleResult *expecteds, const Target &target) {
816 size_t expecteds_index = 0;
817 check_result(expecteds, expecteds_index, target,
818 cplusplus_function_mangled_name("test_function", {}, Int(32), {}, target));
819
820 check_result(expecteds, expecteds_index, target,
821 cplusplus_function_mangled_name("test_function", {"foo"}, Int(32), {}, target));
822
823 check_result(expecteds, expecteds_index, target,
824 cplusplus_function_mangled_name("test_function", {"foo", "bar"}, Int(32), {}, target));
825
826 check_result(expecteds, expecteds_index, target,
827 cplusplus_function_mangled_name("test_function", {"foo", "bar"}, Int(32),
828 {ExternFuncArgument(42)}, target));
829
830 check_result(expecteds, expecteds_index, target,
831 cplusplus_function_mangled_name("test_function", {"foo", "bar"}, Int(32),
832 {ExternFuncArgument(42), ExternFuncArgument(Buffer<>())}, target));
833
834 halide_handle_cplusplus_type enclosed_type_info(halide_handle_cplusplus_type(
835 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "test_struct"),
836 {"test_namespace", "test_namespace"},
837 {halide_cplusplus_type_name(halide_cplusplus_type_name::Class,
838 "enclosing_class")}));
839 Type test_type(Handle(1, &enclosed_type_info));
840 check_result(expecteds, expecteds_index, target,
841 cplusplus_function_mangled_name("test_function", {"test_namespace", "test_namespace"}, Int(32),
842 {ExternFuncArgument(make_zero(test_type))}, target));
843
844 check_result(expecteds, expecteds_index, target,
845 cplusplus_function_mangled_name("test_function", {"foo", "bar"}, Int(32),
846 {ExternFuncArgument(42), ExternFuncArgument(Buffer<>()),
847 ExternFuncArgument(Buffer<>())},
848 target));
849
850 halide_handle_cplusplus_type qual1(halide_handle_cplusplus_type(
851 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "test_struct"),
852 {
853 "test_namespace",
854 },
855 {}, {halide_handle_cplusplus_type::Pointer}));
856 Type qual1_type(Handle(1, &qual1));
857 halide_handle_cplusplus_type qual2(halide_handle_cplusplus_type(
858 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "test_struct"),
859 {
860 "test_namespace",
861 },
862 {}, {halide_handle_cplusplus_type::Pointer | halide_handle_cplusplus_type::Const}));
863 Type qual2_type(Handle(1, &qual2));
864 check_result(expecteds, expecteds_index, target,
865 cplusplus_function_mangled_name("test_function", {"test_namespace", "test_namespace"}, Int(32),
866 {ExternFuncArgument(make_zero(qual1_type)),
867 ExternFuncArgument(make_zero(qual2_type))},
868 target));
869
870 check_result(expecteds, expecteds_index, target,
871 cplusplus_function_mangled_name("test_function", {"test_namespace", "test_namespace"}, Int(32),
872 {ExternFuncArgument(make_zero(test_type)),
873 ExternFuncArgument(make_zero(test_type))},
874 target));
875
876 check_result(expecteds, expecteds_index, target,
877 cplusplus_function_mangled_name("test_function", {"std"}, Int(32), {}, target));
878
879 check_result(expecteds, expecteds_index, target,
880 cplusplus_function_mangled_name("test_function", {"std", "foo"}, Int(32), {}, target));
881
882 halide_handle_cplusplus_type std_enclosed_type_info(halide_handle_cplusplus_type(
883 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "test_struct"), {"std"},
884 {halide_cplusplus_type_name(halide_cplusplus_type_name::Class, "enclosing_class")}));
885 Type std_test_type(Handle(1, &std_enclosed_type_info));
886 check_result(expecteds, expecteds_index, target,
887 cplusplus_function_mangled_name("test_function", {"std"}, Int(32),
888 {ExternFuncArgument(make_zero(std_test_type))}, target));
889
890 halide_handle_cplusplus_type class_type_info(halide_handle_cplusplus_type(
891 halide_cplusplus_type_name(halide_cplusplus_type_name::Class, "test_class"),
892 {
893 "test_namespace",
894 },
895 {}, {halide_handle_cplusplus_type::Pointer}));
896 Type class_type(Handle(1, &class_type_info));
897 check_result(expecteds, expecteds_index, target,
898 cplusplus_function_mangled_name("test_function", {"test_namespace", "test_namespace"}, Int(32),
899 {
900 ExternFuncArgument(make_zero(class_type)),
901 },
902 target));
903
904 halide_handle_cplusplus_type union_type_info(halide_handle_cplusplus_type(
905 halide_cplusplus_type_name(halide_cplusplus_type_name::Union, "test_union"),
906 {
907 "test_namespace",
908 },
909 {}, {halide_handle_cplusplus_type::Pointer}));
910 Type union_type(Handle(1, &union_type_info));
911 check_result(expecteds, expecteds_index, target,
912 cplusplus_function_mangled_name("test_function", {"test_namespace", "test_namespace"}, Int(32),
913 {
914 ExternFuncArgument(make_zero(union_type)),
915 },
916 target));
917
918 halide_handle_cplusplus_type enum_type_info(halide_handle_cplusplus_type(
919 halide_cplusplus_type_name(halide_cplusplus_type_name::Class, "test_enum"),
920 {
921 "test_namespace",
922 },
923 {}, {halide_handle_cplusplus_type::Pointer}));
924 Type enum_type(Handle(1, &enum_type_info));
925 check_result(expecteds, expecteds_index, target,
926 cplusplus_function_mangled_name("test_function", {"test_namespace", "test_namespace"}, Int(32),
927 {
928 ExternFuncArgument(make_zero(enum_type)),
929 },
930 target));
931 }
932
933 } // namespace
934
cplusplus_mangle_test()935 void cplusplus_mangle_test() {
936 Target targets[kTestTargetCount]{
937 Target(Target::Linux, Target::X86, 32),
938 Target(Target::Linux, Target::X86, 64),
939 Target(Target::OSX, Target::X86, 32),
940 Target(Target::OSX, Target::X86, 64),
941 Target(Target::IOS, Target::ARM, 32),
942 Target(Target::IOS, Target::ARM, 64),
943 Target(Target::Windows, Target::X86, 32),
944 Target(Target::Windows, Target::X86, 64)};
945 MangleResult *expecteds[kTestTargetCount]{
946 ItaniumABIMangling_main, ItaniumABIMangling_main,
947 ItaniumABIMangling_main, ItaniumABIMangling_main,
948 ItaniumABIMangling_main, ItaniumABIMangling_main,
949 win32_expecteds, win64_expecteds};
950
951 size_t i = 0;
952 for (const auto &target : targets) {
953 main_tests(expecteds[i++], target);
954 }
955
956 {
957 // Test all primitive types.
958 std::vector<ExternFuncArgument> args;
959 args.emplace_back(make_zero(Bool()));
960 args.emplace_back(make_zero(Int(8)));
961 args.emplace_back(make_zero(UInt(8)));
962 args.emplace_back(make_zero(Int(16)));
963 args.emplace_back(make_zero(UInt(16)));
964 args.emplace_back(make_zero(Int(32)));
965 args.emplace_back(make_zero(UInt(32)));
966 args.emplace_back(make_zero(Int(64)));
967 args.emplace_back(make_zero(UInt(64)));
968 args.emplace_back(make_zero(Float(32)));
969 args.emplace_back(make_zero(Float(64)));
970
971 size_t expecteds_index = 0;
972 for (const auto &target : targets) {
973 check_result(all_types_by_target, expecteds_index, target,
974 cplusplus_function_mangled_name("test_function", {}, Int(32), args, target));
975 }
976 }
977
978 {
979 // Test a whole ton of substitutions on type.
980 std::vector<halide_handle_cplusplus_type> type_info;
981 std::vector<ExternFuncArgument> args;
982 for (int i = 0; i < 100; i++) {
983 std::stringstream oss;
984 oss << i;
985 halide_handle_cplusplus_type t(halide_handle_cplusplus_type(
986 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "s" + oss.str()),
987 {
988 "test_namespace",
989 },
990 {}, {halide_handle_cplusplus_type::Pointer}));
991 type_info.push_back(t);
992 }
993 for (int i = 0; i < 200; i++) {
994 args.emplace_back(make_zero(Handle(1, &type_info[i % 100])));
995 }
996
997 size_t expecteds_index = 0;
998 for (const auto &target : targets) {
999 check_result(many_type_subs, expecteds_index, target,
1000 cplusplus_function_mangled_name("test_function", {}, Int(32), args, target));
1001 }
1002 }
1003
1004 {
1005 // Test a whole ton of substitutions on names.
1006 std::vector<halide_handle_cplusplus_type> type_info;
1007 std::vector<ExternFuncArgument> args;
1008 for (int i = 0; i < 25; i++) {
1009 std::stringstream oss;
1010 oss << i;
1011 halide_handle_cplusplus_type t(halide_handle_cplusplus_type(
1012 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "s"),
1013 {
1014 "test_namespace" + oss.str(),
1015 },
1016 {}, {halide_handle_cplusplus_type::Pointer}));
1017 type_info.push_back(t);
1018 }
1019 for (int i = 0; i < 50; i++) {
1020 args.emplace_back(make_zero(Handle(1, &type_info[i % 25])));
1021 }
1022
1023 size_t expecteds_index = 0;
1024 for (const auto &target : targets) {
1025 check_result(many_name_subs, expecteds_index, target,
1026 cplusplus_function_mangled_name("test_function", {}, Int(32), args, target));
1027 }
1028 }
1029
1030 {
1031 // Stack up a bunch of pointers and qualifiers.
1032 // int test_function(int * const, int *const*const, int *const*const*const*, ...);
1033 std::vector<halide_handle_cplusplus_type> type_info;
1034 std::vector<ExternFuncArgument> args;
1035 for (size_t i = 1; i <= 8; i++) {
1036 std::vector<uint8_t> mods;
1037 for (size_t j = 0; j < i; j++) {
1038 mods.push_back(halide_handle_cplusplus_type::Pointer | halide_handle_cplusplus_type::Const);
1039 }
1040 halide_handle_cplusplus_type t(halide_handle_cplusplus_type(
1041 halide_cplusplus_type_name(halide_cplusplus_type_name::Simple, "int32_t"),
1042 {}, {}, mods));
1043 type_info.push_back(t);
1044 }
1045 for (const auto &ti : type_info) {
1046 args.emplace_back(make_zero(Handle(1, &ti)));
1047 }
1048 size_t expecteds_index = 0;
1049 for (const auto &target : targets) {
1050 check_result(stacked_indirections, expecteds_index, target,
1051 cplusplus_function_mangled_name("test_function", {}, Int(32), args, target));
1052 }
1053 }
1054
1055 {
1056 // Test all qualifiers and all ref arguments
1057 for (const auto &target : targets) {
1058 size_t expecteds_index = 0;
1059 for (uint8_t mods = 0; mods < 16; mods++) {
1060 halide_handle_cplusplus_type t1(halide_handle_cplusplus_type(
1061 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "s"), {}, {}, {mods}));
1062 halide_handle_cplusplus_type t2(halide_handle_cplusplus_type(
1063 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "s"), {}, {}, {mods}, halide_handle_cplusplus_type::LValueReference));
1064 halide_handle_cplusplus_type t3(halide_handle_cplusplus_type(
1065 halide_cplusplus_type_name(halide_cplusplus_type_name::Struct, "s"), {}, {}, {mods}, halide_handle_cplusplus_type::RValueReference));
1066 std::vector<ExternFuncArgument> args;
1067 args.emplace_back(make_zero(Handle(1, &t1)));
1068 args.emplace_back(make_zero(Handle(1, &t2)));
1069 args.emplace_back(make_zero(Handle(1, &t3)));
1070
1071 MangleResult *expecteds = (target.os == Target::Windows) ? (target.bits == 64 ? all_mods_win64 : all_mods_win32) : all_mods_itanium;
1072 check_result(expecteds, expecteds_index, target,
1073 cplusplus_function_mangled_name("test_function", {}, Int(32), args, target));
1074 }
1075 }
1076 }
1077
1078 {
1079 // Test two void * arguments to ensure substititon handles void * correctly.
1080 // (This is a special case as "void *" is represented using nullptr for the type info.)
1081 for (const auto &target : targets) {
1082 size_t expecteds_index = 0;
1083 std::vector<ExternFuncArgument> args;
1084 args.emplace_back(make_zero(Handle(1, nullptr)));
1085 args.emplace_back(make_zero(Handle(1, nullptr)));
1086
1087 MangleResult *expecteds = (target.os == Target::Windows) ? (target.bits == 64 ? two_void_stars_win64 : two_void_stars_win32) : two_void_stars_itanium;
1088 check_result(expecteds, expecteds_index, target,
1089 cplusplus_function_mangled_name("test_function", {}, Int(32), args, target));
1090 }
1091 }
1092 }
1093
1094 } // namespace Internal
1095
1096 } // namespace Halide
1097