source: src/Validate/Autogen.cpp @ 1e30df7

ADTast-experimental
Last change on this file since 1e30df7 was 20737104, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Wrote a new asForward helper for Autogen.

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