source: src/SymTab/Autogen.cc @ bd98b58

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since bd98b58 was 1486116, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

autogenerate functions for seen tuple types

  • Property mode set to 100644
File size: 31.5 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 : Tue Jul 12 17:47:17 2016
13// Update Count     : 2
14//
15
16#include <list>
17#include <iterator>
18#include "SynTree/Visitor.h"
19#include "SynTree/Type.h"
20#include "SynTree/Statement.h"
21#include "SynTree/TypeSubstitution.h"
22#include "Common/utility.h"
23#include "AddVisit.h"
24#include "MakeLibCfa.h"
25#include "Autogen.h"
26#include "GenPoly/ScopedSet.h"
27#include "SymTab/Mangler.h"
28#include "GenPoly/DeclMutator.h"
29
30namespace SymTab {
31        Type * SizeType = 0;
32
33        class AutogenerateRoutines : public Visitor {
34          public:
35                std::list< Declaration * > &get_declsToAdd() { return declsToAdd; }
36
37                typedef Visitor Parent;
38                using Parent::visit;
39
40                virtual void visit( EnumDecl *enumDecl );
41                virtual void visit( StructDecl *structDecl );
42                virtual void visit( UnionDecl *structDecl );
43                virtual void visit( TypeDecl *typeDecl );
44                virtual void visit( TraitDecl *ctxDecl );
45                virtual void visit( FunctionDecl *functionDecl );
46
47                virtual void visit( FunctionType *ftype );
48                virtual void visit( PointerType *ftype );
49
50                virtual void visit( CompoundStmt *compoundStmt );
51                virtual void visit( SwitchStmt *switchStmt );
52
53          private:
54                template< typename StmtClass > void visitStatement( StmtClass *stmt );
55
56                std::list< Declaration * > declsToAdd;
57                std::set< std::string > structsDone;
58                unsigned int functionNesting = 0;     // current level of nested functions
59        };
60
61        /// generates routines for tuple types.
62        /// Doesn't really need to be a mutator, but it's easier to reuse DeclMutator than it is to use AddVisit
63        /// or anything we currently have that supports adding new declarations for visitors
64        class AutogenTupleRoutines : public GenPoly::DeclMutator {
65          public:
66                typedef GenPoly::DeclMutator Parent;
67                using Parent::mutate;
68
69                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl );
70
71                virtual Type * mutate( TupleType *tupleType );
72
73                virtual CompoundStmt * mutate( CompoundStmt *compoundStmt );
74
75          private:
76                unsigned int functionNesting = 0;     // current level of nested functions
77                GenPoly::ScopedSet< std::string > seenTuples;
78        };
79
80        void autogenerateRoutines( std::list< Declaration * > &translationUnit ) {
81                AutogenerateRoutines generator;
82                acceptAndAdd( translationUnit, generator, false );
83
84                // needs to be done separately because AutogenerateRoutines skips types that appear as function arguments, etc.
85                // AutogenTupleRoutines tupleGenerator;
86                // tupleGenerator.mutateDeclarationList( translationUnit );
87        }
88
89        bool isUnnamedBitfield( ObjectDecl * obj ) {
90                return obj != NULL && obj->get_name() == "" && obj->get_bitfieldWidth() != NULL;
91        }
92
93        /// inserts a forward declaration for functionDecl into declsToAdd
94        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
95                FunctionDecl * decl = functionDecl->clone();
96                delete decl->get_statements();
97                decl->set_statements( NULL );
98                declsToAdd.push_back( decl );
99                decl->fixUniqueId();
100        }
101
102        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
103        FunctionType * genDefaultType( Type * paramType ) {
104                FunctionType *ftype = new FunctionType( Type::Qualifiers(), false );
105                ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), paramType->clone() ), nullptr );
106                ftype->get_parameters().push_back( dstParam );
107
108                return ftype;
109        }
110
111        /// given type T, generate type of copy ctor, i.e. function type void (*) (T *, T)
112        FunctionType * genCopyType( Type * paramType ) {
113                FunctionType *ftype = genDefaultType( paramType );
114                ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
115                ftype->get_parameters().push_back( srcParam );
116                return ftype;
117        }
118
119        /// given type T, generate type of assignment, i.e. function type T (*) (T *, T)
120        FunctionType * genAssignType( Type * paramType ) {
121                FunctionType *ftype = genCopyType( paramType );
122                ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
123                ftype->get_returnVals().push_back( returnVal );
124                return ftype;
125        }
126
127        /// true if the aggregate's layout is dynamic
128        template< typename AggrDecl >
129        bool hasDynamicLayout( AggrDecl * aggregateDecl ) {
130                for ( TypeDecl * param : aggregateDecl->get_parameters() ) {
131                        if ( param->get_kind() == TypeDecl::Any ) return true;
132                }
133                return false;
134        }
135
136        /// generate a function decl from a name and type. Nesting depth determines whether
137        /// the declaration is static or not; optional paramter determines if declaration is intrinsic
138        FunctionDecl * genFunc( const std::string & fname, FunctionType * ftype, unsigned int functionNesting, bool isIntrinsic = false  ) {
139                // Routines at global scope marked "static" to prevent multiple definitions in separate translation units
140                // because each unit generates copies of the default routines for each aggregate.
141                DeclarationNode::StorageClass sc = functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static;
142                LinkageSpec::Spec spec = isIntrinsic ? LinkageSpec::Intrinsic : LinkageSpec::AutoGen;
143                FunctionDecl * decl = new FunctionDecl( fname, sc, spec, ftype, new CompoundStmt( noLabels ), true, false );
144                decl->fixUniqueId();
145                return decl;
146        }
147
148        /// generates a single enumeration assignment expression
149        ApplicationExpr * genEnumAssign( FunctionType * ftype, FunctionDecl * assignDecl ) {
150                // enum copy construct and assignment is just C-style assignment.
151                // this looks like a bad recursive call, but code gen will turn it into
152                // a C-style assignment.
153                // This happens before function pointer type conversion, so need to do it manually here
154                // NOTE: ftype is not necessarily the functionType belonging to assignDecl - ftype is the
155                // type of the function that this expression is being generated for (so that the correct
156                // parameters) are using in the variable exprs
157                assert( ftype->get_parameters().size() == 2 );
158                ObjectDecl * dstParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
159                ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
160
161                VariableExpr * assignVarExpr = new VariableExpr( assignDecl );
162                Type * assignVarExprType = assignVarExpr->get_result();
163                assignVarExprType = new PointerType( Type::Qualifiers(), assignVarExprType );
164                assignVarExpr->set_result( assignVarExprType );
165                ApplicationExpr * assignExpr = new ApplicationExpr( assignVarExpr );
166                assignExpr->get_args().push_back( new VariableExpr( dstParam ) );
167                assignExpr->get_args().push_back( new VariableExpr( srcParam ) );
168                return assignExpr;
169        }
170
171        // E ?=?(E volatile*, int),
172        //   ?=?(E _Atomic volatile*, int);
173        void makeEnumFunctions( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
174
175                // T ?=?(E *, E);
176                FunctionType *assignType = genAssignType( refType );
177
178                // void ?{}(E *); void ^?{}(E *);
179                FunctionType * ctorType = genDefaultType( refType->clone() );
180                FunctionType * dtorType = genDefaultType( refType->clone() );
181
182                // void ?{}(E *, E);
183                FunctionType *copyCtorType = genCopyType( refType->clone() );
184
185                // xxx - should we also generate void ?{}(E *, int) and E ?{}(E *, E)?
186                // right now these cases work, but that might change.
187
188                // xxx - Temporary: make these functions intrinsic so they codegen as C assignment.
189                // Really they're something of a cross between instrinsic and autogen, so should
190                // probably make a new linkage type
191                FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting, true );
192                FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting, true );
193                FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting, true );
194                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting, true );
195
196                // body is either return stmt or expr stmt
197                assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, genEnumAssign( assignType, assignDecl ) ) );
198                copyCtorDecl->get_statements()->get_kids().push_back( new ExprStmt( noLabels, genEnumAssign( copyCtorType, assignDecl ) ) );
199
200                declsToAdd.push_back( ctorDecl );
201                declsToAdd.push_back( copyCtorDecl );
202                declsToAdd.push_back( dtorDecl );
203                declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return
204        }
205
206        /// generates a single struct member operation (constructor call, destructor call, assignment call)
207        void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool isDynamicLayout, bool forward = true ) {
208                ObjectDecl * returnVal = NULL;
209                if ( ! func->get_functionType()->get_returnVals().empty() ) {
210                        returnVal = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_returnVals().front() );
211                }
212
213                InitTweak::InitExpander srcParam( src );
214
215                // assign to destination (and return value if generic)
216                UntypedExpr *derefExpr = UntypedExpr::createDeref( new VariableExpr( dstParam ) );
217                Expression *dstselect = new MemberExpr( field, derefExpr );
218                genImplicitCall( srcParam, dstselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
219
220                if ( isDynamicLayout && returnVal ) {
221                        // xxx - there used to be a dereference on returnVal, but this seems to have been wrong?
222                        Expression *retselect = new MemberExpr( field, new VariableExpr( returnVal ) );
223                        genImplicitCall( srcParam, retselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
224                } // if
225        }
226
227        /// 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
228        template<typename Iterator>
229        void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool isDynamicLayout, bool forward = true ) {
230                for ( ; member != end; ++member ) {
231                        if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate
232                                // query the type qualifiers of this field and skip assigning it if it is marked const.
233                                // If it is an array type, we need to strip off the array layers to find its qualifiers.
234                                Type * type = field->get_type();
235                                while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
236                                        type = at->get_base();
237                                }
238
239                                if ( type->get_qualifiers().isConst && func->get_name() == "?=?" ) {
240                                        // don't assign const members, but do construct/destruct
241                                        continue;
242                                }
243
244                                if ( field->get_name() == "" ) {
245                                        // don't assign to anonymous members
246                                        // xxx - this is a temporary fix. Anonymous members tie into
247                                        // our inheritance model. I think the correct way to handle this is to
248                                        // cast the structure to the type of the member and let the resolver
249                                        // figure out whether it's valid and have a pass afterwards that fixes
250                                        // the assignment to use pointer arithmetic with the offset of the
251                                        // member, much like how generic type members are handled.
252                                        continue;
253                                }
254
255                                assert( ! func->get_functionType()->get_parameters().empty() );
256                                ObjectDecl * dstParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().front() );
257                                ObjectDecl * srcParam = NULL;
258                                if ( func->get_functionType()->get_parameters().size() == 2 ) {
259                                        srcParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().back() );
260                                }
261                                // srcParam may be NULL, in which case we have default ctor/dtor
262                                assert( dstParam );
263
264                                Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : NULL;
265                                makeStructMemberOp( dstParam, srcselect, field, func, isDynamicLayout, forward );
266                        } // if
267                } // for
268        } // makeStructFunctionBody
269
270        /// generate the body of a constructor which takes parameters that match fields, e.g.
271        /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.
272        template<typename Iterator>
273        void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func, bool isDynamicLayout ) {
274                FunctionType * ftype = func->get_functionType();
275                std::list<DeclarationWithType*> & params = ftype->get_parameters();
276                assert( params.size() >= 2 );  // should not call this function for default ctor, etc.
277
278                // skip 'this' parameter
279                ObjectDecl * dstParam = dynamic_cast<ObjectDecl*>( params.front() );
280                assert( dstParam );
281                std::list<DeclarationWithType*>::iterator parameter = params.begin()+1;
282                for ( ; member != end; ++member ) {
283                        if ( DeclarationWithType * field = dynamic_cast<DeclarationWithType*>( *member ) ) {
284                                if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
285                                        // don't make a function whose parameter is an unnamed bitfield
286                                        continue;
287                                } else if ( field->get_name() == "" ) {
288                                        // don't assign to anonymous members
289                                        // xxx - this is a temporary fix. Anonymous members tie into
290                                        // our inheritance model. I think the correct way to handle this is to
291                                        // cast the structure to the type of the member and let the resolver
292                                        // figure out whether it's valid and have a pass afterwards that fixes
293                                        // the assignment to use pointer arithmetic with the offset of the
294                                        // member, much like how generic type members are handled.
295                                        continue;
296                                } else if ( parameter != params.end() ) {
297                                        // matching parameter, initialize field with copy ctor
298                                        Expression *srcselect = new VariableExpr(*parameter);
299                                        makeStructMemberOp( dstParam, srcselect, field, func, isDynamicLayout );
300                                        ++parameter;
301                                } else {
302                                        // no matching parameter, initialize field with default ctor
303                                        makeStructMemberOp( dstParam, NULL, field, func, isDynamicLayout );
304                                }
305                        }
306                }
307        }
308
309        /// generates struct constructors, destructor, and assignment functions
310        void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
311
312                // Make function polymorphic in same parameters as generic struct, if applicable
313                const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
314                bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
315
316                // T ?=?(T *, T);
317                FunctionType *assignType = genAssignType( refType );
318                cloneAll( typeParams, assignType->get_forall() );
319
320                // void ?{}(T *); void ^?{}(T *);
321                FunctionType *ctorType = genDefaultType( refType );
322                cloneAll( typeParams, ctorType->get_forall() );
323                FunctionType *dtorType = genDefaultType( refType );
324                cloneAll( typeParams, dtorType->get_forall() );
325
326                // void ?{}(T *, T);
327                FunctionType *copyCtorType = genCopyType( refType );
328                cloneAll( typeParams, copyCtorType->get_forall() );
329
330                FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
331                FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting );
332                FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
333                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
334
335                if ( functionNesting == 0 ) {
336                        // forward declare if top-level struct, so that
337                        // type is complete as soon as its body ends
338                        // Note: this is necessary if we want structs which contain
339                        // generic (otype) structs as members.
340                        addForwardDecl( assignDecl, declsToAdd );
341                        addForwardDecl( ctorDecl, declsToAdd );
342                        addForwardDecl( copyCtorDecl, declsToAdd );
343                        addForwardDecl( dtorDecl, declsToAdd );
344                }
345
346                // create constructors which take each member type as a parameter.
347                // for example, for struct A { int x, y; }; generate
348                // void ?{}(A *, int) and void ?{}(A *, int, int)
349                std::list<Declaration *> memCtors;
350                FunctionType * memCtorType = ctorType->clone();
351                for ( std::list<Declaration *>::iterator i = aggregateDecl->get_members().begin(); i != aggregateDecl->get_members().end(); ++i ) {
352                        DeclarationWithType * member = dynamic_cast<DeclarationWithType *>( *i );
353                        assert( member );
354                        if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( member ) ) ) {
355                                // don't make a function whose parameter is an unnamed bitfield
356                                continue;
357                        } else if ( member->get_name() == "" ) {
358                                // don't assign to anonymous members
359                                // xxx - this is a temporary fix. Anonymous members tie into
360                                // our inheritance model. I think the correct way to handle this is to
361                                // cast the structure to the type of the member and let the resolver
362                                // figure out whether it's valid and have a pass afterwards that fixes
363                                // the assignment to use pointer arithmetic with the offset of the
364                                // member, much like how generic type members are handled.
365                                continue;
366                        }
367                        memCtorType->get_parameters().push_back( new ObjectDecl( member->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, member->get_type()->clone(), 0 ) );
368                        FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
369                        makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, isDynamicLayout );
370                        memCtors.push_back( ctor );
371                }
372                delete memCtorType;
373
374                // generate appropriate calls to member ctor, assignment
375                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, isDynamicLayout );
376                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, isDynamicLayout );
377                makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, isDynamicLayout );
378                // needs to do everything in reverse, so pass "forward" as false
379                makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, isDynamicLayout, false );
380
381                assert( assignType->get_parameters().size() == 2 );
382                ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( assignType->get_parameters().back() );
383                assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
384
385                declsToAdd.push_back( ctorDecl );
386                declsToAdd.push_back( copyCtorDecl );
387                declsToAdd.push_back( dtorDecl );
388                declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return
389                declsToAdd.splice( declsToAdd.end(), memCtors );
390        }
391
392        /// generate a single union assignment expression (using memcpy)
393        template< typename OutputIterator >
394        void makeUnionFieldsAssignment( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) {
395                UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) );
396                copy->get_args().push_back( new VariableExpr( dstParam ) );
397                copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
398                copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
399                *out++ = new ExprStmt( noLabels, copy );
400        }
401
402        /// generates the body of a union assignment/copy constructor/field constructor
403        void makeUnionAssignBody( FunctionDecl * funcDecl, bool isDynamicLayout ) {
404                FunctionType * ftype = funcDecl->get_functionType();
405                assert( ftype->get_parameters().size() == 2 );
406                ObjectDecl * dstParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
407                ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
408                ObjectDecl * returnVal = nullptr;
409                if ( ! ftype->get_returnVals().empty() ) {
410                        returnVal = safe_dynamic_cast< ObjectDecl * >( ftype->get_returnVals().front() );
411                }
412
413                makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( funcDecl->get_statements()->get_kids() ) );
414                if ( returnVal ) {
415                        if ( isDynamicLayout ) makeUnionFieldsAssignment( srcParam, returnVal, back_inserter( funcDecl->get_statements()->get_kids() ) );
416                        else funcDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
417                }
418        }
419
420        /// generates union constructors, destructors, and assignment operator
421        void makeUnionFunctions( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
422                // Make function polymorphic in same parameters as generic union, if applicable
423                const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
424                bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
425
426                // default ctor/dtor need only first parameter
427                // void ?{}(T *); void ^?{}(T *);
428                FunctionType *ctorType = genDefaultType( refType );
429                FunctionType *dtorType = genDefaultType( refType );
430
431                // copy ctor needs both parameters
432                // void ?{}(T *, T);
433                FunctionType *copyCtorType = genCopyType( refType );
434
435                // assignment needs both and return value
436                // T ?=?(T *, T);
437                FunctionType *assignType = genAssignType( refType );
438
439                cloneAll( typeParams, ctorType->get_forall() );
440                cloneAll( typeParams, dtorType->get_forall() );
441                cloneAll( typeParams, copyCtorType->get_forall() );
442                cloneAll( typeParams, assignType->get_forall() );
443
444                // Routines at global scope marked "static" to prevent multiple definitions is separate translation units
445                // because each unit generates copies of the default routines for each aggregate.
446                FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
447                FunctionDecl *ctorDecl = genFunc( "?{}",  ctorType, functionNesting );
448                FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
449                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
450
451                makeUnionAssignBody( assignDecl, isDynamicLayout );
452
453                // body of assignment and copy ctor is the same
454                makeUnionAssignBody( copyCtorDecl, isDynamicLayout );
455
456                // create a constructor which takes the first member type as a parameter.
457                // for example, for Union A { int x; double y; }; generate
458                // void ?{}(A *, int)
459                // This is to mimic C's behaviour which initializes the first member of the union.
460                std::list<Declaration *> memCtors;
461                for ( Declaration * member : aggregateDecl->get_members() ) {
462                        if ( DeclarationWithType * field = dynamic_cast< DeclarationWithType * >( member ) ) {
463                                ObjectDecl * srcParam = new ObjectDecl( "src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 );
464
465                                FunctionType * memCtorType = ctorType->clone();
466                                memCtorType->get_parameters().push_back( srcParam );
467                                FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting );
468
469                                makeUnionAssignBody( ctor, isDynamicLayout );
470                                memCtors.push_back( ctor );
471                                // only generate a ctor for the first field
472                                break;
473                        }
474                }
475
476                declsToAdd.push_back( ctorDecl );
477                declsToAdd.push_back( copyCtorDecl );
478                declsToAdd.push_back( dtorDecl );
479                declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return
480                declsToAdd.splice( declsToAdd.end(), memCtors );
481        }
482
483        void AutogenerateRoutines::visit( EnumDecl *enumDecl ) {
484                if ( ! enumDecl->get_members().empty() ) {
485                        EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() );
486                        // enumInst->set_baseEnum( enumDecl );
487                        // declsToAdd.push_back(
488                        makeEnumFunctions( enumDecl, enumInst, functionNesting, declsToAdd );
489                }
490        }
491
492        void AutogenerateRoutines::visit( StructDecl *structDecl ) {
493                if ( ! structDecl->get_members().empty() && structsDone.find( structDecl->get_name() ) == structsDone.end() ) {
494                        StructInstType structInst( Type::Qualifiers(), structDecl->get_name() );
495                        for ( TypeDecl * typeDecl : structDecl->get_parameters() ) {
496                                structInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
497                        }
498                        structInst.set_baseStruct( structDecl );
499                        makeStructFunctions( structDecl, &structInst, functionNesting, declsToAdd );
500                        structsDone.insert( structDecl->get_name() );
501                } // if
502        }
503
504        void AutogenerateRoutines::visit( UnionDecl *unionDecl ) {
505                if ( ! unionDecl->get_members().empty() ) {
506                        UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() );
507                        unionInst.set_baseUnion( unionDecl );
508                        for ( TypeDecl * typeDecl : unionDecl->get_parameters() ) {
509                                unionInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
510                        }
511                        makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAdd );
512                } // if
513        }
514
515        void AutogenerateRoutines::visit( TypeDecl *typeDecl ) {
516                TypeInstType *typeInst = new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), false );
517                typeInst->set_baseType( typeDecl );
518                ObjectDecl *src = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, typeInst->clone(), nullptr );
519                ObjectDecl *dst = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), typeInst->clone() ), nullptr );
520
521                std::list< Statement * > stmts;
522                if ( typeDecl->get_base() ) {
523                        // xxx - generate ctor/dtors for typedecls, e.g.
524                        // otype T = int *;
525                        UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) );
526                        assign->get_args().push_back( new CastExpr( new VariableExpr( dst ), new PointerType( Type::Qualifiers(), typeDecl->get_base()->clone() ) ) );
527                        assign->get_args().push_back( new CastExpr( new VariableExpr( src ), typeDecl->get_base()->clone() ) );
528                        stmts.push_back( new ReturnStmt( std::list< Label >(), assign ) );
529                } // if
530                FunctionType *type = new FunctionType( Type::Qualifiers(), false );
531                type->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, typeInst, 0 ) );
532                type->get_parameters().push_back( dst );
533                type->get_parameters().push_back( src );
534                FunctionDecl *func = genFunc( "?=?", type, functionNesting );
535                func->get_statements()->get_kids() = stmts;
536                declsToAdd.push_back( func );
537        }
538
539        void addDecls( std::list< Declaration * > &declsToAdd, std::list< Statement * > &statements, std::list< Statement * >::iterator i ) {
540                for ( std::list< Declaration * >::iterator decl = declsToAdd.begin(); decl != declsToAdd.end(); ++decl ) {
541                        statements.insert( i, new DeclStmt( noLabels, *decl ) );
542                } // for
543                declsToAdd.clear();
544        }
545
546        void AutogenerateRoutines::visit( FunctionType *) {
547                // ensure that we don't add assignment ops for types defined as part of the function
548        }
549
550        void AutogenerateRoutines::visit( PointerType *) {
551                // ensure that we don't add assignment ops for types defined as part of the pointer
552        }
553
554        void AutogenerateRoutines::visit( TraitDecl *) {
555                // ensure that we don't add assignment ops for types defined as part of the trait
556        }
557
558        template< typename StmtClass >
559        inline void AutogenerateRoutines::visitStatement( StmtClass *stmt ) {
560                std::set< std::string > oldStructs = structsDone;
561                addVisit( stmt, *this );
562                structsDone = oldStructs;
563        }
564
565        void AutogenerateRoutines::visit( FunctionDecl *functionDecl ) {
566                maybeAccept( functionDecl->get_functionType(), *this );
567                acceptAll( functionDecl->get_oldDecls(), *this );
568                functionNesting += 1;
569                maybeAccept( functionDecl->get_statements(), *this );
570                functionNesting -= 1;
571        }
572
573        void AutogenerateRoutines::visit( CompoundStmt *compoundStmt ) {
574                visitStatement( compoundStmt );
575        }
576
577        void AutogenerateRoutines::visit( SwitchStmt *switchStmt ) {
578                visitStatement( switchStmt );
579        }
580
581        void makeTupleFunctionBody( FunctionDecl * function ) {
582                FunctionType * ftype = function->get_functionType();
583                assertf( ftype->get_parameters().size() == 1 || ftype->get_parameters().size() == 2, "too many parameters in generated tuple function" );
584
585                UntypedExpr * untyped = new UntypedExpr( new NameExpr( function->get_name() ) );
586
587                /// xxx - &* is used to make this easier for later passes to handle
588                untyped->get_args().push_back( new AddressExpr( UntypedExpr::createDeref( new VariableExpr( ftype->get_parameters().front() ) ) ) );
589                if ( ftype->get_parameters().size() == 2 ) {
590                        untyped->get_args().push_back( new VariableExpr( ftype->get_parameters().back() ) );
591                }
592                function->get_statements()->get_kids().push_back( new ExprStmt( noLabels, untyped ) );
593                function->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, UntypedExpr::createDeref( new VariableExpr( ftype->get_parameters().front() ) ) ) );
594        }
595
596        Type * AutogenTupleRoutines::mutate( TupleType * tupleType ) {
597                tupleType = safe_dynamic_cast< TupleType * >( Parent::mutate( tupleType ) );
598                std::string mangleName = SymTab::Mangler::mangleType( tupleType );
599                if ( seenTuples.find( mangleName ) != seenTuples.end() ) return tupleType;
600                seenTuples.insert( mangleName );
601
602                // T ?=?(T *, T);
603                FunctionType *assignType = genAssignType( tupleType );
604
605                // void ?{}(T *); void ^?{}(T *);
606                FunctionType *ctorType = genDefaultType( tupleType );
607                FunctionType *dtorType = genDefaultType( tupleType );
608
609                // void ?{}(T *, T);
610                FunctionType *copyCtorType = genCopyType( tupleType );
611
612                std::set< TypeDecl* > done;
613                std::list< TypeDecl * > typeParams;
614                for ( Type * t : *tupleType ) {
615                        if ( TypeInstType * ty = dynamic_cast< TypeInstType * >( t ) ) {
616                                if ( ! done.count( ty->get_baseType() ) ) {
617                                        TypeDecl * newDecl = new TypeDecl( ty->get_baseType()->get_name(), DeclarationNode::NoStorageClass, nullptr, TypeDecl::Any );
618                                        TypeInstType * inst = new TypeInstType( Type::Qualifiers(), newDecl->get_name(), newDecl );
619                                        newDecl->get_assertions().push_back( new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, genAssignType( inst ), nullptr, true, false ) );
620                                        newDecl->get_assertions().push_back( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, genDefaultType( inst ), nullptr, true, false ) );
621                                        newDecl->get_assertions().push_back( new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, genCopyType( inst ), nullptr, true, false ) );
622                                        newDecl->get_assertions().push_back( new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, genDefaultType( inst ), nullptr, true, false ) );
623                                        typeParams.push_back( newDecl );
624                                        done.insert( ty->get_baseType() );
625                                }
626                        }
627                }
628                cloneAll( typeParams, ctorType->get_forall() );
629                cloneAll( typeParams, dtorType->get_forall() );
630                cloneAll( typeParams, copyCtorType->get_forall() );
631                cloneAll( typeParams, assignType->get_forall() );
632
633                FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
634                FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting );
635                FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
636                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
637
638                makeTupleFunctionBody( assignDecl );
639                makeTupleFunctionBody( ctorDecl );
640                makeTupleFunctionBody( copyCtorDecl );
641                makeTupleFunctionBody( dtorDecl );
642
643                addDeclaration( ctorDecl );
644                addDeclaration( copyCtorDecl );
645                addDeclaration( dtorDecl );
646                addDeclaration( assignDecl ); // assignment should come last since it uses copy constructor in return
647
648                return tupleType;
649        }
650
651        DeclarationWithType * AutogenTupleRoutines::mutate( FunctionDecl *functionDecl ) {
652                functionDecl->set_functionType( maybeMutate( functionDecl->get_functionType(), *this ) );
653                mutateAll( functionDecl->get_oldDecls(), *this );
654                functionNesting += 1;
655                functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
656                functionNesting -= 1;
657                return functionDecl;
658        }
659
660        CompoundStmt * AutogenTupleRoutines::mutate( CompoundStmt *compoundStmt ) {
661                seenTuples.beginScope();
662                compoundStmt = safe_dynamic_cast< CompoundStmt * >( Parent::mutate( compoundStmt ) );
663                seenTuples.endScope();
664                return compoundStmt;
665        }
666} // SymTab
Note: See TracBrowser for help on using the repository browser.