source: src/AST/Pass.impl.hpp @ 54db6ba

ADTarm-ehast-experimentalcleanup-dtorsenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 54db6ba was 6d51bd7, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Fixes to the new templated pass and started on conversions

  • Property mode set to 100644
File size: 17.5 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#include <type_traits>
20#include <unordered_map>
21
22#define VISIT_START( node ) \
23        using namespace ast; \
24        /* back-up the visit children */ \
25        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
26        /* setup the scope for passes that want to run code at exit */ \
27        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
28        /* call the implementation of the previsit of this pass */ \
29        __pass::previsit( pass, node, 0 );
30
31#define VISIT( code... ) \
32        /* if this node should visit its children */ \
33        if ( __visit_children() ) { \
34                /* visit the children */ \
35                code \
36        }
37
38#define VISIT_END( type, node ) \
39        /* call the implementation of the postvisit of this pass */ \
40        auto __return = __pass::postvisit( pass, node, 0 ); \
41        assertf(__return, "post visit should never return null"); \
42        return __return;
43
44#ifdef PEDANTIC_PASS_ASSERT
45#define __pedantic_pass_assert(...) assert (__VA_ARGS__)
46#define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
47#else
48#define __pedantic_pass_assert(...)
49#define __pedantic_pass_assertf(...)
50#endif
51
52namespace ast {
53        namespace __pass {
54                // Check if this is either a null pointer or a pointer to an empty container
55                template<typename T>
56                static inline bool empty( T * ptr ) {
57                        return !ptr || ptr->empty();
58                }
59
60                //------------------------------
61                template<typename it_t, template <class...> class container_t>
62                static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
63                        if(empty(decls)) return;
64
65                        std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
66                                        return new DeclStmt( decl );
67                                });
68                        decls->clear();
69                        if(mutated) *mutated = true;
70                }
71
72                template<typename it_t, template <class...> class container_t>
73                static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * decls, bool * mutated = nullptr ) {
74                        if(empty(decls)) return;
75
76                        std::move(decls->begin(), decls->end(), it);
77                        decls->clear();
78                        if(mutated) *mutated = true;
79                }
80
81                //------------------------------
82                /// Check if should be skipped, different for pointers and containers
83                template<typename node_t>
84                bool skip( const ast::ptr<node_t> & val) {
85                        return !val;
86                }
87
88                template< template <class...> class container_t, typename node_t >
89                bool skip( const container_t<ast::ptr< node_t >> & val ) {
90                        return val.empty();
91                }
92
93                //------------------------------
94                /// Get the value to visit, different for pointers and containers
95                template<typename node_t>
96                auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) {
97                        return val.get();
98                }
99
100                template<typename node_t>
101                const node_t & get( const node_t & val, long) {
102                        return val;
103                }
104
105
106                //------------------------------
107                /// Check if value was mutated, different for pointers and containers
108                template<typename lhs_t, typename rhs_t>
109                bool differs( const lhs_t * old_val, const rhs_t * new_val ) {
110                        return old_val != new_val;
111                }
112
113                template< template <class...> class container_t, typename node_t >
114                bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & new_val ) {
115                        return !new_val.empty();
116                }
117        }
118
119        template< typename pass_t >
120        template< typename node_t >
121        auto Pass< pass_t >::call_accept( const node_t * node ) -> decltype( node->accept(*this) ) {
122                __pedantic_pass_assert( __visit_children() );
123                __pedantic_pass_assert( expr );
124
125                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
126                static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
127
128                return node->accept( *this );
129        }
130
131        template< typename pass_t >
132        const ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
133                __pedantic_pass_assert( __visit_children() );
134                __pedantic_pass_assert( expr );
135
136                const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
137                if ( env_ptr && expr->env ) {
138                        *env_ptr = expr->env;
139                }
140
141                return expr->accept( *this );
142        }
143
144        template< typename pass_t >
145        const ast::Stmt * Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
146                __pedantic_pass_assert( __visit_children() );
147                __pedantic_pass_assert( stmt );
148
149                // add a few useful symbols to the scope
150                using __pass::empty;
151
152                // get the stmts/decls that will need to be spliced in
153                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
154                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
155                auto decls_before = __pass::declsToAddBefore( pass, 0);
156                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
157
158                // These may be modified by subnode but most be restored once we exit this statemnet.
159                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
160                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > > __old_decls_before( stmts_before );
161                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > > __old_decls_after ( stmts_after  );
162                ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > > __old_stmts_before( decls_before );
163                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > > __old_stmts_after ( decls_after  );
164
165                // Now is the time to actually visit the node
166                const ast::Stmt * nstmt = stmt->accept( *this );
167
168                // If the pass doesn't want to add anything then we are done
169                if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
170                        return nstmt;
171                }
172
173                // Make sure that it is either adding statements or declartions but not both
174                // this is because otherwise the order would be awkward to predict
175                assert(( empty( stmts_before ) && empty( stmts_after ))
176                    || ( empty( decls_before ) && empty( decls_after )) );
177
178                // Create a new Compound Statement to hold the new decls/stmts
179                ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
180
181                // Take all the declarations that go before
182                __pass::take_all( std::back_inserter( compound->kids ), decls_before );
183                __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
184
185                // Insert the original declaration
186                compound->kids.emplace_back( nstmt );
187
188                // Insert all the declarations that go before
189                __pass::take_all( std::back_inserter( compound->kids ), decls_after );
190                __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
191
192                return compound;
193        }
194
195        template< typename pass_t >
196        template< template <class...> class container_t >
197        container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
198                __pedantic_pass_assert( __visit_children() );
199                if( statements.empty() ) return {};
200
201                // We are going to aggregate errors for all these statements
202                SemanticErrorException errors;
203
204                // add a few useful symbols to the scope
205                using __pass::empty;
206
207                // get the stmts/decls that will need to be spliced in
208                auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
209                auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
210                auto decls_before = __pass::declsToAddBefore( pass, 0);
211                auto decls_after  = __pass::declsToAddAfter ( pass, 0);
212
213                // These may be modified by subnode but most be restored once we exit this statemnet.
214                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > > __old_decls_before( stmts_before );
215                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > > __old_decls_after ( stmts_after  );
216                ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > > __old_stmts_before( decls_before );
217                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > > __old_stmts_after ( decls_after  );
218
219                // update pass statitistics
220                pass_visitor_stats.depth++;
221                pass_visitor_stats.max->push(pass_visitor_stats.depth);
222                pass_visitor_stats.avg->push(pass_visitor_stats.depth);
223
224                bool mutated = false;
225                container_t< ptr<Stmt> > new_kids;
226                for( const Stmt * stmt : statements ) {
227                        try {
228                                __pedantic_pass_assert( stmt );
229                                const ast::Stmt * new_stmt = stmt->accept( *this );
230                                assert( new_stmt );
231                                if(new_stmt != stmt ) mutated = true;
232
233                                // Make sure that it is either adding statements or declartions but not both
234                                // this is because otherwise the order would be awkward to predict
235                                assert(( empty( stmts_before ) && empty( stmts_after ))
236                                    || ( empty( decls_before ) && empty( decls_after )) );
237
238
239
240                                // Take all the statements which should have gone after, N/A for first iteration
241                                __pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
242                                __pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
243
244                                // Now add the statement if there is one
245                                new_kids.emplace_back( new_stmt );
246
247                                // Take all the declarations that go before
248                                __pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
249                                __pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
250                        }
251                        catch ( SemanticErrorException &e ) {
252                                errors.append( e );
253                        }
254                }
255                pass_visitor_stats.depth--;
256                if ( !errors.isEmpty() ) { throw errors; }
257
258                return mutated ? new_kids : container_t< ptr<Stmt> >();
259        }
260
261        template< typename pass_t >
262        template< template <class...> class container_t, typename node_t >
263        container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
264                __pedantic_pass_assert( __visit_children() );
265                if( container.empty() ) return {};
266                SemanticErrorException errors;
267
268                pass_visitor_stats.depth++;
269                pass_visitor_stats.max->push(pass_visitor_stats.depth);
270                pass_visitor_stats.avg->push(pass_visitor_stats.depth);
271
272                bool mutated = false;
273                container_t< ast::ptr<node_t> > new_kids;
274                for ( const node_t * node : container ) {
275                        try {
276                                __pedantic_pass_assert( node );
277                                const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
278                                if(new_stmt != node ) mutated = true;
279
280                                new_kids.emplace_back( new_stmt );
281                        }
282                        catch( SemanticErrorException &e ) {
283                                errors.append( e );
284                        }
285                }
286                pass_visitor_stats.depth--;
287                if ( ! errors.isEmpty() ) { throw errors; }
288
289                return mutated ? new_kids : container_t< ast::ptr<node_t> >();
290        }
291
292        template< typename pass_t >
293        template<typename node_t, typename parent_t, typename child_t>
294        void Pass< pass_t >::maybe_accept(
295                const node_t * & parent,
296                child_t parent_t::*child
297        ) {
298                static_assert( std::is_base_of<parent_t, node_t>::value, "Error deductiing member object" );
299
300                if(__pass::skip(parent->*child)) return;
301                const auto & old_val = __pass::get(parent->*child, 0);
302
303                static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
304
305                auto new_val = call_accept( old_val );
306
307                static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
308
309                if( __pass::differs(old_val, new_val) ) {
310                        auto new_parent = mutate(parent);
311                        new_parent->*child = new_val;
312                        parent = new_parent;
313                }
314        }
315
316}
317
318//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
319//========================================================================================================================================================================
320//========================================================================================================================================================================
321//========================================================================================================================================================================
322//========================================================================================================================================================================
323//========================================================================================================================================================================
324//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
325
326template< typename pass_t >
327inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
328        // We are going to aggregate errors for all these statements
329        SemanticErrorException errors;
330
331        // add a few useful symbols to the scope
332        using __pass::empty;
333
334        // get the stmts/decls that will need to be spliced in
335        auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
336        auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
337
338        // update pass statitistics
339        pass_visitor_stats.depth++;
340        pass_visitor_stats.max->push(pass_visitor_stats.depth);
341        pass_visitor_stats.avg->push(pass_visitor_stats.depth);
342
343        for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
344                // splice in new declarations after previous decl
345                if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
346
347                if ( i == decls.end() ) break;
348
349                try {
350                        // run visitor on declaration
351                        ast::ptr<ast::Decl> & node = *i;
352                        assert( node );
353                        node = node->accept( visitor );
354                }
355                catch( SemanticErrorException &e ) {
356                        errors.append( e );
357                }
358
359                // splice in new declarations before current decl
360                if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
361        }
362        pass_visitor_stats.depth--;
363        if ( !errors.isEmpty() ) { throw errors; }
364}
365
366// A NOTE ON THE ORDER OF TRAVERSAL
367//
368// Types and typedefs have their base types visited before they are added to the type table.  This is ok, since there is
369// no such thing as a recursive type or typedef.
370//
371//             typedef struct { T *x; } T; // never allowed
372//
373// for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the
374// members are traversed, and then the complete type should be added (assuming the type is completed by this particular
375// declaration).
376//
377//             struct T { struct T *x; }; // allowed
378//
379// It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that
380// traversal may modify the definition of the type and these modifications should be visible when the symbol table is
381// queried later in this pass.
382
383//--------------------------------------------------------------------------
384// ObjectDecl
385template< typename pass_t >
386const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
387        VISIT_START( node );
388
389        VISIT(
390                {
391                        guard_indexer guard { *this };
392                        maybe_accept( node, &ast::ObjectDecl::type );
393                }
394                maybe_accept( node, &ast::ObjectDecl::init          );
395                maybe_accept( node, &ast::ObjectDecl::bitfieldWidth );
396                maybe_accept( node, &ast::ObjectDecl::attributes    );
397        )
398
399        __pass::indexer::addId( pass, 0, node );
400
401        VISIT_END( DeclWithType, node );
402}
403
404//--------------------------------------------------------------------------
405// SingleInit
406template< typename pass_t >
407const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
408        VISIT_START( node );
409
410        VISIT(
411                maybe_accept( node, &SingleInit::value );
412        )
413
414        VISIT_END( Init, node );
415}
416
417//--------------------------------------------------------------------------
418// ListInit
419template< typename pass_t >
420const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
421        VISIT_START( node );
422
423        VISIT(
424                maybe_accept( node, &ListInit::designations );
425                maybe_accept( node, &ListInit::initializers );
426        )
427
428        VISIT_END( Init, node );
429}
430
431//--------------------------------------------------------------------------
432// ConstructorInit
433template< typename pass_t >
434const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
435        VISIT_START( node );
436
437        VISIT(
438                maybe_accept( node, &ConstructorInit::ctor );
439                maybe_accept( node, &ConstructorInit::dtor );
440                maybe_accept( node, &ConstructorInit::init );
441        )
442
443        VISIT_END( Init, node );
444}
445
446//--------------------------------------------------------------------------
447// Attribute
448template< typename pass_t >
449const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
450        VISIT_START( node );
451
452        VISIT(
453                maybe_accept( node, &Attribute::parameters );
454        )
455
456        VISIT_END( Attribute *, node );
457}
458
459//--------------------------------------------------------------------------
460// TypeSubstitution
461template< typename pass_t >
462const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
463        VISIT_START( node );
464
465        VISIT(
466                {
467                        bool mutated = false;
468                        std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
469                        for ( const auto & p : node->typeEnv ) {
470                                guard_indexer guard { *this };
471                                auto new_node = p.second->accept( *this );
472                                if (new_node != p.second) mutated = false;
473                                new_map.insert({ p.first, new_node });
474                        }
475                        if (mutated) {
476                                auto new_node = mutate( node );
477                                new_node->typeEnv.swap( new_map );
478                                node = new_node;
479                        }
480                }
481
482                {
483                        bool mutated = false;
484                        std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
485                        for ( const auto & p : node->varEnv ) {
486                                guard_indexer guard { *this };
487                                auto new_node = p.second->accept( *this );
488                                if (new_node != p.second) mutated = false;
489                                new_map.insert({ p.first, new_node });
490                        }
491                        if (mutated) {
492                                auto new_node = mutate( node );
493                                new_node->varEnv.swap( new_map );
494                                node = new_node;
495                        }
496                }
497        )
498
499        VISIT_END( TypeSubstitution, node );
500}
501
502#undef VISIT_START
503#undef VISIT
504#undef VISIT_END
Note: See TracBrowser for help on using the repository browser.