source: src/SymTab/Autogen.cc @ a137d5a

Last change on this file since a137d5a was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 13 months ago

Moved new ast code out of one of the old files. The new file may have to change if SymTab? is removed entirely, but for now at least, there is a lot less template code in headers.

  • Property mode set to 100644
File size: 33.9 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// Autogen.cc --
8//
9// Author           : Rob Schluntz
10// Created On       : Thu Mar 03 15:45:56 2016
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Apr 14 15:03:00 2023
13// Update Count     : 64
14//
15
16#include "Autogen.h"
17
18#include <algorithm>               // for count_if
19#include <cassert>                 // for strict_dynamic_cast, assert, assertf
20#include <iterator>                // for back_insert_iterator, back_inserter
21#include <list>                    // for list, _List_iterator, list<>::iter...
22#include <set>                     // for set, _Rb_tree_const_iterator
23#include <utility>                 // for pair
24#include <vector>                  // for vector
25
26#include "AST/Decl.hpp"
27#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
28#include "Common/PassVisitor.h"    // for PassVisitor
29#include "Common/ScopedMap.h"      // for ScopedMap<>::const_iterator, Scope...
30#include "Common/utility.h"        // for cloneAll, operator+
31#include "GenPoly/ScopedSet.h"     // for ScopedSet, ScopedSet<>::iterator
32#include "InitTweak/GenInit.h"     // for fixReturnStatements
33#include "ResolvExpr/Resolver.h"   // for resolveDecl
34#include "SymTab/Mangler.h"        // for Mangler
35#include "SynTree/Attribute.h"     // For Attribute
36#include "SynTree/Mutator.h"       // for maybeMutate
37#include "SynTree/Statement.h"     // for CompoundStmt, ReturnStmt, ExprStmt
38#include "SynTree/Type.h"          // for FunctionType, Type, TypeInstType
39#include "SynTree/Visitor.h"       // for maybeAccept, Visitor, acceptAll
40#include "CompilationState.h"
41
42class Attribute;
43
44namespace SymTab {
45        /// Data used to generate functions generically. Specifically, the name of the generated function and a function which generates the routine protoype
46        struct FuncData {
47                typedef FunctionType * (*TypeGen)( Type *, bool );
48                FuncData( const std::string & fname, const TypeGen & genType ) : fname( fname ), genType( genType ) {}
49                std::string fname;
50                TypeGen genType;
51        };
52
53        struct AutogenerateRoutines final : public WithDeclsToAdd, public WithVisitorRef<AutogenerateRoutines>, public WithGuards, public WithShortCircuiting, public WithIndexer {
54                AutogenerateRoutines();
55
56                void previsit( EnumDecl * enumDecl );
57                void previsit( StructDecl * structDecl );
58                void previsit( UnionDecl * structDecl );
59                void previsit( TypeDecl * typeDecl );
60                void previsit( TraitDecl * traitDecl );
61                void previsit( FunctionDecl * functionDecl );
62
63                void previsit( CompoundStmt * compoundStmt );
64
65          private:
66
67                GenPoly::ScopedSet< std::string > structsDone;
68                unsigned int functionNesting = 0;     // current level of nested functions
69
70                std::vector< FuncData > data;
71        };
72
73        /// generates routines for tuple types.
74        struct AutogenTupleRoutines : public WithDeclsToAdd, public WithVisitorRef<AutogenTupleRoutines>, public WithGuards, public WithShortCircuiting {
75                void previsit( FunctionDecl * functionDecl );
76
77                void postvisit( TupleType * tupleType );
78
79                void previsit( CompoundStmt * compoundStmt );
80
81          private:
82                unsigned int functionNesting = 0;     // current level of nested functions
83                GenPoly::ScopedSet< std::string > seenTuples;
84        };
85
86        void autogenerateRoutines( std::list< Declaration * > &translationUnit ) {
87                PassVisitor<AutogenerateRoutines> generator;
88                acceptAll( translationUnit, generator );
89
90                // needs to be done separately because AutogenerateRoutines skips types that appear as function arguments, etc.
91                // AutogenTupleRoutines tupleGenerator;
92                // acceptAll( translationUnit, tupleGenerator );
93        }
94
95        //=============================================================================================
96        // FuncGenerator definitions
97        //=============================================================================================
98        class FuncGenerator {
99        public:
100                std::list< Declaration * > definitions, forwards;
101
102                FuncGenerator( Type * type, const std::vector< FuncData > & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : type( type ), data( data ), functionNesting( functionNesting ), indexer( indexer ) {}
103
104                virtual bool shouldAutogen() const = 0;
105                void genStandardFuncs();
106                virtual void genFieldCtors() = 0;
107        protected:
108                Type * type;
109                const std::vector< FuncData > & data;
110                unsigned int functionNesting;
111                SymTab::Indexer & indexer;
112
113                virtual void genFuncBody( FunctionDecl * dcl ) = 0;
114                virtual bool isConcurrentType() const = 0;
115
116                void resolve( FunctionDecl * dcl );
117                void generatePrototypes( std::list< FunctionDecl * > & newFuncs );
118        };
119
120        class StructFuncGenerator : public FuncGenerator {
121                StructDecl * aggregateDecl;
122        public:
123                StructFuncGenerator( StructDecl * aggregateDecl, StructInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), aggregateDecl( aggregateDecl) {}
124
125                virtual bool shouldAutogen() const override;
126                virtual bool isConcurrentType() const override;
127
128                virtual void genFuncBody( FunctionDecl * dcl ) override;
129                virtual void genFieldCtors() override;
130
131        private:
132                /// generates a single struct member operation (constructor call, destructor call, assignment call)
133                void makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward = true );
134
135                /// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies
136                template<typename Iterator>
137                void makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward = true );
138
139                /// generate the body of a constructor which takes parameters that match fields, e.g.
140                /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.
141                template<typename Iterator>
142                void makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func );
143        };
144
145        class UnionFuncGenerator : public FuncGenerator {
146                UnionDecl * aggregateDecl;
147        public:
148                UnionFuncGenerator( UnionDecl * aggregateDecl, UnionInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), aggregateDecl( aggregateDecl) {}
149
150                virtual bool shouldAutogen() const override;
151                virtual bool isConcurrentType() const override;
152
153                virtual void genFuncBody( FunctionDecl * dcl ) override;
154                virtual void genFieldCtors() override;
155
156        private:
157                /// generates a single struct member operation (constructor call, destructor call, assignment call)
158                template<typename OutputIterator>
159                void makeMemberOp( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out );
160
161                /// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies
162                template<typename Iterator>
163                void makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward = true );
164
165                /// generate the body of a constructor which takes parameters that match fields, e.g.
166                /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.
167                template<typename Iterator>
168                void makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func );
169        };
170
171        class EnumFuncGenerator : public FuncGenerator {
172        public:
173                EnumFuncGenerator( EnumInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ) {}
174
175                virtual bool shouldAutogen() const override;
176                virtual bool isConcurrentType() const override;
177
178                virtual void genFuncBody( FunctionDecl * dcl ) override;
179                virtual void genFieldCtors() override;
180
181        private:
182        };
183
184        class TypeFuncGenerator : public FuncGenerator {
185                TypeDecl * typeDecl;
186        public:
187                TypeFuncGenerator( TypeDecl * typeDecl, TypeInstType * refType, const std::vector<FuncData> & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), typeDecl( typeDecl ) {}
188
189                virtual bool shouldAutogen() const override;
190                virtual void genFuncBody( FunctionDecl * dcl ) override;
191                virtual bool isConcurrentType() const override;
192                virtual void genFieldCtors() override;
193        };
194
195        //=============================================================================================
196        // helper functions
197        //=============================================================================================
198        void generateFunctions( FuncGenerator & gen, std::list< Declaration * > & declsToAdd ) {
199                if ( ! gen.shouldAutogen() ) return;
200
201                // generate each of the functions based on the supplied FuncData objects
202                gen.genStandardFuncs();
203                gen.genFieldCtors();
204
205                declsToAdd.splice( declsToAdd.end(), gen.forwards );
206                declsToAdd.splice( declsToAdd.end(), gen.definitions );
207        }
208
209        bool isUnnamedBitfield( ObjectDecl * obj ) {
210                return obj != nullptr && obj->name == "" && obj->bitfieldWidth != nullptr;
211        }
212
213        /// inserts a forward declaration for functionDecl into declsToAdd
214        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
215                FunctionDecl * decl = functionDecl->clone();
216                delete decl->statements;
217                decl->statements = nullptr;
218                declsToAdd.push_back( decl );
219                decl->fixUniqueId();
220        }
221
222        const std::list< TypeDecl * > getGenericParams( Type * t ) {
223                std::list< TypeDecl * > * ret = nullptr;
224                if ( StructInstType * inst = dynamic_cast< StructInstType * > ( t ) ) {
225                        ret = inst->get_baseParameters();
226                } else if ( UnionInstType * inst = dynamic_cast< UnionInstType * >( t ) ) {
227                        ret = inst->get_baseParameters();
228                }
229                return ret ? *ret : std::list< TypeDecl * >();
230        }
231
232        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
233        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
234                FunctionType *ftype = new FunctionType( Type::Qualifiers(), false );
235                if ( maybePolymorphic ) {
236                        // only copy in
237                        const auto & typeParams = getGenericParams( paramType );
238                        cloneAll( typeParams, ftype->forall );
239                }
240                ObjectDecl *dstParam = new ObjectDecl( "_dst", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), paramType->clone() ), nullptr );
241                ftype->parameters.push_back( dstParam );
242                return ftype;
243        }
244
245        /// given type T, generate type of copy ctor, i.e. function type void (*) (T *, T)
246        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic ) {
247                FunctionType *ftype = genDefaultType( paramType, maybePolymorphic );
248                ObjectDecl *srcParam = new ObjectDecl( "_src", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
249                ftype->parameters.push_back( srcParam );
250                return ftype;
251        }
252
253        /// given type T, generate type of assignment, i.e. function type T (*) (T *, T)
254        FunctionType * genAssignType( Type * paramType, bool maybePolymorphic ) {
255                FunctionType *ftype = genCopyType( paramType, maybePolymorphic );
256                ObjectDecl *returnVal = new ObjectDecl( "_ret", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
257                ftype->returnVals.push_back( returnVal );
258                return ftype;
259        }
260
261        /// generate a function decl from a name and type. Nesting depth determines whether
262        /// the declaration is static or not; optional paramter determines if declaration is intrinsic
263        FunctionDecl * genFunc( const std::string & fname, FunctionType * ftype, unsigned int functionNesting, bool isIntrinsic = false  ) {
264                // Routines at global scope marked "static" to prevent multiple definitions in separate translation units
265                // because each unit generates copies of the default routines for each aggregate.
266                Type::StorageClasses scs = functionNesting > 0 ? Type::StorageClasses() : Type::StorageClasses( Type::Static );
267                LinkageSpec::Spec spec = isIntrinsic ? LinkageSpec::Intrinsic : LinkageSpec::AutoGen;
268                FunctionDecl * decl = new FunctionDecl( fname, scs, spec, ftype, new CompoundStmt(),
269                                                                                                std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) );
270                decl->fixUniqueId();
271                return decl;
272        }
273
274        Type * declToType( Declaration * decl ) {
275                if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
276                        return dwt->get_type();
277                }
278                return nullptr;
279        }
280
281        Type * declToTypeDeclBase( Declaration * decl ) {
282                if ( TypeDecl * td = dynamic_cast< TypeDecl * >( decl ) ) {
283                        return td->base;
284                }
285                return nullptr;
286        }
287
288        //=============================================================================================
289        // FuncGenerator member definitions
290        //=============================================================================================
291        void FuncGenerator::genStandardFuncs() {
292                std::list< FunctionDecl * > newFuncs;
293                generatePrototypes( newFuncs );
294
295                for ( FunctionDecl * dcl : newFuncs ) {
296                        genFuncBody( dcl );
297                        if ( CodeGen::isAssignment( dcl->name ) ) {
298                                // assignment needs to return a value
299                                FunctionType * assignType = dcl->type;
300                                assert( assignType->parameters.size() == 2 );
301                                assert( assignType->returnVals.size() == 1 );
302                                ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( assignType->parameters.front() );
303                                dcl->statements->push_back( new ReturnStmt( new VariableExpr( dstParam ) ) );
304                        }
305                        resolve( dcl );
306                }
307        }
308
309        void FuncGenerator::generatePrototypes( std::list< FunctionDecl * > & newFuncs ) {
310                bool concurrent_type = isConcurrentType();
311                for ( const FuncData & d : data ) {
312                        // generate a function (?{}, ?=?, ^?{}) based on the current FuncData.
313                        FunctionType * ftype = d.genType( type, true );
314
315                        // destructor for concurrent type must be mutex
316                        if ( concurrent_type && CodeGen::isDestructor( d.fname ) ) {
317                                ftype->parameters.front()->get_type()->set_mutex( true );
318                        }
319
320                        newFuncs.push_back( genFunc( d.fname, ftype, functionNesting ) );
321                }
322        }
323
324        void FuncGenerator::resolve( FunctionDecl * dcl ) {
325                try {
326                        if (!useNewAST) // attempt to delay resolver call
327                                ResolvExpr::resolveDecl( dcl, indexer );
328                        if ( functionNesting == 0 ) {
329                                // forward declare if top-level struct, so that
330                                // type is complete as soon as its body ends
331                                // Note: this is necessary if we want structs which contain
332                                // generic (otype) structs as members.
333                                addForwardDecl( dcl, forwards );
334                        }
335                        definitions.push_back( dcl );
336                        indexer.addId( dcl );
337                } catch ( SemanticErrorException & ) {
338                        // okay if decl does not resolve - that means the function should not be generated
339                        // delete dcl;
340                        delete dcl->statements;
341                        dcl->statements = nullptr;
342                        dcl->isDeleted = true;
343                        definitions.push_back( dcl );
344                        indexer.addId( dcl );
345                }
346        }
347
348        bool StructFuncGenerator::shouldAutogen() const {
349                // Builtins do not use autogeneration.
350                return ! aggregateDecl->linkage.is_builtin;
351        }
352        bool StructFuncGenerator::isConcurrentType() const { return aggregateDecl->is_thread() || aggregateDecl->is_monitor(); }
353
354        void StructFuncGenerator::genFuncBody( FunctionDecl * dcl ) {
355                // generate appropriate calls to member ctor, assignment
356                // destructor needs to do everything in reverse, so pass "forward" based on whether the function is a destructor
357                if ( ! CodeGen::isDestructor( dcl->name ) ) {
358                        makeFunctionBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), dcl );
359                } else {
360                        makeFunctionBody( aggregateDecl->members.rbegin(), aggregateDecl->members.rend(), dcl, false );
361                }
362        }
363
364        void StructFuncGenerator::genFieldCtors() {
365                // field ctors are only generated if default constructor and copy constructor are both generated
366                unsigned numCtors = std::count_if( definitions.begin(), definitions.end(), [](Declaration * dcl) { return CodeGen::isConstructor( dcl->name ); } );
367
368                // Field constructors are only generated if default and copy constructor
369                // are generated, since they need access to both
370                if ( numCtors != 2 ) return;
371
372                // create constructors which take each member type as a parameter.
373                // for example, for struct A { int x, y; }; generate
374                //   void ?{}(A *, int) and void ?{}(A *, int, int)
375                FunctionType * memCtorType = genDefaultType( type );
376                for ( Declaration * member : aggregateDecl->members ) {
377                        DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member );
378                        if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
379                                // don't make a function whose parameter is an unnamed bitfield
380                                continue;
381                        }
382                        // do not carry over field's attributes to parameter type
383                        Type * paramType = field->get_type()->clone();
384                        deleteAll( paramType->attributes );
385                        paramType->attributes.clear();
386                        // add a parameter corresponding to this field
387                        ObjectDecl * param = new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType, nullptr );
388                        cloneAll_if( field->attributes, param->attributes, [](Attribute * attr) { return attr->isValidOnFuncParam(); } );
389                        memCtorType->parameters.push_back( param );
390                        FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
391                        makeFieldCtorBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), ctor );
392                        resolve( ctor );
393                }
394                delete memCtorType;
395        }
396
397        void StructFuncGenerator::makeMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool forward ) {
398                InitTweak::InitExpander_old srcParam( src );
399
400                // assign to destination
401                Expression *dstselect = new MemberExpr( field, new CastExpr( new VariableExpr( dstParam ), strict_dynamic_cast< ReferenceType* >( dstParam->get_type() )->base->clone() ) );
402                genImplicitCall( srcParam, dstselect, func->name, back_inserter( func->statements->kids ), field, forward );
403        }
404
405        template<typename Iterator>
406        void StructFuncGenerator::makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward ) {
407                for ( ; member != end; ++member ) {
408                        if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate
409                                // query the type qualifiers of this field and skip assigning it if it is marked const.
410                                // If it is an array type, we need to strip off the array layers to find its qualifiers.
411                                Type * type = field->get_type();
412                                while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
413                                        type = at->get_base();
414                                }
415
416                                if ( type->get_const() && CodeGen::isAssignment( func->name ) ) {
417                                        // don't assign const members, but do construct/destruct
418                                        continue;
419                                }
420
421                                assert( ! func->get_functionType()->get_parameters().empty() );
422                                ObjectDecl * dstParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().front() );
423                                ObjectDecl * srcParam = nullptr;
424                                if ( func->get_functionType()->get_parameters().size() == 2 ) {
425                                        srcParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().back() );
426                                }
427
428                                // srcParam may be NULL, in which case we have default ctor/dtor
429                                assert( dstParam );
430
431                                Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : nullptr;
432                                makeMemberOp( dstParam, srcselect, field, func, forward );
433                        } // if
434                } // for
435        } // makeFunctionBody
436
437        template<typename Iterator>
438        void StructFuncGenerator::makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func ) {
439                FunctionType * ftype = func->type;
440                std::list<DeclarationWithType*> & params = ftype->parameters;
441                assert( params.size() >= 2 );  // should not call this function for default ctor, etc.
442
443                // skip 'this' parameter
444                ObjectDecl * dstParam = dynamic_cast<ObjectDecl*>( params.front() );
445                assert( dstParam );
446                std::list<DeclarationWithType*>::iterator parameter = params.begin()+1;
447                for ( ; member != end; ++member ) {
448                        if ( DeclarationWithType * field = dynamic_cast<DeclarationWithType*>( *member ) ) {
449                                if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
450                                        // don't make a function whose parameter is an unnamed bitfield
451                                        continue;
452                                } else if ( parameter != params.end() ) {
453                                        // matching parameter, initialize field with copy ctor
454                                        Expression *srcselect = new VariableExpr(*parameter);
455                                        makeMemberOp( dstParam, srcselect, field, func );
456                                        ++parameter;
457                                } else {
458                                        // no matching parameter, initialize field with default ctor
459                                        makeMemberOp( dstParam, nullptr, field, func );
460                                }
461                        }
462                }
463        }
464
465        bool UnionFuncGenerator::shouldAutogen() const {
466                // Builtins do not use autogeneration.
467                return ! aggregateDecl->linkage.is_builtin;
468        }
469
470        // xxx - is this right?
471        bool UnionFuncGenerator::isConcurrentType() const { return false; };
472
473        /// generate a single union assignment expression (using memcpy)
474        template< typename OutputIterator >
475        void UnionFuncGenerator::makeMemberOp( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) {
476                UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) );
477                copy->args.push_back( new AddressExpr( new VariableExpr( dstParam ) ) );
478                copy->args.push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
479                copy->args.push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
480                *out++ = new ExprStmt( copy );
481        }
482
483        /// generates the body of a union assignment/copy constructor/field constructor
484        void UnionFuncGenerator::genFuncBody( FunctionDecl * funcDecl ) {
485                FunctionType * ftype = funcDecl->type;
486                if ( InitTweak::isCopyConstructor( funcDecl ) || InitTweak::isAssignment( funcDecl ) ) {
487                        assert( ftype->parameters.size() == 2 );
488                        ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() );
489                        ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.back() );
490                        makeMemberOp( srcParam, dstParam, back_inserter( funcDecl->statements->kids ) );
491                } else {
492                        // default ctor/dtor body is empty - add unused attribute to parameter to silence warnings
493                        assert( ftype->parameters.size() == 1 );
494                        ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() );
495                        dstParam->attributes.push_back( new Attribute( "unused" ) );
496                }
497        }
498
499        /// generate the body of a constructor which takes parameters that match fields, e.g.
500        /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.
501        void UnionFuncGenerator::genFieldCtors() {
502                // field ctors are only generated if default constructor and copy constructor are both generated
503                unsigned numCtors = std::count_if( definitions.begin(), definitions.end(), [](Declaration * dcl) { return CodeGen::isConstructor( dcl->get_name() ); } );
504
505                // Field constructors are only generated if default and copy constructor
506                // are generated, since they need access to both
507                if ( numCtors != 2 ) return;
508
509                // create a constructor which takes the first member type as a parameter.
510                // for example, for Union A { int x; double y; }; generate
511                // void ?{}(A *, int)
512                // This is to mimic C's behaviour which initializes the first member of the union.
513                FunctionType * memCtorType = genDefaultType( type );
514                for ( Declaration * member : aggregateDecl->members ) {
515                        DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member );
516                        if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
517                                // don't make a function whose parameter is an unnamed bitfield
518                                break;
519                        }
520                        // do not carry over field's attributes to parameter type
521                        Type * paramType = field->get_type()->clone();
522                        deleteAll( paramType->attributes );
523                        paramType->attributes.clear();
524                        // add a parameter corresponding to this field
525                        memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, paramType, nullptr ) );
526                        FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
527                        ObjectDecl * srcParam = strict_dynamic_cast<ObjectDecl *>( ctor->type->parameters.back() );
528                        srcParam->fixUniqueId();
529                        ObjectDecl * dstParam = InitTweak::getParamThis( ctor->type );
530                        makeMemberOp( srcParam, dstParam, back_inserter( ctor->statements->kids ) );
531                        resolve( ctor );
532                        // only generate one field ctor for unions
533                        break;
534                }
535                delete memCtorType;
536        }
537
538        void EnumFuncGenerator::genFuncBody( FunctionDecl * funcDecl ) {
539                // xxx - Temporary: make these functions intrinsic so they codegen as C assignment.
540                // Really they're something of a cross between instrinsic and autogen, so should
541                // probably make a new linkage type
542                funcDecl->linkage = LinkageSpec::Intrinsic;
543                FunctionType * ftype = funcDecl->type;
544                if ( InitTweak::isCopyConstructor( funcDecl ) || InitTweak::isAssignment( funcDecl ) ) {
545                        assert( ftype->parameters.size() == 2 );
546                        ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() );
547                        ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.back() );
548
549                        // enum copy construct and assignment is just C-style assignment.
550                        // this looks like a bad recursive call, but code gen will turn it into
551                        // a C-style assignment.
552                        // This happens before function pointer type conversion, so need to do it manually here
553                        ApplicationExpr * callExpr = new ApplicationExpr( VariableExpr::functionPointer( funcDecl ) );
554                        callExpr->get_args().push_back( new VariableExpr( dstParam ) );
555                        callExpr->get_args().push_back( new VariableExpr( srcParam ) );
556                        funcDecl->statements->push_back( new ExprStmt( callExpr ) );
557                } else {
558                        // default ctor/dtor body is empty - add unused attribute to parameter to silence warnings
559                        assert( ftype->parameters.size() == 1 );
560                        ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() );
561                        dstParam->attributes.push_back( new Attribute( "unused" ) );
562                }
563        }
564
565        bool EnumFuncGenerator::shouldAutogen() const { return true; }
566        bool EnumFuncGenerator::isConcurrentType() const { return false; }
567        // enums do not have field constructors
568        void EnumFuncGenerator::genFieldCtors() {}
569
570        bool TypeFuncGenerator::shouldAutogen() const { return true; };
571
572        void TypeFuncGenerator::genFuncBody( FunctionDecl * dcl ) {
573                FunctionType * ftype = dcl->type;
574                assertf( ftype->parameters.size() == 1 || ftype->parameters.size() == 2, "Incorrect number of parameters in autogenerated typedecl function: %zd", ftype->parameters.size() );
575                DeclarationWithType * dst = ftype->parameters.front();
576                DeclarationWithType * src = ftype->parameters.size() == 2 ? ftype->parameters.back() : nullptr;
577                // generate appropriate calls to member ctor, assignment
578                UntypedExpr * expr = new UntypedExpr( new NameExpr( dcl->name ) );
579                expr->args.push_back( new CastExpr( new VariableExpr( dst ), new ReferenceType( Type::Qualifiers(), typeDecl->base->clone() ) ) );
580                if ( src ) expr->args.push_back( new CastExpr( new VariableExpr( src ), typeDecl->base->clone() ) );
581                dcl->statements->kids.push_back( new ExprStmt( expr ) );
582        };
583
584        // xxx - should reach in and determine if base type is concurrent?
585        bool TypeFuncGenerator::isConcurrentType() const { return false; };
586
587        // opaque types do not have field constructors
588        void TypeFuncGenerator::genFieldCtors() {};
589
590        //=============================================================================================
591        // Visitor definitions
592        //=============================================================================================
593        AutogenerateRoutines::AutogenerateRoutines() {
594                // the order here determines the order that these functions are generated.
595                // assignment should come last since it uses copy constructor in return.
596                data.emplace_back( "?{}", genDefaultType );
597                data.emplace_back( "?{}", genCopyType );
598                data.emplace_back( "^?{}", genDefaultType );
599                data.emplace_back( "?=?", genAssignType );
600        }
601
602        void AutogenerateRoutines::previsit( EnumDecl * enumDecl ) {
603                // must visit children (enum constants) to add them to the indexer
604                if ( enumDecl->has_body() ) {
605                        EnumInstType enumInst( Type::Qualifiers(), enumDecl->get_name() );
606                        enumInst.set_baseEnum( enumDecl );
607                        EnumFuncGenerator gen( &enumInst, data, functionNesting, indexer );
608                        generateFunctions( gen, declsToAddAfter );
609                }
610        }
611
612        void AutogenerateRoutines::previsit( StructDecl * structDecl ) {
613                visit_children = false;
614                if ( structDecl->has_body() ) {
615                        StructInstType structInst( Type::Qualifiers(), structDecl->name );
616                        structInst.set_baseStruct( structDecl );
617                        for ( TypeDecl * typeDecl : structDecl->parameters ) {
618                                structInst.parameters.push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->name, typeDecl ) ) );
619                        }
620                        StructFuncGenerator gen( structDecl, &structInst, data, functionNesting, indexer );
621                        generateFunctions( gen, declsToAddAfter );
622                } // if
623        }
624
625        void AutogenerateRoutines::previsit( UnionDecl * unionDecl ) {
626                visit_children = false;
627                if ( unionDecl->has_body()  ) {
628                        UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() );
629                        unionInst.set_baseUnion( unionDecl );
630                        for ( TypeDecl * typeDecl : unionDecl->get_parameters() ) {
631                                unionInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
632                        }
633                        UnionFuncGenerator gen( unionDecl, &unionInst, data, functionNesting, indexer );
634                        generateFunctions( gen, declsToAddAfter );
635                } // if
636        }
637
638        // generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
639        void AutogenerateRoutines::previsit( TypeDecl * typeDecl ) {
640                if ( ! typeDecl->base ) return;
641
642                TypeInstType refType( Type::Qualifiers(), typeDecl->name, typeDecl );
643                TypeFuncGenerator gen( typeDecl, &refType, data, functionNesting, indexer );
644                generateFunctions( gen, declsToAddAfter );
645
646        }
647
648        void AutogenerateRoutines::previsit( TraitDecl * ) {
649                // ensure that we don't add assignment ops for types defined as part of the trait
650                visit_children = false;
651        }
652
653        void AutogenerateRoutines::previsit( FunctionDecl * ) {
654                // Track whether we're currently in a function.
655                // Can ignore function type idiosyncrasies, because function type can never
656                // declare a new type.
657                functionNesting += 1;
658                GuardAction( [this]()  { functionNesting -= 1; } );
659        }
660
661        void AutogenerateRoutines::previsit( CompoundStmt * ) {
662                GuardScope( structsDone );
663        }
664
665        void makeTupleFunctionBody( FunctionDecl * function ) {
666                FunctionType * ftype = function->get_functionType();
667                assertf( ftype->get_parameters().size() == 1 || ftype->get_parameters().size() == 2, "too many parameters in generated tuple function" );
668
669                UntypedExpr * untyped = new UntypedExpr( new NameExpr( function->get_name() ) );
670
671                /// xxx - &* is used to make this easier for later passes to handle
672                untyped->get_args().push_back( new AddressExpr( UntypedExpr::createDeref( new VariableExpr( ftype->get_parameters().front() ) ) ) );
673                if ( ftype->get_parameters().size() == 2 ) {
674                        untyped->get_args().push_back( new VariableExpr( ftype->get_parameters().back() ) );
675                }
676                function->get_statements()->get_kids().push_back( new ExprStmt( untyped ) );
677                function->get_statements()->get_kids().push_back( new ReturnStmt( UntypedExpr::createDeref( new VariableExpr( ftype->get_parameters().front() ) ) ) );
678        }
679
680        void AutogenTupleRoutines::postvisit( TupleType * tupleType ) {
681                std::string mangleName = SymTab::Mangler::mangleType( tupleType );
682                if ( seenTuples.find( mangleName ) != seenTuples.end() ) return;
683                seenTuples.insert( mangleName );
684
685                // T ?=?(T *, T);
686                FunctionType *assignType = genAssignType( tupleType );
687
688                // void ?{}(T *); void ^?{}(T *);
689                FunctionType *ctorType = genDefaultType( tupleType );
690                FunctionType *dtorType = genDefaultType( tupleType );
691
692                // void ?{}(T *, T);
693                FunctionType *copyCtorType = genCopyType( tupleType );
694
695                std::set< TypeDecl* > done;
696                std::list< TypeDecl * > typeParams;
697                for ( Type * t : *tupleType ) {
698                        if ( TypeInstType * ty = dynamic_cast< TypeInstType * >( t ) ) {
699                                if ( ! done.count( ty->get_baseType() ) ) {
700                                        TypeDecl * newDecl = new TypeDecl( ty->get_baseType()->get_name(), Type::StorageClasses(), nullptr, TypeDecl::Dtype, true );
701                                        TypeInstType * inst = new TypeInstType( Type::Qualifiers(), newDecl->get_name(), newDecl );
702                                        newDecl->get_assertions().push_back( new FunctionDecl( "?=?", Type::StorageClasses(), LinkageSpec::Cforall, genAssignType( inst ), nullptr,
703                                                                                                                                                   std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) ) );
704                                        newDecl->get_assertions().push_back( new FunctionDecl( "?{}", Type::StorageClasses(), LinkageSpec::Cforall, genDefaultType( inst ), nullptr,
705                                                                                                                                                   std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) ) );
706                                        newDecl->get_assertions().push_back( new FunctionDecl( "?{}", Type::StorageClasses(), LinkageSpec::Cforall, genCopyType( inst ), nullptr,
707                                                                                                                                                   std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) ) );
708                                        newDecl->get_assertions().push_back( new FunctionDecl( "^?{}", Type::StorageClasses(), LinkageSpec::Cforall, genDefaultType( inst ), nullptr,
709                                                                                                                                                   std::list< Attribute * >(), Type::FuncSpecifiers( Type::Inline ) ) );
710                                        typeParams.push_back( newDecl );
711                                        done.insert( ty->get_baseType() );
712                                }
713                        }
714                }
715                cloneAll( typeParams, ctorType->get_forall() );
716                cloneAll( typeParams, dtorType->get_forall() );
717                cloneAll( typeParams, copyCtorType->get_forall() );
718                cloneAll( typeParams, assignType->get_forall() );
719
720                FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
721                FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting );
722                FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
723                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
724
725                makeTupleFunctionBody( assignDecl );
726                makeTupleFunctionBody( ctorDecl );
727                makeTupleFunctionBody( copyCtorDecl );
728                makeTupleFunctionBody( dtorDecl );
729
730                declsToAddBefore.push_back( ctorDecl );
731                declsToAddBefore.push_back( copyCtorDecl );
732                declsToAddBefore.push_back( dtorDecl );
733                declsToAddBefore.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return
734        }
735
736        void AutogenTupleRoutines::previsit( FunctionDecl *functionDecl ) {
737                visit_children = false;
738                maybeAccept( functionDecl->type, *visitor );
739                functionNesting += 1;
740                maybeAccept( functionDecl->statements, *visitor );
741                functionNesting -= 1;
742        }
743
744        void AutogenTupleRoutines::previsit( CompoundStmt * ) {
745                GuardScope( seenTuples );
746        }
747} // SymTab
748
749// Local Variables: //
750// tab-width: 4 //
751// mode: c++ //
752// compile-command: "make install" //
753// End: //
Note: See TracBrowser for help on using the repository browser.