source: src/Validate/Autogen.cpp @ fc134a48

ADTast-experimentalpthread-emulationqualifiedEnum
Last change on this file since fc134a48 was fc134a48, checked in by JiadaL <j82liang@…>, 23 months ago

Implement the struct enum

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