source: src/SymTab/Autogen.h@ 158b026

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 158b026 was b8524ca, checked in by Aaron Moss <a3moss@…>, 6 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
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
[6b0b624]12// Last Modified On : Sat Jul 22 09:50:25 2017
13// Update Count : 15
[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"
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"
[1a5ad8c]28#include "CodeGen/OperatorTable.h"
[30f9072]29#include "Common/UniqueName.h" // for UniqueName
[b8524ca]30#include "Common/utility.h" // for splice
[30f9072]31#include "InitTweak/InitTweak.h" // for InitExpander
32#include "SynTree/Constant.h" // for Constant
[d180746]33#include "SynTree/Declaration.h" // for DeclarationWithType, ObjectDecl
34#include "SynTree/Expression.h" // for NameExpr, ConstantExpr, UntypedExpr...
[30f9072]35#include "SynTree/Type.h" // for Type, ArrayType, Type::Qualifiers
[972e6f7]36
[d180746]37class CompoundStmt;
38class Statement;
39
[972e6f7]40namespace SymTab {
[2be1023]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 );
[b8524ca]46 bool isUnnamedBitfield( const ast::ObjectDecl * obj );
[2be1023]47
[837ce06]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 );
[8a6cf7e]51
[837ce06]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 );
[8404321]55
[837ce06]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 );
[8404321]59
[b8524ca]60 /// Enum for loop direction
61 enum LoopDirection { LoopBackward, LoopForward };
62
[2be1023]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 >
[b8524ca]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 );
[2be1023]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.
[f9cebb5]74 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
[2be1023]75 template< typename OutputIterator >
[b8524ca]76 Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
[1a5ad8c]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 );
[b95fe40]83 addCast = nullptr;
[1a5ad8c]84 isReferenceCtorDtor = true;
85 }
86
[49148d5]87 // want to be able to generate assignment, ctor, and dtor generically,
88 // so fname is either ?=?, ?{}, or ^?{}
[1a5ad8c]89 UntypedExpr * fExpr = new UntypedExpr( new NameExpr( fname ) );
[49148d5]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();
[b95fe40]98 Type * castType = addCast->clone();
[49148d5]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 }
[1a5ad8c]103 fExpr->args.push_back( dstParam );
[2be1023]104
[49148d5]105 Statement * listInit = srcParam.buildListInit( fExpr );
[39f84a4]106
[1a5ad8c]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 );
[4d2434a]118
[ba3706f]119 *out++ = new ExprStmt( fExpr );
[4d2434a]120
[49148d5]121 srcParam.clearArrayIndices();
[f9cebb5]122
[49148d5]123 return listInit;
[2be1023]124 }
125
[b8524ca]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
[2be1023]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 >
[b8524ca]186 void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
[2be1023]187 static UniqueName indexName( "_index" );
188
189 // for a flexible array member nothing is done -- user must define own assignment
[b95fe40]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 }
[2be1023]197
198 Expression * begin, * end, * update, * cmp;
199 if ( forward ) {
[579263a]200 // generate: for ( int i = 0; i < N; ++i )
201 begin = new ConstantExpr( Constant::from_int( 0 ) );
[1a5ad8c]202 end = array->dimension->clone();
[2be1023]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( "?-?" ) );
[1a5ad8c]208 ((UntypedExpr*)begin)->args.push_back( array->dimension->clone() );
209 ((UntypedExpr*)begin)->args.push_back( new ConstantExpr( Constant::from_int( 1 ) ) );
[579263a]210 end = new ConstantExpr( Constant::from_int( 0 ) );
[2be1023]211 cmp = new NameExpr( "?>=?" );
212 update = new NameExpr( "--?" );
213 }
214
[e4d829b]215 ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin ) );
[2be1023]216
217 UntypedExpr *cond = new UntypedExpr( cmp );
[1a5ad8c]218 cond->args.push_back( new VariableExpr( index ) );
219 cond->args.push_back( end );
[2be1023]220
221 UntypedExpr *inc = new UntypedExpr( update );
[1a5ad8c]222 inc->args.push_back( new VariableExpr( index ) );
[2be1023]223
224 UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
[1a5ad8c]225 dstIndex->args.push_back( dstParam );
226 dstIndex->args.push_back( new VariableExpr( index ) );
[2be1023]227 dstParam = dstIndex;
228
[39f84a4]229 // srcParam must keep track of the array indices to build the
230 // source parameter and/or array list initializer
[1a5ad8c]231 srcParam.addArrayIndex( new VariableExpr( index ), array->dimension->clone() );
[39f84a4]232
[2be1023]233 // for stmt's body, eventually containing call
[ba3706f]234 CompoundStmt * body = new CompoundStmt();
[1a5ad8c]235 Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->kids ), array->base, addCast, forward );
[2be1023]236
237 // block containing for stmt and index variable
238 std::list<Statement *> initList;
[ba3706f]239 CompoundStmt * block = new CompoundStmt();
240 block->push_back( new DeclStmt( index ) );
[f9cebb5]241 if ( listInit ) block->get_kids().push_back( listInit );
[ba3706f]242 block->push_back( new ForStmt( initList, cond, inc, body ) );
[2be1023]243
244 *out++ = block;
245 }
246
[b8524ca]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
[2be1023]317 template< typename OutputIterator >
[b8524ca]318 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
[2be1023]319 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
[4d2434a]320 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
[f9cebb5]321 return 0;
[2be1023]322 } else {
[f9cebb5]323 return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
[2be1023]324 }
325 }
326
[b8524ca]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
[2be1023]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 >
[b8524ca]349 void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
[2be1023]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
[b95fe40]355 Type * addCast = nullptr;
356 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) {
357 assert( dstParam->result );
358 addCast = dstParam->result;
359 }
[2be1023]360 std::list< Statement * > stmts;
[1a5ad8c]361 genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward );
[2be1023]362
[6cf27a07]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 );
[f9cebb5]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 }
[2be1023]376 }
[b8524ca]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 }
[972e6f7]411} // namespace SymTab
[6b0b624]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.