source: src/Validate/Autogen.cpp@ 3a513d89

ADT
Last change on this file since 3a513d89 was d6c464d, checked in by JiadaL <j82liang@…>, 2 years ago

reset enum's autogen as non adt

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