source: src/SymTab/Autogen.cc@ 3a7aa94

Last change on this file since 3a7aa94 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 2 years ago

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

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