source: src/Validate/Autogen.cpp @ fee4436

Last change on this file since fee4436 was 9d5eacb, checked in by JiadaL <j82liang@…>, 4 months ago

Fix the bug with typed anomynous enum got incorrect forward declaration

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