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

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 8d61d620 was b8524ca, checked in by Aaron Moss <a3moss@…>, 5 years ago

new AST porting

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