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