source: src/Validate/Autogen.cpp@ dbff8ec

Last change on this file since dbff8ec was bb336a6, checked in by JiadaL <j82liang@…>, 16 months ago

Fixed the problem when enum use another enumerator as initializer

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