source: src/Validate/Autogen.cpp @ 0522ebe

Last change on this file since 0522ebe was 0522ebe, checked in by JiadaL <j82liang@…>, 5 months ago

Add EnumPosType? to type system

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