source: src/Validate/Autogen.cpp @ 8463136

ast-experimental
Last change on this file since 8463136 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 15 months ago

Moved new ast code out of one of the old files. The new file may have to change if SymTab? is removed entirely, but for now at least, there is a lot less template code in headers.

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