source: src/Validate/Autogen.cpp@ 53a768d

ADT ast-experimental pthread-emulation
Last change on this file since 53a768d was 4520b77e, checked in by JiadaL <j82liang@…>, 3 years ago

Merge to Master Sept 19

  • Property mode set to 100644
File size: 27.3 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.cpp -- Generate automatic routines for data types.
8//
9// Author : Andrew Beach
10// Created On : Thu Dec 2 13:44:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Thr Jan 27 9:29:00 2022
13// Update Count : 1
14//
15
16#include "Autogen.hpp"
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/Attribute.hpp"
27#include "AST/Decl.hpp"
28#include "AST/DeclReplacer.hpp"
29#include "AST/Expr.hpp"
30#include "AST/Inspect.hpp"
31#include "AST/Pass.hpp"
32#include "AST/Stmt.hpp"
33#include "AST/SymbolTable.hpp"
34#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
35#include "Common/ScopedMap.h" // for ScopedMap<>::const_iterator, Scope...
36#include "Common/utility.h" // for cloneAll, operator+
37#include "GenPoly/ScopedSet.h" // for ScopedSet, ScopedSet<>::iterator
38#include "InitTweak/GenInit.h" // for fixReturnStatements
39#include "InitTweak/InitTweak.h" // for isAssignment, isCopyConstructor
40#include "SymTab/Mangler.h" // for Mangler
41#include "CompilationState.h"
42
43// TODO: The other new ast function should be moved over to this file.
44#include "SymTab/Autogen.h"
45
46namespace Validate {
47
48namespace {
49
50// --------------------------------------------------------------------------
51struct AutogenerateRoutines_new final :
52 public ast::WithDeclsToAdd<>,
53 public ast::WithShortCircuiting {
54 void previsit( const ast::EnumDecl * enumDecl );
55 void previsit( const ast::StructDecl * structDecl );
56 void previsit( const ast::UnionDecl * structDecl );
57 void previsit( const ast::TypeDecl * typeDecl );
58 void previsit( const ast::TraitDecl * traitDecl );
59 void previsit( const ast::FunctionDecl * functionDecl );
60 void postvisit( const ast::FunctionDecl * functionDecl );
61
62private:
63 // Current level of nested functions.
64 unsigned int functionNesting = 0;
65};
66
67// --------------------------------------------------------------------------
68/// Class used to generate functions for a particular declaration.
69/// Note it isn't really stored, it is just a class for organization and to
70/// help pass around some of the common arguments.
71class FuncGenerator {
72public:
73 std::list<ast::ptr<ast::Decl>> forwards;
74 std::list<ast::ptr<ast::Decl>> definitions;
75
76 FuncGenerator( const ast::Type * type, unsigned int functionNesting ) :
77 type( type ), functionNesting( functionNesting )
78 {}
79
80 /// Generate functions (and forward decls.) and append them to the list.
81 void generateAndAppendFunctions( std::list<ast::ptr<ast::Decl>> & );
82
83 virtual bool shouldAutogen() const = 0;
84protected:
85 const ast::Type * type;
86 unsigned int functionNesting;
87 ast::Linkage::Spec proto_linkage = ast::Linkage::AutoGen;
88
89 // Internal helpers:
90 void genStandardFuncs();
91 void produceDecl( const ast::FunctionDecl * decl );
92 void produceForwardDecl( const ast::FunctionDecl * decl );
93
94 const CodeLocation& getLocation() const { return getDecl()->location; }
95 ast::FunctionDecl * genProto( const std::string& name,
96 std::vector<ast::ptr<ast::DeclWithType>>&& params,
97 std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const;
98
99 ast::ObjectDecl * dstParam() const;
100 ast::ObjectDecl * srcParam() const;
101 ast::FunctionDecl * genCtorProto() const;
102 ast::FunctionDecl * genCopyProto() const;
103 ast::FunctionDecl * genDtorProto() const;
104 ast::FunctionDecl * genAssignProto() const;
105 ast::FunctionDecl * genFieldCtorProto( unsigned int fields ) const;
106
107 // Internal Hooks:
108 virtual void genFuncBody( ast::FunctionDecl * decl ) = 0;
109 virtual void genFieldCtors() = 0;
110 virtual bool isConcurrentType() const { return false; }
111 virtual const ast::Decl * getDecl() const = 0;
112};
113
114class StructFuncGenerator final : public FuncGenerator {
115 const ast::StructDecl * decl;
116public:
117 StructFuncGenerator( const ast::StructDecl * decl,
118 const ast::StructInstType * type,
119 unsigned int functionNesting ) :
120 FuncGenerator( type, functionNesting ), decl( decl )
121 {}
122
123 // Built-ins do not use autogeneration.
124 bool shouldAutogen() const final { return !decl->linkage.is_builtin && !structHasFlexibleArray(decl); }
125private:
126 void genFuncBody( ast::FunctionDecl * decl ) final;
127 void genFieldCtors() final;
128 bool isConcurrentType() const final {
129 return decl->is_thread() || decl->is_monitor();
130 }
131 virtual const ast::Decl * getDecl() const final { return decl; }
132
133 /// Generates a single struct member operation.
134 /// (constructor call, destructor call, assignment call)
135 // This is managed because it uses another helper that returns a ast::ptr.
136 ast::ptr<ast::Stmt> makeMemberOp(
137 const CodeLocation& location,
138 const ast::ObjectDecl * dstParam, const ast::Expr * src,
139 const ast::ObjectDecl * field, ast::FunctionDecl * func,
140 SymTab::LoopDirection direction );
141
142 /// Generates the body of a struct function by iterating the struct members
143 /// (via parameters). Generates default constructor, copy constructor,
144 /// copy assignment, and destructor bodies. No field constructor bodies.
145 template<typename Iterator>
146 void makeFunctionBody( Iterator member, Iterator end,
147 ast::FunctionDecl * func, SymTab::LoopDirection direction );
148
149 /// Generate the body of a constructor which takes parameters that match
150 /// fields. (With arguments for one to all of the fields.)
151 template<typename Iterator>
152 void makeFieldCtorBody( Iterator member, Iterator end,
153 ast::FunctionDecl * func );
154};
155
156class UnionFuncGenerator final : public FuncGenerator {
157 const ast::UnionDecl * decl;
158public:
159 UnionFuncGenerator( const ast::UnionDecl * decl,
160 const ast::UnionInstType * type,
161 unsigned int functionNesting ) :
162 FuncGenerator( type, functionNesting ), decl( decl )
163 {}
164
165 // Built-ins do not use autogeneration.
166 bool shouldAutogen() const final { return !decl->linkage.is_builtin; }
167private:
168 void genFuncBody( ast::FunctionDecl * decl ) final;
169 void genFieldCtors() final;
170 const ast::Decl * getDecl() const final { return decl; }
171
172 /// Generate a single union assignment expression (using memcpy).
173 ast::ExprStmt * makeAssignOp( const CodeLocation& location,
174 const ast::ObjectDecl * dstParam, const ast::ObjectDecl * srcParam );
175};
176
177class EnumFuncGenerator final : public FuncGenerator {
178 const ast::EnumDecl * decl;
179public:
180 EnumFuncGenerator( const ast::EnumDecl * decl,
181 const ast::EnumInstType * type,
182 unsigned int functionNesting ) :
183 FuncGenerator( type, functionNesting ), decl( decl )
184 {
185 // TODO: These functions are somewhere between instrinsic and autogen,
186 // could possibly use a new linkage type. For now we just make the
187 // basic ones intrinsic to code-gen them as C assignments.
188 const auto & real_type = decl->base;
189 const auto & basic = real_type.as<ast::BasicType>();
190 if(!real_type || (basic && basic->isInteger())) proto_linkage = ast::Linkage::Intrinsic;
191 }
192
193 bool shouldAutogen() const final { return true; }
194private:
195 void genFuncBody( ast::FunctionDecl * decl ) final;
196 void genFieldCtors() final;
197 const ast::Decl * getDecl() const final { return decl; }
198};
199
200class TypeFuncGenerator final : public FuncGenerator {
201 const ast::TypeDecl * decl;
202public:
203 TypeFuncGenerator( const ast::TypeDecl * decl,
204 ast::TypeInstType * type,
205 unsigned int functionNesting ) :
206 FuncGenerator( type, functionNesting ), decl( decl )
207 {}
208
209 bool shouldAutogen() const final { return true; }
210 void genFieldCtors() final;
211private:
212 void genFuncBody( ast::FunctionDecl * decl ) final;
213 const ast::Decl * getDecl() const final { return decl; }
214};
215
216// --------------------------------------------------------------------------
217const std::vector<ast::ptr<ast::TypeDecl>>& getGenericParams( const ast::Type * t ) {
218 if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {
219 return inst->base->params;
220 } else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {
221 return inst->base->params;
222 }
223 static std::vector<ast::ptr<ast::TypeDecl>> const empty;
224 return empty;
225}
226
227/// Changes the node inside a pointer so that it has the unused attribute.
228void addUnusedAttribute( ast::ptr<ast::DeclWithType> & declPtr ) {
229 ast::DeclWithType * decl = declPtr.get_and_mutate();
230 decl->attributes.push_back( new ast::Attribute( "unused" ) );
231}
232
233// --------------------------------------------------------------------------
234void AutogenerateRoutines_new::previsit( const ast::EnumDecl * enumDecl ) {
235 // Must visit children (enum constants) to add them to the symbol table.
236 if ( !enumDecl->body ) return;
237
238 // if ( auto enumBaseType = enumDecl->base ) {
239 // if ( auto enumBaseTypeAsStructInst = dynamic_cast<const ast::StructInstType *>(enumBaseType.get()) ) {
240 // const ast::StructDecl * structDecl = enumBaseTypeAsStructInst->base.get();
241 // this->previsit( structDecl );
242 // }
243 // }
244
245 ast::EnumInstType enumInst( enumDecl->name );
246 enumInst.base = enumDecl;
247 EnumFuncGenerator gen( enumDecl, &enumInst, functionNesting );
248 gen.generateAndAppendFunctions( declsToAddAfter );
249}
250
251void AutogenerateRoutines_new::previsit( const ast::StructDecl * structDecl ) {
252 visit_children = false;
253 if ( !structDecl->body ) return;
254
255 ast::StructInstType structInst( structDecl->name );
256 structInst.base = structDecl;
257 for ( const ast::TypeDecl * typeDecl : structDecl->params ) {
258 structInst.params.push_back( new ast::TypeExpr(
259 typeDecl->location,
260 new ast::TypeInstType( typeDecl )
261 ) );
262 }
263 StructFuncGenerator gen( structDecl, &structInst, functionNesting );
264 gen.generateAndAppendFunctions( declsToAddAfter );
265}
266
267void AutogenerateRoutines_new::previsit( const ast::UnionDecl * unionDecl ) {
268 visit_children = false;
269 if ( !unionDecl->body ) return;
270
271 ast::UnionInstType unionInst( unionDecl->name );
272 unionInst.base = unionDecl;
273 for ( const ast::TypeDecl * typeDecl : unionDecl->params ) {
274 unionInst.params.push_back( new ast::TypeExpr(
275 unionDecl->location,
276 new ast::TypeInstType( typeDecl )
277 ) );
278 }
279 UnionFuncGenerator gen( unionDecl, &unionInst, functionNesting );
280 gen.generateAndAppendFunctions( declsToAddAfter );
281}
282
283/// Generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
284void AutogenerateRoutines_new::previsit( const ast::TypeDecl * typeDecl ) {
285 if ( !typeDecl->base ) return;
286
287 ast::TypeInstType refType( typeDecl->name, typeDecl );
288 TypeFuncGenerator gen( typeDecl, &refType, functionNesting );
289 gen.generateAndAppendFunctions( declsToAddAfter );
290}
291
292void AutogenerateRoutines_new::previsit( const ast::TraitDecl * ) {
293 // Ensure that we don't add assignment ops for types defined as part of the trait
294 visit_children = false;
295}
296
297void AutogenerateRoutines_new::previsit( const ast::FunctionDecl * ) {
298 // Track whether we're currently in a function.
299 // Can ignore function type idiosyncrasies, because function type can never
300 // declare a new type.
301 functionNesting += 1;
302}
303
304void AutogenerateRoutines_new::postvisit( const ast::FunctionDecl * ) {
305 functionNesting -= 1;
306}
307
308void FuncGenerator::generateAndAppendFunctions(
309 std::list<ast::ptr<ast::Decl>> & decls ) {
310 if ( !shouldAutogen() ) return;
311
312 // Generate the functions (they go into forwards and definitions).
313 genStandardFuncs();
314 genFieldCtors();
315
316 // Now export the lists contents.
317 decls.splice( decls.end(), forwards );
318 decls.splice( decls.end(), definitions );
319}
320
321void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) {
322 assert( nullptr != decl->stmts );
323
324 definitions.push_back( decl );
325}
326
327/// Make a forward declaration of the decl and add it to forwards.
328void FuncGenerator::produceForwardDecl( const ast::FunctionDecl * decl ) {
329 if (0 != functionNesting) return;
330 ast::FunctionDecl * fwd = ast::deepCopy( decl );
331 fwd->stmts = nullptr;
332 fwd->fixUniqueId();
333 forwards.push_back( fwd );
334}
335
336/// Generates a basic prototype function declaration.
337ast::FunctionDecl * FuncGenerator::genProto( const std::string& name,
338 std::vector<ast::ptr<ast::DeclWithType>>&& params,
339 std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const {
340
341 // Handle generic prameters and assertions, if any.
342 auto const & old_type_params = getGenericParams( type );
343 std::vector<ast::ptr<ast::TypeDecl>> type_params;
344 std::vector<ast::ptr<ast::DeclWithType>> assertions;
345 for ( auto & old_param : old_type_params ) {
346 ast::TypeDecl * decl = ast::deepCopy( old_param );
347 for ( auto assertion : decl->assertions ) {
348 assertions.push_back( assertion );
349 }
350 decl->assertions.clear();
351 type_params.push_back( decl );
352 }
353 // TODO: The values in params and returns still may point at the old
354 // generic params, that does not appear to be an issue but perhaps it
355 // should be addressed.
356
357 ast::FunctionDecl * decl = new ast::FunctionDecl(
358 // Auto-generated routines use the type declaration's location.
359 getLocation(),
360 name,
361 std::move( type_params ),
362 std::move( assertions ),
363 std::move( params ),
364 std::move( returns ),
365 // Only a prototype, no body.
366 nullptr,
367 // Use static storage if we are at the top level.
368 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
369 proto_linkage,
370 std::vector<ast::ptr<ast::Attribute>>(),
371 // Auto-generated routines are inline to avoid conflicts.
372 ast::Function::Specs( ast::Function::Inline ) );
373 decl->fixUniqueId();
374 return decl;
375}
376
377ast::ObjectDecl * FuncGenerator::dstParam() const {
378 return new ast::ObjectDecl( getLocation(), "_dst",
379 new ast::ReferenceType( ast::deepCopy( type ) ) );
380}
381
382ast::ObjectDecl * FuncGenerator::srcParam() const {
383 return new ast::ObjectDecl( getLocation(), "_src",
384 ast::deepCopy( type ) );
385}
386
387/// Use the current type T to create `void ?{}(T & _dst)`.
388ast::FunctionDecl * FuncGenerator::genCtorProto() const {
389 return genProto( "?{}", { dstParam() }, {} );
390}
391
392/// Use the current type T to create `void ?{}(T & _dst, T _src)`.
393ast::FunctionDecl * FuncGenerator::genCopyProto() const {
394 return genProto( "?{}", { dstParam(), srcParam() }, {} );
395}
396
397/// Use the current type T to create `void ?{}(T & _dst)`.
398ast::FunctionDecl * FuncGenerator::genDtorProto() const {
399 // The destructor must be mutex on a concurrent type.
400 auto dst = dstParam();
401 if ( isConcurrentType() ) {
402 add_qualifiers( dst->type, ast::CV::Qualifiers( ast::CV::Mutex ) );
403 }
404 return genProto( "^?{}", { dst }, {} );
405}
406
407/// Use the current type T to create `T ?{}(T & _dst, T _src)`.
408ast::FunctionDecl * FuncGenerator::genAssignProto() const {
409 // Only the name is different, so just reuse the generation function.
410 auto retval = srcParam();
411 retval->name = "_ret";
412 return genProto( "?=?", { dstParam(), srcParam() }, { retval } );
413}
414
415// This one can return null if the last field is an unnamed bitfield.
416ast::FunctionDecl * FuncGenerator::genFieldCtorProto(
417 unsigned int fields ) const {
418 assert( 0 < fields );
419 auto aggr = strict_dynamic_cast<const ast::AggregateDecl *>( getDecl() );
420
421 std::vector<ast::ptr<ast::DeclWithType>> params = { dstParam() };
422 for ( unsigned int index = 0 ; index < fields ; ++index ) {
423 auto member = aggr->members[index].strict_as<ast::DeclWithType>();
424 if ( SymTab::isUnnamedBitfield(
425 dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
426 if ( index == fields - 1 ) {
427 return nullptr;
428 }
429 continue;
430 }
431
432 auto * paramType = ast::deepCopy( member->get_type() );
433 paramType->attributes.clear();
434 ast::ObjectDecl * param = new ast::ObjectDecl(
435 getLocation(), member->name, paramType );
436 for ( auto & attr : member->attributes ) {
437 if ( attr->isValidOnFuncParam() ) {
438 param->attributes.push_back( attr );
439 }
440 }
441 params.emplace_back( param );
442 }
443 return genProto( "?{}", std::move( params ), {} );
444}
445
446void appendReturnThis( ast::FunctionDecl * decl ) {
447 assert( 1 <= decl->params.size() );
448 assert( 1 == decl->returns.size() );
449 assert( decl->stmts );
450
451 const CodeLocation& location = (decl->stmts->kids.empty())
452 ? decl->stmts->location : decl->stmts->kids.back()->location;
453 const ast::DeclWithType * thisParam = decl->params.front();
454 decl->stmts.get_and_mutate()->push_back(
455 new ast::ReturnStmt( location,
456 new ast::VariableExpr( location, thisParam )
457 )
458 );
459}
460
461void FuncGenerator::genStandardFuncs() {
462 // The order here determines the order that these functions are generated.
463 // Assignment should come last since it uses copy constructor in return.
464 ast::FunctionDecl *(FuncGenerator::*standardProtos[4])() const = {
465 &FuncGenerator::genCtorProto, &FuncGenerator::genCopyProto,
466 &FuncGenerator::genDtorProto, &FuncGenerator::genAssignProto };
467 for ( auto & generator : standardProtos ) {
468 ast::FunctionDecl * decl = (this->*generator)();
469 produceForwardDecl( decl );
470 genFuncBody( decl );
471 if ( CodeGen::isAssignment( decl->name ) ) {
472 appendReturnThis( decl );
473 }
474 produceDecl( decl );
475 }
476}
477
478void StructFuncGenerator::genFieldCtors() {
479 // The field constructors are only generated if the default constructor
480 // and copy constructor are both generated, since the need both.
481 unsigned numCtors = std::count_if( definitions.begin(), definitions.end(),
482 [](const ast::Decl * decl){ return CodeGen::isConstructor( decl->name ); }
483 );
484 if ( 2 != numCtors ) return;
485
486 for ( unsigned int num = 1 ; num <= decl->members.size() ; ++num ) {
487 ast::FunctionDecl * ctor = genFieldCtorProto( num );
488 if ( nullptr == ctor ) {
489 continue;
490 }
491 produceForwardDecl( ctor );
492 makeFieldCtorBody( decl->members.begin(), decl->members.end(), ctor );
493 produceDecl( ctor );
494 }
495}
496
497void StructFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
498 // Generate appropriate calls to member constructors and assignment.
499 // Destructor needs to do everything in reverse,
500 // so pass "forward" based on whether the function is a destructor
501 if ( CodeGen::isDestructor( functionDecl->name ) ) {
502 makeFunctionBody( decl->members.rbegin(), decl->members.rend(),
503 functionDecl, SymTab::LoopBackward );
504 } else {
505 makeFunctionBody( decl->members.begin(), decl->members.end(),
506 functionDecl, SymTab::LoopForward );
507 }
508}
509
510ast::ptr<ast::Stmt> StructFuncGenerator::makeMemberOp(
511 const CodeLocation& location, const ast::ObjectDecl * dstParam,
512 const ast::Expr * src, const ast::ObjectDecl * field,
513 ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
514 InitTweak::InitExpander_new srcParam( src );
515 // Assign to destination.
516 ast::Expr * dstSelect = new ast::MemberExpr(
517 location,
518 field,
519 new ast::CastExpr(
520 location,
521 new ast::VariableExpr( location, dstParam ),
522 dstParam->type.strict_as<ast::ReferenceType>()->base
523 )
524 );
525 return genImplicitCall(
526 srcParam, dstSelect, location, func->name,
527 field, direction
528 );
529}
530
531template<typename Iterator>
532void StructFuncGenerator::makeFunctionBody( Iterator current, Iterator end,
533 ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
534 // Trying to get the best code location. Should probably use a helper or
535 // just figure out what that would be given where this is called.
536 assert( nullptr == func->stmts );
537 const CodeLocation& location = func->location;
538
539 ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
540
541 for ( ; current != end ; ++current ) {
542 const ast::ptr<ast::Decl> & member = *current;
543 auto field = member.as<ast::ObjectDecl>();
544 if ( nullptr == field ) {
545 continue;
546 }
547
548 // Don't assign to constant members (but do construct/destruct them).
549 if ( CodeGen::isAssignment( func->name ) ) {
550 // For array types we need to strip off the array layers.
551 const ast::Type * type = field->get_type();
552 while ( auto at = dynamic_cast<const ast::ArrayType *>( type ) ) {
553 type = at->base;
554 }
555 if ( type->is_const() ) {
556 continue;
557 }
558 }
559
560 assert( !func->params.empty() );
561 const ast::ObjectDecl * dstParam =
562 func->params.front().strict_as<ast::ObjectDecl>();
563 const ast::ObjectDecl * srcParam = nullptr;
564 if ( 2 == func->params.size() ) {
565 srcParam = func->params.back().strict_as<ast::ObjectDecl>();
566 }
567
568 ast::Expr * srcSelect = (srcParam) ? new ast::MemberExpr(
569 location, field, new ast::VariableExpr( location, srcParam )
570 ) : nullptr;
571 ast::ptr<ast::Stmt> stmt =
572 makeMemberOp( location, dstParam, srcSelect, field, func, direction );
573
574 if ( nullptr != stmt ) {
575 stmts->kids.push_back( stmt );
576 }
577 }
578
579 func->stmts = stmts;
580}
581
582template<typename Iterator>
583void StructFuncGenerator::makeFieldCtorBody( Iterator current, Iterator end,
584 ast::FunctionDecl * func ) {
585 const CodeLocation& location = func->location;
586 auto & params = func->params;
587 // Need at least the constructed parameter and one field parameter.
588 assert( 2 <= params.size() );
589
590 ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
591
592 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
593 // Skip over the 'this' parameter.
594 for ( auto param = params.begin() + 1 ; current != end ; ++current ) {
595 const ast::ptr<ast::Decl> & member = *current;
596 ast::ptr<ast::Stmt> stmt = nullptr;
597 auto field = member.as<ast::ObjectDecl>();
598 // Not sure why it could be null.
599 // Don't make a function for a parameter that is an unnamed bitfield.
600 if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
601 continue;
602 // Matching Parameter: Initialize the field by copy.
603 } else if ( params.end() != param ) {
604 const ast::Expr *srcSelect = new ast::VariableExpr(
605 func->location, param->get() );
606 stmt = makeMemberOp( location, dstParam, srcSelect, field, func, SymTab::LoopForward );
607 ++param;
608 // No Matching Parameter: Initialize the field by default constructor.
609 } else {
610 stmt = makeMemberOp( location, dstParam, nullptr, field, func, SymTab::LoopForward );
611 }
612
613 if ( nullptr != stmt ) {
614 stmts->kids.push_back( stmt );
615 }
616 }
617 func->stmts = stmts;
618}
619
620void UnionFuncGenerator::genFieldCtors() {
621 // Field constructors are only generated if default and copy constructor
622 // are generated, since they need access to both
623 unsigned numCtors = std::count_if( definitions.begin(), definitions.end(),
624 []( const ast::Decl * d ){ return CodeGen::isConstructor( d->name ); }
625 );
626 if ( 2 != numCtors ) {
627 return;
628 }
629
630 // Create a constructor which takes the first member type as a
631 // parameter. For example for `union A { int x; char y; };` generate
632 // a function with signature `void ?{}(A *, int)`. This mimics C's
633 // behaviour which initializes the first member of the union.
634
635 // Still, there must be some members.
636 if ( !decl->members.empty() ) {
637 ast::FunctionDecl * ctor = genFieldCtorProto( 1 );
638 if ( nullptr == ctor ) {
639 return;
640 }
641 produceForwardDecl( ctor );
642 auto params = ctor->params;
643 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
644 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
645 ctor->stmts = new ast::CompoundStmt( getLocation(),
646 { makeAssignOp( getLocation(), dstParam, srcParam ) }
647 );
648 produceDecl( ctor );
649 }
650}
651
652void UnionFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
653 const CodeLocation& location = functionDecl->location;
654 auto & params = functionDecl->params;
655 if ( InitTweak::isCopyConstructor( functionDecl )
656 || InitTweak::isAssignment( functionDecl ) ) {
657 assert( 2 == params.size() );
658 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
659 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
660 functionDecl->stmts = new ast::CompoundStmt( location,
661 { makeAssignOp( location, dstParam, srcParam ) }
662 );
663 } else {
664 assert( 1 == params.size() );
665 // Default constructor and destructor is empty.
666 functionDecl->stmts = new ast::CompoundStmt( location );
667 // Add unused attribute to parameter to silence warnings.
668 addUnusedAttribute( params.front() );
669
670 // Just an extra step to make the forward and declaration match.
671 if ( forwards.empty() ) return;
672 ast::FunctionDecl * fwd = strict_dynamic_cast<ast::FunctionDecl *>(
673 forwards.back().get_and_mutate() );
674 addUnusedAttribute( fwd->params.front() );
675 }
676}
677
678ast::ExprStmt * UnionFuncGenerator::makeAssignOp( const CodeLocation& location,
679 const ast::ObjectDecl * dstParam, const ast::ObjectDecl * srcParam ) {
680 return new ast::ExprStmt( location, new ast::UntypedExpr(
681 location,
682 new ast::NameExpr( location, "__builtin_memcpy" ),
683 {
684 new ast::AddressExpr( location,
685 new ast::VariableExpr( location, dstParam ) ),
686 new ast::AddressExpr( location,
687 new ast::VariableExpr( location, srcParam ) ),
688 new ast::SizeofExpr( location, srcParam->type ),
689 } ) );
690}
691
692void EnumFuncGenerator::genFieldCtors() {
693 // Enumerations to not have field constructors.
694}
695
696void EnumFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
697 const CodeLocation& location = functionDecl->location;
698 auto & params = functionDecl->params;
699 if ( InitTweak::isCopyConstructor( functionDecl )
700 || InitTweak::isAssignment( functionDecl ) ) {
701 assert( 2 == params.size() );
702 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
703 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
704
705 /* This looks like a recursive call, but code-gen will turn it into
706 * a C-style assignment.
707 *
708 * This is still before function pointer type conversion,
709 * so this will have to do it manually.
710 *
711 * It will also reference the parent function declaration, creating
712 * a cycle for references. This also means that the ref-counts are
713 * now non-zero and the declaration will be deleted if it ever
714 * returns to zero.
715 */
716 auto callExpr = new ast::ApplicationExpr( location,
717 ast::VariableExpr::functionPointer( location, functionDecl ),
718 {
719 new ast::VariableExpr( location, dstParam ),
720 new ast::VariableExpr( location, srcParam ),
721 }
722 );
723 functionDecl->stmts = new ast::CompoundStmt( location,
724 { new ast::ExprStmt( location, callExpr ) }
725 );
726 } else {
727 assert( 1 == params.size() );
728 // Default constructor and destructor is empty.
729 functionDecl->stmts = new ast::CompoundStmt( location );
730 // Just add unused attribute to parameter to silence warnings.
731 addUnusedAttribute( params.front() );
732
733 // Just an extra step to make the forward and declaration match.
734 if ( forwards.empty() ) return;
735 ast::FunctionDecl * fwd = strict_dynamic_cast<ast::FunctionDecl *>(
736 forwards.back().get_and_mutate() );
737 addUnusedAttribute( fwd->params.front() );
738 }
739}
740
741void TypeFuncGenerator::genFieldCtors() {
742 // Opaque types do not have field constructors.
743}
744
745void TypeFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
746 const CodeLocation& location = functionDecl->location;
747 auto & params = functionDecl->type->params;
748 assertf( 1 == params.size() || 2 == params.size(),
749 "Incorrect number of parameters in autogenerated typedecl function: %zd",
750 params.size() );
751 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
752 auto srcParam = (2 == params.size())
753 ? params.back().strict_as<ast::ObjectDecl>() : nullptr;
754 // Generate appropriate calls to member constructor and assignment.
755 ast::UntypedExpr * expr = new ast::UntypedExpr( location,
756 new ast::NameExpr( location, functionDecl->name )
757 );
758 expr->args.push_back( new ast::CastExpr( location,
759 new ast::VariableExpr( location, dstParam ),
760 new ast::ReferenceType( decl->base )
761 ) );
762 if ( srcParam ) {
763 expr->args.push_back( new ast::CastExpr( location,
764 new ast::VariableExpr( location, srcParam ),
765 decl->base
766 ) );
767 }
768 functionDecl->stmts = new ast::CompoundStmt( location,
769 { new ast::ExprStmt( location, expr ) }
770 );
771}
772
773} // namespace
774
775void autogenerateRoutines( ast::TranslationUnit & translationUnit ) {
776 ast::Pass<AutogenerateRoutines_new>::run( translationUnit );
777}
778
779} // Validate
780
781// Local Variables: //
782// tab-width: 4 //
783// mode: c++ //
784// compile-command: "make install" //
785// End: //
Note: See TracBrowser for help on using the repository browser.