source: src/SymTab/Autogen.cc@ c84e80a

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 c84e80a was 1486116, checked in by Rob Schluntz <rschlunt@…>, 9 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.