source: src/SymTab/Autogen.h @ df9e412

ADTast-experimental
Last change on this file since df9e412 was e6cf857f, checked in by Andrew Beach <ajbeach@…>, 2 years ago

call -> createCall: The template wrapper has been removed and now it is beside similar helper functions.

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