source: src/SymTab/Autogen.h @ 4d5c855

ast-experimental
Last change on this file since 4d5c855 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 19 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: 9.9 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.h --
8//
9// Author           : Rob Schluntz
10// Created On       : Sun May 17 21:53:34 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Apr 14 15:06:00 2023
13// Update Count     : 17
14//
15
16#pragma once
17
18#include <cassert>                // for assert
19#include <iterator>               // for back_inserter
20#include <string>                 // for string
21
22#include "AST/Decl.hpp"
23#include "AST/Expr.hpp"
24#include "AST/Init.hpp"
25#include "AST/Node.hpp"
26#include "AST/Stmt.hpp"
27#include "AST/Type.hpp"
28#include "CodeGen/OperatorTable.h"
29#include "Common/UniqueName.h"    // for UniqueName
30#include "Common/utility.h"       // for splice
31#include "InitTweak/InitTweak.h"  // for InitExpander
32#include "SynTree/Constant.h"     // for Constant
33#include "SynTree/Declaration.h"  // for DeclarationWithType, ObjectDecl
34#include "SynTree/Expression.h"   // for NameExpr, ConstantExpr, UntypedExpr...
35#include "SynTree/Type.h"         // for Type, ArrayType, Type::Qualifiers
36#include "SynTree/Statement.h"    // for CompoundStmt, DeclStmt, ExprStmt
37
38class CompoundStmt;
39class Statement;
40
41namespace SymTab {
42        /// Generates assignment operators, constructors, and destructor for aggregate types as required
43        void autogenerateRoutines( std::list< Declaration * > &translationUnit );
44
45        /// returns true if obj's name is the empty string and it has a bitfield width
46        bool isUnnamedBitfield( ObjectDecl * obj );
47
48        /// generate the type of an assignment function for paramType.
49        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
50        FunctionType * genAssignType( Type * paramType, bool maybePolymorphic = true );
51
52        /// generate the type of a default constructor or destructor for paramType.
53        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
54        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
55
56        /// generate the type of a copy constructor for paramType.
57        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
58        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic = true );
59
60        /// Enum for loop direction
61        enum LoopDirection { LoopBackward, LoopForward };
62
63        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
64        template< typename OutputIterator >
65        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
66
67        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
68        /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
69        template< typename OutputIterator >
70        Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
71                bool isReferenceCtorDtor = false;
72                if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
73                        // reference constructors are essentially application of the rebind operator.
74                        // apply & to both arguments, do not need a cast
75                        fname = "?=?";
76                        dstParam = new AddressExpr( dstParam );
77                        addCast = nullptr;
78                        isReferenceCtorDtor = true;
79                }
80
81                // want to be able to generate assignment, ctor, and dtor generically,
82                // so fname is either ?=?, ?{}, or ^?{}
83                UntypedExpr * fExpr = new UntypedExpr( new NameExpr( fname ) );
84
85                if ( addCast ) {
86                        // cast to T& with qualifiers removed, so that qualified objects can be constructed
87                        // and destructed with the same functions as non-qualified objects.
88                        // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
89                        // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
90                        // remove lvalue as a qualifier, this can change to
91                        //   type->get_qualifiers() = Type::Qualifiers();
92                        Type * castType = addCast->clone();
93                        castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
94                        // castType->set_lvalue( true ); // xxx - might not need this
95                        dstParam = new CastExpr( dstParam, new ReferenceType( Type::Qualifiers(), castType ) );
96                }
97                fExpr->args.push_back( dstParam );
98
99                Statement * listInit = srcParam.buildListInit( fExpr );
100
101                // fetch next set of arguments
102                ++srcParam;
103
104                // return if adding reference fails - will happen on default constructor and destructor
105                if ( isReferenceCtorDtor && ! srcParam.addReference() ) {
106                        delete fExpr;
107                        return listInit;
108                }
109
110                std::list< Expression * > args = *srcParam;
111                fExpr->args.splice( fExpr->args.end(), args );
112
113                *out++ = new ExprStmt( fExpr );
114
115                srcParam.clearArrayIndices();
116
117                return listInit;
118        }
119
120        /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
121        /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
122        template< typename OutputIterator >
123        void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
124                static UniqueName indexName( "_index" );
125
126                // for a flexible array member nothing is done -- user must define own assignment
127                if ( ! array->get_dimension() ) return;
128
129                if ( addCast ) {
130                        // peel off array layer from cast
131                        ArrayType * at = strict_dynamic_cast< ArrayType * >( addCast );
132                        addCast = at->base;
133                }
134
135                Expression * begin, * end, * update, * cmp;
136                if ( forward ) {
137                        // generate: for ( int i = 0; i < N; ++i )
138                        begin = new ConstantExpr( Constant::from_int( 0 ) );
139                        end = array->dimension->clone();
140                        cmp = new NameExpr( "?<?" );
141                        update = new NameExpr( "++?" );
142                } else {
143                        // generate: for ( int i = N-1; i >= 0; --i )
144                        begin = new UntypedExpr( new NameExpr( "?-?" ) );
145                        ((UntypedExpr*)begin)->args.push_back( array->dimension->clone() );
146                        ((UntypedExpr*)begin)->args.push_back( new ConstantExpr( Constant::from_int( 1 ) ) );
147                        end = new ConstantExpr( Constant::from_int( 0 ) );
148                        cmp = new NameExpr( "?>=?" );
149                        update = new NameExpr( "--?" );
150                }
151
152                ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin ) );
153
154                UntypedExpr *cond = new UntypedExpr( cmp );
155                cond->args.push_back( new VariableExpr( index ) );
156                cond->args.push_back( end );
157
158                UntypedExpr *inc = new UntypedExpr( update );
159                inc->args.push_back( new VariableExpr( index ) );
160
161                UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
162                dstIndex->args.push_back( dstParam );
163                dstIndex->args.push_back( new VariableExpr( index ) );
164                dstParam = dstIndex;
165
166                // srcParam must keep track of the array indices to build the
167                // source parameter and/or array list initializer
168                srcParam.addArrayIndex( new VariableExpr( index ), array->dimension->clone() );
169
170                // for stmt's body, eventually containing call
171                CompoundStmt * body = new CompoundStmt();
172                Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->kids ), array->base, addCast, forward );
173
174                // block containing for stmt and index variable
175                std::list<Statement *> initList;
176                CompoundStmt * block = new CompoundStmt();
177                block->push_back( new DeclStmt( index ) );
178                if ( listInit ) block->get_kids().push_back( listInit );
179                block->push_back( new ForStmt( initList, cond, inc, body ) );
180
181                *out++ = block;
182        }
183
184        template< typename OutputIterator >
185        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
186                if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
187                        genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
188                        return 0;
189                } else {
190                        return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
191                }
192        }
193
194        /// inserts into out a generated call expression to function fname with arguments dstParam
195        /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
196        /// object being constructed. The function wraps constructor and destructor calls in an
197        /// ImplicitCtorDtorStmt node.
198        template< typename OutputIterator >
199        void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
200                ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
201                assert( obj );
202                // unnamed bit fields are not copied as they cannot be accessed
203                if ( isUnnamedBitfield( obj ) ) return;
204
205                Type * addCast = nullptr;
206                if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) {
207                        assert( dstParam->result );
208                        addCast = dstParam->result;
209                }
210                std::list< Statement * > stmts;
211                genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward );
212
213                // currently genCall should produce at most one element, but if that changes then the next line needs to be updated to grab the statement which contains the call
214                assert( stmts.size() <= 1 );
215                if ( stmts.size() == 1 ) {
216                        Statement * callStmt = stmts.front();
217                        if ( addCast ) {
218                                // implicitly generated ctor/dtor calls should be wrapped
219                                // so that later passes are aware they were generated.
220                                // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
221                                // because this causes the address to be taken at codegen, which is illegal in C.
222                                callStmt = new ImplicitCtorDtorStmt( callStmt );
223                        }
224                        *out++ = callStmt;
225                }
226        }
227
228} // namespace SymTab
229
230// Local Variables: //
231// tab-width: 4 //
232// mode: c++ //
233// compile-command: "make install" //
234// End: //
Note: See TracBrowser for help on using the repository browser.