Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Concurrency/Waituntil.cpp

    rfc1a3e2 r7a780ad  
    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) )
     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) )
    952952                );
    953 
     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
Note: See TracChangeset for help on using the changeset viewer.