source: src/SymTab/Autogen.h @ 81f93e0

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 81f93e0 was 16ba4a6f, checked in by Fangren Yu <f37yu@…>, 4 years ago

factor out resolver calls in pre-resolution stage

  • Property mode set to 100644
File size: 16.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 : Peter A. Buhr
12// Last Modified On : Fri Dec 13 16:38:06 2019
13// Update Count     : 16
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/Eval.hpp"
24#include "AST/Expr.hpp"
25#include "AST/Init.hpp"
26#include "AST/Node.hpp"
27#include "AST/Stmt.hpp"
28#include "AST/Type.hpp"
29#include "CodeGen/OperatorTable.h"
30#include "Common/UniqueName.h"    // for UniqueName
31#include "Common/utility.h"       // for splice
32#include "InitTweak/InitTweak.h"  // for InitExpander
33#include "SynTree/Constant.h"     // for Constant
34#include "SynTree/Declaration.h"  // for DeclarationWithType, ObjectDecl
35#include "SynTree/Expression.h"   // for NameExpr, ConstantExpr, UntypedExpr...
36#include "SynTree/Type.h"         // for Type, ArrayType, Type::Qualifiers
37#include "SynTree/Statement.h"    // for CompoundStmt, DeclStmt, ExprStmt
38
39class CompoundStmt;
40class Statement;
41
42namespace SymTab {
43        /// Generates assignment operators, constructors, and destructor for aggregate types as required
44        void autogenerateRoutines( std::list< Declaration * > &translationUnit );
45
46        /// returns true if obj's name is the empty string and it has a bitfield width
47        bool isUnnamedBitfield( ObjectDecl * obj );
48        bool isUnnamedBitfield( const ast::ObjectDecl * obj );
49
50        /// generate the type of an assignment function for paramType.
51        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
52        FunctionType * genAssignType( Type * paramType, bool maybePolymorphic = true );
53
54        /// generate the type of a default constructor or destructor for paramType.
55        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
56        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
57
58        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
59
60        /// generate the type of a copy constructor for paramType.
61        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
62        FunctionType * genCopyType( Type * paramType, bool maybePolymorphic = true );
63
64        /// Enum for loop direction
65        enum LoopDirection { LoopBackward, LoopForward };
66
67        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
68        template< typename OutputIterator >
69        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
70
71        template< typename OutIter >
72        ast::ptr< ast::Stmt > genCall(
73                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
74                const CodeLocation & loc, const std::string & fname, OutIter && out, 
75                const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
76
77        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
78        /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
79        template< typename OutputIterator >
80        Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
81                bool isReferenceCtorDtor = false;
82                if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
83                        // reference constructors are essentially application of the rebind operator.
84                        // apply & to both arguments, do not need a cast
85                        fname = "?=?";
86                        dstParam = new AddressExpr( dstParam );
87                        addCast = nullptr;
88                        isReferenceCtorDtor = true;
89                }
90
91                // want to be able to generate assignment, ctor, and dtor generically,
92                // so fname is either ?=?, ?{}, or ^?{}
93                UntypedExpr * fExpr = new UntypedExpr( new NameExpr( fname ) );
94
95                if ( addCast ) {
96                        // cast to T& with qualifiers removed, so that qualified objects can be constructed
97                        // and destructed with the same functions as non-qualified objects.
98                        // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
99                        // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
100                        // remove lvalue as a qualifier, this can change to
101                        //   type->get_qualifiers() = Type::Qualifiers();
102                        Type * castType = addCast->clone();
103                        castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
104                        // castType->set_lvalue( true ); // xxx - might not need this
105                        dstParam = new CastExpr( dstParam, new ReferenceType( Type::Qualifiers(), castType ) );
106                }
107                fExpr->args.push_back( dstParam );
108
109                Statement * listInit = srcParam.buildListInit( fExpr );
110
111                // fetch next set of arguments
112                ++srcParam;
113
114                // return if adding reference fails - will happen on default constructor and destructor
115                if ( isReferenceCtorDtor && ! srcParam.addReference() ) {
116                        delete fExpr;
117                        return listInit;
118                }
119
120                std::list< Expression * > args = *srcParam;
121                fExpr->args.splice( fExpr->args.end(), args );
122
123                *out++ = new ExprStmt( fExpr );
124
125                srcParam.clearArrayIndices();
126
127                return listInit;
128        }
129
130        /// inserts into out a generated call expression to function fname with arguments dstParam and
131        /// srcParam. Should only be called with non-array types.
132        /// optionally returns a statement which must be inserted prior to the containing loop, if
133        /// there is one
134        template< typename OutIter >
135        ast::ptr< ast::Stmt > genScalarCall( 
136                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
137                const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 
138                const ast::Type * addCast = nullptr
139        ) {
140                bool isReferenceCtorDtor = false;
141                if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
142                        // reference constructors are essentially application of the rebind operator.
143                        // apply & to both arguments, do not need a cast
144                        fname = "?=?";
145                        dstParam = new ast::AddressExpr{ dstParam };
146                        addCast = nullptr;
147                        isReferenceCtorDtor = true;
148                }
149
150                // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
151                // "?=?", "?{}", or "^?{}"
152                ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } };
153
154                if ( addCast ) {
155                        // cast to T& with qualifiers removed, so that qualified objects can be constructed and
156                        // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
157                        // is considered a qualifier - for AddressExpr to resolve, its argument must have an
158                        // lvalue-qualified type, so remove all qualifiers except lvalue.
159                        // xxx -- old code actually removed lvalue too...
160                        ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
161                        ast::ptr< ast::Type > castType = addCast;
162                        ast::remove_qualifiers( 
163                                castType, 
164                                ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
165                        dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
166                }
167                fExpr->args.emplace_back( dstParam );
168
169                ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
170
171                // fetch next set of arguments
172                ++srcParam;
173
174                // return if adding reference fails -- will happen on default ctor and dtor
175                if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
176
177                std::vector< ast::ptr< ast::Expr > > args = *srcParam;
178                splice( fExpr->args, args );
179
180                *out++ = new ast::ExprStmt{ loc, fExpr };
181
182                srcParam.clearArrayIndices();
183               
184                return listInit;
185        }
186
187        /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
188        /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
189        template< typename OutputIterator >
190        void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
191                static UniqueName indexName( "_index" );
192
193                // for a flexible array member nothing is done -- user must define own assignment
194                if ( ! array->get_dimension() ) return;
195
196                if ( addCast ) {
197                        // peel off array layer from cast
198                        ArrayType * at = strict_dynamic_cast< ArrayType * >( addCast );
199                        addCast = at->base;
200                }
201
202                Expression * begin, * end, * update, * cmp;
203                if ( forward ) {
204                        // generate: for ( int i = 0; i < N; ++i )
205                        begin = new ConstantExpr( Constant::from_int( 0 ) );
206                        end = array->dimension->clone();
207                        cmp = new NameExpr( "?<?" );
208                        update = new NameExpr( "++?" );
209                } else {
210                        // generate: for ( int i = N-1; i >= 0; --i )
211                        begin = new UntypedExpr( new NameExpr( "?-?" ) );
212                        ((UntypedExpr*)begin)->args.push_back( array->dimension->clone() );
213                        ((UntypedExpr*)begin)->args.push_back( new ConstantExpr( Constant::from_int( 1 ) ) );
214                        end = new ConstantExpr( Constant::from_int( 0 ) );
215                        cmp = new NameExpr( "?>=?" );
216                        update = new NameExpr( "--?" );
217                }
218
219                ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin ) );
220
221                UntypedExpr *cond = new UntypedExpr( cmp );
222                cond->args.push_back( new VariableExpr( index ) );
223                cond->args.push_back( end );
224
225                UntypedExpr *inc = new UntypedExpr( update );
226                inc->args.push_back( new VariableExpr( index ) );
227
228                UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
229                dstIndex->args.push_back( dstParam );
230                dstIndex->args.push_back( new VariableExpr( index ) );
231                dstParam = dstIndex;
232
233                // srcParam must keep track of the array indices to build the
234                // source parameter and/or array list initializer
235                srcParam.addArrayIndex( new VariableExpr( index ), array->dimension->clone() );
236
237                // for stmt's body, eventually containing call
238                CompoundStmt * body = new CompoundStmt();
239                Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->kids ), array->base, addCast, forward );
240
241                // block containing for stmt and index variable
242                std::list<Statement *> initList;
243                CompoundStmt * block = new CompoundStmt();
244                block->push_back( new DeclStmt( index ) );
245                if ( listInit ) block->get_kids().push_back( listInit );
246                block->push_back( new ForStmt( initList, cond, inc, body ) );
247
248                *out++ = block;
249        }
250
251        /// Store in out a loop which calls fname on each element of the array with srcParam and
252        /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
253        template< typename OutIter >
254        void genArrayCall(
255                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
256                const CodeLocation & loc, const std::string & fname, OutIter && out, 
257                const ast::ArrayType * array, const ast::Type * addCast = nullptr, 
258                LoopDirection forward = LoopForward
259        ) {
260                static UniqueName indexName( "_index" );
261
262                // for a flexible array member nothing is done -- user must define own assignment
263                if ( ! array->dimension ) return;
264
265                if ( addCast ) {
266                        // peel off array layer from cast
267                        addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
268                }
269
270                ast::ptr< ast::Expr > begin, end;
271                std::string cmp, update;
272
273                if ( forward ) {
274                        // generate: for ( int i = 0; i < N; ++i )
275                        begin = ast::ConstantExpr::from_int( loc, 0 );
276                        end = array->dimension;
277                        cmp = "?<?";
278                        update = "++?";
279                } else {
280                        // generate: for ( int i = N-1; i >= 0; --i )
281                        begin = ast::call( 
282                                loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
283                        end = ast::ConstantExpr::from_int( loc, 0 );
284                        cmp = "?>=?";
285                        update = "--?";
286                }
287
288                ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 
289                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 
290                        new ast::SingleInit{ loc, begin } };
291                ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
292               
293                ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
294               
295                ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
296               
297                ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
298               
299                // srcParam must keep track of the array indices to build the source parameter and/or
300                // array list initializer
301                srcParam.addArrayIndex( indexVar, array->dimension );
302
303                // for stmt's body, eventually containing call
304                ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
305                ast::ptr< ast::Stmt > listInit = genCall( 
306                        srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 
307                        forward );
308               
309                // block containing the stmt and index variable
310                ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
311                block->push_back( new ast::DeclStmt{ loc, index } );
312                if ( listInit ) { block->push_back( listInit ); }
313                block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } );
314
315                *out++ = block;
316        }
317
318        template< typename OutputIterator >
319        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
320                if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
321                        genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
322                        return 0;
323                } else {
324                        return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
325                }
326        }
327
328        template< typename OutIter >
329        ast::ptr< ast::Stmt > genCall(
330                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
331                const CodeLocation & loc, const std::string & fname, OutIter && out, 
332                const ast::Type * type, const ast::Type * addCast, LoopDirection forward
333        ) {
334                if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
335                        genArrayCall( 
336                                srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 
337                                forward );
338                        return {};
339                } else {
340                        return genScalarCall( 
341                                srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
342                }
343        }
344
345        /// inserts into out a generated call expression to function fname with arguments dstParam
346        /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
347        /// object being constructed. The function wraps constructor and destructor calls in an
348        /// ImplicitCtorDtorStmt node.
349        template< typename OutputIterator >
350        void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
351                ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
352                assert( obj );
353                // unnamed bit fields are not copied as they cannot be accessed
354                if ( isUnnamedBitfield( obj ) ) return;
355
356                Type * addCast = nullptr;
357                if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) {
358                        assert( dstParam->result );
359                        addCast = dstParam->result;
360                }
361                std::list< Statement * > stmts;
362                genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward );
363
364                // 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
365                assert( stmts.size() <= 1 );
366                if ( stmts.size() == 1 ) {
367                        Statement * callStmt = stmts.front();
368                        if ( addCast ) {
369                                // implicitly generated ctor/dtor calls should be wrapped
370                                // so that later passes are aware they were generated.
371                                // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
372                                // because this causes the address to be taken at codegen, which is illegal in C.
373                                callStmt = new ImplicitCtorDtorStmt( callStmt );
374                        }
375                        *out++ = callStmt;
376                }
377        }
378
379        static inline ast::ptr< ast::Stmt > genImplicitCall( 
380                InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 
381                const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 
382                LoopDirection forward = LoopForward
383        ) {
384                // unnamed bit fields are not copied as they cannot be accessed
385                if ( isUnnamedBitfield( obj ) ) return {};
386
387                ast::ptr< ast::Type > addCast;
388                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
389                        assert( dstParam->result );
390                        addCast = dstParam->result;
391                }
392
393                std::vector< ast::ptr< ast::Stmt > > stmts;
394                genCall( 
395                        srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
396
397                if ( stmts.empty() ) {
398                        return {};
399                } else if ( stmts.size() == 1 ) {
400                        const ast::Stmt * callStmt = stmts.front();
401                        if ( addCast ) {
402                                // implicitly generated ctor/dtor calls should be wrapped so that later passes are
403                                // aware they were generated.
404                                callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
405                        }
406                        return callStmt;
407                } else {
408                        assert( false );
409                        return {};
410                }
411        }
412} // namespace SymTab
413
414// Local Variables: //
415// tab-width: 4 //
416// mode: c++ //
417// compile-command: "make install" //
418// End: //
419
Note: See TracBrowser for help on using the repository browser.