Changeset fc1a3e2


Ignore:
Timestamp:
Apr 19, 2024, 2:36:52 PM (17 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
ba97ebf
Parents:
b9b6efb
Message:

Style update. Focused on indentation and trailing whitespace.

Location:
src
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Print.cpp

    rb9b6efb rfc1a3e2  
    15791579                preprint( node );
    15801580                os << "enum attr ";
    1581         if ( node->attr == ast::EnumAttribute::Label ) {
    1582             os << "Label ";
    1583         } else if ( node->attr == ast::EnumAttribute::Value ) {
    1584             os << "Value ";
    1585         } else {
    1586             os << "Posn ";
    1587         }
     1581                if ( node->attr == ast::EnumAttribute::Label ) {
     1582                        os << "Label ";
     1583                } else if ( node->attr == ast::EnumAttribute::Value ) {
     1584                        os << "Value ";
     1585                } else {
     1586                        os << "Posn ";
     1587                }
    15881588                (*(node->instance)).accept( *this );
    15891589                return node;
  • src/AST/Type.hpp

    rb9b6efb rfc1a3e2  
    3131// Must be included in *all* AST classes; should be #undef'd at the end of the file
    3232#define MUTATE_FRIEND \
    33     template<typename node_t> friend node_t * mutate(const node_t * node); \
     33        template<typename node_t> friend node_t * mutate(const node_t * node); \
    3434        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3535
     
    322322public:
    323323        readonly<EnumInstType> instance;
    324     EnumAttribute attr;
     324        EnumAttribute attr;
    325325        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    326326        EnumAttrType( const EnumInstType * instance, EnumAttribute attr = EnumAttribute::Posn )
    327327                : instance(instance), attr(attr) {}
    328        
    329     bool match( const ast::EnumAttrType * other) const {
    330         return instance->base->name == other->instance->base->name && attr == other->attr;
    331     }
     328
     329        bool match( const ast::EnumAttrType * other) const {
     330                return instance->base->name == other->instance->base->name && attr == other->attr;
     331        }
    332332private:
    333333        EnumAttrType * clone() const override { return new EnumAttrType{ *this }; }
  • src/BasicTypes-gen.cc

    rb9b6efb rfc1a3e2  
    415415        code << "\t" << BYMK << endl;
    416416        code << "\t#define BT ast::BasicKind::" << endl;
    417         code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
     417        code << "\tstatic const ast::BasicKind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
    418418             << "\t\t/*\t\t ";
    419419        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
  • src/Common/PersistentMap.h

    rb9b6efb rfc1a3e2  
    2323#include <utility>        // for forward, move
    2424
    25 /// Wraps a hash table in a persistent data structure, using a technique based 
    26 /// on the persistent array in Conchon & Filliatre "A Persistent Union-Find 
     25/// Wraps a hash table in a persistent data structure, using a technique based
     26/// on the persistent array in Conchon & Filliatre "A Persistent Union-Find
    2727/// Data Structure"
    2828
    2929template<typename Key, typename Val,
    30          typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
    31 class PersistentMap 
     30                typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
     31class PersistentMap
    3232        : public std::enable_shared_from_this<PersistentMap<Key, Val, Hash, Eq>> {
    3333public:
     
    3838
    3939        /// Types of version nodes
    40         enum Mode { 
     40        enum Mode {
    4141                BASE,  ///< Root node of version tree
    4242                REM,   ///< Key removal node
     
    6363                Ptr base;  ///< Modified map
    6464                Key key;   ///< Key removed
    65                
     65
    6666                template<typename P, typename K>
    6767                Rem(P&& p, K&& k) : base(std::forward<P>(p)), key(std::forward<K>(k)) {}
     
    155155                                auto it = base_map.find( self.key );
    156156
    157                                 base->template init<Ins>( 
     157                                base->template init<Ins>(
    158158                                                mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
    159159                                base->mode = INS;
     
    175175                                auto it = base_map.find( self.key );
    176176
    177                                 base->template init<Ins>( 
     177                                base->template init<Ins>(
    178178                                                mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
    179179                                base->mode = UPD;
     
    267267        Ptr erase(const Key& k) {
    268268                reroot();
    269                
     269
    270270                // exit early if key does not exist in map
    271271                if ( ! as<Base>().count( k ) ) return this->shared_from_this();
  • src/Common/VectorMap.h

    rb9b6efb rfc1a3e2  
    3636        typedef const value_type* pointer;
    3737        typedef const const_value_type* const_pointer;
    38        
    39         class iterator : public std::iterator< std::random_access_iterator_tag,
    40                                                value_type,
    41                                                                                    difference_type,
    42                                                                                    pointer,
    43                                                                                    reference > {
    44         friend class VectorMap;
    45         friend class const_iterator;
    46        
     38
     39        class iterator : public std::iterator<
     40                        std::random_access_iterator_tag,
     41                        value_type, difference_type, pointer, reference > {
     42                friend class VectorMap;
     43                friend class const_iterator;
     44
    4745                value_type data;
    4846
     
    9997                        return data.first == o.data.first && &data.second == &o.data.second;
    10098                }
    101                
     99
    102100                bool operator!= (const iterator& that) const { return !(*this == that); }
    103101
     
    111109        };
    112110
    113         class const_iterator : public std::iterator< std::bidirectional_iterator_tag,
    114                                                      const_value_type,
    115                                                                                                   difference_type,
    116                                                                                                   const_pointer,
    117                                                                                                   const_reference  > {
    118         friend class VectorMap;
     111        class const_iterator : public std::iterator<
     112                        std::bidirectional_iterator_tag,
     113                        const_value_type, difference_type, const_pointer, const_reference > {
     114                friend class VectorMap;
    119115                const_value_type data;
    120116
     
    181177                        return data.first == o.data.first && &data.second == &o.data.second;
    182178                }
    183                
     179
    184180                bool operator!= (const const_iterator& that) const { return !(*this == that); }
    185181
     
    233229
    234230template<typename T>
    235 typename VectorMap<T>::iterator operator+ (typename VectorMap<T>::difference_type i,
    236                                            const typename VectorMap<T>::iterator& it) {
     231typename VectorMap<T>::iterator operator+(
     232                typename VectorMap<T>::difference_type i,
     233                const typename VectorMap<T>::iterator& it) {
    237234        return it + i;
    238235}
    239236
    240237template<typename T>
    241 typename VectorMap<T>::const_iterator operator+ (typename VectorMap<T>::difference_type i,
    242                                                  const typename VectorMap<T>::const_iterator& it) {
     238typename VectorMap<T>::const_iterator operator+(
     239                typename VectorMap<T>::difference_type i,
     240                const typename VectorMap<T>::const_iterator& it) {
    243241        return it + i;
    244242}
  • src/Concurrency/Actors.cpp

    rb9b6efb rfc1a3e2  
    2828
    2929struct CollectactorStructDecls : public ast::WithGuards {
    30     unordered_set<const StructDecl *> & actorStructDecls;
    31     unordered_set<const StructDecl *>  & messageStructDecls;
    32     const StructDecl ** requestDecl;
    33     const EnumDecl ** allocationDecl;
    34     const StructDecl ** actorDecl;
    35     const StructDecl ** msgDecl;
    36     StructDecl * parentDecl;
    37     bool insideStruct = false;
    38     bool namedDecl = false;
    39 
    40     // finds and sets a ptr to the allocation enum, which is needed in the next pass
    41     void previsit( const EnumDecl * decl ) {
    42         if( decl->name == "allocation" ) *allocationDecl = decl;
    43     }
    44 
    45     // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
    46     void previsit( const StructDecl * decl ) {
    47         if ( !decl->body ) return;
    48         if ( decl->name == "actor" ) {
    49             actorStructDecls.insert( decl ); // skip inserting fwd decl
    50             *actorDecl = decl;
    51         } else if( decl->name == "message" ) {
    52             messageStructDecls.insert( decl ); // skip inserting fwd decl
    53             *msgDecl = decl;
    54         } else if( decl->name == "request" ) *requestDecl = decl;
    55         else {
    56             GuardValue(insideStruct);
    57             insideStruct = true;
    58             parentDecl = mutate( decl );
    59         }
    60         }
    61 
    62     // this catches structs of the form:
    63     //     struct dummy_actor { actor a; };
    64     // since they should be:
    65     //     struct dummy_actor { inline actor; };
    66     void previsit ( const ObjectDecl * decl ) {
    67         if ( insideStruct && ! decl->name.empty() ) {
    68             GuardValue(namedDecl);
    69             namedDecl = true;
    70         }
    71     }
    72 
    73     // this collects the derived actor and message struct decl ptrs
    74     void postvisit( const StructInstType * node ) {
    75         if ( ! *actorDecl || ! *msgDecl ) return;
    76         if ( insideStruct && !namedDecl ) {
    77             auto actorIter = actorStructDecls.find( node->aggr() );   
    78             if ( actorIter != actorStructDecls.end() ) {
    79                 actorStructDecls.insert( parentDecl );
    80                 return;
    81             }
    82             auto messageIter = messageStructDecls.find( node->aggr() );
    83             if ( messageIter != messageStructDecls.end() ) {
    84                 messageStructDecls.insert( parentDecl );
    85             }
    86         }
     30        unordered_set<const StructDecl *> & actorStructDecls;
     31        unordered_set<const StructDecl *>  & messageStructDecls;
     32        const StructDecl ** requestDecl;
     33        const EnumDecl ** allocationDecl;
     34        const StructDecl ** actorDecl;
     35        const StructDecl ** msgDecl;
     36        StructDecl * parentDecl;
     37        bool insideStruct = false;
     38        bool namedDecl = false;
     39
     40        // finds and sets a ptr to the allocation enum, which is needed in the next pass
     41        void previsit( const EnumDecl * decl ) {
     42                if( decl->name == "allocation" ) *allocationDecl = decl;
     43        }
     44
     45        // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
     46        void previsit( const StructDecl * decl ) {
     47                if ( !decl->body ) return;
     48                if ( decl->name == "actor" ) {
     49                        actorStructDecls.insert( decl ); // skip inserting fwd decl
     50                        *actorDecl = decl;
     51                } else if( decl->name == "message" ) {
     52                        messageStructDecls.insert( decl ); // skip inserting fwd decl
     53                        *msgDecl = decl;
     54                } else if( decl->name == "request" ) *requestDecl = decl;
     55                else {
     56                        GuardValue(insideStruct);
     57                        insideStruct = true;
     58                        parentDecl = mutate( decl );
     59                }
     60        }
     61
     62        // this catches structs of the form:
     63        //     struct dummy_actor { actor a; };
     64        // since they should be:
     65        //     struct dummy_actor { inline actor; };
     66        void previsit ( const ObjectDecl * decl ) {
     67                if ( insideStruct && ! decl->name.empty() ) {
     68                        GuardValue(namedDecl);
     69                        namedDecl = true;
     70                }
     71        }
     72
     73        // this collects the derived actor and message struct decl ptrs
     74        void postvisit( const StructInstType * node ) {
     75                if ( ! *actorDecl || ! *msgDecl ) return;
     76                if ( insideStruct && !namedDecl ) {
     77                        auto actorIter = actorStructDecls.find( node->aggr() );
     78                        if ( actorIter != actorStructDecls.end() ) {
     79                                actorStructDecls.insert( parentDecl );
     80                                return;
     81                        }
     82                        auto messageIter = messageStructDecls.find( node->aggr() );
     83                        if ( messageIter != messageStructDecls.end() ) {
     84                                messageStructDecls.insert( parentDecl );
     85                        }
     86                }
    8787        }
    8888
    8989  public:
    90     CollectactorStructDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    91         const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl )
    92         : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ),
    93         allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
     90        CollectactorStructDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     91                const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl )
     92                : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ),
     93                allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
    9494};
    9595
     
    9797class FwdDeclTable {
    9898
    99     // tracks which decls we have seen so that we can hoist the FunctionDecl to the highest point possible
    100     struct FwdDeclData {
    101         const StructDecl * actorDecl;
    102         const StructDecl * msgDecl;
    103         FunctionDecl * fwdDecl;
    104         bool actorFound;
    105         bool msgFound;
    106 
    107         bool readyToInsert() { return actorFound && msgFound; }
    108         bool foundActor() { actorFound = true; return readyToInsert(); }
    109         bool foundMsg() { msgFound = true; return readyToInsert(); }
    110 
    111         FwdDeclData( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) :
    112             actorDecl(actorDecl), msgDecl(msgDecl), fwdDecl(fwdDecl), actorFound(false), msgFound(false) {}
    113     };
    114 
    115     // map indexed by actor struct ptr
    116     // value is map of all FwdDeclData that contains said actor struct ptr
    117     // inner map is indexed by the message struct ptr of FwdDeclData
    118     unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> actorMap;
    119 
    120     // this map is the same except the outer map is indexed by message ptr and the inner is indexed by actor ptr
    121     unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> msgMap;
    122 
    123     void insert( const StructDecl * decl, const StructDecl * otherDecl, unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map, FwdDeclData * data ) {
    124         auto iter = map.find( decl );
    125         if ( iter != map.end() ) { // if decl exists in map append data to existing inner map
    126             iter->second.emplace( make_pair( otherDecl, data ) );
    127         } else { // else create inner map for key
    128             map.emplace( make_pair( decl, unordered_map<const StructDecl *, FwdDeclData *>( { make_pair( otherDecl, data ) } ) ) );
    129         }
    130     }
     99        // tracks which decls we have seen so that we can hoist the FunctionDecl to the highest point possible
     100        struct FwdDeclData {
     101                const StructDecl * actorDecl;
     102                const StructDecl * msgDecl;
     103                FunctionDecl * fwdDecl;
     104                bool actorFound;
     105                bool msgFound;
     106
     107                bool readyToInsert() { return actorFound && msgFound; }
     108                bool foundActor() { actorFound = true; return readyToInsert(); }
     109                bool foundMsg() { msgFound = true; return readyToInsert(); }
     110
     111                FwdDeclData( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) :
     112                        actorDecl(actorDecl), msgDecl(msgDecl), fwdDecl(fwdDecl), actorFound(false), msgFound(false) {}
     113        };
     114
     115        // map indexed by actor struct ptr
     116        // value is map of all FwdDeclData that contains said actor struct ptr
     117        // inner map is indexed by the message struct ptr of FwdDeclData
     118        unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> actorMap;
     119
     120        // this map is the same except the outer map is indexed by message ptr and the inner is indexed by actor ptr
     121        unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> msgMap;
     122
     123        void insert( const StructDecl * decl, const StructDecl * otherDecl, unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map, FwdDeclData * data ) {
     124                auto iter = map.find( decl );
     125                if ( iter != map.end() ) { // if decl exists in map append data to existing inner map
     126                        iter->second.emplace( make_pair( otherDecl, data ) );
     127                } else { // else create inner map for key
     128                        map.emplace( make_pair( decl, unordered_map<const StructDecl *, FwdDeclData *>( { make_pair( otherDecl, data ) } ) ) );
     129                }
     130        }
    131131
    132132  public:
    133     // insert decl into table so that we can fwd declare it later (average cost: O(1))
    134     void insertDecl( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) {
    135         FwdDeclData * declToInsert = new FwdDeclData( actorDecl, msgDecl, fwdDecl );
    136         insert( actorDecl, msgDecl, actorMap, declToInsert );
    137         insert( msgDecl, actorDecl, msgMap, declToInsert );
    138     }
    139 
    140     // returns list of decls to insert after current struct decl
    141     // Over the entire pass the runtime of this routine is O(r) where r is the # of receive routines
    142     list<FunctionDecl *> updateDecl( const StructDecl * decl, bool isMsg ) {
    143         unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map = isMsg ? msgMap : actorMap;
    144         unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & otherMap =  isMsg ? actorMap : msgMap;
    145         auto iter = map.find( decl );
    146         list<FunctionDecl *> toInsertAfter; // this is populated with decls that are ready to insert
    147         if ( iter == map.end() ) return toInsertAfter;
    148        
    149         // iterate over inner map
    150         unordered_map<const StructDecl *, FwdDeclData *> & currInnerMap = iter->second;
    151         for ( auto innerIter = currInnerMap.begin(); innerIter != currInnerMap.end(); ) {
    152             FwdDeclData * currentDatum = innerIter->second;
    153             bool readyToInsert = isMsg ? currentDatum->foundMsg() : currentDatum->foundActor();
    154             if ( ! readyToInsert ) { ++innerIter; continue; }
    155            
    156             // readyToInsert is true so we are good to insert the forward decl of the message fn
    157             toInsertAfter.push_back( currentDatum->fwdDecl );
    158 
    159             // need to remove from other map before deleting
    160             // find inner map in other map ( other map is actor map if original is msg map and vice versa )
    161             const StructDecl * otherDecl = isMsg ? currentDatum->actorDecl : currentDatum->msgDecl;
    162             auto otherMapIter = otherMap.find( otherDecl );
    163 
    164             unordered_map<const StructDecl *, FwdDeclData *> & otherInnerMap = otherMapIter->second;
    165 
    166             // find the FwdDeclData we need to remove in the other inner map
    167             auto otherInnerIter = otherInnerMap.find( decl );
    168 
    169             // remove references to deleted FwdDeclData from current inner map
    170             innerIter = currInnerMap.erase( innerIter ); // this does the increment so no explicit inc needed
    171 
    172             // remove references to deleted FwdDeclData from other inner map
    173             otherInnerMap.erase( otherInnerIter );
    174            
    175             // if other inner map is now empty, remove key from other outer map
    176             if ( otherInnerMap.empty() )
    177                 otherMap.erase( otherDecl );
    178 
    179             // now we are safe to delete the FwdDeclData since we are done with it
    180             // and we have removed all references to it from our data structures
    181             delete currentDatum;
    182         }
    183 
    184         // if current inner map is now empty, remove key from outer map.
    185         // Have to do this after iterating for safety
    186         if ( currInnerMap.empty() )
    187             map.erase( decl );
    188 
    189         return toInsertAfter;
    190     }
     133        // insert decl into table so that we can fwd declare it later (average cost: O(1))
     134        void insertDecl( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) {
     135                FwdDeclData * declToInsert = new FwdDeclData( actorDecl, msgDecl, fwdDecl );
     136                insert( actorDecl, msgDecl, actorMap, declToInsert );
     137                insert( msgDecl, actorDecl, msgMap, declToInsert );
     138        }
     139
     140        // returns list of decls to insert after current struct decl
     141        // Over the entire pass the runtime of this routine is O(r) where r is the # of receive routines
     142        list<FunctionDecl *> updateDecl( const StructDecl * decl, bool isMsg ) {
     143                unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map = isMsg ? msgMap : actorMap;
     144                unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & otherMap =  isMsg ? actorMap : msgMap;
     145                auto iter = map.find( decl );
     146                list<FunctionDecl *> toInsertAfter; // this is populated with decls that are ready to insert
     147                if ( iter == map.end() ) return toInsertAfter;
     148
     149                // iterate over inner map
     150                unordered_map<const StructDecl *, FwdDeclData *> & currInnerMap = iter->second;
     151                for ( auto innerIter = currInnerMap.begin(); innerIter != currInnerMap.end(); ) {
     152                        FwdDeclData * currentDatum = innerIter->second;
     153                        bool readyToInsert = isMsg ? currentDatum->foundMsg() : currentDatum->foundActor();
     154                        if ( ! readyToInsert ) { ++innerIter; continue; }
     155
     156                        // readyToInsert is true so we are good to insert the forward decl of the message fn
     157                        toInsertAfter.push_back( currentDatum->fwdDecl );
     158
     159                        // need to remove from other map before deleting
     160                        // find inner map in other map ( other map is actor map if original is msg map and vice versa )
     161                        const StructDecl * otherDecl = isMsg ? currentDatum->actorDecl : currentDatum->msgDecl;
     162                        auto otherMapIter = otherMap.find( otherDecl );
     163
     164                        unordered_map<const StructDecl *, FwdDeclData *> & otherInnerMap = otherMapIter->second;
     165
     166                        // find the FwdDeclData we need to remove in the other inner map
     167                        auto otherInnerIter = otherInnerMap.find( decl );
     168
     169                        // remove references to deleted FwdDeclData from current inner map
     170                        innerIter = currInnerMap.erase( innerIter ); // this does the increment so no explicit inc needed
     171
     172                        // remove references to deleted FwdDeclData from other inner map
     173                        otherInnerMap.erase( otherInnerIter );
     174
     175                        // if other inner map is now empty, remove key from other outer map
     176                        if ( otherInnerMap.empty() )
     177                                otherMap.erase( otherDecl );
     178
     179                        // now we are safe to delete the FwdDeclData since we are done with it
     180                        // and we have removed all references to it from our data structures
     181                        delete currentDatum;
     182                }
     183
     184                // if current inner map is now empty, remove key from outer map.
     185                // Have to do this after iterating for safety
     186                if ( currInnerMap.empty() )
     187                        map.erase( decl );
     188
     189                return toInsertAfter;
     190        }
    191191};
    192192
    193193// generates the definitions of send operators for actors
    194 // collects data needed for next pass that does the circular defn resolution 
     194// collects data needed for next pass that does the circular defn resolution
    195195//     for message send operators (via table above)
    196196struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
    197     unordered_set<const StructDecl *> & actorStructDecls;
    198     unordered_set<const StructDecl *>  & messageStructDecls;
    199     const StructDecl ** requestDecl;
    200     const EnumDecl ** allocationDecl;
    201     const StructDecl ** actorDecl;
    202     const StructDecl ** msgDecl;
    203     FwdDeclTable & forwardDecls;
    204 
    205     // generates the operator for actor message sends
     197        unordered_set<const StructDecl *> & actorStructDecls;
     198        unordered_set<const StructDecl *>  & messageStructDecls;
     199        const StructDecl ** requestDecl;
     200        const EnumDecl ** allocationDecl;
     201        const StructDecl ** actorDecl;
     202        const StructDecl ** msgDecl;
     203        FwdDeclTable & forwardDecls;
     204
     205        // generates the operator for actor message sends
    206206        void postvisit( const FunctionDecl * decl ) {
    207         // return if not of the form receive( param1, param2 ) or if it is a forward decl
    208         if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
    209 
    210         // the params should be references
    211         const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
    212         const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
    213         if ( !derivedActorRef || !derivedMsgRef ) return;
    214 
    215         // the references should be to struct instances
    216         const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
    217         const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
    218         if ( !arg1InstType || !arg2InstType ) return;
    219 
    220         // If the struct instances are derived actor and message types then generate the message send routine
    221         auto actorIter = actorStructDecls.find( arg1InstType->aggr() );
    222         auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
    223         if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
    224             //////////////////////////////////////////////////////////////////////
    225             // The following generates this wrapper for all receive(derived_actor &, derived_msg &) functions
    226             /* base_actor and base_msg are output params
    227             static inline allocation __CFA_receive_wrap( derived_actor & receiver, derived_msg & msg, actor ** base_actor, message ** base_msg ) {
    228                 base_actor = &receiver;
    229                 base_msg = &msg;
    230                 return receive( receiver, msg );
    231             }
    232             */
    233             CompoundStmt * wrapBody = new CompoundStmt( decl->location );
    234 
    235             // generates: base_actor = &receiver;
    236             wrapBody->push_back( new ExprStmt( decl->location,
    237                 UntypedExpr::createAssign( decl->location,
    238                     UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_actor" ) ),
    239                     new AddressExpr( decl->location, new NameExpr( decl->location, "receiver" ) )
    240                 )
    241             ));
    242 
    243             // generates: base_msg = &msg;
    244             wrapBody->push_back( new ExprStmt( decl->location,
    245                 UntypedExpr::createAssign( decl->location,
    246                     UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_msg" ) ),
    247                     new AddressExpr( decl->location, new NameExpr( decl->location, "msg" ) )
    248                 )
    249             ));
    250 
    251             // generates: return receive( receiver, msg );
    252             wrapBody->push_back( new ReturnStmt( decl->location,
    253                 new UntypedExpr ( decl->location,
    254                     new NameExpr( decl->location, "receive" ),
    255                     {
    256                         new NameExpr( decl->location, "receiver" ),
    257                         new NameExpr( decl->location, "msg" )
    258                     }
    259                 )
    260             ));
    261 
    262             // create receive wrapper to extract base message and actor pointer
    263             // put it all together into the complete function decl from above
    264             FunctionDecl * receiveWrapper = new FunctionDecl(
    265                 decl->location,
    266                 "__CFA_receive_wrap",
    267                 {
    268                     new ObjectDecl(
    269                         decl->location,
    270                         "receiver",
    271                         ast::deepCopy( derivedActorRef )
    272                     ),
    273                     new ObjectDecl(
    274                         decl->location,
    275                         "msg",
    276                         ast::deepCopy( derivedMsgRef )
    277                     ),
    278                     new ObjectDecl(
    279                         decl->location,
    280                         "base_actor",
    281                         new PointerType( new PointerType( new StructInstType( *actorDecl ) ) )
    282                     ),
    283                     new ObjectDecl(
    284                         decl->location,
    285                         "base_msg",
    286                         new PointerType( new PointerType( new StructInstType( *msgDecl ) ) )
    287                     )
    288                 },                      // params
    289                 {
    290                     new ObjectDecl(
    291                         decl->location,
    292                         "__CFA_receive_wrap_ret",
    293                         new EnumInstType( *allocationDecl )
    294                     )
    295                 },
    296                 wrapBody,               // body
    297                 { Storage::Static },    // storage
    298                 Linkage::Cforall,       // linkage
    299                 {},                     // attributes
    300                 { Function::Inline }
    301             );
    302 
    303             declsToAddAfter.push_back( receiveWrapper );
    304 
    305             //////////////////////////////////////////////////////////////////////
    306             // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
    307             /*
    308                 static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
    309                     request new_req;
    310                     allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
    311                     __receive_fn fn = (__receive_fn)my_work_fn;
    312                     new_req{ &receiver, &msg, fn };
    313                     send( receiver, new_req );
    314                     return receiver;
    315                 }
    316             */
    317             CompoundStmt * sendBody = new CompoundStmt( decl->location );
    318 
    319             // Generates: request new_req;
    320             sendBody->push_back( new DeclStmt(
    321                 decl->location,
    322                 new ObjectDecl(
    323                     decl->location,
    324                     "new_req",
    325                     new StructInstType( *requestDecl )
    326                 )
    327             ));
    328            
    329             // Function type is: allocation (*)( derived_actor &, derived_msg &, actor **, message ** )
    330             FunctionType * derivedReceive = new FunctionType();
    331             derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
    332             derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
    333             derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
    334             derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
    335             derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    336 
    337             // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg &, actor **, message ** ) = receive;
    338             sendBody->push_back( new DeclStmt(
    339                 decl->location,
    340                 new ObjectDecl(
    341                     decl->location,
    342                     "my_work_fn",
    343                     new PointerType( derivedReceive ),
    344                     new SingleInit( decl->location, new NameExpr( decl->location, "__CFA_receive_wrap" ) )
    345                 )
    346             ));
    347 
    348             // Function type is: allocation (*)( actor &, message & )
    349             FunctionType * genericReceive = new FunctionType();
    350             genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
    351             genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
    352             genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
    353             genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
    354             genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    355 
    356             // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
    357             // More readable synonymous code:
    358             //     typedef allocation (*__receive_fn)(actor &, message &);
    359             //     __receive_fn fn = (__receive_fn)my_work_fn;
    360             sendBody->push_back( new DeclStmt(
    361                 decl->location,
    362                 new ObjectDecl(
    363                     decl->location,
    364                     "fn",
    365                     new PointerType( genericReceive ),
    366                     new SingleInit( decl->location,
    367                         new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
    368                     )
    369                 )
    370             ));
    371 
    372             // Generates: new_req{ (actor *)&receiver, (message *)&msg, fn };
    373             sendBody->push_back( new ExprStmt(
    374                 decl->location,
     207                // return if not of the form receive( param1, param2 ) or if it is a forward decl
     208                if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
     209
     210                // the params should be references
     211                const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
     212                const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
     213                if ( !derivedActorRef || !derivedMsgRef ) return;
     214
     215                // the references should be to struct instances
     216                const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
     217                const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
     218                if ( !arg1InstType || !arg2InstType ) return;
     219
     220                // If the struct instances are derived actor and message types then generate the message send routine
     221                auto actorIter = actorStructDecls.find( arg1InstType->aggr() );
     222                auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
     223                if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
     224                        //////////////////////////////////////////////////////////////////////
     225                        // The following generates this wrapper for all receive(derived_actor &, derived_msg &) functions
     226                        /* base_actor and base_msg are output params
     227                        static inline allocation __CFA_receive_wrap( derived_actor & receiver, derived_msg & msg, actor ** base_actor, message ** base_msg ) {
     228                                base_actor = &receiver;
     229                                base_msg = &msg;
     230                                return receive( receiver, msg );
     231                        }
     232                        */
     233                        CompoundStmt * wrapBody = new CompoundStmt( decl->location );
     234
     235                        // generates: base_actor = &receiver;
     236                        wrapBody->push_back( new ExprStmt( decl->location,
     237                                UntypedExpr::createAssign( decl->location,
     238                                        UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_actor" ) ),
     239                                        new AddressExpr( decl->location, new NameExpr( decl->location, "receiver" ) )
     240                                )
     241                        ));
     242
     243                        // generates: base_msg = &msg;
     244                        wrapBody->push_back( new ExprStmt( decl->location,
     245                                UntypedExpr::createAssign( decl->location,
     246                                        UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_msg" ) ),
     247                                        new AddressExpr( decl->location, new NameExpr( decl->location, "msg" ) )
     248                                )
     249                        ));
     250
     251                        // generates: return receive( receiver, msg );
     252                        wrapBody->push_back( new ReturnStmt( decl->location,
     253                                new UntypedExpr ( decl->location,
     254                                        new NameExpr( decl->location, "receive" ),
     255                                        {
     256                                                new NameExpr( decl->location, "receiver" ),
     257                                                new NameExpr( decl->location, "msg" )
     258                                        }
     259                                )
     260                        ));
     261
     262                        // create receive wrapper to extract base message and actor pointer
     263                        // put it all together into the complete function decl from above
     264                        FunctionDecl * receiveWrapper = new FunctionDecl(
     265                                decl->location,
     266                                "__CFA_receive_wrap",
     267                                {
     268                                        new ObjectDecl(
     269                                                decl->location,
     270                                                "receiver",
     271                                                ast::deepCopy( derivedActorRef )
     272                                        ),
     273                                        new ObjectDecl(
     274                                                decl->location,
     275                                                "msg",
     276                                                ast::deepCopy( derivedMsgRef )
     277                                        ),
     278                                        new ObjectDecl(
     279                                                decl->location,
     280                                                "base_actor",
     281                                                new PointerType( new PointerType( new StructInstType( *actorDecl ) ) )
     282                                        ),
     283                                        new ObjectDecl(
     284                                                decl->location,
     285                                                "base_msg",
     286                                                new PointerType( new PointerType( new StructInstType( *msgDecl ) ) )
     287                                        )
     288                                },                      // params
     289                                {
     290                                        new ObjectDecl(
     291                                                decl->location,
     292                                                "__CFA_receive_wrap_ret",
     293                                                new EnumInstType( *allocationDecl )
     294                                        )
     295                                },
     296                                wrapBody,               // body
     297                                { Storage::Static },    // storage
     298                                Linkage::Cforall,       // linkage
     299                                {},                     // attributes
     300                                { Function::Inline }
     301                        );
     302
     303                        declsToAddAfter.push_back( receiveWrapper );
     304
     305                        //////////////////////////////////////////////////////////////////////
     306                        // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
     307                        /*
     308                                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
     309                                        request new_req;
     310                                        allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
     311                                        __receive_fn fn = (__receive_fn)my_work_fn;
     312                                        new_req{ &receiver, &msg, fn };
     313                                        send( receiver, new_req );
     314                                        return receiver;
     315                                }
     316                        */
     317                        CompoundStmt * sendBody = new CompoundStmt( decl->location );
     318
     319                        // Generates: request new_req;
     320                        sendBody->push_back( new DeclStmt(
     321                                decl->location,
     322                                new ObjectDecl(
     323                                        decl->location,
     324                                        "new_req",
     325                                        new StructInstType( *requestDecl )
     326                                )
     327                        ));
     328
     329                        // Function type is: allocation (*)( derived_actor &, derived_msg &, actor **, message ** )
     330                        FunctionType * derivedReceive = new FunctionType();
     331                        derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
     332                        derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
     333                        derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
     334                        derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
     335                        derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
     336
     337                        // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg &, actor **, message ** ) = receive;
     338                        sendBody->push_back( new DeclStmt(
     339                                decl->location,
     340                                new ObjectDecl(
     341                                        decl->location,
     342                                        "my_work_fn",
     343                                        new PointerType( derivedReceive ),
     344                                        new SingleInit( decl->location, new NameExpr( decl->location, "__CFA_receive_wrap" ) )
     345                                )
     346                        ));
     347
     348                        // Function type is: allocation (*)( actor &, message & )
     349                        FunctionType * genericReceive = new FunctionType();
     350                        genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
     351                        genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
     352                        genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
     353                        genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
     354                        genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
     355
     356                        // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
     357                        // More readable synonymous code:
     358                        //     typedef allocation (*__receive_fn)(actor &, message &);
     359                        //     __receive_fn fn = (__receive_fn)my_work_fn;
     360                        sendBody->push_back( new DeclStmt(
     361                                decl->location,
     362                                new ObjectDecl(
     363                                        decl->location,
     364                                        "fn",
     365                                        new PointerType( genericReceive ),
     366                                        new SingleInit( decl->location,
     367                                                new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
     368                                        )
     369                                )
     370                        ));
     371
     372                        // Generates: new_req{ (actor *)&receiver, (message *)&msg, fn };
     373                        sendBody->push_back( new ExprStmt(
     374                                decl->location,
    375375                                new UntypedExpr (
    376                     decl->location,
     376                                        decl->location,
    377377                                        new NameExpr( decl->location, "?{}" ),
    378378                                        {
    379379                                                new NameExpr( decl->location, "new_req" ),
    380                         new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
    381                         new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
    382                         new NameExpr( decl->location, "fn" )
     380                                                new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
     381                                                new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
     382                                                new NameExpr( decl->location, "fn" )
    383383                                        }
    384384                                )
    385385                        ));
    386386
    387             // Generates: send( receiver, new_req );
    388             sendBody->push_back( new ExprStmt(
    389                 decl->location,
     387                        // Generates: send( receiver, new_req );
     388                        sendBody->push_back( new ExprStmt(
     389                                decl->location,
    390390                                new UntypedExpr (
    391                     decl->location,
     391                                        decl->location,
    392392                                        new NameExpr( decl->location, "send" ),
    393393                                        {
    394394                                                {
    395                             new NameExpr( decl->location, "receiver" ),
    396                             new NameExpr( decl->location, "new_req" )
    397                         }
     395                                                        new NameExpr( decl->location, "receiver" ),
     396                                                        new NameExpr( decl->location, "new_req" )
     397                                                }
    398398                                        }
    399399                                )
    400400                        ));
    401401
    402             // Generates: return receiver;
    403             sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
    404 
    405             // put it all together into the complete function decl from above
    406             FunctionDecl * sendOperatorFunction = new FunctionDecl(
    407                 decl->location,
    408                 "?|?",
    409                 {
    410                     new ObjectDecl(
    411                         decl->location,
    412                         "receiver",
    413                         ast::deepCopy( derivedActorRef )
    414                     ),
    415                     new ObjectDecl(
    416                         decl->location,
    417                         "msg",
    418                         ast::deepCopy( derivedMsgRef )
    419                     )
    420                 },                      // params
    421                 {
    422                     new ObjectDecl(
    423                         decl->location,
    424                         "receiver_ret",
    425                         ast::deepCopy( derivedActorRef )
    426                     )
    427                 },
    428                 nullptr,               // body
    429                 { Storage::Static },    // storage
    430                 Linkage::Cforall,       // linkage
    431                 {},                     // attributes
    432                 { Function::Inline }
    433             );
    434 
    435             // forward decls to resolve use before decl problem for '|' routines
    436             forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
    437 
    438             sendOperatorFunction->stmts = sendBody;
    439             declsToAddAfter.push_back( sendOperatorFunction );
    440         }
     402                        // Generates: return receiver;
     403                        sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
     404
     405                        // put it all together into the complete function decl from above
     406                        FunctionDecl * sendOperatorFunction = new FunctionDecl(
     407                                decl->location,
     408                                "?|?",
     409                                {
     410                                        new ObjectDecl(
     411                                                decl->location,
     412                                                "receiver",
     413                                                ast::deepCopy( derivedActorRef )
     414                                        ),
     415                                        new ObjectDecl(
     416                                                decl->location,
     417                                                "msg",
     418                                                ast::deepCopy( derivedMsgRef )
     419                                        )
     420                                },                      // params
     421                                {
     422                                        new ObjectDecl(
     423                                                decl->location,
     424                                                "receiver_ret",
     425                                                ast::deepCopy( derivedActorRef )
     426                                        )
     427                                },
     428                                nullptr,               // body
     429                                { Storage::Static },    // storage
     430                                Linkage::Cforall,       // linkage
     431                                {},                     // attributes
     432                                { Function::Inline }
     433                        );
     434
     435                        // forward decls to resolve use before decl problem for '|' routines
     436                        forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
     437
     438                        sendOperatorFunction->stmts = sendBody;
     439                        declsToAddAfter.push_back( sendOperatorFunction );
     440                }
    441441        }
    442442
    443443  public:
    444     GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    445         const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
    446         FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
    447         requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
     444        GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     445                const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
     446                FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
     447                requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
    448448};
    449449
     
    452452// generates the forward declarations of the send operator for actor routines
    453453struct FwdDeclOperator : public ast::WithDeclsToAdd<> {
    454     unordered_set<const StructDecl *> & actorStructDecls;
    455     unordered_set<const StructDecl *>  & messageStructDecls;
    456     FwdDeclTable & forwardDecls;
    457 
    458     // handles forward declaring the message operator
    459     void postvisit( const StructDecl * decl ) {
    460         list<FunctionDecl *> toAddAfter;
    461         auto actorIter = actorStructDecls.find( decl );
    462         if ( actorIter != actorStructDecls.end() ) { // this is a derived actor decl
    463             // get list of fwd decls that we can now insert
    464             toAddAfter = forwardDecls.updateDecl( decl, false );
    465 
    466             // get rid of decl from actorStructDecls since we no longer need it
    467             actorStructDecls.erase( actorIter );
    468         } else {
    469             auto messageIter = messageStructDecls.find( decl );
    470             if ( messageIter == messageStructDecls.end() ) return;
    471 
    472             toAddAfter = forwardDecls.updateDecl( decl, true );
    473 
    474             // get rid of decl from messageStructDecls since we no longer need it
    475             messageStructDecls.erase( messageIter );
    476         }
    477 
    478         // add the fwd decls to declsToAddAfter
    479         for ( FunctionDecl * func : toAddAfter ) {
    480             declsToAddAfter.push_back( func );
    481         }
    482     }
     454        unordered_set<const StructDecl *> & actorStructDecls;
     455        unordered_set<const StructDecl *>  & messageStructDecls;
     456        FwdDeclTable & forwardDecls;
     457
     458        // handles forward declaring the message operator
     459        void postvisit( const StructDecl * decl ) {
     460                list<FunctionDecl *> toAddAfter;
     461                auto actorIter = actorStructDecls.find( decl );
     462                if ( actorIter != actorStructDecls.end() ) { // this is a derived actor decl
     463                        // get list of fwd decls that we can now insert
     464                        toAddAfter = forwardDecls.updateDecl( decl, false );
     465
     466                        // get rid of decl from actorStructDecls since we no longer need it
     467                        actorStructDecls.erase( actorIter );
     468                } else {
     469                        auto messageIter = messageStructDecls.find( decl );
     470                        if ( messageIter == messageStructDecls.end() ) return;
     471
     472                        toAddAfter = forwardDecls.updateDecl( decl, true );
     473
     474                        // get rid of decl from messageStructDecls since we no longer need it
     475                        messageStructDecls.erase( messageIter );
     476                }
     477
     478                // add the fwd decls to declsToAddAfter
     479                for ( FunctionDecl * func : toAddAfter ) {
     480                        declsToAddAfter.push_back( func );
     481                }
     482        }
    483483
    484484  public:
    485     FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    486         FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
     485        FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     486                FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
    487487};
    488488
    489489void implementActors( TranslationUnit & translationUnit ) {
    490     // unordered_maps to collect all derived actor and message types
    491     unordered_set<const StructDecl *> actorStructDecls;
    492     unordered_set<const StructDecl *> messageStructDecls;
    493     FwdDeclTable forwardDecls;
    494 
    495     // for storing through the passes
    496     // these are populated with various important struct decls
    497     const StructDecl * requestDeclPtr = nullptr;
    498     const EnumDecl * allocationDeclPtr = nullptr;
    499     const StructDecl * actorDeclPtr = nullptr;
    500     const StructDecl * msgDeclPtr = nullptr;
    501 
    502     // double pointer to modify local ptrs above
    503     const StructDecl ** requestDecl = &requestDeclPtr;
    504     const EnumDecl ** allocationDecl = &allocationDeclPtr;
    505     const StructDecl ** actorDecl = &actorDeclPtr;
    506     const StructDecl ** msgDecl = &msgDeclPtr;
    507 
    508     // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
    509     // also populates maps of all derived actors and messages
    510     Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    511         allocationDecl, actorDecl, msgDecl );
    512 
    513     // check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
    514     if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr )
    515         return;
    516 
    517     // second pass locates all receive() routines that overload the generic receive fn
    518     // it then generates the appropriate operator '|' send routines for the receive routines
    519     Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    520         allocationDecl, actorDecl, msgDecl, forwardDecls );
    521 
    522     // The third pass forward declares operator '|' send routines
    523     Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
     490        // unordered_maps to collect all derived actor and message types
     491        unordered_set<const StructDecl *> actorStructDecls;
     492        unordered_set<const StructDecl *> messageStructDecls;
     493        FwdDeclTable forwardDecls;
     494
     495        // for storing through the passes
     496        // these are populated with various important struct decls
     497        const StructDecl * requestDeclPtr = nullptr;
     498        const EnumDecl * allocationDeclPtr = nullptr;
     499        const StructDecl * actorDeclPtr = nullptr;
     500        const StructDecl * msgDeclPtr = nullptr;
     501
     502        // double pointer to modify local ptrs above
     503        const StructDecl ** requestDecl = &requestDeclPtr;
     504        const EnumDecl ** allocationDecl = &allocationDeclPtr;
     505        const StructDecl ** actorDecl = &actorDeclPtr;
     506        const StructDecl ** msgDecl = &msgDeclPtr;
     507
     508        // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
     509        // also populates maps of all derived actors and messages
     510        Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
     511                allocationDecl, actorDecl, msgDecl );
     512
     513        // check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
     514        if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr )
     515                return;
     516
     517        // second pass locates all receive() routines that overload the generic receive fn
     518        // it then generates the appropriate operator '|' send routines for the receive routines
     519        Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
     520                allocationDecl, actorDecl, msgDecl, forwardDecls );
     521
     522        // The third pass forward declares operator '|' send routines
     523        Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
    524524}
    525 
    526525
    527526} // namespace Concurrency
  • src/Concurrency/Corun.cpp

    rb9b6efb rfc1a3e2  
    2626
    2727struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
    28     UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
    29     UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
    30     // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
    31     UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
    32    
    33     string coforArgName = "__CFA_cofor_lambda_arg";
    34     string numProcsName = "__CFA_cofor_num_procs";
    35     string currProcsName = "__CFA_cofor_curr_procs";
    36     string thdArrName = "__CFA_cofor_thread_array";
    37     string loopTempName = "__CFA_cofor_loop_temp";
    38    
    39 
    40     const StructDecl * runnerBlockDecl = nullptr;
    41     const StructDecl * coforRunnerDecl = nullptr;
    42 
    43     // Finds runner_block (corun task) and cofor_runner (cofor task) decls
    44     void previsit( const StructDecl * decl ) {
    45         if ( !decl->body ) {
    46             return;
    47         } else if ( "runner_block" == decl->name ) {
    48             assert( !runnerBlockDecl );
    49             runnerBlockDecl = decl;
    50         } else if ( "cofor_runner" == decl->name ) {
    51             assert( !coforRunnerDecl );
    52             coforRunnerDecl = decl;
    53         }
    54     }
    55 
    56     // codegen for cofor statements
    57     Stmt * postvisit( const CoforStmt * stmt ) {
    58         if ( !runnerBlockDecl || !coforRunnerDecl )
    59             SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>" );
    60 
    61         if ( stmt->inits.size() != 1 )
    62             SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control" );
    63 
    64         if ( !stmt->body )
    65             return nullptr;
    66 
    67         const CodeLocation & loc = stmt->location;
    68         const string fnName = CoforFnNamer.newName();
    69 
    70         CompoundStmt * body = new CompoundStmt( loc );
    71 
    72         // push back cofor initializer to generated body
    73         body->push_back( deepCopy( stmt->inits.at(0) ) );
    74 
    75         CompoundStmt * fnBody = new CompoundStmt( loc );
    76 
    77         const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
    78         if ( ! declStmtPtr )
    79             SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?" );
    80 
    81         const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
    82         if ( ! declPtr )
    83             SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?" );
    84 
    85         Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
    86 
    87         // Generates:
    88         // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
    89         fnBody->push_back( new DeclStmt( loc,
    90             new ObjectDecl( loc,
    91                 declPtr->name,
    92                 initType,
    93                 new SingleInit( loc,
    94                     UntypedExpr::createDeref( loc,
    95                         new CastExpr( loc,
    96                             new NameExpr( loc, coforArgName ),
    97                             new PointerType( initType ), ExplicitCast
    98                         )
    99                     )
    100                 )
    101             )
    102         ));
    103 
    104         // push rest of cofor body into loop lambda
    105         fnBody->push_back( deepCopy( stmt->body ) );
    106 
    107         // Generates:
    108         // void __CFA_cofor_lambda_() {
    109         //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
    110         //    stmt->body;
    111         // }
    112         Stmt * coforLambda = new DeclStmt( loc,
    113             new FunctionDecl( loc,
    114                 fnName,                                             // name
    115                 {
    116                     new ObjectDecl( loc,
    117                         coforArgName,
    118                         new ast::PointerType( new ast::VoidType() )
    119                     )
    120                 },                                                  // params
    121                 {},                                                 // return
    122                 fnBody   // body
    123             )
    124         );
    125         body->push_back( coforLambda );
    126 
    127         // Generates:
    128         // unsigned __CFA_cofor_num_procs = get_proc_count();
    129         body->push_back( new DeclStmt( loc,
    130                 new ObjectDecl( loc,
    131                     numProcsName,
    132                     new BasicType( BasicKind::UnsignedInt ),
    133                     new SingleInit( loc,
    134                         new UntypedExpr( loc,
    135                             new NameExpr( loc, "get_proc_count" ),
    136                             {}
    137                         )
    138                     )
    139                 )
    140             )
    141         );
    142 
    143         // Generates:
    144         // unsigned __CFA_cofor_curr_procs = 0;
    145         body->push_back( new DeclStmt( loc,
    146                 new ObjectDecl( loc,
    147                     currProcsName,
    148                     new BasicType( BasicKind::UnsignedInt ),
    149                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    150                 )
    151             )
    152         );
    153 
    154         // Generates:
    155         // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
    156         body->push_back( new DeclStmt( loc,
    157                 new ObjectDecl( loc,
    158                     thdArrName,
    159                     new ast::ArrayType(
    160                         new StructInstType( coforRunnerDecl ),
    161                         new NameExpr( loc, numProcsName ),
    162                         ast::FixedLen,
    163                         ast::DynamicDim
    164                     )
    165                 )
    166             )
    167         );
    168 
    169         // Generates:
    170         // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
    171         body->push_back( new ExprStmt( loc,
    172             new UntypedExpr( loc,
    173                 new NameExpr( loc, "start_runners" ),
    174                 {
    175                     new NameExpr( loc, thdArrName ),
    176                     new NameExpr( loc, numProcsName ),
    177                     new NameExpr( loc, fnName )
    178                 }
    179             )
    180         ));
    181 
    182         // Generates:
    183         // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
    184         CompoundStmt * forLoopBody = new CompoundStmt( loc );
    185         forLoopBody->push_back( new DeclStmt( loc,
    186                 new ObjectDecl( loc,
    187                     loopTempName,
    188                     new PointerType( initType ),
    189                     new SingleInit( loc,
    190                         new UntypedExpr( loc,
    191                             new NameExpr( loc, "malloc" ),
    192                             {}
    193                         )
    194                     )
    195                 )
    196             )
    197         );
    198 
    199         // Generates:
    200         // *__CFA_cofor_loop_temp = initializer;
    201         forLoopBody->push_back( new ExprStmt( loc,
    202             UntypedExpr::createAssign( loc,
    203                 UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
    204                 new NameExpr( loc, declPtr->name )
    205             )
    206         ));
    207 
    208         // Generates:
    209         // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
    210         //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
    211         forLoopBody->push_back( new ExprStmt( loc,
    212             new UntypedExpr( loc,
    213                 new NameExpr( loc, "send_work" ),
    214                 {
    215                     new NameExpr( loc, thdArrName ),
    216                     new NameExpr( loc, numProcsName ),
    217                     new NameExpr( loc, currProcsName ),
    218                     new NameExpr( loc, loopTempName )
    219                 }
    220             )
    221         ));
    222 
    223         body->push_back( new ForStmt( loc,
    224             {},
    225             deepCopy( stmt->cond ),
    226             deepCopy( stmt->inc ),
    227             forLoopBody
    228         ));
    229 
    230         // Generates:
    231         // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
    232         body->push_back( new ExprStmt( loc,
    233             new UntypedExpr( loc,
    234                 new NameExpr( loc, "end_runners" ),
    235                 {
    236                     new NameExpr( loc, thdArrName ),
    237                     new NameExpr( loc, numProcsName )
    238                 }
    239             )
    240         ));
    241 
    242         return body;
    243     }
    244 
    245     // codegen for corun statements
    246     Stmt * postvisit( const CorunStmt * stmt ) {
    247         if ( !runnerBlockDecl || !coforRunnerDecl )
    248             SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>" );
    249 
    250         if ( !stmt->stmt )
    251             return nullptr;
    252 
    253         const CodeLocation & loc = stmt->location;
    254         const string fnName = CorunFnNamer.newName();
    255         const string objName = RunnerBlockNamer.newName();
    256 
    257         // Generates:
    258         // void __CFA_corun_lambda_() { ... stmt->stmt ... }
    259         Stmt * runnerLambda = new DeclStmt( loc,
    260             new FunctionDecl( loc,
    261                 fnName,                                             // name
    262                 {},                                                 // params
    263                 {},                                                 // return
    264                 new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
    265             )
    266         );
    267 
    268         // Generates:
    269         // runner_block __CFA_corun_block_;
    270         Stmt * objDecl = new DeclStmt( loc,
    271             new ObjectDecl( loc,
    272                 objName,
    273                 new StructInstType( runnerBlockDecl )
    274             )
    275         );
    276 
    277         // Generates:
    278         // __CFA_corun_block_{ __CFA_corun_lambda_ };
    279         Stmt * threadStart = new ExprStmt( loc,
    280             new UntypedExpr ( loc,
    281                 new NameExpr( loc, "?{}" ),
    282                 {
    283                     new NameExpr( loc, objName ),
    284                     new NameExpr( loc, fnName )
    285                 }
    286             )
    287         );
    288 
    289         stmtsToAddBefore.push_back( runnerLambda );
    290         stmtsToAddBefore.push_back( objDecl );
    291 
    292         return threadStart;
    293     }
     28        UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
     29        UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
     30        // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
     31        UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
     32
     33        string coforArgName = "__CFA_cofor_lambda_arg";
     34        string numProcsName = "__CFA_cofor_num_procs";
     35        string currProcsName = "__CFA_cofor_curr_procs";
     36        string thdArrName = "__CFA_cofor_thread_array";
     37        string loopTempName = "__CFA_cofor_loop_temp";
     38
     39
     40        const StructDecl * runnerBlockDecl = nullptr;
     41        const StructDecl * coforRunnerDecl = nullptr;
     42
     43        // Finds runner_block (corun task) and cofor_runner (cofor task) decls
     44        void previsit( const StructDecl * decl ) {
     45                if ( !decl->body ) {
     46                        return;
     47                } else if ( "runner_block" == decl->name ) {
     48                        assert( !runnerBlockDecl );
     49                        runnerBlockDecl = decl;
     50                } else if ( "cofor_runner" == decl->name ) {
     51                        assert( !coforRunnerDecl );
     52                        coforRunnerDecl = decl;
     53                }
     54        }
     55
     56        // codegen for cofor statements
     57        Stmt * postvisit( const CoforStmt * stmt ) {
     58                if ( !runnerBlockDecl || !coforRunnerDecl )
     59                        SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>" );
     60
     61                if ( stmt->inits.size() != 1 )
     62                        SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control" );
     63
     64                if ( !stmt->body )
     65                        return nullptr;
     66
     67                const CodeLocation & loc = stmt->location;
     68                const string fnName = CoforFnNamer.newName();
     69
     70                CompoundStmt * body = new CompoundStmt( loc );
     71
     72                // push back cofor initializer to generated body
     73                body->push_back( deepCopy( stmt->inits.at(0) ) );
     74
     75                CompoundStmt * fnBody = new CompoundStmt( loc );
     76
     77                const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
     78                if ( ! declStmtPtr )
     79                        SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?" );
     80
     81                const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
     82                if ( ! declPtr )
     83                        SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?" );
     84
     85                Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
     86
     87                // Generates:
     88                // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     89                fnBody->push_back( new DeclStmt( loc,
     90                        new ObjectDecl( loc,
     91                                declPtr->name,
     92                                initType,
     93                                new SingleInit( loc,
     94                                        UntypedExpr::createDeref( loc,
     95                                                new CastExpr( loc,
     96                                                        new NameExpr( loc, coforArgName ),
     97                                                        new PointerType( initType ), ExplicitCast
     98                                                )
     99                                        )
     100                                )
     101                        )
     102                ));
     103
     104                // push rest of cofor body into loop lambda
     105                fnBody->push_back( deepCopy( stmt->body ) );
     106
     107                // Generates:
     108                // void __CFA_cofor_lambda_() {
     109                //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     110                //    stmt->body;
     111                // }
     112                Stmt * coforLambda = new DeclStmt( loc,
     113                        new FunctionDecl( loc,
     114                                fnName,                                             // name
     115                                {
     116                                        new ObjectDecl( loc,
     117                                                coforArgName,
     118                                                new ast::PointerType( new ast::VoidType() )
     119                                        )
     120                                },                                                  // params
     121                                {},                                                 // return
     122                                fnBody   // body
     123                        )
     124                );
     125                body->push_back( coforLambda );
     126
     127                // Generates:
     128                // unsigned __CFA_cofor_num_procs = get_proc_count();
     129                body->push_back( new DeclStmt( loc,
     130                                new ObjectDecl( loc,
     131                                        numProcsName,
     132                                        new BasicType( BasicKind::UnsignedInt ),
     133                                        new SingleInit( loc,
     134                                                new UntypedExpr( loc,
     135                                                        new NameExpr( loc, "get_proc_count" ),
     136                                                        {}
     137                                                )
     138                                        )
     139                                )
     140                        )
     141                );
     142
     143                // Generates:
     144                // unsigned __CFA_cofor_curr_procs = 0;
     145                body->push_back( new DeclStmt( loc,
     146                                new ObjectDecl( loc,
     147                                        currProcsName,
     148                                        new BasicType( BasicKind::UnsignedInt ),
     149                                        new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     150                                )
     151                        )
     152                );
     153
     154                // Generates:
     155                // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
     156                body->push_back( new DeclStmt( loc,
     157                                new ObjectDecl( loc,
     158                                        thdArrName,
     159                                        new ast::ArrayType(
     160                                                new StructInstType( coforRunnerDecl ),
     161                                                new NameExpr( loc, numProcsName ),
     162                                                ast::FixedLen,
     163                                                ast::DynamicDim
     164                                        )
     165                                )
     166                        )
     167                );
     168
     169                // Generates:
     170                // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
     171                body->push_back( new ExprStmt( loc,
     172                        new UntypedExpr( loc,
     173                                new NameExpr( loc, "start_runners" ),
     174                                {
     175                                        new NameExpr( loc, thdArrName ),
     176                                        new NameExpr( loc, numProcsName ),
     177                                        new NameExpr( loc, fnName )
     178                                }
     179                        )
     180                ));
     181
     182                // Generates:
     183                // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
     184                CompoundStmt * forLoopBody = new CompoundStmt( loc );
     185                forLoopBody->push_back( new DeclStmt( loc,
     186                                new ObjectDecl( loc,
     187                                        loopTempName,
     188                                        new PointerType( initType ),
     189                                        new SingleInit( loc,
     190                                                new UntypedExpr( loc,
     191                                                        new NameExpr( loc, "malloc" ),
     192                                                        {}
     193                                                )
     194                                        )
     195                                )
     196                        )
     197                );
     198
     199                // Generates:
     200                // *__CFA_cofor_loop_temp = initializer;
     201                forLoopBody->push_back( new ExprStmt( loc,
     202                        UntypedExpr::createAssign( loc,
     203                                UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
     204                                new NameExpr( loc, declPtr->name )
     205                        )
     206                ));
     207
     208                // Generates:
     209                // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
     210                //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
     211                forLoopBody->push_back( new ExprStmt( loc,
     212                        new UntypedExpr( loc,
     213                                new NameExpr( loc, "send_work" ),
     214                                {
     215                                        new NameExpr( loc, thdArrName ),
     216                                        new NameExpr( loc, numProcsName ),
     217                                        new NameExpr( loc, currProcsName ),
     218                                        new NameExpr( loc, loopTempName )
     219                                }
     220                        )
     221                ));
     222
     223                body->push_back( new ForStmt( loc,
     224                        {},
     225                        deepCopy( stmt->cond ),
     226                        deepCopy( stmt->inc ),
     227                        forLoopBody
     228                ));
     229
     230                // Generates:
     231                // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
     232                body->push_back( new ExprStmt( loc,
     233                        new UntypedExpr( loc,
     234                                new NameExpr( loc, "end_runners" ),
     235                                {
     236                                        new NameExpr( loc, thdArrName ),
     237                                        new NameExpr( loc, numProcsName )
     238                                }
     239                        )
     240                ));
     241
     242                return body;
     243        }
     244
     245        // codegen for corun statements
     246        Stmt * postvisit( const CorunStmt * stmt ) {
     247                if ( !runnerBlockDecl || !coforRunnerDecl )
     248                        SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>" );
     249
     250                if ( !stmt->stmt )
     251                        return nullptr;
     252
     253                const CodeLocation & loc = stmt->location;
     254                const string fnName = CorunFnNamer.newName();
     255                const string objName = RunnerBlockNamer.newName();
     256
     257                // Generates:
     258                // void __CFA_corun_lambda_() { ... stmt->stmt ... }
     259                Stmt * runnerLambda = new DeclStmt( loc,
     260                        new FunctionDecl( loc,
     261                                fnName,                                             // name
     262                                {},                                                 // params
     263                                {},                                                 // return
     264                                new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
     265                        )
     266                );
     267
     268                // Generates:
     269                // runner_block __CFA_corun_block_;
     270                Stmt * objDecl = new DeclStmt( loc,
     271                        new ObjectDecl( loc,
     272                                objName,
     273                                new StructInstType( runnerBlockDecl )
     274                        )
     275                );
     276
     277                // Generates:
     278                // __CFA_corun_block_{ __CFA_corun_lambda_ };
     279                Stmt * threadStart = new ExprStmt( loc,
     280                        new UntypedExpr ( loc,
     281                                new NameExpr( loc, "?{}" ),
     282                                {
     283                                        new NameExpr( loc, objName ),
     284                                        new NameExpr( loc, fnName )
     285                                }
     286                        )
     287                );
     288
     289                stmtsToAddBefore.push_back( runnerLambda );
     290                stmtsToAddBefore.push_back( objDecl );
     291
     292                return threadStart;
     293        }
    294294};
    295295
    296296void implementCorun( TranslationUnit & translationUnit ) {
    297     Pass<CorunKeyword>::run( translationUnit );
     297        Pass<CorunKeyword>::run( translationUnit );
    298298}
    299299
  • src/Concurrency/Keywords.cpp

    rb9b6efb rfc1a3e2  
    991991        ast::CompoundStmt * body =
    992992                        new ast::CompoundStmt( stmt->location, { stmt->stmt } );
    993        
     993
    994994        return addStatements( body, stmt->mutexObjs );;
    995995}
     
    11801180
    11811181// generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
    1182 // used to undo the type erasure done by storing all the lock pointers as void 
     1182// used to undo the type erasure done by storing all the lock pointers as void
    11831183ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
    11841184        return new ast::ExprStmt( location,
     
    11871187                                ast::UntypedExpr::createDeref(
    11881188                                        location,
    1189                                         new ast::CastExpr( location, 
     1189                                        new ast::CastExpr( location,
    11901190                                                param,
    11911191                                                new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
     
    12081208        //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
    12091209        for ( long unsigned int i = 0; i < args.size(); i++ ) {
    1210                
     1210
    12111211                ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
    12121212                        new ast::NameExpr( location, "?==?" ), {
     
    12161216                );
    12171217
    1218                 ast::IfStmt * currLockIf = new ast::IfStmt( 
     1218                ast::IfStmt * currLockIf = new ast::IfStmt(
    12191219                        location,
    12201220                        ifCond,
    12211221                        genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
    12221222                );
    1223                
     1223
    12241224                if ( i == 0 ) {
    12251225                        outerLockIf = currLockIf;
     
    12351235
    12361236void flattenTuple( const ast::UntypedTupleExpr * tuple, std::vector<ast::ptr<ast::Expr>> & output ) {
    1237     for ( auto & expr : tuple->exprs ) {
    1238         const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
    1239         if ( innerTuple ) flattenTuple( innerTuple, output );
    1240         else output.emplace_back( ast::deepCopy( expr ));
    1241     }
     1237        for ( auto & expr : tuple->exprs ) {
     1238                const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
     1239                if ( innerTuple ) flattenTuple( innerTuple, output );
     1240                else output.emplace_back( ast::deepCopy( expr ));
     1241        }
    12421242}
    12431243
     
    12551255        // std::string unlockFnName = mutex_func_namer.newName();
    12561256
    1257     // If any arguments to the mutex stmt are tuples, flatten them
    1258     std::vector<ast::ptr<ast::Expr>> flattenedArgs;
    1259     for ( auto & arg : args ) {
    1260         const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
    1261         if ( tuple ) flattenTuple( tuple, flattenedArgs );
    1262         else flattenedArgs.emplace_back( ast::deepCopy( arg ));
    1263     }
     1257        // If any arguments to the mutex stmt are tuples, flatten them
     1258        std::vector<ast::ptr<ast::Expr>> flattenedArgs;
     1259        for ( auto & arg : args ) {
     1260                const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
     1261                if ( tuple ) flattenTuple( tuple, flattenedArgs );
     1262                else flattenedArgs.emplace_back( ast::deepCopy( arg ));
     1263        }
    12641264
    12651265        // Make pointer to the monitors.
     
    13021302        // adds a nested try stmt for each lock we are locking
    13031303        for ( long unsigned int i = 0; i < flattenedArgs.size(); i++ ) {
    1304                 ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 
     1304                ast::UntypedExpr * innerAccess = new ast::UntypedExpr(
    13051305                        location,
    13061306                        new ast::NameExpr( location,"?[?]" ), {
     
    14261426        //      );
    14271427
    1428         //      ast::IfStmt * currLockIf = new ast::IfStmt( 
     1428        //      ast::IfStmt * currLockIf = new ast::IfStmt(
    14291429        //              location,
    14301430        //              ast::deepCopy( ifCond ),
     
    14321432        //      );
    14331433
    1434         //      ast::IfStmt * currUnlockIf = new ast::IfStmt( 
     1434        //      ast::IfStmt * currUnlockIf = new ast::IfStmt(
    14351435        //              location,
    14361436        //              ifCond,
    14371437        //              genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
    14381438        //      );
    1439                
     1439
    14401440        //      if ( i == 0 ) {
    14411441        //              outerLockIf = currLockIf;
     
    14501450        //      lastUnlockIf = currUnlockIf;
    14511451        // }
    1452        
     1452
    14531453        // // add pointer typing if/elifs to body of routines
    14541454        // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
  • src/Concurrency/Waituntil.cpp

    rb9b6efb rfc1a3e2  
    3131/* So this is what this pass dones:
    3232{
    33     when ( condA ) waituntil( A ){ doA(); }
    34     or when ( condB ) waituntil( B ){ doB(); }
    35     and when ( condC ) waituntil( C ) { doC(); }
     33        when ( condA ) waituntil( A ){ doA(); }
     34        or when ( condB ) waituntil( B ){ doB(); }
     35        and when ( condC ) waituntil( C ) { doC(); }
    3636}
    3737                 ||
     
    4242Generates these two routines:
    4343static inline bool is_full_sat_1( int * clause_statuses ) {
    44     return clause_statuses[0]
    45         || clause_statuses[1]
    46         && clause_statuses[2];
     44        return clause_statuses[0]
     45                || clause_statuses[1]
     46                && clause_statuses[2];
    4747}
    4848
    4949static inline bool is_done_sat_1( int * clause_statuses ) {
    50     return has_run(clause_statuses[0])
    51         || has_run(clause_statuses[1])
    52         && has_run(clause_statuses[2]);
     50        return has_run(clause_statuses[0])
     51                || has_run(clause_statuses[1])
     52                && has_run(clause_statuses[2]);
    5353}
    5454
    5555Replaces the waituntil statement above with the following code:
    5656{
    57     // used with atomic_dec/inc to get binary semaphore behaviour
    58     int park_counter = 0;
    59 
    60     // status (one for each clause)
    61     int clause_statuses[3] = { 0 };
    62 
    63     bool whenA = condA;
    64     bool whenB = condB;
    65     bool whenC = condC;
    66 
    67     if ( !whenB ) clause_statuses[1] = __SELECT_RUN;
    68     if ( !whenC ) clause_statuses[2] = __SELECT_RUN;
    69 
    70     // some other conditional settors for clause_statuses are set here, see genSubtreeAssign and related routines
    71 
    72     // three blocks
    73     // for each block, create, setup, then register select_node
    74     select_node clause1;
    75     select_node clause2;
    76     select_node clause3;
    77 
    78     try {
    79         if ( whenA ) { register_select(A, clause1); setup_clause( clause1, &clause_statuses[0], &park_counter ); }
    80         ... repeat ^ for B and C ...
    81 
    82         // if else clause is defined a separate branch can occur here to set initial values, see genWhenStateConditions
    83 
    84         // loop & park until done
    85         while( !is_full_sat_1( clause_statuses ) ) {
    86            
    87             // binary sem P();
    88             if ( __atomic_sub_fetch( &park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
    89                 park();
    90            
    91             // execute any blocks available with status set to 0
    92             for ( int i = 0; i < 3; i++ ) {
    93                 if (clause_statuses[i] == __SELECT_SAT) {
    94                     switch (i) {
    95                         case 0:
    96                             try {
    97                                     on_selected( A, clause1 );
    98                                     doA();
    99                             }
    100                             finally { clause_statuses[i] = __SELECT_RUN; unregister_select(A, clause1); }
    101                             break;
    102                         case 1:
    103                             ... same gen as A but for B and clause2 ...
    104                             break;
    105                         case 2:
    106                             ... same gen as A but for C and clause3 ...
    107                             break;
    108                     }
    109                 }
    110             }
    111         }
    112 
    113         // ensure that the blocks that triggered is_full_sat_1 are run
    114         // by running every un-run block that is SAT from the start until
    115         // the predicate is SAT when considering RUN status = true
    116         for ( int i = 0; i < 3; i++ ) {
    117             if (is_done_sat_1( clause_statuses )) break;
    118             if (clause_statuses[i] == __SELECT_SAT)
    119                 ... Same if body here as in loop above ...
    120         }
    121     } finally {
    122         // the unregister and on_selected calls are needed to support primitives where the acquire has side effects
    123         // so the corresponding block MUST be run for those primitives to not lose state (example is channels)
    124         if ( !has_run(clause_statuses[0]) && whenA && unregister_select(A, clause1) )
    125             on_selected( A, clause1 )
    126             doA();
    127         ... repeat if above for B and C ...
    128     }
     57        // used with atomic_dec/inc to get binary semaphore behaviour
     58        int park_counter = 0;
     59
     60        // status (one for each clause)
     61        int clause_statuses[3] = { 0 };
     62
     63        bool whenA = condA;
     64        bool whenB = condB;
     65        bool whenC = condC;
     66
     67        if ( !whenB ) clause_statuses[1] = __SELECT_RUN;
     68        if ( !whenC ) clause_statuses[2] = __SELECT_RUN;
     69
     70        // some other conditional settors for clause_statuses are set here, see genSubtreeAssign and related routines
     71
     72        // three blocks
     73        // for each block, create, setup, then register select_node
     74        select_node clause1;
     75        select_node clause2;
     76        select_node clause3;
     77
     78        try {
     79                if ( whenA ) { register_select(A, clause1); setup_clause( clause1, &clause_statuses[0], &park_counter ); }
     80                ... repeat ^ for B and C ...
     81
     82                // if else clause is defined a separate branch can occur here to set initial values, see genWhenStateConditions
     83
     84                // loop & park until done
     85                while( !is_full_sat_1( clause_statuses ) ) {
     86
     87                        // binary sem P();
     88                        if ( __atomic_sub_fetch( &park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
     89                                park();
     90
     91                        // execute any blocks available with status set to 0
     92                        for ( int i = 0; i < 3; i++ ) {
     93                                if (clause_statuses[i] == __SELECT_SAT) {
     94                                    switch (i) {
     95                                        case 0:
     96                                            try {
     97                                                    on_selected( A, clause1 );
     98                                                    doA();
     99                                            }
     100                                            finally { clause_statuses[i] = __SELECT_RUN; unregister_select(A, clause1); }
     101                                            break;
     102                                        case 1:
     103                                            ... same gen as A but for B and clause2 ...
     104                                            break;
     105                                        case 2:
     106                                            ... same gen as A but for C and clause3 ...
     107                                            break;
     108                                    }
     109                                }
     110                        }
     111                }
     112
     113                // ensure that the blocks that triggered is_full_sat_1 are run
     114                // by running every un-run block that is SAT from the start until
     115                // the predicate is SAT when considering RUN status = true
     116                for ( int i = 0; i < 3; i++ ) {
     117                        if (is_done_sat_1( clause_statuses )) break;
     118                        if (clause_statuses[i] == __SELECT_SAT)
     119                                ... Same if body here as in loop above ...
     120                }
     121        } finally {
     122                // the unregister and on_selected calls are needed to support primitives where the acquire has side effects
     123                // so the corresponding block MUST be run for those primitives to not lose state (example is channels)
     124                if ( !has_run(clause_statuses[0]) && whenA && unregister_select(A, clause1) )
     125                        on_selected( A, clause1 )
     126                        doA();
     127                ... repeat if above for B and C ...
     128        }
    129129}
    130130
     
    134134
    135135class GenerateWaitUntilCore final {
    136     vector<FunctionDecl *> & satFns;
     136        vector<FunctionDecl *> & satFns;
    137137        UniqueName namer_sat = "__is_full_sat_"s;
    138     UniqueName namer_run = "__is_run_sat_"s;
     138        UniqueName namer_run = "__is_run_sat_"s;
    139139        UniqueName namer_park = "__park_counter_"s;
    140140        UniqueName namer_status = "__clause_statuses_"s;
    141141        UniqueName namer_node = "__clause_"s;
    142     UniqueName namer_target = "__clause_target_"s;
    143     UniqueName namer_when = "__when_cond_"s;
    144     UniqueName namer_label = "__waituntil_label_"s;
    145 
    146     string idxName = "__CFA_clause_idx_";
    147 
    148     struct ClauseData {
    149         string nodeName;
    150         string targetName;
    151         string whenName;
    152         int index;
    153         string & statusName;
    154         ClauseData( int index, string & statusName ) : index(index), statusName(statusName) {}
    155     };
    156 
    157     const StructDecl * selectNodeDecl = nullptr;
    158 
    159     // This first set of routines are all used to do the complicated job of
    160     //    dealing with how to set predicate statuses with certain when_conds T/F
    161     //    so that the when_cond == F effectively makes that clause "disappear"
    162     void updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow );
    163     void paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow );
    164     bool paintWhenTree( WaitUntilStmt::ClauseNode * currNode );
    165     void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd );
    166     void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs );
    167     void updateWhenState( WaitUntilStmt::ClauseNode * currNode );
    168     void genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
    169     void genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
    170     CompoundStmt * getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData );
    171     Stmt * genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx );
    172 
    173     // These routines are just code-gen helpers
    174     void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
    175     void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
    176     CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
    177     Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
    178     CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
    179     Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
    180     Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
    181     void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
    182     Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
    183     Stmt * buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data );
    184     Stmt * genAllOr( const WaitUntilStmt * stmt );
     142        UniqueName namer_target = "__clause_target_"s;
     143        UniqueName namer_when = "__when_cond_"s;
     144        UniqueName namer_label = "__waituntil_label_"s;
     145
     146        string idxName = "__CFA_clause_idx_";
     147
     148        struct ClauseData {
     149                string nodeName;
     150                string targetName;
     151                string whenName;
     152                int index;
     153                string & statusName;
     154                ClauseData( int index, string & statusName ) : index(index), statusName(statusName) {}
     155        };
     156
     157        const StructDecl * selectNodeDecl = nullptr;
     158
     159        // This first set of routines are all used to do the complicated job of
     160        //    dealing with how to set predicate statuses with certain when_conds T/F
     161        //    so that the when_cond == F effectively makes that clause "disappear"
     162        void updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow );
     163        void paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow );
     164        bool paintWhenTree( WaitUntilStmt::ClauseNode * currNode );
     165        void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd );
     166        void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs );
     167        void updateWhenState( WaitUntilStmt::ClauseNode * currNode );
     168        void genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
     169        void genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
     170        CompoundStmt * getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData );
     171        Stmt * genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx );
     172
     173        // These routines are just code-gen helpers
     174        void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
     175        void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
     176        CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
     177        Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
     178        CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
     179        Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
     180        Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
     181        void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
     182        Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
     183        Stmt * buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data );
     184        Stmt * genAllOr( const WaitUntilStmt * stmt );
    185185
    186186  public:
    187     void previsit( const StructDecl * decl );
     187        void previsit( const StructDecl * decl );
    188188        Stmt * postvisit( const WaitUntilStmt * stmt );
    189     GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
     189        GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
    190190};
    191191
    192192// Finds select_node decl
    193193void GenerateWaitUntilCore::previsit( const StructDecl * decl ) {
    194     if ( !decl->body ) {
     194        if ( !decl->body ) {
    195195                return;
    196196        } else if ( "select_node" == decl->name ) {
     
    201201
    202202void GenerateWaitUntilCore::updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow ) {
    203     // all children when-ambiguous
    204     if ( currNode->left->ambiguousWhen && currNode->right->ambiguousWhen )
    205         // true iff an ancestor/descendant has a different operation
    206         currNode->ambiguousWhen = (orAbove || orBelow) && (andBelow || andAbove);
    207     // ambiguousWhen is initially false so theres no need to set it here
     203        // all children when-ambiguous
     204        if ( currNode->left->ambiguousWhen && currNode->right->ambiguousWhen )
     205                // true iff an ancestor/descendant has a different operation
     206                currNode->ambiguousWhen = (orAbove || orBelow) && (andBelow || andAbove);
     207        // ambiguousWhen is initially false so theres no need to set it here
    208208}
    209209
     
    215215// - All of its descendent clauses are optional, i.e. they have a when_cond defined on the WhenClause
    216216void GenerateWaitUntilCore::paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow ) {
    217     bool aBelow = false; // updated by child nodes
    218     bool oBelow = false; // updated by child nodes
    219     switch (currNode->op) {
    220         case WaitUntilStmt::ClauseNode::AND:
    221             paintWhenTree( currNode->left, true, orAbove, aBelow, oBelow );
    222             paintWhenTree( currNode->right, true, orAbove, aBelow, oBelow );
    223 
    224             // update currNode's when flag based on conditions listed in fn signature comment above
    225             updateAmbiguousWhen(currNode, true, orAbove, aBelow, oBelow );
    226 
    227             // set return flags to tell parents which decendant ops have been seen
    228             andBelow = true;
    229             orBelow = oBelow;
    230             return;
    231         case WaitUntilStmt::ClauseNode::OR:
    232             paintWhenTree( currNode->left, andAbove, true, aBelow, oBelow );
    233             paintWhenTree( currNode->right, andAbove, true, aBelow, oBelow );
    234 
    235             // update currNode's when flag based on conditions listed in fn signature comment above
    236             updateAmbiguousWhen(currNode, andAbove, true, aBelow, oBelow );
    237 
    238             // set return flags to tell parents which decendant ops have been seen
    239             andBelow = aBelow;
    240             orBelow = true;
    241             return;
    242         case WaitUntilStmt::ClauseNode::LEAF:
    243             if ( currNode->leaf->when_cond )
    244                 currNode->ambiguousWhen = true;
    245             return;
    246         default:
    247             assertf(false, "Unreachable waituntil clause node type. How did you get here???");
    248     }
     217        bool aBelow = false; // updated by child nodes
     218        bool oBelow = false; // updated by child nodes
     219        switch (currNode->op) {
     220                case WaitUntilStmt::ClauseNode::AND:
     221                        paintWhenTree( currNode->left, true, orAbove, aBelow, oBelow );
     222                        paintWhenTree( currNode->right, true, orAbove, aBelow, oBelow );
     223
     224                        // update currNode's when flag based on conditions listed in fn signature comment above
     225                        updateAmbiguousWhen(currNode, true, orAbove, aBelow, oBelow );
     226
     227                        // set return flags to tell parents which decendant ops have been seen
     228                        andBelow = true;
     229                        orBelow = oBelow;
     230                        return;
     231                case WaitUntilStmt::ClauseNode::OR:
     232                        paintWhenTree( currNode->left, andAbove, true, aBelow, oBelow );
     233                        paintWhenTree( currNode->right, andAbove, true, aBelow, oBelow );
     234
     235                        // update currNode's when flag based on conditions listed in fn signature comment above
     236                        updateAmbiguousWhen(currNode, andAbove, true, aBelow, oBelow );
     237
     238                        // set return flags to tell parents which decendant ops have been seen
     239                        andBelow = aBelow;
     240                        orBelow = true;
     241                        return;
     242                case WaitUntilStmt::ClauseNode::LEAF:
     243                        if ( currNode->leaf->when_cond )
     244                                currNode->ambiguousWhen = true;
     245                        return;
     246                default:
     247                        assertf(false, "Unreachable waituntil clause node type. How did you get here???");
     248        }
    249249}
    250250
     
    252252// returns true if entire tree is OR's (special case)
    253253bool GenerateWaitUntilCore::paintWhenTree( WaitUntilStmt::ClauseNode * currNode ) {
    254     bool aBelow = false, oBelow = false; // unused by initial call
    255     paintWhenTree( currNode, false, false, aBelow, oBelow );
    256     return !aBelow;
     254        bool aBelow = false, oBelow = false; // unused by initial call
     255        paintWhenTree( currNode, false, false, aBelow, oBelow );
     256        return !aBelow;
    257257}
    258258
    259259// Helper: returns Expr that represents arrName[index]
    260260Expr * genArrAccessExpr( const CodeLocation & loc, int index, string arrName ) {
    261     return new UntypedExpr ( loc,
    262         new NameExpr( loc, "?[?]" ),
    263         {
    264             new NameExpr( loc, arrName ),
    265             ConstantExpr::from_int( loc, index )
    266         }
    267     );
     261        return new UntypedExpr ( loc,
     262                new NameExpr( loc, "?[?]" ),
     263                {
     264                        new NameExpr( loc, arrName ),
     265                        ConstantExpr::from_int( loc, index )
     266                }
     267        );
    268268}
    269269
     
    273273// - updates LEAF nodes to be when-ambiguous if their direct parent is when-ambiguous.
    274274void GenerateWaitUntilCore::collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd ) {
    275     switch (currNode->op) {
    276         case WaitUntilStmt::ClauseNode::AND:
    277             collectWhens( currNode->left, ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
    278             collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
    279             return;
    280         case WaitUntilStmt::ClauseNode::OR:
    281             collectWhens( currNode->left,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
    282             collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
    283             return;
    284         case WaitUntilStmt::ClauseNode::LEAF:
    285             if ( parentAmbig ) {
    286                 ambigIdxs.push_back(make_pair(index, currNode));
    287             }
    288             if ( parentAnd && currNode->leaf->when_cond ) {
    289                 currNode->childOfAnd = true;
    290                 andIdxs.push_back(index);
    291             }
    292             index++;
    293             return;
    294         default:
    295             assertf(false, "Unreachable waituntil clause node type. How did you get here???");
    296     }
     275        switch (currNode->op) {
     276                case WaitUntilStmt::ClauseNode::AND:
     277                        collectWhens( currNode->left, ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
     278                        collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
     279                        return;
     280                case WaitUntilStmt::ClauseNode::OR:
     281                        collectWhens( currNode->left,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
     282                        collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
     283                        return;
     284                case WaitUntilStmt::ClauseNode::LEAF:
     285                        if ( parentAmbig ) {
     286                                ambigIdxs.push_back(make_pair(index, currNode));
     287                        }
     288                        if ( parentAnd && currNode->leaf->when_cond ) {
     289                                currNode->childOfAnd = true;
     290                                andIdxs.push_back(index);
     291                        }
     292                        index++;
     293                        return;
     294                default:
     295                        assertf(false, "Unreachable waituntil clause node type. How did you get here???");
     296        }
    297297}
    298298
    299299// overloaded wrapper for collectWhens that sets initial values
    300300void GenerateWaitUntilCore::collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs ) {
    301     int idx = 0;
    302     collectWhens( currNode, ambigIdxs, andIdxs, idx, false, false );
    303 }
    304 
    305 // recursively updates ClauseNode whenState on internal nodes so that next pass can see which 
     301        int idx = 0;
     302        collectWhens( currNode, ambigIdxs, andIdxs, idx, false, false );
     303}
     304
     305// recursively updates ClauseNode whenState on internal nodes so that next pass can see which
    306306//    subtrees are "turned off"
    307307// sets whenState = false iff both children have whenState == false.
     
    309309// since the ambiguous clauses were filtered in paintWhenTree we don't need to worry about that here
    310310void GenerateWaitUntilCore::updateWhenState( WaitUntilStmt::ClauseNode * currNode ) {
    311     if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) return;
    312     updateWhenState( currNode->left );
    313     updateWhenState( currNode->right );
    314     if ( !currNode->left->whenState && !currNode->right->whenState )
    315         currNode->whenState = false;
    316     else
    317         currNode->whenState = true;
     311        if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) return;
     312        updateWhenState( currNode->left );
     313        updateWhenState( currNode->right );
     314        if ( !currNode->left->whenState && !currNode->right->whenState )
     315                currNode->whenState = false;
     316        else
     317                currNode->whenState = true;
    318318}
    319319
     
    321321// assumes that this will only be called on subtrees that are entirely whenState == false
    322322void GenerateWaitUntilCore::genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData ) {
    323     if ( ( currNode->op == WaitUntilStmt::ClauseNode::AND && status )
    324         || ( currNode->op == WaitUntilStmt::ClauseNode::OR && !status ) ) {
    325         // need to recurse on both subtrees if && subtree needs to be true or || subtree needs to be false
    326         genSubtreeAssign( stmt, currNode->left, status, idx, retStmt, clauseData );
    327         genSubtreeAssign( stmt, currNode->right, status, idx, retStmt, clauseData );
    328     } else if ( ( currNode->op == WaitUntilStmt::ClauseNode::OR && status )
    329         || ( currNode->op == WaitUntilStmt::ClauseNode::AND && !status ) ) {
    330         // only one subtree needs to evaluate to status if && subtree needs to be true or || subtree needs to be false
    331         CompoundStmt * leftStmt = new CompoundStmt( stmt->location );
    332         CompoundStmt * rightStmt = new CompoundStmt( stmt->location );
    333 
    334         // only one side needs to evaluate to status so we recurse on both subtrees
    335         //    but only keep the statements from the subtree with minimal statements
    336         genSubtreeAssign( stmt, currNode->left, status, idx, leftStmt, clauseData );
    337         genSubtreeAssign( stmt, currNode->right, status, idx, rightStmt, clauseData );
    338        
    339         // append minimal statements to retStmt
    340         if ( leftStmt->kids.size() < rightStmt->kids.size() ) {
    341             retStmt->kids.splice( retStmt->kids.end(), leftStmt->kids );
    342         } else {
    343             retStmt->kids.splice( retStmt->kids.end(), rightStmt->kids );
    344         }
    345        
    346         delete leftStmt;
    347         delete rightStmt;
    348     } else if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) {
    349         const CodeLocation & loc = stmt->location;
    350         if ( status && !currNode->childOfAnd ) {
    351             retStmt->push_back(
    352                 new ExprStmt( loc,
    353                     UntypedExpr::createAssign( loc,
    354                         genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
    355                         new NameExpr( loc, "__SELECT_RUN" )
    356                     )
    357                 )
    358             );
    359         } else if ( !status && currNode->childOfAnd ) {
    360             retStmt->push_back(
    361                 new ExprStmt( loc,
    362                     UntypedExpr::createAssign( loc,
    363                         genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
    364                         new NameExpr( loc, "__SELECT_UNSAT" )
    365                     )
    366                 )
    367             );
    368         }
    369 
    370         // No need to generate statements for the following cases since childOfAnd are always set to true
    371         //    and !childOfAnd are always false
    372         // - status && currNode->childOfAnd
    373         // - !status && !currNode->childOfAnd
    374         idx++;
    375     }
     323        if ( ( currNode->op == WaitUntilStmt::ClauseNode::AND && status )
     324                || ( currNode->op == WaitUntilStmt::ClauseNode::OR && !status ) ) {
     325                // need to recurse on both subtrees if && subtree needs to be true or || subtree needs to be false
     326                genSubtreeAssign( stmt, currNode->left, status, idx, retStmt, clauseData );
     327                genSubtreeAssign( stmt, currNode->right, status, idx, retStmt, clauseData );
     328        } else if ( ( currNode->op == WaitUntilStmt::ClauseNode::OR && status )
     329                || ( currNode->op == WaitUntilStmt::ClauseNode::AND && !status ) ) {
     330                // only one subtree needs to evaluate to status if && subtree needs to be true or || subtree needs to be false
     331                CompoundStmt * leftStmt = new CompoundStmt( stmt->location );
     332                CompoundStmt * rightStmt = new CompoundStmt( stmt->location );
     333
     334                // only one side needs to evaluate to status so we recurse on both subtrees
     335                //    but only keep the statements from the subtree with minimal statements
     336                genSubtreeAssign( stmt, currNode->left, status, idx, leftStmt, clauseData );
     337                genSubtreeAssign( stmt, currNode->right, status, idx, rightStmt, clauseData );
     338
     339                // append minimal statements to retStmt
     340                if ( leftStmt->kids.size() < rightStmt->kids.size() ) {
     341                        retStmt->kids.splice( retStmt->kids.end(), leftStmt->kids );
     342                } else {
     343                        retStmt->kids.splice( retStmt->kids.end(), rightStmt->kids );
     344                }
     345
     346                delete leftStmt;
     347                delete rightStmt;
     348        } else if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) {
     349                const CodeLocation & loc = stmt->location;
     350                if ( status && !currNode->childOfAnd ) {
     351                        retStmt->push_back(
     352                                new ExprStmt( loc,
     353                                    UntypedExpr::createAssign( loc,
     354                                        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
     355                                        new NameExpr( loc, "__SELECT_RUN" )
     356                                    )
     357                                )
     358                        );
     359                } else if ( !status && currNode->childOfAnd ) {
     360                        retStmt->push_back(
     361                                new ExprStmt( loc,
     362                                    UntypedExpr::createAssign( loc,
     363                                        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
     364                                        new NameExpr( loc, "__SELECT_UNSAT" )
     365                                    )
     366                                )
     367                        );
     368                }
     369
     370                // No need to generate statements for the following cases since childOfAnd are always set to true
     371                //    and !childOfAnd are always false
     372                // - status && currNode->childOfAnd
     373                // - !status && !currNode->childOfAnd
     374                idx++;
     375        }
    376376}
    377377
    378378void GenerateWaitUntilCore::genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData ) {
    379     switch (currNode->op) {
    380         case WaitUntilStmt::ClauseNode::AND:
    381             // check which subtrees have all whenState == false (disabled)
    382             if (!currNode->left->whenState && !currNode->right->whenState) {
    383                 // this case can only occur when whole tree is disabled since otherwise
    384                 //    genStatusAssign( ... ) isn't called on nodes with whenState == false
    385                 assert( !currNode->whenState ); // paranoidWWW
    386                 // whole tree disabled so pass true so that select is SAT vacuously
    387                 genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
    388             } else if ( !currNode->left->whenState ) {
    389                 // pass true since x && true === x
    390                 genSubtreeAssign( stmt, currNode->left, true, idx, retStmt, clauseData );
    391                 genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
    392             } else if ( !currNode->right->whenState ) {
    393                 genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
    394                 genSubtreeAssign( stmt, currNode->right, true, idx, retStmt, clauseData );
    395             } else {
    396                 // if no children with whenState == false recurse normally via break
    397                 break;
    398             }
    399             return;
    400         case WaitUntilStmt::ClauseNode::OR:
    401             if (!currNode->left->whenState && !currNode->right->whenState) {
    402                 assert( !currNode->whenState ); // paranoid
    403                 genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
    404             } else if ( !currNode->left->whenState ) {
    405                 // pass false since x || false === x
    406                 genSubtreeAssign( stmt, currNode->left, false, idx, retStmt, clauseData );
    407                 genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
    408             } else if ( !currNode->right->whenState ) {
    409                 genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
    410                 genSubtreeAssign( stmt, currNode->right, false, idx, retStmt, clauseData );
    411             } else {
    412                 break;
    413             }
    414             return;
    415         case WaitUntilStmt::ClauseNode::LEAF:
    416             idx++;
    417             return;
    418         default:
    419             assertf(false, "Unreachable waituntil clause node type. How did you get here???");
    420     }
    421     genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
    422     genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
     379        switch (currNode->op) {
     380                case WaitUntilStmt::ClauseNode::AND:
     381                        // check which subtrees have all whenState == false (disabled)
     382                        if (!currNode->left->whenState && !currNode->right->whenState) {
     383                                // this case can only occur when whole tree is disabled since otherwise
     384                                //    genStatusAssign( ... ) isn't called on nodes with whenState == false
     385                                assert( !currNode->whenState ); // paranoidWWW
     386                                // whole tree disabled so pass true so that select is SAT vacuously
     387                                genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
     388                        } else if ( !currNode->left->whenState ) {
     389                                // pass true since x && true === x
     390                                genSubtreeAssign( stmt, currNode->left, true, idx, retStmt, clauseData );
     391                                genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
     392                        } else if ( !currNode->right->whenState ) {
     393                                genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
     394                                genSubtreeAssign( stmt, currNode->right, true, idx, retStmt, clauseData );
     395                        } else {
     396                                // if no children with whenState == false recurse normally via break
     397                                break;
     398                        }
     399                        return;
     400                case WaitUntilStmt::ClauseNode::OR:
     401                        if (!currNode->left->whenState && !currNode->right->whenState) {
     402                                assert( !currNode->whenState ); // paranoid
     403                                genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
     404                        } else if ( !currNode->left->whenState ) {
     405                                // pass false since x || false === x
     406                                genSubtreeAssign( stmt, currNode->left, false, idx, retStmt, clauseData );
     407                                genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
     408                        } else if ( !currNode->right->whenState ) {
     409                                genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
     410                                genSubtreeAssign( stmt, currNode->right, false, idx, retStmt, clauseData );
     411                        } else {
     412                                break;
     413                        }
     414                        return;
     415                case WaitUntilStmt::ClauseNode::LEAF:
     416                        idx++;
     417                        return;
     418                default:
     419                        assertf(false, "Unreachable waituntil clause node type. How did you get here???");
     420        }
     421        genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
     422        genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
    423423}
    424424
    425425// generates a minimal set of assignments for status arr based on which whens are toggled on/off
    426426CompoundStmt * GenerateWaitUntilCore::getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData ) {
    427     updateWhenState( stmt->predicateTree );
    428     CompoundStmt * retval = new CompoundStmt( stmt->location );
    429     int idx = 0;
    430     genStatusAssign( stmt, stmt->predicateTree, idx, retval, clauseData );
    431     return retval;
     427        updateWhenState( stmt->predicateTree );
     428        CompoundStmt * retval = new CompoundStmt( stmt->location );
     429        int idx = 0;
     430        genStatusAssign( stmt, stmt->predicateTree, idx, retval, clauseData );
     431        return retval;
    432432}
    433433
    434434// generates nested if/elses for all possible assignments of ambiguous when_conds
    435435// exponential size of code gen but linear runtime O(n), where n is number of ambiguous whens()
    436 Stmt * GenerateWaitUntilCore::genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, 
    437     vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx ) {
    438     // I hate C++ sometimes, using vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type for size() comparison seems silly.
    439     //    Why is size_type parameterized on the type stored in the vector?????
    440 
    441     const CodeLocation & loc = stmt->location;
    442     int clauseIdx = ambigClauses.at(ambigIdx).first;
    443     WaitUntilStmt::ClauseNode * currNode = ambigClauses.at(ambigIdx).second;
    444     Stmt * thenStmt;
    445     Stmt * elseStmt;
    446    
    447     if ( ambigIdx == ambigClauses.size() - 1 ) { // base case
    448         currNode->whenState = true;
    449         thenStmt = getStatusAssignment( stmt, clauseData );
    450         currNode->whenState = false;
    451         elseStmt = getStatusAssignment( stmt, clauseData );
    452     } else {
    453         // recurse both with when enabled and disabled to generate all possible cases
    454         currNode->whenState = true;
    455         thenStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
    456         currNode->whenState = false;
    457         elseStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
    458     }
    459 
    460     // insert first recursion result in if ( __when_cond_ ) { ... }
    461     // insert second recursion result in else { ... }
    462     return new CompoundStmt ( loc,
    463         {
    464             new IfStmt( loc,
    465                 new NameExpr( loc, clauseData.at(clauseIdx)->whenName ),
    466                 thenStmt,
    467                 elseStmt
    468             )
    469         }
    470     );
     436Stmt * GenerateWaitUntilCore::genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData,
     437        vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx ) {
     438        // I hate C++ sometimes, using vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type for size() comparison seems silly.
     439        //    Why is size_type parameterized on the type stored in the vector?????
     440
     441        const CodeLocation & loc = stmt->location;
     442        int clauseIdx = ambigClauses.at(ambigIdx).first;
     443        WaitUntilStmt::ClauseNode * currNode = ambigClauses.at(ambigIdx).second;
     444        Stmt * thenStmt;
     445        Stmt * elseStmt;
     446
     447        if ( ambigIdx == ambigClauses.size() - 1 ) { // base case
     448                currNode->whenState = true;
     449                thenStmt = getStatusAssignment( stmt, clauseData );
     450                currNode->whenState = false;
     451                elseStmt = getStatusAssignment( stmt, clauseData );
     452        } else {
     453                // recurse both with when enabled and disabled to generate all possible cases
     454                currNode->whenState = true;
     455                thenStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
     456                currNode->whenState = false;
     457                elseStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
     458        }
     459
     460        // insert first recursion result in if ( __when_cond_ ) { ... }
     461        // insert second recursion result in else { ... }
     462        return new CompoundStmt ( loc,
     463                {
     464                        new IfStmt( loc,
     465                                new NameExpr( loc, clauseData.at(clauseIdx)->whenName ),
     466                                thenStmt,
     467                                elseStmt
     468                        )
     469                }
     470        );
    471471}
    472472
     
    478478// mutates index to be index + 1
    479479Expr * genSatExpr( const CodeLocation & loc, int & index ) {
    480     return genArrAccessExpr( loc, index++, "clause_statuses" );
     480        return genArrAccessExpr( loc, index++, "clause_statuses" );
    481481}
    482482
    483483// return Expr that represents has_run(clause_statuses[index])
    484484Expr * genRunExpr( const CodeLocation & loc, int & index ) {
    485     return new UntypedExpr ( loc,
    486         new NameExpr( loc, "__CFA_has_clause_run" ),
    487         { genSatExpr( loc, index ) }
    488     );
     485        return new UntypedExpr ( loc,
     486                new NameExpr( loc, "__CFA_has_clause_run" ),
     487                { genSatExpr( loc, index ) }
     488        );
    489489}
    490490
     
    492492// the predicate expr used inside the predicate functions
    493493Expr * genPredExpr( const CodeLocation & loc, WaitUntilStmt::ClauseNode * currNode, int & idx, GenLeafExpr genLeaf ) {
    494     Expr * leftExpr, * rightExpr;
    495     switch (currNode->op) {
    496         case WaitUntilStmt::ClauseNode::AND:
    497             leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
    498             rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
    499             return new LogicalExpr( loc,
    500                 new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    501                 new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    502                 LogicalFlag::AndExpr
    503             );
    504             break;
    505         case WaitUntilStmt::ClauseNode::OR:
    506             leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
    507             rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
    508             return new LogicalExpr( loc,
    509                 new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    510                 new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    511                 LogicalFlag::OrExpr );
    512             break;
    513         case WaitUntilStmt::ClauseNode::LEAF:
    514             return genLeaf( loc, idx );
    515             break;
    516         default:
    517             assertf(false, "Unreachable waituntil clause node type. How did you get here???");\
    518             return nullptr;
    519             break;
    520     }
    521     return nullptr;
     494        Expr * leftExpr, * rightExpr;
     495        switch (currNode->op) {
     496                case WaitUntilStmt::ClauseNode::AND:
     497                        leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
     498                        rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
     499                        return new LogicalExpr( loc,
     500                                new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     501                                new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     502                                LogicalFlag::AndExpr
     503                        );
     504                        break;
     505                case WaitUntilStmt::ClauseNode::OR:
     506                        leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
     507                        rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
     508                        return new LogicalExpr( loc,
     509                                new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     510                                new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     511                                LogicalFlag::OrExpr );
     512                        break;
     513                case WaitUntilStmt::ClauseNode::LEAF:
     514                        return genLeaf( loc, idx );
     515                        break;
     516                default:
     517                        assertf(false, "Unreachable waituntil clause node type. How did you get here???");\
     518                        return nullptr;
     519                        break;
     520        }
     521        return nullptr;
    522522}
    523523
     
    526526/* Ex:
    527527{
    528     waituntil( A ){ doA(); }
    529     or waituntil( B ){ doB(); }
    530     and waituntil( C ) { doC(); }
     528        waituntil( A ){ doA(); }
     529        or waituntil( B ){ doB(); }
     530        and waituntil( C ) { doC(); }
    531531}
    532532generates =>
    533533static inline bool is_full_sat_1( int * clause_statuses ) {
    534     return clause_statuses[0]
    535         || clause_statuses[1]
    536         && clause_statuses[2];
     534        return clause_statuses[0]
     535                || clause_statuses[1]
     536                && clause_statuses[2];
    537537}
    538538
    539539static inline bool is_done_sat_1( int * clause_statuses ) {
    540     return has_run(clause_statuses[0])
    541         || has_run(clause_statuses[1])
    542         && has_run(clause_statuses[2]);
     540        return has_run(clause_statuses[0])
     541                || has_run(clause_statuses[1])
     542                && has_run(clause_statuses[2]);
    543543}
    544544*/
     
    546546// predName and genLeaf determine if this generates an is_done or an is_full predicate
    547547FunctionDecl * buildPredicate( const WaitUntilStmt * stmt, GenLeafExpr genLeaf, string & predName ) {
    548     int arrIdx = 0;
    549     const CodeLocation & loc = stmt->location;
    550     CompoundStmt * body = new CompoundStmt( loc );
    551     body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
    552 
    553     return new FunctionDecl( loc,
    554         predName,
    555         {
    556             new ObjectDecl( loc,
    557                 "clause_statuses",
    558                 new PointerType( new BasicType( BasicKind::LongUnsignedInt ) )
    559             )
    560         },
    561         {
    562             new ObjectDecl( loc,
    563                 "sat_ret",
    564                 new BasicType( BasicKind::Bool )
    565             )
    566         },
    567         body,               // body
    568         { Storage::Static },    // storage
    569         Linkage::Cforall,       // linkage
    570         {},                     // attributes
    571         { Function::Inline }
    572     );
     548        int arrIdx = 0;
     549        const CodeLocation & loc = stmt->location;
     550        CompoundStmt * body = new CompoundStmt( loc );
     551        body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
     552
     553        return new FunctionDecl( loc,
     554                predName,
     555                {
     556                        new ObjectDecl( loc,
     557                                "clause_statuses",
     558                                new PointerType( new BasicType( BasicKind::LongUnsignedInt ) )
     559                        )
     560                },
     561                {
     562                        new ObjectDecl( loc,
     563                                "sat_ret",
     564                                new BasicType( BasicKind::Bool )
     565                        )
     566                },
     567                body,               // body
     568                { Storage::Static },    // storage
     569                Linkage::Cforall,       // linkage
     570                {},                     // attributes
     571                { Function::Inline }
     572        );
    573573}
    574574
    575575// Creates is_done and is_full predicates
    576576void GenerateWaitUntilCore::addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName ) {
    577     if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
    578         satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) );
    579     satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
     577        if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
     578                satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) );
     579        satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
    580580}
    581581
     
    585585//      register_select(A, clause1);
    586586// }
    587 void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {   
    588     CompoundStmt * currBody = body;
    589     const CodeLocation & loc = clause->location;
    590 
    591     // If we have a when_cond make the initialization conditional
    592     if ( clause->when_cond )
    593         currBody = new CompoundStmt( loc );
    594 
    595     // Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
    596     currBody->push_back( new ExprStmt( loc,
    597         new UntypedExpr ( loc,
    598             new NameExpr( loc, "setup_clause" ),
    599             {
    600                 new NameExpr( loc, data->nodeName ),
    601                 new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
    602                 new AddressExpr( loc, new NameExpr( loc, pCountName ) )
    603             }
    604         )
    605     ));
    606 
    607     // Generates: register_select(A, clause1);
    608     currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
    609 
    610     // generates: if ( when_cond ) { ... currBody ... }
    611     if ( clause->when_cond )
    612         body->push_back(
    613             new IfStmt( loc,
    614                 new NameExpr( loc, data->whenName ),
    615                 currBody
    616             )
    617         );
     587void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {
     588        CompoundStmt * currBody = body;
     589        const CodeLocation & loc = clause->location;
     590
     591        // If we have a when_cond make the initialization conditional
     592        if ( clause->when_cond )
     593                currBody = new CompoundStmt( loc );
     594
     595        // Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
     596        currBody->push_back( new ExprStmt( loc,
     597                new UntypedExpr ( loc,
     598                        new NameExpr( loc, "setup_clause" ),
     599                        {
     600                                new NameExpr( loc, data->nodeName ),
     601                                new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
     602                                new AddressExpr( loc, new NameExpr( loc, pCountName ) )
     603                        }
     604                )
     605        ));
     606
     607        // Generates: register_select(A, clause1);
     608        currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
     609
     610        // generates: if ( when_cond ) { ... currBody ... }
     611        if ( clause->when_cond )
     612                body->push_back(
     613                        new IfStmt( loc,
     614                                new NameExpr( loc, data->whenName ),
     615                                currBody
     616                        )
     617                );
    618618}
    619619
    620620// Used to generate a call to one of the select trait routines
    621621Expr * GenerateWaitUntilCore::genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName ) {
    622     const CodeLocation & loc = clause->location;
    623     return new UntypedExpr ( loc,
    624         new NameExpr( loc, fnName ),
    625         {
    626             new NameExpr( loc, data->targetName ),
    627             new NameExpr( loc, data->nodeName )
    628         }
    629     );
     622        const CodeLocation & loc = clause->location;
     623        return new UntypedExpr ( loc,
     624                new NameExpr( loc, fnName ),
     625                {
     626                        new NameExpr( loc, data->targetName ),
     627                        new NameExpr( loc, data->nodeName )
     628                }
     629        );
    630630}
    631631
    632632// Generates:
    633 /* on_selected( target_1, node_1 ); ... corresponding body of target_1 ... 
     633/* on_selected( target_1, node_1 ); ... corresponding body of target_1 ...
    634634*/
    635635CompoundStmt * GenerateWaitUntilCore::genStmtBlock( const WhenClause * clause, const ClauseData * data ) {
    636     const CodeLocation & cLoc = clause->location;
    637     return new CompoundStmt( cLoc,
    638         {
    639             new IfStmt( cLoc,
    640                 genSelectTraitCall( clause, data, "on_selected" ),
    641                 ast::deepCopy( clause->stmt )
    642             )
    643         }
    644     );
     636        const CodeLocation & cLoc = clause->location;
     637        return new CompoundStmt( cLoc,
     638                {
     639                        new IfStmt( cLoc,
     640                                genSelectTraitCall( clause, data, "on_selected" ),
     641                                ast::deepCopy( clause->stmt )
     642                        )
     643                }
     644        );
    645645}
    646646
    647647// this routine generates and returns the following
    648648/*for ( int i = 0; i < numClauses; i++ ) {
    649     if ( predName(clause_statuses) ) break;
    650     if (clause_statuses[i] == __SELECT_SAT) {
    651         switch (i) {
    652             case 0:
    653                 try {
    654                     on_selected( target1, clause1 );
    655                     dotarget1stmt();
    656                 }
    657                 finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
    658                 break;
    659             ...
    660             case N:
    661                 ...
    662                 break;
    663         }
    664     }
     649        if ( predName(clause_statuses) ) break;
     650        if (clause_statuses[i] == __SELECT_SAT) {
     651                switch (i) {
     652                        case 0:
     653                                try {
     654                                    on_selected( target1, clause1 );
     655                                    dotarget1stmt();
     656                                }
     657                                finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
     658                                break;
     659                        ...
     660                        case N:
     661                                ...
     662                                break;
     663                }
     664        }
    665665}*/
    666666CompoundStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {
    667     CompoundStmt * ifBody = new CompoundStmt( stmt->location );
    668     const CodeLocation & loc = stmt->location;
    669 
    670     string switchLabel = namer_label.newName();
    671 
    672     /* generates:
    673     switch (i) {
    674         case 0:
    675             try {
    676                 on_selected( target1, clause1 );
    677                 dotarget1stmt();
    678             }
    679             finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
    680             break;
    681             ...
    682         case N:
    683             ...
    684             break;
    685     }*/
    686     std::vector<ptr<CaseClause>> switchCases;
    687     int idx = 0;
    688     for ( const auto & clause: stmt->clauses ) {
    689         const CodeLocation & cLoc = clause->location;
    690         switchCases.push_back(
    691             new CaseClause( cLoc,
    692                 ConstantExpr::from_int( cLoc, idx ),
    693                 {
    694                     new CompoundStmt( cLoc,
    695                         {
    696                             new ast::TryStmt( cLoc,
    697                                 genStmtBlock( clause, clauseData.at(idx) ),
    698                                 {},
    699                                 new ast::FinallyClause( cLoc,
    700                                     new CompoundStmt( cLoc,
    701                                         {
    702                                             new ExprStmt( loc,
    703                                                 new UntypedExpr ( loc,
    704                                                     new NameExpr( loc, "?=?" ),
    705                                                     {
    706                                                         new UntypedExpr ( loc,
    707                                                             new NameExpr( loc, "?[?]" ),
    708                                                             {
    709                                                                 new NameExpr( loc, clauseData.at(0)->statusName ),
    710                                                                 new NameExpr( loc, idxName )
    711                                                             }
    712                                                         ),
    713                                                         new NameExpr( loc, "__SELECT_RUN" )
    714                                                     }
    715                                                 )
    716                                             ),
    717                                             new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
    718                                         }
    719                                     )
    720                                 )
    721                             ),
    722                             new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
    723                         }
    724                     )
    725                 }
    726             )
    727         );
    728         idx++;
    729     }
    730 
    731     ifBody->push_back(
    732         new SwitchStmt( loc,
    733             new NameExpr( loc, idxName ),
    734             std::move( switchCases ),
    735             { Label( loc, switchLabel ) }
    736         )
    737     );
    738 
    739     // gens:
    740     // if (clause_statuses[i] == __SELECT_SAT) {
    741     //      ... ifBody  ...
    742     // }
    743     IfStmt * ifSwitch = new IfStmt( loc,
    744         new UntypedExpr ( loc,
    745             new NameExpr( loc, "?==?" ),
    746             {
    747                 new UntypedExpr ( loc,
    748                     new NameExpr( loc, "?[?]" ),
    749                     {
    750                         new NameExpr( loc, clauseData.at(0)->statusName ),
    751                         new NameExpr( loc, idxName )
    752                     }
    753                 ),
    754                 new NameExpr( loc, "__SELECT_SAT" )
    755             }
    756         ),      // condition
    757         ifBody  // body
    758     );
    759 
    760     string forLabel = namer_label.newName();
    761 
    762     // we hoist init here so that this pass can happen after hoistdecls pass
    763     return new CompoundStmt( loc,
    764         {
    765             new DeclStmt( loc,
    766                 new ObjectDecl( loc,
    767                     idxName,
    768                     new BasicType( BasicKind::SignedInt ),
    769                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    770                 )
    771             ),
    772             new ForStmt( loc,
    773                 {},  // inits
    774                 new UntypedExpr ( loc,
    775                     new NameExpr( loc, "?<?" ),
    776                     {
    777                         new NameExpr( loc, idxName ),
    778                         ConstantExpr::from_int( loc, stmt->clauses.size() )
    779                     }
    780                 ),  // cond
    781                 new UntypedExpr ( loc,
    782                     new NameExpr( loc, "?++" ),
    783                     { new NameExpr( loc, idxName ) }
    784                 ),  // inc
    785                 new CompoundStmt( loc,
    786                     {
    787                         new IfStmt( loc,
    788                             new UntypedExpr ( loc,
    789                                 new NameExpr( loc, predName ),
    790                                 { new NameExpr( loc, clauseData.at(0)->statusName ) }
    791                             ),
    792                             new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
    793                         ),
    794                         ifSwitch
    795                     }
    796                 ),   // body
    797                 { Label( loc, forLabel ) }
    798             )
    799         }
    800     );
     667        CompoundStmt * ifBody = new CompoundStmt( stmt->location );
     668        const CodeLocation & loc = stmt->location;
     669
     670        string switchLabel = namer_label.newName();
     671
     672        /* generates:
     673        switch (i) {
     674                case 0:
     675                        try {
     676                                on_selected( target1, clause1 );
     677                                dotarget1stmt();
     678                        }
     679                        finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
     680                        break;
     681                        ...
     682                case N:
     683                        ...
     684                        break;
     685        }*/
     686        std::vector<ptr<CaseClause>> switchCases;
     687        int idx = 0;
     688        for ( const auto & clause: stmt->clauses ) {
     689                const CodeLocation & cLoc = clause->location;
     690                switchCases.push_back(
     691                        new CaseClause( cLoc,
     692                                ConstantExpr::from_int( cLoc, idx ),
     693                                {
     694                                    new CompoundStmt( cLoc,
     695                                        {
     696                                            new ast::TryStmt( cLoc,
     697                                                genStmtBlock( clause, clauseData.at(idx) ),
     698                                                {},
     699                                                new ast::FinallyClause( cLoc,
     700                                                    new CompoundStmt( cLoc,
     701                                                        {
     702                                                            new ExprStmt( loc,
     703                                                                new UntypedExpr ( loc,
     704                                                                    new NameExpr( loc, "?=?" ),
     705                                                                    {
     706                                                                        new UntypedExpr ( loc,
     707                                                                            new NameExpr( loc, "?[?]" ),
     708                                                                            {
     709                                                                                new NameExpr( loc, clauseData.at(0)->statusName ),
     710                                                                                new NameExpr( loc, idxName )
     711                                                                            }
     712                                                                        ),
     713                                                                        new NameExpr( loc, "__SELECT_RUN" )
     714                                                                    }
     715                                                                )
     716                                                            ),
     717                                                            new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
     718                                                        }
     719                                                    )
     720                                                )
     721                                            ),
     722                                            new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
     723                                        }
     724                                    )
     725                                }
     726                        )
     727                );
     728                idx++;
     729        }
     730
     731        ifBody->push_back(
     732                new SwitchStmt( loc,
     733                        new NameExpr( loc, idxName ),
     734                        std::move( switchCases ),
     735                        { Label( loc, switchLabel ) }
     736                )
     737        );
     738
     739        // gens:
     740        // if (clause_statuses[i] == __SELECT_SAT) {
     741        //      ... ifBody  ...
     742        // }
     743        IfStmt * ifSwitch = new IfStmt( loc,
     744                new UntypedExpr ( loc,
     745                        new NameExpr( loc, "?==?" ),
     746                        {
     747                                new UntypedExpr ( loc,
     748                                    new NameExpr( loc, "?[?]" ),
     749                                    {
     750                                        new NameExpr( loc, clauseData.at(0)->statusName ),
     751                                        new NameExpr( loc, idxName )
     752                                    }
     753                                ),
     754                                new NameExpr( loc, "__SELECT_SAT" )
     755                        }
     756                ),      // condition
     757                ifBody  // body
     758        );
     759
     760        string forLabel = namer_label.newName();
     761
     762        // we hoist init here so that this pass can happen after hoistdecls pass
     763        return new CompoundStmt( loc,
     764                {
     765                        new DeclStmt( loc,
     766                                new ObjectDecl( loc,
     767                                    idxName,
     768                                    new BasicType( BasicKind::SignedInt ),
     769                                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     770                                )
     771                        ),
     772                        new ForStmt( loc,
     773                                {},  // inits
     774                                new UntypedExpr ( loc,
     775                                    new NameExpr( loc, "?<?" ),
     776                                    {
     777                                        new NameExpr( loc, idxName ),
     778                                        ConstantExpr::from_int( loc, stmt->clauses.size() )
     779                                    }
     780                                ),  // cond
     781                                new UntypedExpr ( loc,
     782                                    new NameExpr( loc, "?++" ),
     783                                    { new NameExpr( loc, idxName ) }
     784                                ),  // inc
     785                                new CompoundStmt( loc,
     786                                    {
     787                                        new IfStmt( loc,
     788                                            new UntypedExpr ( loc,
     789                                                new NameExpr( loc, predName ),
     790                                                { new NameExpr( loc, clauseData.at(0)->statusName ) }
     791                                            ),
     792                                            new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
     793                                        ),
     794                                        ifSwitch
     795                                    }
     796                                ),   // body
     797                                { Label( loc, forLabel ) }
     798                        )
     799                }
     800        );
    801801}
    802802
    803803// Generates: !is_full_sat_n() / !is_run_sat_n()
    804804Expr * genNotSatExpr( const WaitUntilStmt * stmt, string & satName, string & arrName ) {
    805     const CodeLocation & loc = stmt->location;
    806     return new UntypedExpr ( loc,
    807         new NameExpr( loc, "!?" ),
    808         {
    809             new UntypedExpr ( loc,
    810                 new NameExpr( loc, satName ),
    811                 { new NameExpr( loc, arrName ) }
    812             )
    813         }
    814     );
     805        const CodeLocation & loc = stmt->location;
     806        return new UntypedExpr ( loc,
     807                new NameExpr( loc, "!?" ),
     808                {
     809                        new UntypedExpr ( loc,
     810                                new NameExpr( loc, satName ),
     811                                { new NameExpr( loc, arrName ) }
     812                        )
     813                }
     814        );
    815815}
    816816
     
    819819// If not enough have run to satisfy predicate after one pass then the else is run
    820820Stmt * GenerateWaitUntilCore::genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData ) {
    821     return new CompoundStmt( stmt->else_stmt->location,
    822         {
    823             genStatusCheckFor( stmt, clauseData, runName ),
    824             new IfStmt( stmt->else_stmt->location,
    825                 genNotSatExpr( stmt, runName, arrName ),
    826                 ast::deepCopy( stmt->else_stmt )
    827             )
    828         }
    829     );
     821        return new CompoundStmt( stmt->else_stmt->location,
     822                {
     823                        genStatusCheckFor( stmt, clauseData, runName ),
     824                        new IfStmt( stmt->else_stmt->location,
     825                                genNotSatExpr( stmt, runName, arrName ),
     826                                ast::deepCopy( stmt->else_stmt )
     827                        )
     828                }
     829        );
    830830}
    831831
    832832Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {
    833     CompoundStmt * whileBody = new CompoundStmt( stmt->location );
    834     const CodeLocation & loc = stmt->location;
    835 
    836     // generates: __CFA_maybe_park( &park_counter );
    837     whileBody->push_back(
    838         new ExprStmt( loc,
    839             new UntypedExpr ( loc,
    840                 new NameExpr( loc, "__CFA_maybe_park" ),
    841                 { new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
    842             )
    843         )
    844     );
    845 
    846     whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
    847 
    848     return new CompoundStmt( loc,
    849         {
    850             new WhileDoStmt( loc,
    851                 genNotSatExpr( stmt, runName, arrName ),
    852                 whileBody,  // body
    853                 {}          // no inits
    854             )
    855         }
    856     );
     833        CompoundStmt * whileBody = new CompoundStmt( stmt->location );
     834        const CodeLocation & loc = stmt->location;
     835
     836        // generates: __CFA_maybe_park( &park_counter );
     837        whileBody->push_back(
     838                new ExprStmt( loc,
     839                        new UntypedExpr ( loc,
     840                                new NameExpr( loc, "__CFA_maybe_park" ),
     841                                { new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
     842                        )
     843                )
     844        );
     845
     846        whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
     847
     848        return new CompoundStmt( loc,
     849                {
     850                        new WhileDoStmt( loc,
     851                                genNotSatExpr( stmt, runName, arrName ),
     852                                whileBody,  // body
     853                                {}          // no inits
     854                        )
     855                }
     856        );
    857857}
    858858
     
    862862// select_node clause1;
    863863void GenerateWaitUntilCore::genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName ) {
    864     ClauseData * currClause;
    865     for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
    866         currClause = new ClauseData( i, statusName );
    867         currClause->nodeName = namer_node.newName();
    868         currClause->targetName = namer_target.newName();
    869         currClause->whenName = namer_when.newName();
    870         clauseData.push_back(currClause);
    871         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    872 
    873         // typeof(target) & __clause_target_0 = target;
    874         body->push_back(
    875             new DeclStmt( cLoc,
    876                 new ObjectDecl( cLoc,
    877                     currClause->targetName,
    878                     new ReferenceType(
    879                         new TypeofType( new UntypedExpr( cLoc,
    880                             new NameExpr( cLoc, "__CFA_select_get_type" ),
    881                             { ast::deepCopy( stmt->clauses.at(i)->target ) }
    882                         ))
    883                     ),
    884                     new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
    885                 )
    886             )
    887         );
    888 
    889         // bool __when_cond_0 = when_cond; // only generated if when_cond defined
    890         if ( stmt->clauses.at(i)->when_cond )
    891             body->push_back(
    892                 new DeclStmt( cLoc,
    893                     new ObjectDecl( cLoc,
    894                         currClause->whenName,
    895                         new BasicType( BasicKind::Bool ),
    896                         new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
    897                     )
    898                 )
    899             );
    900        
    901         // select_node clause1;
    902         body->push_back(
    903             new DeclStmt( cLoc,
    904                 new ObjectDecl( cLoc,
    905                     currClause->nodeName,
    906                     new StructInstType( selectNodeDecl )
    907                 )
    908             )
    909         );
    910     }
    911 
    912     if ( stmt->else_stmt && stmt->else_cond ) {
    913         body->push_back(
    914             new DeclStmt( stmt->else_cond->location,
    915                 new ObjectDecl( stmt->else_cond->location,
    916                     elseWhenName,
    917                     new BasicType( BasicKind::Bool ),
    918                     new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
    919                 )
    920             )
    921         );
    922     }
     864        ClauseData * currClause;
     865        for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
     866                currClause = new ClauseData( i, statusName );
     867                currClause->nodeName = namer_node.newName();
     868                currClause->targetName = namer_target.newName();
     869                currClause->whenName = namer_when.newName();
     870                clauseData.push_back(currClause);
     871                const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     872
     873                // typeof(target) & __clause_target_0 = target;
     874                body->push_back(
     875                        new DeclStmt( cLoc,
     876                                new ObjectDecl( cLoc,
     877                                    currClause->targetName,
     878                                    new ReferenceType(
     879                                        new TypeofType( new UntypedExpr( cLoc,
     880                                            new NameExpr( cLoc, "__CFA_select_get_type" ),
     881                                            { ast::deepCopy( stmt->clauses.at(i)->target ) }
     882                                        ))
     883                                    ),
     884                                    new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
     885                                )
     886                        )
     887                );
     888
     889                // bool __when_cond_0 = when_cond; // only generated if when_cond defined
     890                if ( stmt->clauses.at(i)->when_cond )
     891                        body->push_back(
     892                                new DeclStmt( cLoc,
     893                                    new ObjectDecl( cLoc,
     894                                        currClause->whenName,
     895                                        new BasicType( BasicKind::Bool ),
     896                                        new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
     897                                    )
     898                                )
     899                        );
     900
     901                // select_node clause1;
     902                body->push_back(
     903                        new DeclStmt( cLoc,
     904                                new ObjectDecl( cLoc,
     905                                    currClause->nodeName,
     906                                    new StructInstType( selectNodeDecl )
     907                                )
     908                        )
     909                );
     910        }
     911
     912        if ( stmt->else_stmt && stmt->else_cond ) {
     913                body->push_back(
     914                        new DeclStmt( stmt->else_cond->location,
     915                                new ObjectDecl( stmt->else_cond->location,
     916                                    elseWhenName,
     917                                    new BasicType( BasicKind::Bool ),
     918                                    new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
     919                                )
     920                        )
     921                );
     922        }
    923923}
    924924
     
    929929*/
    930930Stmt * GenerateWaitUntilCore::buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data ) {
    931     const CodeLocation & loc = stmt->location;
    932 
    933     IfStmt * outerIf = nullptr;
     931        const CodeLocation & loc = stmt->location;
     932
     933        IfStmt * outerIf = nullptr;
    934934        IfStmt * lastIf = nullptr;
    935935
    936936        //adds an if/elif clause for each select clause address to run the corresponding clause stmt
    937937        for ( long unsigned int i = 0; i < data.size(); i++ ) {
    938         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     938                const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    939939
    940940                IfStmt * currIf = new IfStmt( cLoc,
    941                         new UntypedExpr( cLoc, 
    942                 new NameExpr( cLoc, "?==?" ),
    943                 {
    944                     new NameExpr( cLoc, statusName ),
    945                     new CastExpr( cLoc,
    946                         new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
    947                         new BasicType( BasicKind::LongUnsignedInt ), GeneratedFlag::ExplicitCast
    948                     )
    949                 }
    950             ),
    951             genStmtBlock( stmt->clauses.at(i), data.at(i) )
    952                 );
    953                
     941                        new UntypedExpr( cLoc,
     942                                new NameExpr( cLoc, "?==?" ),
     943                                {
     944                                    new NameExpr( cLoc, statusName ),
     945                                    new CastExpr( cLoc,
     946                                        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
     947                                        new BasicType( BasicKind::LongUnsignedInt ), GeneratedFlag::ExplicitCast
     948                                    )
     949                                }
     950                        ),
     951                        genStmtBlock( stmt->clauses.at(i), data.at(i) )
     952                );
     953
    954954                if ( i == 0 ) {
    955955                        outerIf = currIf;
     
    962962        }
    963963
    964     return new CompoundStmt( loc,
    965         {
    966             new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
    967             outerIf
    968         }
    969     );
     964        return new CompoundStmt( loc,
     965                {
     966                        new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
     967                        outerIf
     968                }
     969        );
    970970}
    971971
    972972Stmt * GenerateWaitUntilCore::recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName ) {
    973     if ( idx == data.size() ) {   // base case, gen last else
    974         const CodeLocation & cLoc = stmt->else_stmt->location;
    975         if ( !stmt->else_stmt ) // normal non-else gen
    976             return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
    977 
    978         Expr * raceFnCall = new UntypedExpr( stmt->location,
    979             new NameExpr( stmt->location, "__select_node_else_race" ),
    980             { new NameExpr( stmt->location, data.at(0)->nodeName ) }
    981         );
    982 
    983         if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
    984             return new IfStmt( cLoc,
    985                 new LogicalExpr( cLoc,
    986                     new CastExpr( cLoc,
    987                         new NameExpr( cLoc, elseWhenName ),
    988                         new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    989                     ),
    990                     new CastExpr( cLoc,
    991                         raceFnCall,
    992                         new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    993                     ),
    994                     LogicalFlag::AndExpr
    995                 ),
    996                 ast::deepCopy( stmt->else_stmt ),
    997                 buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
    998             );
    999         }
    1000 
    1001         // return else conditional on race
    1002         return new IfStmt( stmt->else_stmt->location,
    1003             raceFnCall,
    1004             ast::deepCopy( stmt->else_stmt ),
    1005             buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
    1006         );
    1007     }
    1008     const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
    1009 
    1010     Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
    1011     Expr * ifCond;
    1012 
    1013     // If we have a when_cond make the register call conditional on it
    1014     if ( stmt->clauses.at(idx)->when_cond ) {
    1015         ifCond = new LogicalExpr( cLoc,
    1016             new CastExpr( cLoc,
    1017                 new NameExpr( cLoc, data.at(idx)->whenName ),
    1018                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1019             ),
    1020             new CastExpr( cLoc,
    1021                 baseCond,
    1022                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1023             ),
    1024             LogicalFlag::AndExpr
    1025         );
    1026     } else ifCond = baseCond;
    1027 
    1028     return new CompoundStmt( cLoc,
    1029         {   // gens: setup_clause( clause1, &status, 0p );
    1030             new ExprStmt( cLoc,
    1031                 new UntypedExpr ( cLoc,
    1032                     new NameExpr( cLoc, "setup_clause" ),
    1033                     {
    1034                         new NameExpr( cLoc, data.at(idx)->nodeName ),
    1035                         new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
    1036                         ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::SignedInt ) ) )
    1037                     }
    1038                 )
    1039             ),
    1040             // gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
    1041             new IfStmt( cLoc,
    1042                 ifCond,
    1043                 genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
    1044                 recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
    1045             )
    1046         }
    1047     );
     973        if ( idx == data.size() ) {   // base case, gen last else
     974                const CodeLocation & cLoc = stmt->else_stmt->location;
     975                if ( !stmt->else_stmt ) // normal non-else gen
     976                        return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
     977
     978                Expr * raceFnCall = new UntypedExpr( stmt->location,
     979                        new NameExpr( stmt->location, "__select_node_else_race" ),
     980                        { new NameExpr( stmt->location, data.at(0)->nodeName ) }
     981                );
     982
     983                if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
     984                        return new IfStmt( cLoc,
     985                                new LogicalExpr( cLoc,
     986                                    new CastExpr( cLoc,
     987                                        new NameExpr( cLoc, elseWhenName ),
     988                                        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     989                                    ),
     990                                    new CastExpr( cLoc,
     991                                        raceFnCall,
     992                                        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     993                                    ),
     994                                    LogicalFlag::AndExpr
     995                                ),
     996                                ast::deepCopy( stmt->else_stmt ),
     997                                buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
     998                        );
     999                }
     1000
     1001                // return else conditional on race
     1002                return new IfStmt( stmt->else_stmt->location,
     1003                        raceFnCall,
     1004                        ast::deepCopy( stmt->else_stmt ),
     1005                        buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
     1006                );
     1007        }
     1008        const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
     1009
     1010        Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
     1011        Expr * ifCond;
     1012
     1013        // If we have a when_cond make the register call conditional on it
     1014        if ( stmt->clauses.at(idx)->when_cond ) {
     1015                ifCond = new LogicalExpr( cLoc,
     1016                        new CastExpr( cLoc,
     1017                                new NameExpr( cLoc, data.at(idx)->whenName ),
     1018                                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1019                        ),
     1020                        new CastExpr( cLoc,
     1021                                baseCond,
     1022                                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1023                        ),
     1024                        LogicalFlag::AndExpr
     1025                );
     1026        } else ifCond = baseCond;
     1027
     1028        return new CompoundStmt( cLoc,
     1029                {   // gens: setup_clause( clause1, &status, 0p );
     1030                        new ExprStmt( cLoc,
     1031                                new UntypedExpr ( cLoc,
     1032                                    new NameExpr( cLoc, "setup_clause" ),
     1033                                    {
     1034                                        new NameExpr( cLoc, data.at(idx)->nodeName ),
     1035                                        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
     1036                                        ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::SignedInt ) ) )
     1037                                    }
     1038                                )
     1039                        ),
     1040                        // gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
     1041                        new IfStmt( cLoc,
     1042                                ifCond,
     1043                                genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
     1044                                recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
     1045                        )
     1046                }
     1047        );
    10481048}
    10491049
    10501050// This gens the special case of an all OR waituntil:
    1051 /* 
     1051/*
    10521052int status = 0;
    10531053
     
    10581058
    10591059try {
    1060     setup_clause( clause1, &status, 0p );
    1061     if ( __when_cond_0 && register_select( 1 ) ) {
    1062         ... clause 1 body ...
    1063     } else {
    1064         ... recursively gen for each of n clauses ...
    1065         setup_clause( clausen, &status, 0p );
    1066         if ( __when_cond_n-1 && register_select( n ) ) {
    1067             ... clause n body ...
    1068         } else {
    1069             if ( else_when ) ... else clause body ...
    1070             else {
    1071                 park();
    1072 
    1073                 // after winning the race and before unpark() clause_status is set to be the winning clause index + 1
    1074                 if ( clause_status == &clause1) ... clause 1 body ...
    1075                 ...
    1076                 elif ( clause_status == &clausen ) ... clause n body ...
    1077             }
    1078         }
    1079     }
    1080 }
    1081 finally { 
    1082     if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
    1083     ...
    1084     if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
     1060        setup_clause( clause1, &status, 0p );
     1061        if ( __when_cond_0 && register_select( 1 ) ) {
     1062                ... clause 1 body ...
     1063        } else {
     1064                ... recursively gen for each of n clauses ...
     1065                setup_clause( clausen, &status, 0p );
     1066                if ( __when_cond_n-1 && register_select( n ) ) {
     1067                        ... clause n body ...
     1068                } else {
     1069                        if ( else_when ) ... else clause body ...
     1070                        else {
     1071                                park();
     1072
     1073                                // after winning the race and before unpark() clause_status is set to be the winning clause index + 1
     1074                                if ( clause_status == &clause1) ... clause 1 body ...
     1075                                ...
     1076                                elif ( clause_status == &clausen ) ... clause n body ...
     1077                        }
     1078                }
     1079        }
     1080}
     1081finally {
     1082        if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
     1083        ...
     1084        if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
    10851085}
    10861086*/
    10871087Stmt * GenerateWaitUntilCore::genAllOr( const WaitUntilStmt * stmt ) {
    1088     const CodeLocation & loc = stmt->location;
    1089     string statusName = namer_status.newName();
    1090     string elseWhenName = namer_when.newName();
    1091     int numClauses = stmt->clauses.size();
    1092     CompoundStmt * body = new CompoundStmt( stmt->location );
    1093 
    1094     // Generates: unsigned long int status = 0;
    1095     body->push_back( new DeclStmt( loc,
    1096         new ObjectDecl( loc,
    1097             statusName,
    1098             new BasicType( BasicKind::LongUnsignedInt ),
    1099             new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    1100         )
    1101     ));
    1102 
    1103     vector<ClauseData *> clauseData;
    1104     genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
    1105 
    1106     vector<int> whenIndices; // track which clauses have whens
    1107 
    1108     CompoundStmt * unregisters = new CompoundStmt( loc );
    1109     Expr * ifCond;
    1110     for ( int i = 0; i < numClauses; i++ ) {
    1111         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    1112         // Gens: node.status != 0p
    1113         UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc,
    1114             new NameExpr( cLoc, "?!=?" ),
    1115             {
    1116                 ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::LongUnsignedInt ) ) ),
    1117                 new UntypedExpr( cLoc,
    1118                     new NameExpr( cLoc, "__get_clause_status" ),
    1119                     { new NameExpr( cLoc, clauseData.at(i)->nodeName ) }
    1120                 )
    1121             }
    1122         );
    1123 
    1124         // If we have a when_cond make the unregister call conditional on it
    1125         if ( stmt->clauses.at(i)->when_cond ) {
    1126             whenIndices.push_back(i);
    1127             ifCond = new LogicalExpr( cLoc,
    1128                 new CastExpr( cLoc,
    1129                     new NameExpr( cLoc, clauseData.at(i)->whenName ),
    1130                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1131                 ),
    1132                 new CastExpr( cLoc,
    1133                     statusPtrCheck,
    1134                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1135                 ),
    1136                 LogicalFlag::AndExpr
    1137             );
    1138         } else ifCond = statusPtrCheck;
    1139        
    1140         unregisters->push_back(
    1141             new IfStmt( cLoc,
    1142                 ifCond,
    1143                 new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) )
    1144             )
    1145         );
    1146     }
    1147 
    1148     if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
    1149         body->push_back(
    1150                 new ast::TryStmt( loc,
    1151                 new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
    1152                 {},
    1153                 new ast::FinallyClause( loc, unregisters )
    1154             )
    1155         );
    1156     } else { // If all clauses have whens, we need to skip the waituntil if they are all false
    1157         Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
    1158         Expr * lastExpr = outerIfCond;
    1159 
    1160         for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
    1161             outerIfCond = new LogicalExpr( loc,
    1162                 new CastExpr( loc,
    1163                     new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ),
    1164                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1165                 ),
    1166                 new CastExpr( loc,
    1167                     lastExpr,
    1168                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1169                 ),
    1170                 LogicalFlag::OrExpr
    1171             );
    1172             lastExpr = outerIfCond;
    1173         }
    1174 
    1175         body->push_back(
    1176                 new ast::TryStmt( loc,
    1177                 new CompoundStmt( loc,
    1178                     {
    1179                         new IfStmt( loc,
    1180                             outerIfCond,
    1181                             recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
    1182                         )
    1183                     }
    1184                 ),
    1185                 {},
    1186                 new ast::FinallyClause( loc, unregisters )
    1187             )
    1188         );
    1189     }
    1190 
    1191     for ( ClauseData * datum : clauseData )
    1192         delete datum;
    1193 
    1194     return body;
     1088        const CodeLocation & loc = stmt->location;
     1089        string statusName = namer_status.newName();
     1090        string elseWhenName = namer_when.newName();
     1091        int numClauses = stmt->clauses.size();
     1092        CompoundStmt * body = new CompoundStmt( stmt->location );
     1093
     1094        // Generates: unsigned long int status = 0;
     1095        body->push_back( new DeclStmt( loc,
     1096                new ObjectDecl( loc,
     1097                        statusName,
     1098                        new BasicType( BasicKind::LongUnsignedInt ),
     1099                        new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     1100                )
     1101        ));
     1102
     1103        vector<ClauseData *> clauseData;
     1104        genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
     1105
     1106        vector<int> whenIndices; // track which clauses have whens
     1107
     1108        CompoundStmt * unregisters = new CompoundStmt( loc );
     1109        Expr * ifCond;
     1110        for ( int i = 0; i < numClauses; i++ ) {
     1111                const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     1112                // Gens: node.status != 0p
     1113                UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc,
     1114                        new NameExpr( cLoc, "?!=?" ),
     1115                        {
     1116                                ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::LongUnsignedInt ) ) ),
     1117                                new UntypedExpr( cLoc,
     1118                                    new NameExpr( cLoc, "__get_clause_status" ),
     1119                                    { new NameExpr( cLoc, clauseData.at(i)->nodeName ) }
     1120                                )
     1121                        }
     1122                );
     1123
     1124                // If we have a when_cond make the unregister call conditional on it
     1125                if ( stmt->clauses.at(i)->when_cond ) {
     1126                        whenIndices.push_back(i);
     1127                        ifCond = new LogicalExpr( cLoc,
     1128                                new CastExpr( cLoc,
     1129                                    new NameExpr( cLoc, clauseData.at(i)->whenName ),
     1130                                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1131                                ),
     1132                                new CastExpr( cLoc,
     1133                                    statusPtrCheck,
     1134                                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1135                                ),
     1136                                LogicalFlag::AndExpr
     1137                        );
     1138                } else ifCond = statusPtrCheck;
     1139
     1140                unregisters->push_back(
     1141                        new IfStmt( cLoc,
     1142                                ifCond,
     1143                                new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) )
     1144                        )
     1145                );
     1146        }
     1147
     1148        if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
     1149                body->push_back(
     1150                                new ast::TryStmt( loc,
     1151                                new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
     1152                                {},
     1153                                new ast::FinallyClause( loc, unregisters )
     1154                        )
     1155                );
     1156        } else { // If all clauses have whens, we need to skip the waituntil if they are all false
     1157                Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
     1158                Expr * lastExpr = outerIfCond;
     1159
     1160                for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
     1161                        outerIfCond = new LogicalExpr( loc,
     1162                                new CastExpr( loc,
     1163                                    new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ),
     1164                                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1165                                ),
     1166                                new CastExpr( loc,
     1167                                    lastExpr,
     1168                                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1169                                ),
     1170                                LogicalFlag::OrExpr
     1171                        );
     1172                        lastExpr = outerIfCond;
     1173                }
     1174
     1175                body->push_back(
     1176                                new ast::TryStmt( loc,
     1177                                new CompoundStmt( loc,
     1178                                    {
     1179                                        new IfStmt( loc,
     1180                                            outerIfCond,
     1181                                            recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
     1182                                        )
     1183                                    }
     1184                                ),
     1185                                {},
     1186                                new ast::FinallyClause( loc, unregisters )
     1187                        )
     1188                );
     1189        }
     1190
     1191        for ( ClauseData * datum : clauseData )
     1192                delete datum;
     1193
     1194        return body;
    11951195}
    11961196
    11971197Stmt * GenerateWaitUntilCore::postvisit( const WaitUntilStmt * stmt ) {
    1198     if ( !selectNodeDecl )
    1199         SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
    1200 
    1201     // Prep clause tree to figure out how to set initial statuses
    1202     // setTreeSizes( stmt->predicateTree );
    1203     if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
    1204         return genAllOr( stmt );
    1205 
    1206     CompoundStmt * tryBody = new CompoundStmt( stmt->location );
    1207     CompoundStmt * body = new CompoundStmt( stmt->location );
    1208     string statusArrName = namer_status.newName();
    1209     string pCountName = namer_park.newName();
    1210     string satName = namer_sat.newName();
    1211     string runName = namer_run.newName();
    1212     string elseWhenName = namer_when.newName();
    1213     int numClauses = stmt->clauses.size();
    1214     addPredicates( stmt, satName, runName );
    1215 
    1216     const CodeLocation & loc = stmt->location;
    1217 
    1218     // Generates: int park_counter = 0;
    1219     body->push_back( new DeclStmt( loc,
    1220         new ObjectDecl( loc,
    1221             pCountName,
    1222             new BasicType( BasicKind::SignedInt ),
    1223             new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    1224         )
    1225     ));
    1226 
    1227     // Generates: int clause_statuses[3] = { 0 };
    1228     body->push_back( new DeclStmt( loc,
    1229         new ObjectDecl( loc,
    1230             statusArrName,
    1231             new ArrayType( new BasicType( BasicKind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
    1232             new ListInit( loc,
    1233                 {
    1234                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    1235                 }
    1236             )
    1237         )
    1238     ));
    1239 
    1240     vector<ClauseData *> clauseData;
    1241     genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
    1242 
    1243     vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
    1244     vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
    1245 
    1246     collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
    1247 
    1248     // This is only needed for clauses that have AND as a parent and a when_cond defined
    1249     // generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
    1250     for ( int idx : andWhenClauses ) {
    1251         const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
    1252         body->push_back(
    1253             new IfStmt( cLoc,
    1254                 new UntypedExpr ( cLoc,
    1255                     new NameExpr( cLoc, "!?" ),
    1256                     { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
    1257                 ),  // IfStmt cond
    1258                 new ExprStmt( cLoc,
    1259                     new UntypedExpr ( cLoc,
    1260                         new NameExpr( cLoc, "?=?" ),
    1261                         {
    1262                             new UntypedExpr ( cLoc,
    1263                                 new NameExpr( cLoc, "?[?]" ),
    1264                                 {
    1265                                     new NameExpr( cLoc, statusArrName ),
    1266                                     ConstantExpr::from_int( cLoc, idx )
    1267                                 }
    1268                             ),
    1269                             new NameExpr( cLoc, "__SELECT_RUN" )
    1270                         }
    1271                     )
    1272                 )  // IfStmt then
    1273             )
    1274         );
    1275     }
    1276 
    1277     // Only need to generate conditional initial state setting for ambiguous when clauses
    1278     if ( !ambiguousClauses.empty() ) {
    1279         body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
    1280     }
    1281 
    1282     // generates the following for each clause:
    1283     // setup_clause( clause1, &clause_statuses[0], &park_counter );
    1284     // register_select(A, clause1);
    1285     for ( int i = 0; i < numClauses; i++ ) {
    1286         setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
    1287     }
    1288 
    1289     // generate satisfy logic based on if there is an else clause and if it is conditional
    1290     if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
    1291         tryBody->push_back(
    1292             new IfStmt( stmt->else_cond->location,
    1293                 new NameExpr( stmt->else_cond->location, elseWhenName ),
    1294                 genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
    1295                 genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
    1296             )
    1297         );
    1298     } else if ( !stmt->else_stmt ) { // normal gen
    1299         tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
    1300     } else { // generate just else
    1301         tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
    1302     }
    1303 
    1304     // Collection of unregister calls on resources to be put in finally clause
    1305     // for each clause:
    1306     // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
    1307     // OR if when( ... ) defined on resource
    1308     // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
    1309     CompoundStmt * unregisters = new CompoundStmt( loc );
    1310 
    1311     Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
    1312     for ( int i = 0; i < numClauses; i++ ) {
    1313         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    1314 
    1315         // Generates: !__CFA_has_clause_run( clause_statuses[i] )
    1316         statusExpr = new UntypedExpr ( cLoc,
    1317             new NameExpr( cLoc, "!?" ),
    1318             {
    1319                 new UntypedExpr ( cLoc,
    1320                     new NameExpr( cLoc, "__CFA_has_clause_run" ),
    1321                     {
    1322                         genArrAccessExpr( cLoc, i, statusArrName )
    1323                     }
    1324                 )
    1325             }
    1326         );
    1327        
    1328         // Generates:
    1329         // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
    1330         statusExpr = new LogicalExpr( cLoc,
    1331             new CastExpr( cLoc,
    1332                 statusExpr,
    1333                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1334             ),
    1335             new CastExpr( cLoc,
    1336                 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
    1337                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1338             ),
    1339             LogicalFlag::AndExpr
    1340         );
    1341        
    1342         // if when cond defined generates:
    1343         // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
    1344         if ( stmt->clauses.at(i)->when_cond )
    1345             statusExpr = new LogicalExpr( cLoc,
    1346                 new CastExpr( cLoc,
    1347                     new NameExpr( cLoc, clauseData.at(i)->whenName ),
    1348                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1349                 ),
    1350                 new CastExpr( cLoc,
    1351                     statusExpr,
    1352                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1353                 ),
    1354                 LogicalFlag::AndExpr
    1355             );
    1356 
    1357         // generates:
    1358         // if ( statusExpr ) { ... clausei stmt ... }
    1359         unregisters->push_back(
    1360             new IfStmt( cLoc,
    1361                 statusExpr,
    1362                 new CompoundStmt( cLoc,
    1363                     {
    1364                         new IfStmt( cLoc,
    1365                             genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
    1366                             ast::deepCopy( stmt->clauses.at(i)->stmt )
    1367                         )
    1368                     }
    1369                 )
    1370             )
    1371         );
    1372 
    1373         // // generates:
    1374         // // if ( statusExpr ) { ... clausei stmt ... }
    1375         // unregisters->push_back(
    1376         //     new IfStmt( cLoc,
    1377         //         statusExpr,
    1378         //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
    1379         //     )
    1380         // );
    1381     }
    1382 
    1383     body->push_back(
    1384         new ast::TryStmt(
    1385             loc,
    1386             tryBody,
    1387             {},
    1388             new ast::FinallyClause( loc, unregisters )
    1389         )
    1390     );
    1391 
    1392     for ( ClauseData * datum : clauseData )
    1393         delete datum;
    1394 
    1395     return body;
     1198        if ( !selectNodeDecl )
     1199                SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
     1200
     1201        // Prep clause tree to figure out how to set initial statuses
     1202        // setTreeSizes( stmt->predicateTree );
     1203        if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
     1204                return genAllOr( stmt );
     1205
     1206        CompoundStmt * tryBody = new CompoundStmt( stmt->location );
     1207        CompoundStmt * body = new CompoundStmt( stmt->location );
     1208        string statusArrName = namer_status.newName();
     1209        string pCountName = namer_park.newName();
     1210        string satName = namer_sat.newName();
     1211        string runName = namer_run.newName();
     1212        string elseWhenName = namer_when.newName();
     1213        int numClauses = stmt->clauses.size();
     1214        addPredicates( stmt, satName, runName );
     1215
     1216        const CodeLocation & loc = stmt->location;
     1217
     1218        // Generates: int park_counter = 0;
     1219        body->push_back( new DeclStmt( loc,
     1220                new ObjectDecl( loc,
     1221                        pCountName,
     1222                        new BasicType( BasicKind::SignedInt ),
     1223                        new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     1224                )
     1225        ));
     1226
     1227        // Generates: int clause_statuses[3] = { 0 };
     1228        body->push_back( new DeclStmt( loc,
     1229                new ObjectDecl( loc,
     1230                        statusArrName,
     1231                        new ArrayType( new BasicType( BasicKind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
     1232                        new ListInit( loc,
     1233                                {
     1234                                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     1235                                }
     1236                        )
     1237                )
     1238        ));
     1239
     1240        vector<ClauseData *> clauseData;
     1241        genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
     1242
     1243        vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
     1244        vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
     1245
     1246        collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
     1247
     1248        // This is only needed for clauses that have AND as a parent and a when_cond defined
     1249        // generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
     1250        for ( int idx : andWhenClauses ) {
     1251                const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
     1252                body->push_back(
     1253                        new IfStmt( cLoc,
     1254                                new UntypedExpr ( cLoc,
     1255                                    new NameExpr( cLoc, "!?" ),
     1256                                    { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
     1257                                ),  // IfStmt cond
     1258                                new ExprStmt( cLoc,
     1259                                    new UntypedExpr ( cLoc,
     1260                                        new NameExpr( cLoc, "?=?" ),
     1261                                        {
     1262                                            new UntypedExpr ( cLoc,
     1263                                                new NameExpr( cLoc, "?[?]" ),
     1264                                                {
     1265                                                    new NameExpr( cLoc, statusArrName ),
     1266                                                    ConstantExpr::from_int( cLoc, idx )
     1267                                                }
     1268                                            ),
     1269                                            new NameExpr( cLoc, "__SELECT_RUN" )
     1270                                        }
     1271                                    )
     1272                                )  // IfStmt then
     1273                        )
     1274                );
     1275        }
     1276
     1277        // Only need to generate conditional initial state setting for ambiguous when clauses
     1278        if ( !ambiguousClauses.empty() ) {
     1279                body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
     1280        }
     1281
     1282        // generates the following for each clause:
     1283        // setup_clause( clause1, &clause_statuses[0], &park_counter );
     1284        // register_select(A, clause1);
     1285        for ( int i = 0; i < numClauses; i++ ) {
     1286                setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
     1287        }
     1288
     1289        // generate satisfy logic based on if there is an else clause and if it is conditional
     1290        if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
     1291                tryBody->push_back(
     1292                        new IfStmt( stmt->else_cond->location,
     1293                                new NameExpr( stmt->else_cond->location, elseWhenName ),
     1294                                genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
     1295                                genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
     1296                        )
     1297                );
     1298        } else if ( !stmt->else_stmt ) { // normal gen
     1299                tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
     1300        } else { // generate just else
     1301                tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
     1302        }
     1303
     1304        // Collection of unregister calls on resources to be put in finally clause
     1305        // for each clause:
     1306        // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
     1307        // OR if when( ... ) defined on resource
     1308        // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
     1309        CompoundStmt * unregisters = new CompoundStmt( loc );
     1310
     1311        Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
     1312        for ( int i = 0; i < numClauses; i++ ) {
     1313                const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     1314
     1315                // Generates: !__CFA_has_clause_run( clause_statuses[i] )
     1316                statusExpr = new UntypedExpr ( cLoc,
     1317                        new NameExpr( cLoc, "!?" ),
     1318                        {
     1319                                new UntypedExpr ( cLoc,
     1320                                    new NameExpr( cLoc, "__CFA_has_clause_run" ),
     1321                                    {
     1322                                        genArrAccessExpr( cLoc, i, statusArrName )
     1323                                    }
     1324                                )
     1325                        }
     1326                );
     1327
     1328                // Generates:
     1329                // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
     1330                statusExpr = new LogicalExpr( cLoc,
     1331                        new CastExpr( cLoc,
     1332                                statusExpr,
     1333                                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1334                        ),
     1335                        new CastExpr( cLoc,
     1336                                genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
     1337                                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1338                        ),
     1339                        LogicalFlag::AndExpr
     1340                );
     1341
     1342                // if when cond defined generates:
     1343                // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
     1344                if ( stmt->clauses.at(i)->when_cond )
     1345                        statusExpr = new LogicalExpr( cLoc,
     1346                                new CastExpr( cLoc,
     1347                                    new NameExpr( cLoc, clauseData.at(i)->whenName ),
     1348                                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1349                                ),
     1350                                new CastExpr( cLoc,
     1351                                    statusExpr,
     1352                                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1353                                ),
     1354                                LogicalFlag::AndExpr
     1355                        );
     1356
     1357                // generates:
     1358                // if ( statusExpr ) { ... clausei stmt ... }
     1359                unregisters->push_back(
     1360                        new IfStmt( cLoc,
     1361                                statusExpr,
     1362                                new CompoundStmt( cLoc,
     1363                                    {
     1364                                        new IfStmt( cLoc,
     1365                                            genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
     1366                                            ast::deepCopy( stmt->clauses.at(i)->stmt )
     1367                                        )
     1368                                    }
     1369                                )
     1370                        )
     1371                );
     1372
     1373                // // generates:
     1374                // // if ( statusExpr ) { ... clausei stmt ... }
     1375                // unregisters->push_back(
     1376                //     new IfStmt( cLoc,
     1377                //         statusExpr,
     1378                //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
     1379                //     )
     1380                // );
     1381        }
     1382
     1383        body->push_back(
     1384                new ast::TryStmt(
     1385                        loc,
     1386                        tryBody,
     1387                        {},
     1388                        new ast::FinallyClause( loc, unregisters )
     1389                )
     1390        );
     1391
     1392        for ( ClauseData * datum : clauseData )
     1393                delete datum;
     1394
     1395        return body;
    13961396}
    13971397
     
    13991399// Predicates are added after "struct select_node { ... };"
    14001400class AddPredicateDecls final : public WithDeclsToAdd<> {
    1401     vector<FunctionDecl *> & satFns;
    1402     const StructDecl * selectNodeDecl = nullptr;
     1401        vector<FunctionDecl *> & satFns;
     1402        const StructDecl * selectNodeDecl = nullptr;
    14031403
    14041404  public:
    1405     void previsit( const StructDecl * decl ) {
    1406         if ( !decl->body ) {
    1407             return;
    1408         } else if ( "select_node" == decl->name ) {
    1409             assert( !selectNodeDecl );
    1410             selectNodeDecl = decl;
    1411             for ( FunctionDecl * fn : satFns )
    1412                 declsToAddAfter.push_back(fn);           
    1413         }
    1414     }
    1415     AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
     1405        void previsit( const StructDecl * decl ) {
     1406                if ( !decl->body ) {
     1407                        return;
     1408                } else if ( "select_node" == decl->name ) {
     1409                        assert( !selectNodeDecl );
     1410                        selectNodeDecl = decl;
     1411                        for ( FunctionDecl * fn : satFns )
     1412                                declsToAddAfter.push_back(fn);
     1413                }
     1414        }
     1415        AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
    14161416};
    14171417
    14181418void generateWaitUntil( TranslationUnit & translationUnit ) {
    1419     vector<FunctionDecl *> satFns;
     1419        vector<FunctionDecl *> satFns;
    14201420        Pass<GenerateWaitUntilCore>::run( translationUnit, satFns );
    1421     Pass<AddPredicateDecls>::run( translationUnit, satFns );
     1421        Pass<AddPredicateDecls>::run( translationUnit, satFns );
    14221422}
    14231423
  • src/ResolvExpr/CandidateFinder.cpp

    rb9b6efb rfc1a3e2  
    14121412        }
    14131413
    1414     void Finder::postvisit(const ast::VariableExpr *variableExpr) {
    1415         // not sufficient to just pass `variableExpr` here, type might have changed
    1416 
    1417         auto cand = new Candidate(variableExpr, tenv);
    1418         candidates.emplace_back(cand);
    1419     }
     1414        void Finder::postvisit(const ast::VariableExpr *variableExpr) {
     1415                // not sufficient to just pass `variableExpr` here, type might have changed
     1416
     1417                auto cand = new Candidate(variableExpr, tenv);
     1418                candidates.emplace_back(cand);
     1419        }
    14201420
    14211421        void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
     
    21332133
    21342134// get the valueE(...) ApplicationExpr that returns the enum value
    2135 const ast::Expr * getValueEnumCall( 
    2136         const ast::Expr * expr, 
     2135const ast::Expr * getValueEnumCall(
     2136        const ast::Expr * expr,
    21372137        const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env ) {
    21382138                auto callExpr = new ast::UntypedExpr(
  • src/ResolvExpr/CommonType.cc

    rb9b6efb rfc1a3e2  
    397397                        }
    398398                } else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
    399             if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
    400                             ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
    401                             if (
    402                                     ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
    403                                             || widen.first )
    404                                     && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    405                                             || widen.second )
    406                             ) {
    407                                     result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
    408                             }
    409             }
     399                        if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
     400                                ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
     401                                if (
     402                                        ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
     403                                                || widen.first )
     404                                        && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
     405                                                || widen.second )
     406                                ) {
     407                                        result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
     408                                }
     409                        }
    410410                }
    411411        }
     
    519519                                                                // xxx - assume LHS is always the target type
    520520
    521                                                                 if ( ! ((widen.second && ref2->qualifiers.is_mutex) 
     521                                                                if ( ! ((widen.second && ref2->qualifiers.is_mutex)
    522522                                                                || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
    523523
  • src/ResolvExpr/ConversionCost.cc

    rb9b6efb rfc1a3e2  
    379379
    380380void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
    381     auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
     381        auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
    382382        assert( src->attr != ast::EnumAttribute::Label );
    383     if ( src->attr == ast::EnumAttribute::Value ) {
    384         if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
    385             cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
    386         } else {
    387             auto baseType = src->instance->base->base;
    388             cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
     383        if ( src->attr == ast::EnumAttribute::Value ) {
     384                if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
     385                        cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
     386                } else {
     387                        auto baseType = src->instance->base->base;
     388                        cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
    389389                        if ( cost < Cost::infinity ) {
    390390                                cost.incUnsafe();
    391391                        }
    392         }
    393     } else { // ast::EnumAttribute::Posn
    394         if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
    395                     cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
    396                     if ( cost < Cost::unsafe ) cost.incSafe();
    397             } else {
    398                     static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
    399                     cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    400                     if ( cost < Cost::unsafe ) {
    401                             cost.incSafe();
    402                     }
    403             }
    404     }
     392                }
     393        } else { // ast::EnumAttribute::Posn
     394                if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
     395                        cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
     396                        if ( cost < Cost::unsafe ) cost.incSafe();
     397                } else {
     398                        static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
     399                        cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
     400                        if ( cost < Cost::unsafe ) {
     401                                cost.incSafe();
     402                        }
     403                }
     404        }
    405405}
    406406
  • src/ResolvExpr/Unify.cc

    rb9b6efb rfc1a3e2  
    307307                                // type unification calls expression unification (mutual recursion)
    308308                                if ( ! unify(array->dimension, array2->dimension,
    309                                     tenv, need, have, open, widen) ) return;
     309                                        tenv, need, have, open, widen) ) return;
    310310                        }
    311311
     
    455455                        // check that the other type is compatible and named the same
    456456                        auto otherInst = dynamic_cast< const XInstType * >( other );
    457                         if (otherInst && inst->name == otherInst->name) 
     457                        if (otherInst && inst->name == otherInst->name)
    458458                                this->result = otherInst;
    459459                        return otherInst;
     
    542542                        // Lazy approach for now
    543543                        if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>(type2) ) {
    544                             if ( enumAttr->match(otherPos) ) {
    545                                     result = otherPos;
    546                             }
    547             } 
     544                                if ( enumAttr->match(otherPos) ) {
     545                                        result = otherPos;
     546                                }
     547                        }
    548548                }
    549549
  • src/SymTab/Mangler.cc

    rb9b6efb rfc1a3e2  
    283283        postvisit( enumAttr->instance );
    284284        // mangleName += "_pos";
    285     switch ( enumAttr->attr )
    286     {
    287         case ast::EnumAttribute::Label:
    288             mangleName += "_label_";
    289             break;
    290         case ast::EnumAttribute::Posn:
     285        switch ( enumAttr->attr )
     286        {
     287                case ast::EnumAttribute::Label:
     288                        mangleName += "_label_";
     289                        break;
     290                case ast::EnumAttribute::Posn:
    291291                        mangleName += "_posn_";
    292             break;
    293         case ast::EnumAttribute::Value:
    294             mangleName += "_value_";
    295             break;
    296     }
     292                        break;
     293                case ast::EnumAttribute::Value:
     294                        mangleName += "_value_";
     295                        break;
     296        }
    297297
    298298}
  • src/Validate/ForallPointerDecay.hpp

    rb9b6efb rfc1a3e2  
    3939/// Expand all traits in an assertion list.
    4040std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
    41         std::vector<ast::ptr<ast::DeclWithType>> const & );
     41                std::vector<ast::ptr<ast::DeclWithType>> const & );
    4242
    4343}
  • src/Validate/HoistStruct.cpp

    rb9b6efb rfc1a3e2  
    149149template<typename InstType>
    150150InstType const * HoistStructCore::preCollectionInstType( InstType const * type ) {
    151     if ( !type->base->parent ) return type;
    152     if ( type->base->params.empty() ) return type;
    153 
    154     InstType * mut = ast::mutate( type );
    155     ast::AggregateDecl const * parent =
    156         commonParent( this->parent, mut->base->parent );
    157     assert( parent );
    158 
    159     std::vector<ast::ptr<ast::Expr>> args;
    160     for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
    161         args.emplace_back( new ast::TypeExpr( param->location,
    162             new ast::TypeInstType( param )
    163         ) );
    164     }
    165     spliceBegin( mut->params, args );
    166     return mut;
     151        if ( !type->base->parent ) return type;
     152        if ( type->base->params.empty() ) return type;
     153
     154        InstType * mut = ast::mutate( type );
     155        ast::AggregateDecl const * parent =
     156                commonParent( this->parent, mut->base->parent );
     157        assert( parent );
     158
     159        std::vector<ast::ptr<ast::Expr>> args;
     160        for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
     161                args.emplace_back( new ast::TypeExpr( param->location,
     162                        new ast::TypeInstType( param )
     163                ) );
     164        }
     165        spliceBegin( mut->params, args );
     166        return mut;
    167167}
    168168
  • src/Validate/ImplementEnumFunc.cpp

    rb9b6efb rfc1a3e2  
    88namespace {
    99class EnumAttrFuncGenerator {
    10     const ast::EnumDecl* decl;
    11     const ast::EnumInstType* instType;
    12     // const ast::EnumAttrType* attrType;
    13     unsigned int functionNesting;
    14     ast::Linkage::Spec proto_linkage;
    15 
    16    public:
    17     std::list<ast::ptr<ast::Decl>> forwards;
    18     std::list<ast::ptr<ast::Decl>> definitions;
    19 
    20     void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
    21 
    22     EnumAttrFuncGenerator(const ast::EnumDecl* decl,
    23                           const ast::EnumInstType* instType,
    24                           // const ast::EnumAttrType* enumAttrType,
    25                           unsigned int functionNesting)
    26         : decl(decl),
    27           instType{instType},
    28           // attrType{enumAttrType},
    29           functionNesting{functionNesting},
    30           proto_linkage{ast::Linkage::Cforall} {}
    31 
    32     void genAttrFunctions();
    33     void genSuccPredPosn();
    34     void genSuccPredDecl();
    35 
    36     void appendReturnThis(ast::FunctionDecl* decl) {
    37         assert(1 <= decl->params.size());
    38         assert(1 == decl->returns.size());
    39         assert(decl->stmts);
    40 
    41         const CodeLocation& location = (decl->stmts->kids.empty())
    42                                            ? decl->stmts->location
    43                                            : decl->stmts->kids.back()->location;
    44         const ast::DeclWithType* thisParam = decl->params.front();
    45         decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
    46             location, new ast::VariableExpr(location, thisParam)));
    47     }
    48     void genAttrStandardFuncs() {
    49         ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
    50             const = {&EnumAttrFuncGenerator::genCtorProto,
    51                      &EnumAttrFuncGenerator::genCopyProto,
    52                      &EnumAttrFuncGenerator::genDtorProto,
    53                      &EnumAttrFuncGenerator::genAssignProto};
    54         for (auto& generator : standardProtos) {
    55             ast::FunctionDecl* decl = (this->*generator)();
    56             produceForwardDecl(decl);
    57             genFuncBody(decl);
    58             if (CodeGen::isAssignment(decl->name)) {
    59                 appendReturnThis(decl);
    60             }
    61             produceDecl(decl);
    62         }
    63     }
    64 
    65    private:
    66     const CodeLocation& getLocation() const { return decl->location; }
    67 
    68     ast::FunctionDecl* genProto(
    69         std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
    70         std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
    71 
    72     void produceDecl(const ast::FunctionDecl* decl);
    73     void produceForwardDecl(const ast::FunctionDecl* decl);
    74 
    75     const ast::Decl* getDecl() const { return decl; }
    76 
    77     ast::FunctionDecl* genPosnProto() const;
    78     ast::FunctionDecl* genLabelProto() const;
    79     ast::FunctionDecl* genValueProto() const;
    80     ast::FunctionDecl* genSuccProto() const;
    81     ast::FunctionDecl* genPredProto() const;
    82 
    83     ast::FunctionDecl* genSuccPosProto() const;
    84     ast::FunctionDecl* genPredPosProto() const;
    85 
    86     // ---------------------------------------------------
    87     // ast::FunctionDecl* genAttrCtorProto() const;
    88     /// Changes the node inside a pointer so that it has the unused attribute.
    89     void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
    90         ast::DeclWithType* decl = declPtr.get_and_mutate();
    91         decl->attributes.push_back(new ast::Attribute("unused"));
    92     }
    93 
    94     ast::ObjectDecl* dstParam() const {
    95         return new ast::ObjectDecl(getLocation(), "_dst",
    96                                    new ast::ReferenceType(new ast::EnumAttrType(
    97                                        ast::deepCopy(instType))));
    98     }
    99 
    100     ast::ObjectDecl* srcParam() const {
    101         return new ast::ObjectDecl(
    102             getLocation(), "_src",
    103             new ast::EnumAttrType(ast::deepCopy(instType)));
    104     }
    105 
    106     /// E = EnumAttrType<T>`
    107     /// `void ?{}(E & _dst)`.
    108     ast::FunctionDecl* genCtorProto() const {
    109         return genProto("?{}", {dstParam()}, {});
    110     }
    111 
    112     /// void ?{}(E & _dst, E _src)`.
    113     ast::FunctionDecl* genCopyProto() const {
    114         return genProto("?{}", {dstParam(), srcParam()}, {});
    115     }
    116 
    117     ///`void ^?{}(E & _dst)`.
    118     ast::FunctionDecl* genDtorProto() const {
    119         // The destructor must be mutex on a concurrent type.
    120         return genProto("^?{}", {dstParam()}, {});
    121     }
    122 
    123     /// `E ?{}(E & _dst, E _src)`.
    124     ast::FunctionDecl* genAssignProto() const {
    125         // Only the name is different, so just reuse the generation function.
    126         auto retval = srcParam();
    127         retval->name = "_ret";
    128         return genProto("?=?", {dstParam(), srcParam()}, {retval});
    129     }
    130 
    131     void genFuncBody(ast::FunctionDecl* func) {
    132         const CodeLocation& location = func->location;
    133         auto& params = func->params;
    134         if (InitTweak::isCopyConstructor(func) ||
    135             InitTweak::isAssignment(func)) {
    136             assert(2 == params.size());
    137             auto dstParam = params.front().strict_as<ast::ObjectDecl>();
    138             auto srcParam = params.back().strict_as<ast::ObjectDecl>();
    139             func->stmts = genCopyBody(location, dstParam, srcParam);
    140         } else {
    141             assert(1 == params.size());
    142             // Default constructor and destructor is empty.
    143             func->stmts = new ast::CompoundStmt(location);
    144             // Add unused attribute to parameter to silence warnings.
    145             addUnusedAttribute(params.front());
    146 
    147             // Just an extra step to make the forward and declaration match.
    148             if (forwards.empty()) return;
    149             ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
    150                 forwards.back().get_and_mutate());
    151             addUnusedAttribute(fwd->params.front());
    152         }
    153     }
    154 
    155     const ast::CompoundStmt* genCopyBody(const CodeLocation& location,
    156                                          const ast::ObjectDecl* dstParam,
    157                                          const ast::ObjectDecl* srcParam) {
    158         return new ast::CompoundStmt(
    159             location,
    160             {new ast::ExprStmt(
    161                 location,
    162                 new ast::UntypedExpr(
    163                     location, new ast::NameExpr(location, "__builtin_memcpy"),
    164                     {
    165                         new ast::AddressExpr(location, new ast::VariableExpr(
    166                                                            location, dstParam)),
    167                         new ast::AddressExpr(location, new ast::VariableExpr(
    168                                                            location, srcParam)),
    169                         new ast::SizeofExpr(location, srcParam->type),
    170                     }))});
    171     }
    172 
    173     void genDtorBody(ast::FunctionDecl* func) {
    174         const CodeLocation& location = func->location;
    175         auto& params = func->params;
    176         assert(1 == params.size());
    177         func->stmts = new ast::CompoundStmt(location);
    178         addUnusedAttribute(params.front());
    179 
    180         // Just an extra step to make the forward and declaration match.
    181         if (forwards.empty()) return;
    182         ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
    183             forwards.back().get_and_mutate());
    184         addUnusedAttribute(fwd->params.front());
    185     }
    186 
    187     // ast::FunctionDecl*
    188     // ----------------------------------------------------
    189 
    190     ast::FunctionDecl* genSuccPredFunc(bool succ);
    191 
    192     const ast::Init* getAutoInit(const ast::Init* prev) const;
    193 
    194     std::vector<ast::ptr<ast::Init>> genLabelInit() const;
    195 
    196     std::vector<ast::ptr<ast::Init>> genValueInit() const;
    197     ast::ObjectDecl* genAttrArrayProto(
    198         const ast::EnumAttribute attr, const CodeLocation& location,
    199         std::vector<ast::ptr<ast::Init>>& inits) const;
    200     void genValueOrLabelBody(ast::FunctionDecl* func,
    201                              ast::ObjectDecl* arrDecl) const;
    202     void genPosnBody(ast::FunctionDecl* func) const;
    203     void genAttributesDecls(const ast::EnumAttribute attr);
     10        const ast::EnumDecl* decl;
     11        const ast::EnumInstType* instType;
     12        unsigned int functionNesting;
     13        ast::Linkage::Spec proto_linkage;
     14
     15public:
     16        std::list<ast::ptr<ast::Decl>> forwards;
     17        std::list<ast::ptr<ast::Decl>> definitions;
     18
     19        void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
     20
     21        EnumAttrFuncGenerator(
     22                        const ast::EnumDecl* decl,
     23                        const ast::EnumInstType* instType,
     24                        unsigned int functionNesting )
     25                : decl(decl),
     26                  instType{instType},
     27                  functionNesting{functionNesting},
     28                  proto_linkage{ast::Linkage::Cforall} {}
     29
     30        void genAttrFunctions();
     31        void genSuccPredPosn();
     32        void genSuccPredDecl();
     33
     34        void appendReturnThis(ast::FunctionDecl* decl) {
     35                assert(1 <= decl->params.size());
     36                assert(1 == decl->returns.size());
     37                assert(decl->stmts);
     38
     39                const CodeLocation& location = (decl->stmts->kids.empty())
     40                                                   ? decl->stmts->location
     41                                                   : decl->stmts->kids.back()->location;
     42                const ast::DeclWithType* thisParam = decl->params.front();
     43                decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
     44                        location, new ast::VariableExpr(location, thisParam)));
     45        }
     46        void genAttrStandardFuncs() {
     47                ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
     48                        const = {&EnumAttrFuncGenerator::genCtorProto,
     49                                         &EnumAttrFuncGenerator::genCopyProto,
     50                                         &EnumAttrFuncGenerator::genDtorProto,
     51                                         &EnumAttrFuncGenerator::genAssignProto};
     52                for (auto& generator : standardProtos) {
     53                        ast::FunctionDecl* decl = (this->*generator)();
     54                        produceForwardDecl(decl);
     55                        genFuncBody(decl);
     56                        if (CodeGen::isAssignment(decl->name)) {
     57                                appendReturnThis(decl);
     58                        }
     59                        produceDecl(decl);
     60                }
     61        }
     62
     63private:
     64        const CodeLocation& getLocation() const { return decl->location; }
     65
     66        ast::FunctionDecl* genProto(
     67                std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
     68                std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
     69
     70        void produceDecl(const ast::FunctionDecl* decl);
     71        void produceForwardDecl(const ast::FunctionDecl* decl);
     72
     73        const ast::Decl* getDecl() const { return decl; }
     74
     75        ast::FunctionDecl* genPosnProto() const;
     76        ast::FunctionDecl* genLabelProto() const;
     77        ast::FunctionDecl* genValueProto() const;
     78        ast::FunctionDecl* genSuccProto() const;
     79        ast::FunctionDecl* genPredProto() const;
     80
     81        ast::FunctionDecl* genSuccPosProto() const;
     82        ast::FunctionDecl* genPredPosProto() const;
     83
     84        // ---------------------------------------------------
     85        // ast::FunctionDecl* genAttrCtorProto() const;
     86        /// Changes the node inside a pointer so that it has the unused attribute.
     87        void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
     88                ast::DeclWithType* decl = declPtr.get_and_mutate();
     89                decl->attributes.push_back(new ast::Attribute("unused"));
     90        }
     91
     92        ast::ObjectDecl* dstParam() const {
     93                return new ast::ObjectDecl(getLocation(), "_dst",
     94                                           new ast::ReferenceType(new ast::EnumAttrType(
     95                                               ast::deepCopy(instType))));
     96        }
     97
     98        ast::ObjectDecl* srcParam() const {
     99                return new ast::ObjectDecl(
     100                        getLocation(), "_src",
     101                        new ast::EnumAttrType(ast::deepCopy(instType)));
     102        }
     103
     104        /// E = EnumAttrType<T>`
     105        /// `void ?{}(E & _dst)`.
     106        ast::FunctionDecl* genCtorProto() const {
     107                return genProto("?{}", {dstParam()}, {});
     108        }
     109
     110        /// void ?{}(E & _dst, E _src)`.
     111        ast::FunctionDecl* genCopyProto() const {
     112                return genProto("?{}", {dstParam(), srcParam()}, {});
     113        }
     114
     115        ///`void ^?{}(E & _dst)`.
     116        ast::FunctionDecl* genDtorProto() const {
     117                // The destructor must be mutex on a concurrent type.
     118                return genProto("^?{}", {dstParam()}, {});
     119        }
     120
     121        /// `E ?{}(E & _dst, E _src)`.
     122        ast::FunctionDecl* genAssignProto() const {
     123                // Only the name is different, so just reuse the generation function.
     124                auto retval = srcParam();
     125                retval->name = "_ret";
     126                return genProto("?=?", {dstParam(), srcParam()}, {retval});
     127        }
     128
     129        void genFuncBody(ast::FunctionDecl* func) {
     130                const CodeLocation& location = func->location;
     131                auto& params = func->params;
     132                if (InitTweak::isCopyConstructor(func) ||
     133                        InitTweak::isAssignment(func)) {
     134                        assert(2 == params.size());
     135                        auto dstParam = params.front().strict_as<ast::ObjectDecl>();
     136                        auto srcParam = params.back().strict_as<ast::ObjectDecl>();
     137                        func->stmts = genCopyBody(location, dstParam, srcParam);
     138                } else {
     139                        assert(1 == params.size());
     140                        // Default constructor and destructor is empty.
     141                        func->stmts = new ast::CompoundStmt(location);
     142                        // Add unused attribute to parameter to silence warnings.
     143                        addUnusedAttribute(params.front());
     144
     145                        // Just an extra step to make the forward and declaration match.
     146                        if (forwards.empty()) return;
     147                        ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
     148                                forwards.back().get_and_mutate());
     149                        addUnusedAttribute(fwd->params.front());
     150                }
     151        }
     152
     153        const ast::CompoundStmt* genCopyBody( const CodeLocation& location,
     154                        const ast::ObjectDecl* dstParam, const ast::ObjectDecl* srcParam) {
     155                return new ast::CompoundStmt(
     156                        location,
     157                        {new ast::ExprStmt(
     158                                location,
     159                                new ast::UntypedExpr(
     160                                        location, new ast::NameExpr(location, "__builtin_memcpy"),
     161                                        {
     162                                                new ast::AddressExpr( location,
     163                                                        new ast::VariableExpr( location, dstParam ) ),
     164                                                new ast::AddressExpr( location,
     165                                                        new ast::VariableExpr( location, srcParam ) ),
     166                                                new ast::SizeofExpr( location, srcParam->type ),
     167                                        }))});
     168        }
     169
     170        void genDtorBody(ast::FunctionDecl* func) {
     171                const CodeLocation& location = func->location;
     172                auto& params = func->params;
     173                assert(1 == params.size());
     174                func->stmts = new ast::CompoundStmt(location);
     175                addUnusedAttribute(params.front());
     176
     177                // Just an extra step to make the forward and declaration match.
     178                if (forwards.empty()) return;
     179                ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
     180                        forwards.back().get_and_mutate());
     181                addUnusedAttribute(fwd->params.front());
     182        }
     183
     184        // ast::FunctionDecl*
     185        // ----------------------------------------------------
     186
     187        ast::FunctionDecl* genSuccPredFunc(bool succ);
     188
     189        const ast::Init* getAutoInit(const ast::Init* prev) const;
     190
     191        std::vector<ast::ptr<ast::Init>> genLabelInit() const;
     192
     193        std::vector<ast::ptr<ast::Init>> genValueInit() const;
     194        ast::ObjectDecl* genAttrArrayProto(
     195                const ast::EnumAttribute attr, const CodeLocation& location,
     196                std::vector<ast::ptr<ast::Init>>& inits) const;
     197        void genValueOrLabelBody(
     198                ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
     199        void genPosnBody(ast::FunctionDecl* func) const;
     200        void genAttributesDecls(const ast::EnumAttribute attr);
    204201};
    205202
    206203std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
    207     std::vector<ast::ptr<ast::Init>> inits;
    208     for (size_t i = 0; i < decl->members.size(); i++) {
    209         ast::ptr<ast::Decl> mem = decl->members.at(i);
    210         auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
    211         assert(memAsObjectDecl);
    212         inits.emplace_back(new ast::SingleInit(
    213             mem->location,
    214             ast::ConstantExpr::from_string(mem->location, mem->name)));
    215     }
    216     return inits;
     204        std::vector<ast::ptr<ast::Init>> inits;
     205        for (size_t i = 0; i < decl->members.size(); i++) {
     206                ast::ptr<ast::Decl> mem = decl->members.at(i);
     207                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
     208                assert(memAsObjectDecl);
     209                inits.emplace_back(new ast::SingleInit(
     210                        mem->location,
     211                        ast::ConstantExpr::from_string(mem->location, mem->name)));
     212        }
     213        return inits;
    217214}
    218215
    219216std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
    220     std::vector<ast::ptr<ast::Init>> inits;
    221     for (size_t i = 0; i < decl->members.size(); i++) {
    222         ast::ptr<ast::Decl> mem = decl->members.at(i);
    223         auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
    224         assert(memAsObjectDecl);
    225         if (memAsObjectDecl->init) {
    226             inits.emplace_back(memAsObjectDecl->init);
    227         } else {
    228             const CodeLocation& location = mem->location;
    229             if (i == 0) {
    230                 inits.emplace_back(new ast::SingleInit(
    231                     location, ast::ConstantExpr::from_int(mem->location, 0)));
    232             } else {
    233                 inits.emplace_back(getAutoInit(inits.at(i - 1)));
    234             }
    235         }
    236     }
    237     return inits;
     217        std::vector<ast::ptr<ast::Init>> inits;
     218        for (size_t i = 0; i < decl->members.size(); i++) {
     219                ast::ptr<ast::Decl> mem = decl->members.at(i);
     220                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
     221                assert(memAsObjectDecl);
     222                if (memAsObjectDecl->init) {
     223                        inits.emplace_back(memAsObjectDecl->init);
     224                } else {
     225                        const CodeLocation& location = mem->location;
     226                        if (i == 0) {
     227                                inits.emplace_back(new ast::SingleInit(
     228                                        location, ast::ConstantExpr::from_int(mem->location, 0)));
     229                        } else {
     230                                inits.emplace_back(getAutoInit(inits.at(i - 1)));
     231                        }
     232                }
     233        }
     234        return inits;
    238235}
    239236const ast::Init* EnumAttrFuncGenerator::getAutoInit(
    240     const ast::Init* prev) const {
    241     if (prev == nullptr) {
    242         return new ast::SingleInit(
    243             getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
    244     }
    245     auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
    246     assert(prevInit);
    247     auto prevInitExpr = prevInit->value;
    248     if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
    249         // Assume no string literal for now
    250         return new ast::SingleInit(
    251             getLocation(), ast::ConstantExpr::from_int(
    252                                getLocation(), constInit->intValue() + 1));
    253     } else {
    254         auto untypedThisInit = new ast::UntypedExpr(
    255             getLocation(), new ast::NameExpr(getLocation(), "?++"),
    256             {prevInitExpr});
    257         return new ast::SingleInit(getLocation(), untypedThisInit);
    258     }
     237        const ast::Init* prev) const {
     238        if (prev == nullptr) {
     239                return new ast::SingleInit(
     240                        getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
     241        }
     242        auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
     243        assert(prevInit);
     244        auto prevInitExpr = prevInit->value;
     245        if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
     246                // Assume no string literal for now
     247                return new ast::SingleInit(
     248                        getLocation(), ast::ConstantExpr::from_int(
     249                                getLocation(), constInit->intValue() + 1));
     250        } else {
     251                auto untypedThisInit = new ast::UntypedExpr(
     252                        getLocation(), new ast::NameExpr(getLocation(), "?++"),
     253                        {prevInitExpr});
     254                return new ast::SingleInit(getLocation(), untypedThisInit);
     255        }
    259256}
    260257
    261258ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
    262     std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
    263     std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
    264     ast::FunctionDecl* decl = new ast::FunctionDecl(
    265         // Auto-generated routines use the type declaration's location.
    266         getLocation(), std::move(name), {}, {}, std::move(params),
    267         std::move(returns),
    268         // Only a prototype, no body.
    269         nullptr,
    270         // Use static storage if we are at the top level.
    271         (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
    272         proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
    273         // Auto-generated routines are inline to avoid conflicts.
    274         ast::Function::Specs(ast::Function::Inline));
    275     decl->fixUniqueId();
    276     return decl;
     259        std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
     260        std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
     261        ast::FunctionDecl* decl = new ast::FunctionDecl(
     262                // Auto-generated routines use the type declaration's location.
     263                getLocation(), std::move(name), {}, {}, std::move(params),
     264                std::move(returns),
     265                // Only a prototype, no body.
     266                nullptr,
     267                // Use static storage if we are at the top level.
     268                (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
     269                proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
     270                // Auto-generated routines are inline to avoid conflicts.
     271                ast::Function::Specs(ast::Function::Inline));
     272        decl->fixUniqueId();
     273        return decl;
    277274}
    278275
    279276void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
    280     assert(nullptr != decl->stmts);
    281 
    282     definitions.push_back(decl);
     277        assert(nullptr != decl->stmts);
     278
     279        definitions.push_back(decl);
    283280}
    284281
    285282void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
    286     if (0 != functionNesting) return;
    287     ast::FunctionDecl* fwd =
    288         (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
    289     fwd->fixUniqueId();
    290     forwards.push_back(fwd);
     283        if (0 != functionNesting) return;
     284        ast::FunctionDecl* fwd =
     285                (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
     286        fwd->fixUniqueId();
     287        forwards.push_back(fwd);
    291288}
    292289
    293290ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
    294     return genProto(
    295         "posE",
    296         {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    297         {new ast::ObjectDecl(getLocation(), "_ret",
    298             new ast::BasicType(ast::BasicKind::UnsignedInt))});
     291        return genProto(
     292                "posE",
     293                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     294                {new ast::ObjectDecl(getLocation(), "_ret",
     295                        new ast::BasicType(ast::BasicKind::UnsignedInt))});
    299296}
    300297
    301298ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
    302     return genProto(
    303         "labelE",
    304         {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    305         {new ast::ObjectDecl(
    306             getLocation(), "_ret",
    307             new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
     299        return genProto(
     300                "labelE",
     301                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     302                {new ast::ObjectDecl(
     303                        getLocation(), "_ret",
     304                        new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
    308305}
    309306
    310307ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
    311     return genProto(
    312         "valueE",
    313         {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    314         {new ast::ObjectDecl(getLocation(), "_ret",
    315                              ast::deepCopy(decl->base))});
     308        return genProto(
     309                "valueE",
     310                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     311                {new ast::ObjectDecl(getLocation(), "_ret",
     312                                     ast::deepCopy(decl->base))});
    316313}
    317314
    318315ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
    319     return genProto(
    320         "succ",
    321         {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    322         {new ast::ObjectDecl(getLocation(), "_ret",
    323                              new ast::EnumInstType(decl))});
     316        return genProto(
     317                "succ",
     318                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     319                {new ast::ObjectDecl(getLocation(), "_ret",
     320                                     new ast::EnumInstType(decl))});
    324321}
    325322
    326323ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
    327     return genProto(
    328         "pred",
    329         {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    330         {new ast::ObjectDecl(getLocation(), "_ret",
    331                              new ast::EnumInstType(decl))});
     324        return genProto(
     325                "pred",
     326                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     327                {new ast::ObjectDecl(getLocation(), "_ret",
     328                                     new ast::EnumInstType(decl))});
    332329}
    333330
    334331inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
    335     return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
     332        return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
    336333}
    337334
    338335ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
    339     return genProto(
    340         "_successor_",
    341         {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
    342         {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
    343     );
     336        return genProto(
     337                "_successor_",
     338                {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
     339                {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
     340        );
    344341}
    345342
    346343ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
    347     return genProto(
    348         "_predessor_",
    349         {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
    350         {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
    351     );
     344        return genProto(
     345                "_predessor_",
     346                {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
     347                {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
     348        );
    352349}
    353350
    354351ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
    355     const ast::EnumAttribute attr, const CodeLocation& location,
    356     std::vector<ast::ptr<ast::Init>>& inits) const {
    357     ast::ArrayType* arrT = new ast::ArrayType(
    358         attr == ast::EnumAttribute::Value
    359             ? decl->base
    360             : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
    361         ast::ConstantExpr::from_int(decl->location, decl->members.size()),
    362         ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
    363 
    364     ast::ObjectDecl* objDecl =
    365         new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
    366                             arrT, new ast::ListInit(location, std::move(inits)),
    367                             ast::Storage::Static, ast::Linkage::AutoGen);
    368 
    369     return objDecl;
     352        const ast::EnumAttribute attr, const CodeLocation& location,
     353        std::vector<ast::ptr<ast::Init>>& inits) const {
     354        ast::ArrayType* arrT = new ast::ArrayType(
     355                attr == ast::EnumAttribute::Value
     356                        ? decl->base
     357                        : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
     358                ast::ConstantExpr::from_int(decl->location, decl->members.size()),
     359                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
     360
     361        ast::ObjectDecl* objDecl =
     362                new ast::ObjectDecl(
     363                        decl->location, decl->getUnmangeldArrayName( attr ),
     364                        arrT, new ast::ListInit( location, std::move( inits ) ),
     365                        ast::Storage::Static, ast::Linkage::AutoGen );
     366
     367        return objDecl;
    370368}
    371369
    372370void EnumAttrFuncGenerator::genValueOrLabelBody(
    373     ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
    374     ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
    375         func->location, "?[?]",
    376         {new ast::NameExpr(func->location, arrDecl->name),
    377          new ast::CastExpr(
    378              func->location,
    379              new ast::VariableExpr(func->location, func->params.front()),
    380              new ast::EnumAttrType(new ast::EnumInstType(decl),
    381                                    ast::EnumAttribute::Posn))});
    382     func->stmts = new ast::CompoundStmt(
    383         func->location, {new ast::ReturnStmt(func->location, untyped)});
     371        ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
     372        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
     373                func->location, "?[?]",
     374                {new ast::NameExpr(func->location, arrDecl->name),
     375                        new ast::CastExpr(
     376                                func->location,
     377                                new ast::VariableExpr( func->location, func->params.front() ),
     378                                new ast::EnumAttrType( new ast::EnumInstType(decl),
     379                                        ast::EnumAttribute::Posn))});
     380        func->stmts = new ast::CompoundStmt(
     381                func->location, {new ast::ReturnStmt(func->location, untyped)});
    384382}
    385383
    386384void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
    387     auto castExpr = new ast::CastExpr(
    388         func->location,
    389         new ast::VariableExpr(func->location, func->params.front()),
    390         new ast::EnumAttrType(new ast::EnumInstType(decl),
    391                               ast::EnumAttribute::Posn));
    392     func->stmts = new ast::CompoundStmt(
    393         func->location, {new ast::ReturnStmt(func->location, castExpr)});
     385        auto castExpr = new ast::CastExpr(
     386                func->location,
     387                new ast::VariableExpr(func->location, func->params.front()),
     388                new ast::EnumAttrType(new ast::EnumInstType(decl),
     389                                                          ast::EnumAttribute::Posn));
     390        func->stmts = new ast::CompoundStmt(
     391                func->location, {new ast::ReturnStmt(func->location, castExpr)});
    394392}
    395393
    396394void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
    397     if (attr == ast::EnumAttribute::Value ||
    398         attr == ast::EnumAttribute::Label) {
    399         std::vector<ast::ptr<ast::Init>> inits =
    400             attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
    401         ast::ObjectDecl* arrayProto =
    402             genAttrArrayProto(attr, getLocation(), inits);
    403         forwards.push_back(arrayProto);
    404 
    405         ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
    406                                            ? genValueProto()
    407                                            : genLabelProto();
    408         produceForwardDecl(funcProto);
    409         genValueOrLabelBody(funcProto, arrayProto);
    410         produceDecl(funcProto);
    411     } else {
    412         ast::FunctionDecl* funcProto = genPosnProto();
    413         produceForwardDecl(funcProto);
    414         genPosnBody(funcProto);
    415         produceDecl(funcProto);
    416     }
     395        if (attr == ast::EnumAttribute::Value ||
     396                attr == ast::EnumAttribute::Label) {
     397                std::vector<ast::ptr<ast::Init>> inits =
     398                        attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
     399                ast::ObjectDecl* arrayProto =
     400                        genAttrArrayProto(attr, getLocation(), inits);
     401                forwards.push_back(arrayProto);
     402
     403                ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
     404                                               ? genValueProto()
     405                                               : genLabelProto();
     406                produceForwardDecl(funcProto);
     407                genValueOrLabelBody(funcProto, arrayProto);
     408                produceDecl(funcProto);
     409        } else {
     410                ast::FunctionDecl* funcProto = genPosnProto();
     411                produceForwardDecl(funcProto);
     412                genPosnBody(funcProto);
     413                produceDecl(funcProto);
     414        }
    417415}
    418416
    419417ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
    420     ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
    421     produceForwardDecl(funcDecl);
    422 
    423     const CodeLocation& location = getLocation();
    424 
    425     auto& params = funcDecl->params;
    426     assert(params.size() == 1);
    427     auto param = params.front().strict_as<ast::ObjectDecl>();
    428 
    429 
    430     auto rets = funcDecl->returns;
    431     assert(params.size() == 1);
    432     auto ret = rets.front().strict_as<ast::ObjectDecl>();
    433     auto retType = ret->type.strict_as<ast::EnumAttrType>();
    434 
    435     auto addOneExpr = ast::UntypedExpr::createCall( location,
    436         succ? "?+?": "?-?",
    437         {new ast::VariableExpr(location, param),
    438         ast::ConstantExpr::from_int(location, 1)}
    439     );
    440 
    441     funcDecl->stmts = new ast::CompoundStmt(
    442         location, {
    443             new ast::ReturnStmt(
    444                 location,
    445                 new ast::CastExpr(location, addOneExpr, retType)
    446             )
    447         }
    448     );
    449 
    450     return funcDecl;
     418        ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
     419        produceForwardDecl(funcDecl);
     420
     421        const CodeLocation& location = getLocation();
     422
     423        auto& params = funcDecl->params;
     424        assert(params.size() == 1);
     425        auto param = params.front().strict_as<ast::ObjectDecl>();
     426
     427
     428        auto rets = funcDecl->returns;
     429        assert(params.size() == 1);
     430        auto ret = rets.front().strict_as<ast::ObjectDecl>();
     431        auto retType = ret->type.strict_as<ast::EnumAttrType>();
     432
     433        auto addOneExpr = ast::UntypedExpr::createCall( location,
     434                succ? "?+?": "?-?",
     435                {new ast::VariableExpr(location, param),
     436                ast::ConstantExpr::from_int(location, 1)}
     437        );
     438
     439        funcDecl->stmts = new ast::CompoundStmt(
     440                location, {
     441                        new ast::ReturnStmt(
     442                                location,
     443                                new ast::CastExpr(location, addOneExpr, retType)
     444                        )
     445                }
     446        );
     447
     448        return funcDecl;
    451449}
    452450
    453451void EnumAttrFuncGenerator::genAttrFunctions() {
    454     if (decl->base) {
    455         genAttributesDecls(ast::EnumAttribute::Value);
    456         genAttributesDecls(ast::EnumAttribute::Label);
    457         genAttributesDecls(ast::EnumAttribute::Posn);
    458     }
     452        if (decl->base) {
     453                genAttributesDecls(ast::EnumAttribute::Value);
     454                genAttributesDecls(ast::EnumAttribute::Label);
     455                genAttributesDecls(ast::EnumAttribute::Posn);
     456        }
    459457}
    460458
    461459void EnumAttrFuncGenerator::genSuccPredDecl() {
    462     if (decl->base) {
    463         auto succProto = genSuccProto();
    464         auto predProto = genPredProto();
    465 
    466         produceForwardDecl(succProto);
    467         produceForwardDecl(predProto);
    468     }
     460        if (decl->base) {
     461                auto succProto = genSuccProto();
     462                auto predProto = genPredProto();
     463
     464                produceForwardDecl(succProto);
     465                produceForwardDecl(predProto);
     466        }
    469467}
    470468
    471469void EnumAttrFuncGenerator::genSuccPredPosn() {
    472     if (decl->base) {
    473         ast::FunctionDecl* succ = genSuccPredFunc(true);
    474         ast::FunctionDecl* pred = genSuccPredFunc(false);
    475 
    476         produceDecl(succ);
    477         produceDecl(pred);
    478     }
     470        if (decl->base) {
     471                ast::FunctionDecl* succ = genSuccPredFunc(true);
     472                ast::FunctionDecl* pred = genSuccPredFunc(false);
     473
     474                produceDecl(succ);
     475                produceDecl(pred);
     476        }
    479477}
    480478
    481479void EnumAttrFuncGenerator::generateAndAppendFunctions(
    482     std::list<ast::ptr<ast::Decl>>& decls) {
    483     // Generate the functions (they go into forwards and definitions).
    484     genAttrStandardFuncs();
    485     genAttrFunctions();
    486     genSuccPredDecl();
    487     genSuccPredPosn(); // Posn
    488     // Now export the lists contents.
    489     decls.splice(decls.end(), forwards);
    490     decls.splice(decls.end(), definitions);
     480        std::list<ast::ptr<ast::Decl>>& decls) {
     481        // Generate the functions (they go into forwards and definitions).
     482        genAttrStandardFuncs();
     483        genAttrFunctions();
     484        genSuccPredDecl();
     485        genSuccPredPosn(); // Posn
     486        // Now export the lists contents.
     487        decls.splice(decls.end(), forwards);
     488        decls.splice(decls.end(), definitions);
    491489}
    492490
    493491// ---------------------------------------------------------
    494492
    495 struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
    496                                 public ast::WithShortCircuiting {
    497     void previsit(const ast::EnumDecl* enumDecl);
    498     void previsit(const ast::FunctionDecl* functionDecl);
    499     void postvisit(const ast::FunctionDecl* functionDecl);
    500 
    501    private:
    502     // Current level of nested functions.
    503     unsigned int functionNesting = 0;
     493struct ImplementEnumFunc final :
     494                public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
     495        void previsit(const ast::EnumDecl* enumDecl);
     496        void previsit(const ast::FunctionDecl* functionDecl);
     497        void postvisit(const ast::FunctionDecl* functionDecl);
     498
     499private:
     500        // Current level of nested functions.
     501        unsigned int functionNesting = 0;
    504502};
    505503
    506504void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
    507     if (!enumDecl->body) return;
    508     if (!enumDecl->base) return;
    509 
    510     ast::EnumInstType enumInst(enumDecl->name);
    511     enumInst.base = enumDecl;
    512 
    513     EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
    514     gen.generateAndAppendFunctions(declsToAddAfter);
     505        if (!enumDecl->body) return;
     506        if (!enumDecl->base) return;
     507
     508        ast::EnumInstType enumInst(enumDecl->name);
     509        enumInst.base = enumDecl;
     510
     511        EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
     512        gen.generateAndAppendFunctions(declsToAddAfter);
    515513}
    516514
    517515void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
    518     functionNesting += 1;
     516        functionNesting += 1;
    519517}
    520518
    521519void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
    522     functionNesting -= 1;
    523 }
    524 
    525 }  // namespace
     520        functionNesting -= 1;
     521}
     522
     523} // namespace
    526524
    527525void implementEnumFunc(ast::TranslationUnit& translationUnit) {
    528     ast::Pass<ImplementEnumFunc>::run(translationUnit);
    529 }
    530 }  // namespace Validate
     526        ast::Pass<ImplementEnumFunc>::run(translationUnit);
     527}
     528
     529} // namespace Validate
  • src/Virtual/VirtualDtor.cpp

    rb9b6efb rfc1a3e2  
    2828
    2929struct CtorDtor {
    30     FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
    31     FunctionDecl * deleteFn;
    32     FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
    33 
    34     CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
     30        FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
     31        FunctionDecl * deleteFn;
     32        FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
     33
     34        CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
    3535};
    3636
    3737class CtorDtorTable {
    38     unordered_map<const StructDecl *, CtorDtor> & structMap;
     38        unordered_map<const StructDecl *, CtorDtor> & structMap;
     39
     40public:
     41        // if dtor is last dtor for this decl return the routine to add afterwards
     42        // otherwise return nullptr
     43        FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
     44                auto iter = structMap.find( decl );
     45                if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
     46                *retDeleteFn = iter->second.deleteFn;
     47                return iter->second.dtorSetup;
     48        }
     49
     50        // return if the dtorSetup field has been defined for this decl
     51        bool inTable( const StructDecl * decl ) {
     52                auto iter = structMap.find( decl );
     53                return iter->second.dtorSetup != nullptr;
     54        }
     55
     56        void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
     57                auto iter = structMap.find( decl );
     58                iter->second.dtorSetup = dtorSetup;
     59                iter->second.deleteFn = deleteFn;
     60        }
     61
     62        void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
     63                auto iter = structMap.find( decl );
     64                iter->second.lastDtor = dtor;
     65        }
     66
     67        CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
     68};
     69
     70struct CollectStructDecls : public ast::WithGuards {
     71        unordered_map<const StructDecl *, CtorDtor> & structDecls;
     72        StructDecl * parentDecl;
     73        bool insideStruct = false;
     74        bool namedDecl = false;
     75
     76        const StructDecl ** virtualDtor;
     77
     78        // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
     79        void previsit( const StructDecl * decl ) {
     80                if ( !decl->body ) return;
     81                if( decl->name == "virtual_dtor" ) {
     82                        structDecls.emplace( make_pair( decl, CtorDtor() ) );
     83                        *virtualDtor = decl;
     84                } else {
     85                        GuardValue(insideStruct);
     86                        insideStruct = true;
     87                        parentDecl = mutate( decl );
     88                }
     89        }
     90
     91        // this catches structs of the form:
     92        //     struct derived_type { virtual_dtor a; };
     93        // since they should be:
     94        //     struct derived_type { inline virtual_dtor; };
     95        void previsit ( const ObjectDecl * decl ) {
     96                if ( insideStruct && ! decl->name.empty() ) {
     97                        GuardValue(namedDecl);
     98                        namedDecl = true;
     99                }
     100        }
     101
     102        // this collects the derived actor and message struct decl ptrs
     103        void postvisit( const StructInstType * node ) {
     104                if ( ! *virtualDtor ) return;
     105                if ( insideStruct && !namedDecl ) {
     106                        auto structIter = structDecls.find( node->aggr() );
     107                        if ( structIter != structDecls.end() )
     108                                structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
     109                }
     110        }
    39111
    40112  public:
    41     // if dtor is last dtor for this decl return the routine to add afterwards
    42     // otherwise return nullptr
    43     FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
    44         auto iter = structMap.find( decl );
    45         if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
    46         *retDeleteFn = iter->second.deleteFn;
    47         return iter->second.dtorSetup;
    48     }
    49 
    50     // return if the dtorSetup field has been defined for this decl
    51     bool inTable( const StructDecl * decl ) {
    52         auto iter = structMap.find( decl );
    53         return iter->second.dtorSetup != nullptr;
    54     }
    55 
    56     void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
    57         auto iter = structMap.find( decl );
    58         iter->second.dtorSetup = dtorSetup;
    59         iter->second.deleteFn = deleteFn;
    60     }
    61 
    62     void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
    63         auto iter = structMap.find( decl );
    64         iter->second.lastDtor = dtor;
    65     }
    66 
    67     CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
    68 };
    69 
    70 struct CollectStructDecls : public ast::WithGuards {
    71     unordered_map<const StructDecl *, CtorDtor> & structDecls;
    72     StructDecl * parentDecl;
    73     bool insideStruct = false;
    74     bool namedDecl = false;
    75 
    76     const StructDecl ** virtualDtor;
    77 
    78     // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
    79     void previsit( const StructDecl * decl ) {
    80         if ( !decl->body ) return;
    81         if( decl->name == "virtual_dtor" ) {
    82             structDecls.emplace( make_pair( decl, CtorDtor() ) );
    83             *virtualDtor = decl;
    84         } else {
    85             GuardValue(insideStruct);
    86             insideStruct = true;
    87             parentDecl = mutate( decl );
    88         }
    89         }
    90 
    91     // this catches structs of the form:
    92     //     struct derived_type { virtual_dtor a; };
    93     // since they should be:
    94     //     struct derived_type { inline virtual_dtor; };
    95     void previsit ( const ObjectDecl * decl ) {
    96         if ( insideStruct && ! decl->name.empty() ) {
    97             GuardValue(namedDecl);
    98             namedDecl = true;
    99         }
    100     }
    101 
    102     // this collects the derived actor and message struct decl ptrs
    103     void postvisit( const StructInstType * node ) {
    104         if ( ! *virtualDtor ) return;
    105         if ( insideStruct && !namedDecl ) {
    106             auto structIter = structDecls.find( node->aggr() );   
    107             if ( structIter != structDecls.end() )
    108                 structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
    109         }
    110         }
    111 
    112   public:
    113     CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
    114         structDecls( structDecls ), virtualDtor(virtualDtor) {}
     113        CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
     114                structDecls( structDecls ), virtualDtor(virtualDtor) {}
    115115};
    116116
    117117// generates the forward decl of virtual dtor setting routine and delete routine
    118118// generates the call to the virtual dtor routine in each appropriate ctor
    119 // collects data needed for next pass that does the circular defn resolution 
     119// collects data needed for next pass that does the circular defn resolution
    120120//     for dtor setters and delete fns (via table above)
    121121struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
    122     unordered_map<const StructDecl *, CtorDtor> & structDecls;
    123     CtorDtorTable & torDecls;
    124     const StructDecl ** virtualDtor;
    125 
    126     // collects the dtor info for actors/messages
    127     // gens the dtor fwd decl and dtor call in ctor
    128     void previsit( const FunctionDecl * decl ) {
    129         if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0
    130             || !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
    131 
    132         // the first param should be a reference
    133         const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
    134         if ( !ref ) return;
    135 
    136         // the reference should be to a struct instance
    137         const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
    138         if ( !instType ) return;
    139 
    140         // return if not ctor/dtor for an actor or message
    141         auto structIter = structDecls.find( instType->aggr() );
    142         if ( structIter == structDecls.end() ) return;
    143 
    144         // If first param not named we need to name it to use it
    145         if ( decl->params.at(0)->name == "" )
    146             mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
    147 
    148         if ( decl->name == "^?{}") {
    149             torDecls.addDtor( structIter->first, mutate( decl ) );
    150 
    151             CompoundStmt * dtorBody = mutate( decl->stmts.get() );
    152             // Adds the following to the start of any actor/message dtor:
    153             //  __CFA_dtor_shutdown( this );
    154             dtorBody->push_front(
    155                 new IfStmt( decl->location,
    156                     new UntypedExpr (
    157                         decl->location,
    158                         new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
    159                         {
    160                             new NameExpr( decl->location, decl->params.at(0)->name )
    161                         }
    162                     ),
    163                     new ReturnStmt( decl->location, nullptr )
    164                 )
    165             );
    166             return;
    167         }
    168 
    169         // not dtor by this point so must be ctor
    170         CompoundStmt * ctorBody = mutate( decl->stmts.get() );
    171         // Adds the following to the end of any actor/message ctor:
    172         //  __CFA_set_dtor( this );
    173         ctorBody->push_back( new ExprStmt(
    174             decl->location,
    175             new UntypedExpr (
    176                 decl->location,
    177                 new NameExpr( decl->location, "__CFA_set_dtor" ),
    178                 {
    179                     new NameExpr( decl->location, decl->params.at(0)->name )
    180                 }
    181             )
    182         ));
    183        
    184         if ( torDecls.inTable( structIter->first ) ) return;
    185 
    186         // Generates the following:
    187         // void __CFA_set_dtor( Derived_type & this ){
    188         //     void (*__my_dtor)( Derived_type & ) = ^?{};
    189         //     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
    190         //     this.__virtual_obj_start = (void *)(&this);
    191         // }
    192         CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
    193 
    194         // Function type is: (void (*)(Derived_type &))
    195         FunctionType * derivedDtor = new FunctionType();
    196         derivedDtor->params.push_back( ast::deepCopy( ref ) );
    197 
    198         // Generates:
    199         //      void (*__my_dtor)( Derived_type & ) = ^?{};
    200         setDtorBody->push_back( new DeclStmt(
    201             decl->location,
    202             new ObjectDecl(
    203                 decl->location,
    204                 "__my_dtor",
    205                 new PointerType( derivedDtor ),
    206                 new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
    207             )
    208         ));
    209 
    210         // Function type is: (void (*)( Base_type & ))
    211         FunctionType * baseDtor = new FunctionType();
    212         baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
    213 
    214         // Generates:
    215         //     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
    216         setDtorBody->push_back( new ExprStmt(
    217             decl->location,
    218             new UntypedExpr (
    219                 decl->location,
    220                 new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
    221                 {
    222                     new NameExpr( decl->location, "this" ),
    223                     new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
    224                 }
    225             )
    226         ));
    227 
    228         // Generates:
    229         //     __CFA_set_virt_start( (void *)(&this) );
    230         setDtorBody->push_back( new ExprStmt(
    231             decl->location,
    232             new UntypedExpr (
    233                 decl->location,
    234                 new NameExpr( decl->location, "__CFA_set_virt_start" ),
    235                 {
    236                     new NameExpr( decl->location, "this" ),
    237                     new CastExpr(
    238                         decl->location,
    239                         new AddressExpr( decl->location, new NameExpr( decl->location, "this" )),
    240                         new PointerType( new ast::VoidType() ), ExplicitCast
    241                         )
    242                 }
    243             )
    244         ));
    245 
    246         // put it all together into the complete function decl from above
    247         FunctionDecl * setDtorFunction = new FunctionDecl(
    248             decl->location,
    249             "__CFA_set_dtor",
    250             {
    251                 new ObjectDecl(
    252                     decl->location,
    253                     "this",
    254                     ast::deepCopy( ref )
    255                 ),
    256             },                      // params
    257             {},
    258             nullptr,               // body
    259             { Storage::Static },    // storage
    260             Linkage::Cforall,       // linkage
    261             {},                     // attributes
    262             { Function::Inline }
    263         );
    264 
    265         declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
    266 
    267         setDtorFunction->stmts = setDtorBody;
    268 
    269         // The following generates the following specialized delete routine:
    270         // static inline void delete( derived_type * ptr ) {
    271         //     if ( ptr )
    272         //         ^(*ptr){};
    273         //     __CFA_virt_free( *ptr );
    274         // }
    275         CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
    276 
    277         // Generates:
    278         //     if ( ptr )
    279         //         ^(*ptr){};
    280         deleteFnBody->push_back(
    281             new IfStmt(
    282                 decl->location,
    283                 UntypedExpr::createCall(
    284                     decl->location,
    285                     "?!=?",
    286                     {
    287                         new NameExpr( decl->location, "ptr" ),
    288                         ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
    289                     }
    290                 ),
    291                 new ExprStmt(
    292                     decl->location,
    293                     UntypedExpr::createCall(
    294                         decl->location,
    295                         "^?{}",
    296                         {
    297                             UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
    298                         }
    299                     )
    300                 )
    301             )
    302         );
    303 
    304         // Generates:
    305         //     __CFA_virt_free( *ptr );
    306         deleteFnBody->push_back( new ExprStmt(
    307                 decl->location,
    308                 UntypedExpr::createCall(
    309                     decl->location,
    310                     "__CFA_virt_free",
    311                     {
    312                         UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
    313                     }
    314                 )
    315             )
    316         );
    317 
    318         FunctionDecl * deleteFn = new FunctionDecl(
    319             decl->location,
    320             "delete",
    321             {
    322                 new ObjectDecl(
    323                     decl->location,
    324                     "ptr",
    325                     new PointerType( ast::deepCopy( instType ) )
    326                 ),
    327             },                      // params
    328             {},
    329             nullptr,               // body
    330             { Storage::Static },    // storage
    331             Linkage::Cforall,       // linkage
    332             {},                     // attributes
    333             { Function::Inline }
    334         );
    335 
    336         declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
    337 
    338         deleteFn->stmts = deleteFnBody;
    339 
    340         torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
    341     }
     122        unordered_map<const StructDecl *, CtorDtor> & structDecls;
     123        CtorDtorTable & torDecls;
     124        const StructDecl ** virtualDtor;
     125
     126        // collects the dtor info for actors/messages
     127        // gens the dtor fwd decl and dtor call in ctor
     128        void previsit( const FunctionDecl * decl ) {
     129                if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0
     130                        || !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
     131
     132                // the first param should be a reference
     133                const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
     134                if ( !ref ) return;
     135
     136                // the reference should be to a struct instance
     137                const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
     138                if ( !instType ) return;
     139
     140                // return if not ctor/dtor for an actor or message
     141                auto structIter = structDecls.find( instType->aggr() );
     142                if ( structIter == structDecls.end() ) return;
     143
     144                // If first param not named we need to name it to use it
     145                if ( decl->params.at(0)->name == "" )
     146                        mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
     147
     148                if ( decl->name == "^?{}") {
     149                        torDecls.addDtor( structIter->first, mutate( decl ) );
     150
     151                        CompoundStmt * dtorBody = mutate( decl->stmts.get() );
     152                        // Adds the following to the start of any actor/message dtor:
     153                        //  __CFA_dtor_shutdown( this );
     154                        dtorBody->push_front(
     155                                new IfStmt( decl->location,
     156                                        new UntypedExpr (
     157                                                decl->location,
     158                                                new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
     159                                                {
     160                                                        new NameExpr( decl->location, decl->params.at(0)->name )
     161                                                }
     162                                        ),
     163                                        new ReturnStmt( decl->location, nullptr )
     164                                )
     165                        );
     166                        return;
     167                }
     168
     169                // not dtor by this point so must be ctor
     170                CompoundStmt * ctorBody = mutate( decl->stmts.get() );
     171                // Adds the following to the end of any actor/message ctor:
     172                //  __CFA_set_dtor( this );
     173                ctorBody->push_back( new ExprStmt(
     174                        decl->location,
     175                        new UntypedExpr (
     176                                decl->location,
     177                                new NameExpr( decl->location, "__CFA_set_dtor" ),
     178                                {
     179                                        new NameExpr( decl->location, decl->params.at(0)->name )
     180                                }
     181                        )
     182                ));
     183
     184                if ( torDecls.inTable( structIter->first ) ) return;
     185
     186                // Generates the following:
     187                // void __CFA_set_dtor( Derived_type & this ){
     188                //     void (*__my_dtor)( Derived_type & ) = ^?{};
     189                //     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
     190                //     this.__virtual_obj_start = (void *)(&this);
     191                // }
     192                CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
     193
     194                // Function type is: (void (*)(Derived_type &))
     195                FunctionType * derivedDtor = new FunctionType();
     196                derivedDtor->params.push_back( ast::deepCopy( ref ) );
     197
     198                // Generates:
     199                //      void (*__my_dtor)( Derived_type & ) = ^?{};
     200                setDtorBody->push_back( new DeclStmt(
     201                        decl->location,
     202                        new ObjectDecl(
     203                                decl->location,
     204                                "__my_dtor",
     205                                new PointerType( derivedDtor ),
     206                                new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
     207                        )
     208                ));
     209
     210                // Function type is: (void (*)( Base_type & ))
     211                FunctionType * baseDtor = new FunctionType();
     212                baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
     213
     214                // Generates:
     215                //     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
     216                setDtorBody->push_back( new ExprStmt(
     217                        decl->location,
     218                        new UntypedExpr (
     219                                decl->location,
     220                                new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
     221                                {
     222                                        new NameExpr( decl->location, "this" ),
     223                                        new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
     224                                }
     225                        )
     226                ));
     227
     228                // Generates:
     229                //     __CFA_set_virt_start( (void *)(&this) );
     230                setDtorBody->push_back( new ExprStmt(
     231                        decl->location,
     232                        new UntypedExpr (
     233                                decl->location,
     234                                new NameExpr( decl->location, "__CFA_set_virt_start" ),
     235                                {
     236                                        new NameExpr( decl->location, "this" ),
     237                                        new CastExpr(
     238                                                decl->location,
     239                                                new AddressExpr( decl->location, new NameExpr( decl->location, "this" )),
     240                                                new PointerType( new ast::VoidType() ), ExplicitCast
     241                                                )
     242                                }
     243                        )
     244                ));
     245
     246                // put it all together into the complete function decl from above
     247                FunctionDecl * setDtorFunction = new FunctionDecl(
     248                        decl->location,
     249                        "__CFA_set_dtor",
     250                        {
     251                                new ObjectDecl(
     252                                        decl->location,
     253                                        "this",
     254                                        ast::deepCopy( ref )
     255                                ),
     256                        },                      // params
     257                        {},
     258                        nullptr,               // body
     259                        { Storage::Static },    // storage
     260                        Linkage::Cforall,       // linkage
     261                        {},                     // attributes
     262                        { Function::Inline }
     263                );
     264
     265                declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
     266
     267                setDtorFunction->stmts = setDtorBody;
     268
     269                // The following generates the following specialized delete routine:
     270                // static inline void delete( derived_type * ptr ) {
     271                //     if ( ptr )
     272                //         ^(*ptr){};
     273                //     __CFA_virt_free( *ptr );
     274                // }
     275                CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
     276
     277                // Generates:
     278                //     if ( ptr )
     279                //         ^(*ptr){};
     280                deleteFnBody->push_back(
     281                        new IfStmt(
     282                                decl->location,
     283                                UntypedExpr::createCall(
     284                                        decl->location,
     285                                        "?!=?",
     286                                        {
     287                                                new NameExpr( decl->location, "ptr" ),
     288                                                ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
     289                                        }
     290                                ),
     291                                new ExprStmt(
     292                                        decl->location,
     293                                        UntypedExpr::createCall(
     294                                                decl->location,
     295                                                "^?{}",
     296                                                {
     297                                                        UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
     298                                                }
     299                                        )
     300                                )
     301                        )
     302                );
     303
     304                // Generates:
     305                //     __CFA_virt_free( *ptr );
     306                deleteFnBody->push_back( new ExprStmt(
     307                                decl->location,
     308                                UntypedExpr::createCall(
     309                                        decl->location,
     310                                        "__CFA_virt_free",
     311                                        {
     312                                                UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
     313                                        }
     314                                )
     315                        )
     316                );
     317
     318                FunctionDecl * deleteFn = new FunctionDecl(
     319                        decl->location,
     320                        "delete",
     321                        {
     322                                new ObjectDecl(
     323                                        decl->location,
     324                                        "ptr",
     325                                        new PointerType( ast::deepCopy( instType ) )
     326                                ),
     327                        },                      // params
     328                        {},
     329                        nullptr,               // body
     330                        { Storage::Static },    // storage
     331                        Linkage::Cforall,       // linkage
     332                        {},                     // attributes
     333                        { Function::Inline }
     334                );
     335
     336                declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
     337
     338                deleteFn->stmts = deleteFnBody;
     339
     340                torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
     341        }
    342342
    343343  public:
    344     GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
    345     structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
     344        GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
     345        structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
    346346};
    347347
     
    349349// generates the trailing definitions of dtor setting routines for virtual dtors on messages and actors
    350350// generates the function defns of __CFA_set_dtor
    351 // separate pass is needed since  __CFA_set_dtor needs to be defined after 
     351// separate pass is needed since  __CFA_set_dtor needs to be defined after
    352352//   the last dtor defn which is found in prior pass
    353353struct GenSetDtor : public ast::WithDeclsToAdd<> {
    354     unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
    355     CtorDtorTable & torDecls;
    356 
    357     // handles adding the declaration of the dtor init routine after the last dtor detected
    358     void postvisit( const FunctionDecl * decl ) {
    359         if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
    360 
    361         // the one param should be a reference
    362         const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
    363         if ( !ref ) return;
    364 
    365         // the reference should be to a struct instance
    366         const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
    367         if ( !instType ) return;
    368 
    369         FunctionDecl * deleteRtn;
    370 
    371         // returns nullptr if not in table
    372         FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
    373         if ( maybeAdd ) {
    374             declsToAddAfter.push_back( maybeAdd );
    375             declsToAddAfter.push_back( deleteRtn );
    376         }
    377     }
    378 
    379   public:
    380     GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
    381         structDecls(structDecls), torDecls(torDecls) {}
     354        unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
     355        CtorDtorTable & torDecls;
     356
     357        // handles adding the declaration of the dtor init routine after the last dtor detected
     358        void postvisit( const FunctionDecl * decl ) {
     359                if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
     360
     361                // the one param should be a reference
     362                const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
     363                if ( !ref ) return;
     364
     365                // the reference should be to a struct instance
     366                const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
     367                if ( !instType ) return;
     368
     369                FunctionDecl * deleteRtn;
     370
     371                // returns nullptr if not in table
     372                FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
     373                if ( maybeAdd ) {
     374                        declsToAddAfter.push_back( maybeAdd );
     375                        declsToAddAfter.push_back( deleteRtn );
     376                }
     377        }
     378
     379public:
     380        GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
     381                structDecls(structDecls), torDecls(torDecls) {}
    382382};
    383383
    384384void implementVirtDtors( TranslationUnit & translationUnit ) {
    385     // unordered_map to collect all derived types and associated data
    386     unordered_map<const StructDecl *, CtorDtor> structDecls;
    387     CtorDtorTable torDecls( structDecls );
    388 
    389     const StructDecl * virtualDtorPtr = nullptr;
    390     const StructDecl ** virtualDtor = &virtualDtorPtr;
    391 
    392     // first pass collects all structs that inherit from virtual_dtor
    393     Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
    394 
    395     // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
    396     Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
    397 
    398     // The third pass adds the forward decls needed to resolve circular defn problems
    399     Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
     385        // unordered_map to collect all derived types and associated data
     386        unordered_map<const StructDecl *, CtorDtor> structDecls;
     387        CtorDtorTable torDecls( structDecls );
     388
     389        const StructDecl * virtualDtorPtr = nullptr;
     390        const StructDecl ** virtualDtor = &virtualDtorPtr;
     391
     392        // first pass collects all structs that inherit from virtual_dtor
     393        Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
     394
     395        // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
     396        Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
     397
     398        // The third pass adds the forward decls needed to resolve circular defn problems
     399        Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
    400400}
    401 
    402401
    403402} // namespace Virtual
Note: See TracChangeset for help on using the changeset viewer.