source: src/Validate/Autogen.cpp@ 59c7e3e

ADT ast-experimental
Last change on this file since 59c7e3e was 20737104, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Wrote a new asForward helper for Autogen.

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