source: src/SymTab/Autogen.h@ ef9988b

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since ef9988b 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
RevLine 
[972e6f7]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
[c0aa336]11// Last Modified By : Peter A. Buhr
[07de76b]12// Last Modified On : Fri Dec 13 16:38:06 2019
13// Update Count : 16
[972e6f7]14//
15
[6b0b624]16#pragma once
[972e6f7]17
[30f9072]18#include <cassert> // for assert
[b8524ca]19#include <iterator> // for back_inserter
[d180746]20#include <string> // for string
[30f9072]21
[b8524ca]22#include "AST/Decl.hpp"
[417117e]23#include "AST/Eval.hpp"
[b8524ca]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"
[1a5ad8c]29#include "CodeGen/OperatorTable.h"
[30f9072]30#include "Common/UniqueName.h" // for UniqueName
[b8524ca]31#include "Common/utility.h" // for splice
[30f9072]32#include "InitTweak/InitTweak.h" // for InitExpander
33#include "SynTree/Constant.h" // for Constant
[d180746]34#include "SynTree/Declaration.h" // for DeclarationWithType, ObjectDecl
35#include "SynTree/Expression.h" // for NameExpr, ConstantExpr, UntypedExpr...
[30f9072]36#include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers
[07de76b]37#include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt
[972e6f7]38
[d180746]39class CompoundStmt;
40class Statement;
41
[972e6f7]42namespace SymTab {
[2be1023]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 );
[b8524ca]48 bool isUnnamedBitfield( const ast::ObjectDecl * obj );
[2be1023]49
[837ce06]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 );
[8a6cf7e]53
[837ce06]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 );
[8404321]57
[837ce06]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 );
[8404321]61
[b8524ca]62 /// Enum for loop direction
63 enum LoopDirection { LoopBackward, LoopForward };
64
[2be1023]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 >
[b8524ca]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 );
[2be1023]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.
[f9cebb5]76 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
[2be1023]77 template< typename OutputIterator >
[b8524ca]78 Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
[1a5ad8c]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 );
[b95fe40]85 addCast = nullptr;
[1a5ad8c]86 isReferenceCtorDtor = true;
87 }
88
[49148d5]89 // want to be able to generate assignment, ctor, and dtor generically,
90 // so fname is either ?=?, ?{}, or ^?{}
[1a5ad8c]91 UntypedExpr * fExpr = new UntypedExpr( new NameExpr( fname ) );
[49148d5]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();
[b95fe40]100 Type * castType = addCast->clone();
[b4f8808]101 castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
[49148d5]102 // castType->set_lvalue( true ); // xxx - might not need this
103 dstParam = new CastExpr( dstParam, new ReferenceType( Type::Qualifiers(), castType ) );
104 }
[1a5ad8c]105 fExpr->args.push_back( dstParam );
[2be1023]106
[49148d5]107 Statement * listInit = srcParam.buildListInit( fExpr );
[39f84a4]108
[1a5ad8c]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 );
[4d2434a]120
[ba3706f]121 *out++ = new ExprStmt( fExpr );
[4d2434a]122
[49148d5]123 srcParam.clearArrayIndices();
[f9cebb5]124
[49148d5]125 return listInit;
[2be1023]126 }
127
[b8524ca]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
[2be1023]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 >
[b8524ca]188 void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
[2be1023]189 static UniqueName indexName( "_index" );
190
191 // for a flexible array member nothing is done -- user must define own assignment
[b95fe40]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 }
[2be1023]199
200 Expression * begin, * end, * update, * cmp;
201 if ( forward ) {
[579263a]202 // generate: for ( int i = 0; i < N; ++i )
203 begin = new ConstantExpr( Constant::from_int( 0 ) );
[1a5ad8c]204 end = array->dimension->clone();
[2be1023]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( "?-?" ) );
[1a5ad8c]210 ((UntypedExpr*)begin)->args.push_back( array->dimension->clone() );
211 ((UntypedExpr*)begin)->args.push_back( new ConstantExpr( Constant::from_int( 1 ) ) );
[579263a]212 end = new ConstantExpr( Constant::from_int( 0 ) );
[2be1023]213 cmp = new NameExpr( "?>=?" );
214 update = new NameExpr( "--?" );
215 }
216
[e4d829b]217 ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin ) );
[2be1023]218
219 UntypedExpr *cond = new UntypedExpr( cmp );
[1a5ad8c]220 cond->args.push_back( new VariableExpr( index ) );
221 cond->args.push_back( end );
[2be1023]222
223 UntypedExpr *inc = new UntypedExpr( update );
[1a5ad8c]224 inc->args.push_back( new VariableExpr( index ) );
[2be1023]225
226 UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
[1a5ad8c]227 dstIndex->args.push_back( dstParam );
228 dstIndex->args.push_back( new VariableExpr( index ) );
[2be1023]229 dstParam = dstIndex;
230
[39f84a4]231 // srcParam must keep track of the array indices to build the
232 // source parameter and/or array list initializer
[1a5ad8c]233 srcParam.addArrayIndex( new VariableExpr( index ), array->dimension->clone() );
[39f84a4]234
[2be1023]235 // for stmt's body, eventually containing call
[ba3706f]236 CompoundStmt * body = new CompoundStmt();
[1a5ad8c]237 Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->kids ), array->base, addCast, forward );
[2be1023]238
239 // block containing for stmt and index variable
240 std::list<Statement *> initList;
[ba3706f]241 CompoundStmt * block = new CompoundStmt();
242 block->push_back( new DeclStmt( index ) );
[f9cebb5]243 if ( listInit ) block->get_kids().push_back( listInit );
[ba3706f]244 block->push_back( new ForStmt( initList, cond, inc, body ) );
[2be1023]245
246 *out++ = block;
247 }
248
[b8524ca]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
[417117e]268 ast::ptr< ast::Expr > begin, end;
269 std::string cmp, update;
[b8524ca]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;
[417117e]275 cmp = "?<?";
276 update = "++?";
[b8524ca]277 } else {
278 // generate: for ( int i = N-1; i >= 0; --i )
[417117e]279 begin = ast::call(
280 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
[b8524ca]281 end = ast::ConstantExpr::from_int( loc, 0 );
[417117e]282 cmp = "?>=?";
283 update = "--?";
[b8524ca]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 } };
[417117e]289 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
[b8524ca]290
[417117e]291 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
[b8524ca]292
[417117e]293 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
[b8524ca]294
[417117e]295 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
[b8524ca]296
297 // srcParam must keep track of the array indices to build the source parameter and/or
298 // array list initializer
[417117e]299 srcParam.addArrayIndex( indexVar, array->dimension );
[b8524ca]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
[2be1023]316 template< typename OutputIterator >
[b8524ca]317 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
[2be1023]318 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
[4d2434a]319 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
[f9cebb5]320 return 0;
[2be1023]321 } else {
[f9cebb5]322 return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
[2be1023]323 }
324 }
325
[b8524ca]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
[2be1023]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 >
[b8524ca]348 void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
[2be1023]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
[b95fe40]354 Type * addCast = nullptr;
355 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) {
356 assert( dstParam->result );
357 addCast = dstParam->result;
358 }
[2be1023]359 std::list< Statement * > stmts;
[1a5ad8c]360 genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward );
[2be1023]361
[6cf27a07]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 );
[f9cebb5]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 }
[2be1023]375 }
[b8524ca]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
[417117e]385 ast::ptr< ast::Type > addCast;
[b8524ca]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 }
[972e6f7]410} // namespace SymTab
[6b0b624]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.