source: src/AST/Pass.impl.hpp@ fdbd4fd

ADT arm-eh ast-experimental cleanup-dtors enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since fdbd4fd was 04124c4, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

More comments and naming conventions fix

  • Property mode set to 100644
File size: 14.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2019 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// Pass.impl.hpp --
8//
9// Author : Thierry Delisle
10// Created On : Thu May 09 15::37::05 2019
11// Last Modified By :
12// Last Modified On :
13// Update Count :
14//
15
16#pragma once
17// IWYU pragma: private, include "AST/Pass.hpp"
18
19#define VISIT_START( node ) \
20 using namespace ast; \
21 /* back-up the visit children */ \
22 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
23 /* setup the scope for passes that want to run code at exit */ \
24 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (pass, 0) ); \
25 /* call the implementation of the previsit of this pass */ \
26 __pass::previsit( pass, node, 0 );
27
28#define VISIT( code ) \
29 /* if this node should visit its children */ \
30 if ( __visit_children() ) { \
31 /* visit the children */ \
32 code \
33 }
34
35#define VISIT_END( type, node ) \
36 /* call the implementation of the postvisit of this pass */ \
37 auto __return = __pass::postvisit< type * >( node ); \
38 assertf(__return, "post visit should never return null"); \
39 return __return;
40
41#ifdef PEDANTIC_PASS_ASSERT
42#define __pedantic_pass_assert (...) assert (__VAR_ARGS__)
43#define __pedantic_pass_assertf(...) assertf(__VAR_ARGS__)
44#else
45#define __pedantic_pass_assert (...)
46#define __pedantic_pass_assertf(...)
47#endif
48
49namespace ast {
50 namespace __pass {
51 // Check if this is either a null pointer or a pointer to an empty container
52 template<typename T>
53 static inline bool empty( T * ptr ) {
54 return !ptr || ptr->empty();
55 }
56
57 template<typename it_t, template <class> class container_t>
58 static inline void take_all( it_t it, container_t<ast::ptr<ast::Declaration>> * decls, bool * mutated = nullptr ) {
59 if(empty(decls)) return;
60
61 std::transform(decls->begin(), decls->end(), it, [](Declaration * decl) -> auto {
62 return new DeclStmt( decl );
63 });
64 decls->clear();
65 if(mutated) *mutated = true;
66 }
67
68 template<typename it_t, template <class> class container_t>
69 static inline void take_all( it_t it, container_t<ast::ptr<ast::Statement>> * decls, bool * mutated = nullptr ) {
70 if(empty(decls)) return;
71
72 std::move(decls->begin(), decls->end(), it);
73 decls->clear();
74 if(mutated) *mutated = true;
75 }
76
77 template<typename node_t>
78 bool differs( const node_t * old_val, const node_t * new_val ) {
79 return old_val != new_val;
80 }
81
82 template< template <class> class container_t >
83 bool differs( const container_t<ast::ptr< ast::Statement >> &, const container_t<ast::ptr< ast::Statement >> & new_val ) {
84 return !new_val.empty();
85 }
86 }
87
88 template<typename parent_t, typename child_t>
89 template< typename pass_t >
90 void Pass< pass_t >::maybe_accept(
91 const parent_t * & parent,
92 const typename parent_t::child_t * child
93 ) {
94 const auto & old_val = parent->*child;
95 if(!old_val) return;
96
97 auto new_val = call_accept(old_val);
98
99 if( __pass::differs(old_val, new_val) ) {
100 auto new_parent = mutate(parent);
101 new_parent->*child = new_val;
102 parent = new_parent;
103 }
104 }
105
106 template< typename pass_t >
107 template< typename node_t >
108 auto Pass< pass_t >::call_accept( const node_t * node ) {
109 __pedantic_pass_assert( __visit_children() );
110 __pedantic_pass_assert( expr );
111
112 return node->accept( *this );
113 }
114
115 template< typename pass_t >
116 ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
117 __pedantic_pass_assert( __visit_children() );
118 __pedantic_pass_assert( expr );
119
120 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
121 if ( env_ptr && expr->env ) {
122 *env_ptr = expr->env;
123 }
124
125 return expr->accept( *this );
126 }
127
128 template< typename pass_t >
129 Stmt * Pass< pass_t >::call_accept( const Stmt * stmt ) {
130 __pedantic_pass_assert( __visit_children() );
131 __pedantic_pass_assert( stmt );
132
133 // add a few useful symbols to the scope
134 using __pass::empty;
135
136 // get the stmts/decls that will need to be spliced in
137 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
138 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);
139 auto decls_before = __pass::declsToAddBefore( pass, 0);
140 auto decls_after = __pass::declsToAddAfter ( pass, 0);
141
142 // These may be modified by subnode but most be restored once we exit this statemnet.
143 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::env( pass, 0); );
144 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
145 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after );
146 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
147 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after );
148
149 // Now is the time to actually visit the node
150 ast::Statement * nstmt = stmt->accept( *this );
151
152 // If the pass doesn't want to add anything then we are done
153 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
154 return nstmt;
155 }
156
157 // Make sure that it is either adding statements or declartions but not both
158 // this is because otherwise the order would be awkward to predict
159 assert(( empty( stmts_before ) && empty( stmts_after ))
160 || ( empty( decls_before ) && empty( decls_after )) );
161
162 // Create a new Compound Statement to hold the new decls/stmts
163 ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
164
165 // Take all the declarations that go before
166 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
167 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
168
169 // Insert the original declaration
170 compound->kids.push_back( nstmt );
171
172 // Insert all the declarations that go before
173 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
174 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
175
176 return compound;
177 }
178
179 template< typename pass_t >
180 template< template <class> class container_t >
181 container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
182 __pedantic_pass_assert( __visit_children() );
183 if( statements.empty() ) return {};
184
185 // We are going to aggregate errors for all these statements
186 SemanticErrorException errors;
187
188 // add a few useful symbols to the scope
189 using __pass::empty;
190
191 // get the stmts/decls that will need to be spliced in
192 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
193 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);
194 auto decls_before = __pass::declsToAddBefore( pass, 0);
195 auto decls_after = __pass::declsToAddAfter ( pass, 0);
196
197 // These may be modified by subnode but most be restored once we exit this statemnet.
198 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
199 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after );
200 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
201 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after );
202
203 // update pass statitistics
204 pass_visitor_stats.depth++;
205 pass_visitor_stats.max->push(pass_visitor_stats.depth);
206 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
207
208 bool mutated = false;
209 container_t< ptr<Stmt> > new_kids;
210 for( const Stmt * stmt : statements ) {
211 try {
212 __pedantic_pass_assert( stmt );
213 const ast::Statment * new_stmt = stmt->accept( visitor );
214 assert( new_stmt );
215 if(new_stmt != stmt ) mutated = true;
216
217 // Make sure that it is either adding statements or declartions but not both
218 // this is because otherwise the order would be awkward to predict
219 assert(( empty( stmts_before ) && empty( stmts_after ))
220 || ( empty( decls_before ) && empty( decls_after )) );
221
222
223
224 // Take all the statements which should have gone after, N/A for first iteration
225 __pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
226 __pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
227
228 // Now add the statement if there is one
229 new_kids.emplace_back( new_stmt );
230
231 // Take all the declarations that go before
232 __pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
233 __pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
234 }
235 catch ( SemanticErrorException &e ) {
236 errors.append( e );
237 }
238 }
239 pass_visitor_stats.depth--;
240 if ( !errors.isEmpty() ) { throw errors; }
241
242 return mutated ? new_kids : {};
243 }
244
245 template< typename pass_t >
246 template< template <class> class container_t, typename node_t >
247 container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
248 __pedantic_pass_assert( __visit_children() );
249 if( container.empty() ) return {};
250 SemanticErrorException errors;
251
252 pass_visitor_stats.depth++;
253 pass_visitor_stats.max->push(pass_visitor_stats.depth);
254 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
255
256 bool mutated = false;
257 container_t< ast::ptr<node_t> > new_kids;
258 for ( const node_t * node : container ) {
259 try {
260 __pedantic_pass_assert( node );
261 const node_t * new_node = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
262 if(new_stmt != stmt ) mutated = true;
263
264 new_kids.emplace_back( new_stmt );
265 }
266 catch( SemanticErrorException &e ) {
267 errors.append( e );
268 }
269 }
270 pass_visitor_stats.depth--;
271 if ( ! errors.isEmpty() ) { throw errors; }
272
273 return mutated ? new_kids : {};
274 }
275}
276
277//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
278//========================================================================================================================================================================
279//========================================================================================================================================================================
280//========================================================================================================================================================================
281//========================================================================================================================================================================
282//========================================================================================================================================================================
283//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
284
285template< typename pass_t >
286inline void ast::acceptAll( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
287 // We are going to aggregate errors for all these statements
288 SemanticErrorException errors;
289
290 // add a few useful symbols to the scope
291 using __pass::empty;
292
293 // get the stmts/decls that will need to be spliced in
294 auto decls_before = __pass::declsToAddBefore( pass, 0);
295 auto decls_after = __pass::declsToAddAfter ( pass, 0);
296
297 // update pass statitistics
298 pass_visitor_stats.depth++;
299 pass_visitor_stats.max->push(pass_visitor_stats.depth);
300 pass_visitor_stats.avg->push(pass_visitor_stats.depth);
301
302 for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
303 // splice in new declarations after previous decl
304 if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
305
306 if ( i == decls.end() ) break;
307
308 try {
309 // run visitor on declaration
310 ast::ptr<ast::Decl> & node = *i;
311 assert( node );
312 node = node->accept( visitor );
313 }
314 catch( SemanticErrorException &e ) {
315 errors.append( e );
316 }
317
318 // splice in new declarations before current decl
319 if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
320 }
321 pass_visitor_stats.depth--;
322 if ( !errors.isEmpty() ) { throw errors; }
323}
324
325// A NOTE ON THE ORDER OF TRAVERSAL
326//
327// Types and typedefs have their base types visited before they are added to the type table. This is ok, since there is
328// no such thing as a recursive type or typedef.
329//
330// typedef struct { T *x; } T; // never allowed
331//
332// for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the
333// members are traversed, and then the complete type should be added (assuming the type is completed by this particular
334// declaration).
335//
336// struct T { struct T *x; }; // allowed
337//
338// It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that
339// traversal may modify the definition of the type and these modifications should be visible when the symbol table is
340// queried later in this pass.
341
342//--------------------------------------------------------------------------
343// ObjectDecl
344template< typename pass_t >
345ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
346 VISIT_START( node );
347
348 VISIT(
349 {
350 indexer_guard guard { *this };
351 maybe_accept( node, ObjectDecl::type );
352 }
353 maybe_accept( node, ObjectDecl::init );
354 maybe_accept( node, ObjectDecl::bitfieldWidth );
355 maybe_accept( node, ObjectDecl::attributes );
356 )
357
358 __pass::indexer::AddId( pass, 0, node );
359
360 VISIT_END( DeclWithType, node );
361}
362
363//--------------------------------------------------------------------------
364// Attribute
365template< typename pass_type >
366ast::Attribute * ast::Pass< pass_type >::visit( const ast::Attribute * node ) {
367 VISIT_START(node);
368
369 VISIT(
370 maybe_accept( node, ast::Attribute::parameters );
371 )
372
373 VISIT_END(ast::Attribute *, node );
374}
375
376//--------------------------------------------------------------------------
377// TypeSubstitution
378template< typename pass_type >
379TypeSubstitution * PassVisitor< pass_type >::mutate( const TypeSubstitution * node ) {
380 MUTATE_START( node );
381
382 #error this is broken
383
384 for ( auto & p : node->typeEnv ) {
385 indexerScopedMutate( p.second, *this );
386 }
387 for ( auto & p : node->varEnv ) {
388 indexerScopedMutate( p.second, *this );
389 }
390
391 MUTATE_END( TypeSubstitution, node );
392}
393
394#undef VISIT_START
395#undef VISIT
396#undef VISIT_END
Note: See TracBrowser for help on using the repository browser.