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
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.