source: src/SymTab/Autogen.cc@ e213560

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since e213560 was 33218c6, checked in by Thierry Delisle <tdelisle@…>, 8 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

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