source: src/Validate/Autogen.cpp@ 8fd1b7c

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