source: src/SymTab/Autogen.h@ c083c3d

ADT ast-experimental
Last change on this file since c083c3d was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Moved new ast code out of one of the old files. The new file may have to change if SymTab is removed entirely, but for now at least, there is a lot less template code in headers.

  • Property mode set to 100644
File size: 9.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 : Andrew Beach
12// Last Modified On : Fri Apr 14 15:06:00 2023
13// Update Count : 17
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
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 );
51
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 );
55
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 );
59
60 /// Enum for loop direction
61 enum LoopDirection { LoopBackward, LoopForward };
62
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 >
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 /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
68 /// optionally returns a statement which must be inserted prior to the containing loop, if there is one
69 template< typename OutputIterator >
70 Statement * genScalarCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, std::string fname, OutputIterator out, Type * type, Type * addCast = nullptr ) {
71 bool isReferenceCtorDtor = false;
72 if ( dynamic_cast< ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
73 // reference constructors are essentially application of the rebind operator.
74 // apply & to both arguments, do not need a cast
75 fname = "?=?";
76 dstParam = new AddressExpr( dstParam );
77 addCast = nullptr;
78 isReferenceCtorDtor = true;
79 }
80
81 // want to be able to generate assignment, ctor, and dtor generically,
82 // so fname is either ?=?, ?{}, or ^?{}
83 UntypedExpr * fExpr = new UntypedExpr( new NameExpr( fname ) );
84
85 if ( addCast ) {
86 // cast to T& with qualifiers removed, so that qualified objects can be constructed
87 // and destructed with the same functions as non-qualified objects.
88 // unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
89 // must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
90 // remove lvalue as a qualifier, this can change to
91 // type->get_qualifiers() = Type::Qualifiers();
92 Type * castType = addCast->clone();
93 castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
94 // castType->set_lvalue( true ); // xxx - might not need this
95 dstParam = new CastExpr( dstParam, new ReferenceType( Type::Qualifiers(), castType ) );
96 }
97 fExpr->args.push_back( dstParam );
98
99 Statement * listInit = srcParam.buildListInit( fExpr );
100
101 // fetch next set of arguments
102 ++srcParam;
103
104 // return if adding reference fails - will happen on default constructor and destructor
105 if ( isReferenceCtorDtor && ! srcParam.addReference() ) {
106 delete fExpr;
107 return listInit;
108 }
109
110 std::list< Expression * > args = *srcParam;
111 fExpr->args.splice( fExpr->args.end(), args );
112
113 *out++ = new ExprStmt( fExpr );
114
115 srcParam.clearArrayIndices();
116
117 return listInit;
118 }
119
120 /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
121 /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
122 template< typename OutputIterator >
123 void genArrayCall( InitTweak::InitExpander_old & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, ArrayType *array, Type * addCast = nullptr, bool forward = true ) {
124 static UniqueName indexName( "_index" );
125
126 // for a flexible array member nothing is done -- user must define own assignment
127 if ( ! array->get_dimension() ) return;
128
129 if ( addCast ) {
130 // peel off array layer from cast
131 ArrayType * at = strict_dynamic_cast< ArrayType * >( addCast );
132 addCast = at->base;
133 }
134
135 Expression * begin, * end, * update, * cmp;
136 if ( forward ) {
137 // generate: for ( int i = 0; i < N; ++i )
138 begin = new ConstantExpr( Constant::from_int( 0 ) );
139 end = array->dimension->clone();
140 cmp = new NameExpr( "?<?" );
141 update = new NameExpr( "++?" );
142 } else {
143 // generate: for ( int i = N-1; i >= 0; --i )
144 begin = new UntypedExpr( new NameExpr( "?-?" ) );
145 ((UntypedExpr*)begin)->args.push_back( array->dimension->clone() );
146 ((UntypedExpr*)begin)->args.push_back( new ConstantExpr( Constant::from_int( 1 ) ) );
147 end = new ConstantExpr( Constant::from_int( 0 ) );
148 cmp = new NameExpr( "?>=?" );
149 update = new NameExpr( "--?" );
150 }
151
152 ObjectDecl *index = new ObjectDecl( indexName.newName(), Type::StorageClasses(), LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), new SingleInit( begin ) );
153
154 UntypedExpr *cond = new UntypedExpr( cmp );
155 cond->args.push_back( new VariableExpr( index ) );
156 cond->args.push_back( end );
157
158 UntypedExpr *inc = new UntypedExpr( update );
159 inc->args.push_back( new VariableExpr( index ) );
160
161 UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
162 dstIndex->args.push_back( dstParam );
163 dstIndex->args.push_back( new VariableExpr( index ) );
164 dstParam = dstIndex;
165
166 // srcParam must keep track of the array indices to build the
167 // source parameter and/or array list initializer
168 srcParam.addArrayIndex( new VariableExpr( index ), array->dimension->clone() );
169
170 // for stmt's body, eventually containing call
171 CompoundStmt * body = new CompoundStmt();
172 Statement * listInit = genCall( srcParam, dstParam, fname, back_inserter( body->kids ), array->base, addCast, forward );
173
174 // block containing for stmt and index variable
175 std::list<Statement *> initList;
176 CompoundStmt * block = new CompoundStmt();
177 block->push_back( new DeclStmt( index ) );
178 if ( listInit ) block->get_kids().push_back( listInit );
179 block->push_back( new ForStmt( initList, cond, inc, body ) );
180
181 *out++ = block;
182 }
183
184 template< typename OutputIterator >
185 Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
186 if ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
187 genArrayCall( srcParam, dstParam, fname, out, at, addCast, forward );
188 return 0;
189 } else {
190 return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
191 }
192 }
193
194 /// inserts into out a generated call expression to function fname with arguments dstParam
195 /// and srcParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls. decl is the
196 /// object being constructed. The function wraps constructor and destructor calls in an
197 /// ImplicitCtorDtorStmt node.
198 template< typename OutputIterator >
199 void genImplicitCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, DeclarationWithType * decl, bool forward = true ) {
200 ObjectDecl *obj = dynamic_cast<ObjectDecl *>( decl );
201 assert( obj );
202 // unnamed bit fields are not copied as they cannot be accessed
203 if ( isUnnamedBitfield( obj ) ) return;
204
205 Type * addCast = nullptr;
206 if ( (fname == "?{}" || fname == "^?{}") && ( !obj || ( obj && ! obj->get_bitfieldWidth() ) ) ) {
207 assert( dstParam->result );
208 addCast = dstParam->result;
209 }
210 std::list< Statement * > stmts;
211 genCall( srcParam, dstParam, fname, back_inserter( stmts ), obj->type, addCast, forward );
212
213 // 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
214 assert( stmts.size() <= 1 );
215 if ( stmts.size() == 1 ) {
216 Statement * callStmt = stmts.front();
217 if ( addCast ) {
218 // implicitly generated ctor/dtor calls should be wrapped
219 // so that later passes are aware they were generated.
220 // xxx - don't mark as an implicit ctor/dtor if obj is a bitfield,
221 // because this causes the address to be taken at codegen, which is illegal in C.
222 callStmt = new ImplicitCtorDtorStmt( callStmt );
223 }
224 *out++ = callStmt;
225 }
226 }
227
228} // namespace SymTab
229
230// Local Variables: //
231// tab-width: 4 //
232// mode: c++ //
233// compile-command: "make install" //
234// End: //
Note: See TracBrowser for help on using the repository browser.