source: src/SymTab/Mangler.cc

Last change on this file was fc1a3e2, checked in by Andrew Beach <ajbeach@…>, 9 days ago

Style update. Focused on indentation and trailing whitespace.

  • Property mode set to 100644
File size: 14.0 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Mangler.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 21:40:29 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Oct 21 16:18:00 2022
13// Update Count     : 75
14//
15#include "Mangler.h"
16
17#include <algorithm>                     // for copy, transform
18#include <cassert>                       // for assert, assertf
19#include <functional>                    // for const_mem_fun_t, mem_fun
20#include <iterator>                      // for ostream_iterator, back_insert_ite...
21#include <list>                          // for _List_iterator, list, _List_const...
22#include <string>                        // for string, char_traits, operator<<
23
24#include "AST/Pass.hpp"
25#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
26#include "Common/ToString.hpp"           // for toCString
27#include "Common/SemanticError.h"        // for SemanticError
28
29namespace Mangle {
30
31namespace {
32
33/// Mangles names to a unique C identifier.
34struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards {
35        Mangler( Mangle::Mode mode );
36        Mangler( const Mangler & ) = delete;
37
38        void previsit( const ast::Node * ) { visit_children = false; }
39
40        void postvisit( const ast::ObjectDecl * declaration );
41        void postvisit( const ast::FunctionDecl * declaration );
42        void postvisit( const ast::TypeDecl * declaration );
43
44        void postvisit( const ast::VoidType * voidType );
45        void postvisit( const ast::BasicType * basicType );
46        void postvisit( const ast::PointerType * pointerType );
47        void postvisit( const ast::ArrayType * arrayType );
48        void postvisit( const ast::ReferenceType * refType );
49        void postvisit( const ast::FunctionType * functionType );
50        void postvisit( const ast::StructInstType * aggregateUseType );
51        void postvisit( const ast::UnionInstType * aggregateUseType );
52        void postvisit( const ast::EnumInstType * aggregateUseType );
53        void postvisit( const ast::TypeInstType * aggregateUseType );
54        void postvisit( const ast::TraitInstType * inst );
55        void postvisit( const ast::TupleType * tupleType );
56        void postvisit( const ast::VarArgsType * varArgsType );
57        void postvisit( const ast::ZeroType * zeroType );
58        void postvisit( const ast::OneType * oneType );
59        void postvisit( const ast::QualifiedType * qualType );
60        void postvisit( const ast::EnumAttrType * posType );
61
62        /// The result is the current constructed mangled name.
63        std::string result() const { return mangleName; }
64private:
65        std::string mangleName;         ///< Mangled name being constructed
66        typedef std::map< std::string, std::pair< int, int > > VarMapType;
67        VarMapType varNums;             ///< Map of type variables to indices
68        int nextVarNum;                 ///< Next type variable index
69        bool isTopLevel;                ///< Is the Mangler at the top level
70        bool mangleOverridable;         ///< Specially mangle overridable built-in methods
71        bool typeMode;                  ///< Produce a unique mangled name for a type
72        bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
73        bool inFunctionType = false;    ///< Include type qualifiers if false.
74        bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
75
76private:
77        Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
78                int nextVarNum, const VarMapType& varNums );
79        friend class ast::Pass<Mangler>;
80
81private:
82        void mangleDecl( const ast::DeclWithType *declaration );
83        void mangleRef( const ast::BaseInstType *refType, const std::string & prefix );
84
85        void printQualifiers( const ast::Type *type );
86}; // Mangler
87
88Mangler::Mangler( Mangle::Mode mode )
89        : nextVarNum( 0 ), isTopLevel( true ),
90        mangleOverridable  ( ! mode.no_overrideable   ),
91        typeMode           (   mode.type              ),
92        mangleGenericParams( ! mode.no_generic_params ) {}
93
94Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
95        int nextVarNum, const VarMapType& varNums )
96        : varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
97        mangleOverridable( mangleOverridable ), typeMode( typeMode ),
98        mangleGenericParams( mangleGenericParams ) {}
99
100void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
101        bool wasTopLevel = isTopLevel;
102        if ( isTopLevel ) {
103                varNums.clear();
104                nextVarNum = 0;
105                isTopLevel = false;
106        }
107        mangleName += Encoding::manglePrefix;
108        if ( auto opInfo = CodeGen::operatorLookup( decl->name ) ) {
109                mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
110        } else {
111                mangleName += std::to_string( decl->name.size() ) + decl->name;
112        }
113        decl->get_type()->accept( *visitor );
114        if ( mangleOverridable && decl->linkage.is_overrideable ) {
115                // want to be able to override autogenerated and intrinsic routines,
116                // so they need a different name mangling
117                if ( decl->linkage == ast::Linkage::AutoGen ) {
118                        mangleName += Encoding::autogen;
119                } else if ( decl->linkage == ast::Linkage::Intrinsic ) {
120                        mangleName += Encoding::intrinsic;
121                } else {
122                        // if we add another kind of overridable function, this has to change
123                        assert( false && "unknown overrideable linkage" );
124                }
125        }
126        isTopLevel = wasTopLevel;
127}
128
129void Mangler::postvisit( const ast::ObjectDecl * decl ) {
130        mangleDecl( decl );
131}
132
133void Mangler::postvisit( const ast::FunctionDecl * decl ) {
134        mangleDecl( decl );
135}
136
137void Mangler::postvisit( const ast::VoidType * voidType ) {
138        printQualifiers( voidType );
139        mangleName += Encoding::void_t;
140}
141
142void Mangler::postvisit( const ast::BasicType * basicType ) {
143        printQualifiers( basicType );
144        assertf( basicType->kind < ast::BasicKind::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
145        mangleName += Encoding::basicTypes[ basicType->kind ];
146}
147
148void Mangler::postvisit( const ast::PointerType * pointerType ) {
149        printQualifiers( pointerType );
150        // Mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers.
151        if ( !pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
152        maybe_accept( pointerType->base.get(), *visitor );
153}
154
155void Mangler::postvisit( const ast::ArrayType * arrayType ) {
156        // TODO: encode dimension
157        printQualifiers( arrayType );
158        mangleName += Encoding::array + "0";
159        arrayType->base->accept( *visitor );
160}
161
162void Mangler::postvisit( const ast::ReferenceType * refType ) {
163        // Don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
164        // Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
165        // by pretending every reference type is a function parameter.
166        GuardValue( inFunctionType ) = true;
167        printQualifiers( refType );
168        refType->base->accept( *visitor );
169}
170
171void Mangler::postvisit( const ast::FunctionType * functionType ) {
172        printQualifiers( functionType );
173        mangleName += Encoding::function;
174        // Turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
175        // since qualifiers on outermost parameter type do not differentiate function types, e.g.,
176        // void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different.
177        GuardValue( inFunctionType ) = true;
178        if (functionType->returns.empty()) mangleName += Encoding::void_t;
179        else accept_each( functionType->returns, *visitor );
180        mangleName += "_";
181        accept_each( functionType->params, *visitor );
182        mangleName += "_";
183}
184
185void Mangler::mangleRef(
186                const ast::BaseInstType * refType, const std::string & prefix ) {
187        printQualifiers( refType );
188
189        mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
190
191        if ( mangleGenericParams && ! refType->params.empty() ) {
192                mangleName += "_";
193                for ( const ast::Expr * param : refType->params ) {
194                        auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
195                        assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
196                        paramType->type->accept( *visitor );
197                }
198                mangleName += "_";
199        }
200}
201
202void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
203        mangleRef( aggregateUseType, Encoding::struct_t );
204}
205
206void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
207        mangleRef( aggregateUseType, Encoding::union_t );
208}
209
210void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
211        mangleRef( aggregateUseType, Encoding::enum_t );
212}
213
214void Mangler::postvisit( const ast::TypeInstType * typeInst ) {
215        VarMapType::iterator varNum = varNums.find( typeInst->name );
216        if ( varNum == varNums.end() ) {
217                mangleRef( typeInst, Encoding::type );
218        } else {
219                printQualifiers( typeInst );
220                // Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
221                //   forall(dtype T) void f(T);
222                //   forall(dtype S) void f(S);
223                // are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
224                // are first found and prefixing with the appropriate encoding for the type class.
225                assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
226                mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
227        }
228}
229
230void Mangler::postvisit( const ast::TraitInstType * inst ) {
231        printQualifiers( inst );
232        mangleName += std::to_string( inst->name.size() ) + inst->name;
233}
234
235void Mangler::postvisit( const ast::TupleType * tupleType ) {
236        printQualifiers( tupleType );
237        mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
238        accept_each( tupleType->types, *visitor );
239}
240
241void Mangler::postvisit( const ast::VarArgsType * varArgsType ) {
242        printQualifiers( varArgsType );
243        static const std::string vargs = "__builtin_va_list";
244        mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
245}
246
247void Mangler::postvisit( const ast::ZeroType * ) {
248        mangleName += Encoding::zero;
249}
250
251void Mangler::postvisit( const ast::OneType * ) {
252        mangleName += Encoding::one;
253}
254
255void Mangler::postvisit( const ast::QualifiedType * qualType ) {
256        bool inqual = inQualifiedType;
257        if ( !inqual ) {
258                // N marks the start of a qualified type.
259                inQualifiedType = true;
260                mangleName += Encoding::qualifiedTypeStart;
261        }
262        qualType->parent->accept( *visitor );
263        qualType->child->accept( *visitor );
264        if ( !inqual ) {
265                // E marks the end of a qualified type.
266                inQualifiedType = false;
267                mangleName += Encoding::qualifiedTypeEnd;
268        }
269}
270
271void Mangler::postvisit( const ast::TypeDecl * decl ) {
272        // TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
273        // fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
274        // Note: The current scheme may already work correctly for this case, I have not thought about this deeply
275        // and the case has not yet come up in practice. Alternatively, if not then this code can be removed
276        // aside from the assert false.
277        assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
278        assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
279        mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
280}
281
282void Mangler::postvisit( const ast::EnumAttrType * enumAttr ) {
283        postvisit( enumAttr->instance );
284        // mangleName += "_pos";
285        switch ( enumAttr->attr )
286        {
287                case ast::EnumAttribute::Label:
288                        mangleName += "_label_";
289                        break;
290                case ast::EnumAttribute::Posn:
291                        mangleName += "_posn_";
292                        break;
293                case ast::EnumAttribute::Value:
294                        mangleName += "_value_";
295                        break;
296        }
297
298}
299
300// For debugging:
301__attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
302        for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
303                os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
304        }
305}
306
307void Mangler::printQualifiers( const ast::Type * type ) {
308        // Skip if not including qualifiers:
309        if ( typeMode ) return;
310        auto funcType = dynamic_cast<const ast::FunctionType *>( type );
311        if ( funcType && !funcType->forall.empty() ) {
312                std::list< std::string > assertionNames;
313                int dcount = 0, fcount = 0, vcount = 0, acount = 0;
314                mangleName += Encoding::forall;
315                for ( auto & decl : funcType->forall ) {
316                        switch ( decl->kind ) {
317                        case ast::TypeDecl::Dtype:
318                                dcount++;
319                                break;
320                        case ast::TypeDecl::Ftype:
321                                fcount++;
322                                break;
323                        case ast::TypeDecl::Ttype:
324                                vcount++;
325                                break;
326                        default:
327                                assertf( false, "unimplemented kind for type variable %s", Encoding::typeVariables[decl->kind].c_str() );
328                        }
329                        varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
330                }
331                for ( auto & assert : funcType->assertions ) {
332                        assertionNames.push_back( ast::Pass<Mangler>::read(
333                                assert->var.get(),
334                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
335                        acount++;
336                }
337                mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
338                for ( const auto & a : assertionNames ) mangleName += a;
339                mangleName += "_";
340        }
341        if ( !inFunctionType ) {
342                // These qualifiers do not distinguish the outermost type of a function parameter.
343                if ( type->is_const() ) {
344                        mangleName += Encoding::qualifiers.at( ast::CV::Const );
345                }
346                if ( type->is_volatile() ) {
347                        mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
348                }
349                if ( type->is_atomic() ) {
350                        mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
351                }
352        }
353        if ( type->is_mutex() ) {
354                mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
355        }
356        if ( inFunctionType ) {
357                // Turn off inFunctionType so that types can be differentiated for nested qualifiers.
358                GuardValue( inFunctionType ) = false;
359        }
360}
361
362} // namespace
363
364std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
365        return ast::Pass<Mangler>::read( decl, mode );
366}
367
368} // namespace Mangle
369
370// Local Variables: //
371// tab-width: 4 //
372// mode: c++ //
373// compile-command: "make install" //
374// End: //
Note: See TracBrowser for help on using the repository browser.