source: src/Validate/Autogen.cpp@ 88bb0b4

stuck-waitfor-destruct
Last change on this file since 88bb0b4 was 88bb0b4, checked in by Matthew Au-Yeung <mw2auyeu@…>, 2 days ago

update comment

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