source: src/SymTab/Autogen.h @ 8ff586c

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 8ff586c was 7030dab, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Merge branch 'master' into new-ast

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