source: src/SymTab/Autogen.h@ e9e9f56

ADT ast-experimental pthread-emulation
Last change on this file since e9e9f56 was e6cf857f, checked in by Andrew Beach <ajbeach@…>, 3 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.