source: src/Validate/Autogen.cpp @ bbf2cb1

Last change on this file since bbf2cb1 was bbf2cb1, checked in by JiadaL <j82liang@…>, 3 months ago

Add the Working support to succ() and pred() pseudo function to Enum

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