| 1 | //
 | 
|---|
| 2 | // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // The contents of this file are covered under the licence agreement in the
 | 
|---|
| 5 | // file "LICENCE" distributed with Cforall.
 | 
|---|
| 6 | //
 | 
|---|
| 7 | // WaitforNew.cpp -- Expand waitfor clauses into code.
 | 
|---|
| 8 | //
 | 
|---|
| 9 | // Author           : Andrew Beach
 | 
|---|
| 10 | // Created On       : Fri May 27 10:31:00 2022
 | 
|---|
| 11 | // Last Modified By : Andrew Beach
 | 
|---|
| 12 | // Last Modified On : Tue Jun 13 13:30:00 2022
 | 
|---|
| 13 | // Update Count     : 0
 | 
|---|
| 14 | //
 | 
|---|
| 15 | 
 | 
|---|
| 16 | #include "Waituntil.hpp"
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #include <string>
 | 
|---|
| 19 | 
 | 
|---|
| 20 | #include "AST/Copy.hpp"
 | 
|---|
| 21 | #include "AST/Expr.hpp"
 | 
|---|
| 22 | #include "AST/Pass.hpp"
 | 
|---|
| 23 | #include "AST/Print.hpp"
 | 
|---|
| 24 | #include "AST/Stmt.hpp"
 | 
|---|
| 25 | #include "AST/Type.hpp"
 | 
|---|
| 26 | #include "Common/UniqueName.h"
 | 
|---|
| 27 | 
 | 
|---|
| 28 | using namespace ast;
 | 
|---|
| 29 | using namespace std;
 | 
|---|
| 30 | 
 | 
|---|
| 31 | /* So this is what this pass dones:
 | 
|---|
| 32 | {
 | 
|---|
| 33 |     when ( condA ) waituntil( A ){ doA(); } 
 | 
|---|
| 34 |     or when ( condB ) waituntil( B ){ doB(); } 
 | 
|---|
| 35 |     and when ( condC ) waituntil( C ) { doC(); }
 | 
|---|
| 36 | }
 | 
|---|
| 37 |                  ||
 | 
|---|
| 38 |                  ||
 | 
|---|
| 39 |                 \||/
 | 
|---|
| 40 |                  \/
 | 
|---|
| 41 | 
 | 
|---|
| 42 | Generates these two routines:
 | 
|---|
| 43 | static inline bool is_full_sat_1( int * clause_statuses ) {
 | 
|---|
| 44 |     return clause_statuses[0] 
 | 
|---|
| 45 |         || clause_statuses[1]
 | 
|---|
| 46 |         && clause_statuses[2];
 | 
|---|
| 47 | }
 | 
|---|
| 48 | 
 | 
|---|
| 49 | static 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]);
 | 
|---|
| 53 | }
 | 
|---|
| 54 | 
 | 
|---|
| 55 | Replaces the waituntil statement above with the following code:
 | 
|---|
| 56 | {
 | 
|---|
| 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 |     }
 | 
|---|
| 129 | }
 | 
|---|
| 130 | 
 | 
|---|
| 131 | */
 | 
|---|
| 132 | 
 | 
|---|
| 133 | namespace Concurrency {
 | 
|---|
| 134 | 
 | 
|---|
| 135 | class GenerateWaitUntilCore final {
 | 
|---|
| 136 |     vector<FunctionDecl *> & satFns;
 | 
|---|
| 137 |         UniqueName namer_sat = "__is_full_sat_"s;
 | 
|---|
| 138 |     UniqueName namer_run = "__is_run_sat_"s;
 | 
|---|
| 139 |         UniqueName namer_park = "__park_counter_"s;
 | 
|---|
| 140 |         UniqueName namer_status = "__clause_statuses_"s;
 | 
|---|
| 141 |         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 );
 | 
|---|
| 185 | 
 | 
|---|
| 186 |   public:
 | 
|---|
| 187 |     void previsit( const StructDecl * decl );
 | 
|---|
| 188 |         Stmt * postvisit( const WaitUntilStmt * stmt );
 | 
|---|
| 189 |     GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
 | 
|---|
| 190 | };
 | 
|---|
| 191 | 
 | 
|---|
| 192 | // Finds select_node decl
 | 
|---|
| 193 | void GenerateWaitUntilCore::previsit( const StructDecl * decl ) {
 | 
|---|
| 194 |     if ( !decl->body ) {
 | 
|---|
| 195 |                 return;
 | 
|---|
| 196 |         } else if ( "select_node" == decl->name ) {
 | 
|---|
| 197 |                 assert( !selectNodeDecl );
 | 
|---|
| 198 |                 selectNodeDecl = decl;
 | 
|---|
| 199 |         }
 | 
|---|
| 200 | }
 | 
|---|
| 201 | 
 | 
|---|
| 202 | void 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
 | 
|---|
| 208 | }
 | 
|---|
| 209 | 
 | 
|---|
| 210 | // Traverses ClauseNode tree and paints each AND/OR node as when-ambiguous true or false
 | 
|---|
| 211 | // This tree painting is needed to generate the if statements that set the initial state
 | 
|---|
| 212 | //    of the clause statuses when some clauses are turned off via when_cond
 | 
|---|
| 213 | // An internal AND/OR node is when-ambiguous if it satisfies all of the following:
 | 
|---|
| 214 | // - It has an ancestor or descendant that is a different operation, i.e. (AND has an OR ancestor or vice versa)
 | 
|---|
| 215 | // - All of its descendent clauses are optional, i.e. they have a when_cond defined on the WhenClause
 | 
|---|
| 216 | void 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 |     }
 | 
|---|
| 249 | }
 | 
|---|
| 250 | 
 | 
|---|
| 251 | // overloaded wrapper for paintWhenTree that sets initial values
 | 
|---|
| 252 | // returns true if entire tree is OR's (special case)
 | 
|---|
| 253 | bool 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;
 | 
|---|
| 257 | }
 | 
|---|
| 258 | 
 | 
|---|
| 259 | // Helper: returns Expr that represents arrName[index]
 | 
|---|
| 260 | Expr * 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 |     );
 | 
|---|
| 268 | }
 | 
|---|
| 269 | 
 | 
|---|
| 270 | // After the ClauseNode AND/OR nodes are painted this routine is called to traverses the tree and does the following:
 | 
|---|
| 271 | // - collects a set of indices in the clause arr that refer whenclauses that can have ambiguous status assignments (ambigIdxs)
 | 
|---|
| 272 | // - collects a set of indices in the clause arr that refer whenclauses that have a when() defined and an AND node as a parent (andIdxs)
 | 
|---|
| 273 | // - updates LEAF nodes to be when-ambiguous if their direct parent is when-ambiguous.
 | 
|---|
| 274 | void 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 |     }
 | 
|---|
| 297 | }
 | 
|---|
| 298 | 
 | 
|---|
| 299 | // overloaded wrapper for collectWhens that sets initial values
 | 
|---|
| 300 | void 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 
 | 
|---|
| 306 | //    subtrees are "turned off"
 | 
|---|
| 307 | // sets whenState = false iff both children have whenState == false.
 | 
|---|
| 308 | // similar to paintWhenTree except since paintWhenTree also filtered out clauses we don't need to consider based on op
 | 
|---|
| 309 | // since the ambiguous clauses were filtered in paintWhenTree we don't need to worry about that here
 | 
|---|
| 310 | void 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;
 | 
|---|
| 318 | }
 | 
|---|
| 319 | 
 | 
|---|
| 320 | // generates the minimal set of status assignments to ensure predicate subtree passed as currNode evaluates to status
 | 
|---|
| 321 | // assumes that this will only be called on subtrees that are entirely whenState == false
 | 
|---|
| 322 | void 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 |     }
 | 
|---|
| 376 | }
 | 
|---|
| 377 | 
 | 
|---|
| 378 | void 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 );
 | 
|---|
| 423 | }
 | 
|---|
| 424 | 
 | 
|---|
| 425 | // generates a minimal set of assignments for status arr based on which whens are toggled on/off
 | 
|---|
| 426 | CompoundStmt * 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;
 | 
|---|
| 432 | }
 | 
|---|
| 433 | 
 | 
|---|
| 434 | // generates nested if/elses for all possible assignments of ambiguous when_conds
 | 
|---|
| 435 | // 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 |     );
 | 
|---|
| 471 | }
 | 
|---|
| 472 | 
 | 
|---|
| 473 | // typedef a fn ptr so that we can reuse genPredExpr
 | 
|---|
| 474 | // genLeafExpr is used to refer to one of the following two routines
 | 
|---|
| 475 | typedef Expr * (*GenLeafExpr)( const CodeLocation & loc, int & index );
 | 
|---|
| 476 | 
 | 
|---|
| 477 | // return Expr that represents clause_statuses[index]
 | 
|---|
| 478 | // mutates index to be index + 1
 | 
|---|
| 479 | Expr * genSatExpr( const CodeLocation & loc, int & index ) {
 | 
|---|
| 480 |     return genArrAccessExpr( loc, index++, "clause_statuses" );
 | 
|---|
| 481 | }
 | 
|---|
| 482 | 
 | 
|---|
| 483 | // return Expr that represents has_run(clause_statuses[index])
 | 
|---|
| 484 | Expr * genRunExpr( const CodeLocation & loc, int & index ) {
 | 
|---|
| 485 |     return new UntypedExpr ( loc, 
 | 
|---|
| 486 |         new NameExpr( loc, "__CFA_has_clause_run" ),
 | 
|---|
| 487 |         { genSatExpr( loc, index ) }
 | 
|---|
| 488 |     );
 | 
|---|
| 489 | }
 | 
|---|
| 490 | 
 | 
|---|
| 491 | // Takes in the ClauseNode tree and recursively generates
 | 
|---|
| 492 | // the predicate expr used inside the predicate functions
 | 
|---|
| 493 | Expr * genPredExpr( const CodeLocation & loc, WaitUntilStmt::ClauseNode * currNode, int & idx, GenLeafExpr genLeaf ) {
 | 
|---|
| 494 |     switch (currNode->op) {
 | 
|---|
| 495 |         case WaitUntilStmt::ClauseNode::AND:
 | 
|---|
| 496 |             return new LogicalExpr( loc, 
 | 
|---|
| 497 |                 new CastExpr( loc, genPredExpr( loc, currNode->left, idx, genLeaf ), new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast ),
 | 
|---|
| 498 |                 new CastExpr( loc, genPredExpr( loc, currNode->right, idx, genLeaf ), new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast ), 
 | 
|---|
| 499 |                 LogicalFlag::AndExpr 
 | 
|---|
| 500 |             );
 | 
|---|
| 501 |         case WaitUntilStmt::ClauseNode::OR:
 | 
|---|
| 502 |             return new LogicalExpr( loc,
 | 
|---|
| 503 |                 new CastExpr( loc, genPredExpr( loc, currNode->left, idx, genLeaf ), new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast ),
 | 
|---|
| 504 |                 new CastExpr( loc, genPredExpr( loc, currNode->right, idx, genLeaf ), new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast ), 
 | 
|---|
| 505 |                 LogicalFlag::OrExpr );
 | 
|---|
| 506 |         case WaitUntilStmt::ClauseNode::LEAF:
 | 
|---|
| 507 |             return genLeaf( loc, idx );
 | 
|---|
| 508 |         default:
 | 
|---|
| 509 |             assertf(false, "Unreachable waituntil clause node type. How did you get here???");
 | 
|---|
| 510 |     }
 | 
|---|
| 511 | }
 | 
|---|
| 512 | 
 | 
|---|
| 513 | 
 | 
|---|
| 514 | // Builds the predicate functions used to check the status of the waituntil statement
 | 
|---|
| 515 | /* Ex:
 | 
|---|
| 516 | {
 | 
|---|
| 517 |     waituntil( A ){ doA(); } 
 | 
|---|
| 518 |     or waituntil( B ){ doB(); } 
 | 
|---|
| 519 |     and waituntil( C ) { doC(); }
 | 
|---|
| 520 | }
 | 
|---|
| 521 | generates =>
 | 
|---|
| 522 | static inline bool is_full_sat_1( int * clause_statuses ) {
 | 
|---|
| 523 |     return clause_statuses[0] 
 | 
|---|
| 524 |         || clause_statuses[1]
 | 
|---|
| 525 |         && clause_statuses[2];
 | 
|---|
| 526 | }
 | 
|---|
| 527 | 
 | 
|---|
| 528 | static inline bool is_done_sat_1( int * clause_statuses ) {
 | 
|---|
| 529 |     return has_run(clause_statuses[0])
 | 
|---|
| 530 |         || has_run(clause_statuses[1])
 | 
|---|
| 531 |         && has_run(clause_statuses[2]);
 | 
|---|
| 532 | }
 | 
|---|
| 533 | */
 | 
|---|
| 534 | // Returns a predicate function decl
 | 
|---|
| 535 | // predName and genLeaf determine if this generates an is_done or an is_full predicate
 | 
|---|
| 536 | FunctionDecl * buildPredicate( const WaitUntilStmt * stmt, GenLeafExpr genLeaf, string & predName ) {
 | 
|---|
| 537 |     int arrIdx = 0;
 | 
|---|
| 538 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 539 |     CompoundStmt * body = new CompoundStmt( loc );
 | 
|---|
| 540 |     body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
 | 
|---|
| 541 | 
 | 
|---|
| 542 |     return new FunctionDecl( loc,
 | 
|---|
| 543 |         predName,
 | 
|---|
| 544 |         {},                     // forall
 | 
|---|
| 545 |         {
 | 
|---|
| 546 |             new ObjectDecl( loc,
 | 
|---|
| 547 |                 "clause_statuses",
 | 
|---|
| 548 |                 new PointerType( new BasicType( BasicType::Kind::LongUnsignedInt ) )
 | 
|---|
| 549 |             )
 | 
|---|
| 550 |         },
 | 
|---|
| 551 |         { 
 | 
|---|
| 552 |             new ObjectDecl( loc,
 | 
|---|
| 553 |                 "sat_ret",
 | 
|---|
| 554 |                 new BasicType( BasicType::Kind::Bool )
 | 
|---|
| 555 |             )
 | 
|---|
| 556 |         },
 | 
|---|
| 557 |         body,               // body
 | 
|---|
| 558 |         { Storage::Static },    // storage
 | 
|---|
| 559 |         Linkage::Cforall,       // linkage
 | 
|---|
| 560 |         {},                     // attributes
 | 
|---|
| 561 |         { Function::Inline }
 | 
|---|
| 562 |     );
 | 
|---|
| 563 | }
 | 
|---|
| 564 | 
 | 
|---|
| 565 | // Creates is_done and is_full predicates
 | 
|---|
| 566 | void GenerateWaitUntilCore::addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName ) {
 | 
|---|
| 567 |     if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
 | 
|---|
| 568 |         satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) ); 
 | 
|---|
| 569 |     satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
 | 
|---|
| 570 | }
 | 
|---|
| 571 | 
 | 
|---|
| 572 | // Adds the following to body:
 | 
|---|
| 573 | // if ( when_cond ) { // this if is omitted if no when() condition
 | 
|---|
| 574 | //      setup_clause( clause1, &clause_statuses[0], &park_counter );
 | 
|---|
| 575 | //      register_select(A, clause1);
 | 
|---|
| 576 | // }
 | 
|---|
| 577 | void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {    
 | 
|---|
| 578 |     CompoundStmt * currBody = body;
 | 
|---|
| 579 |     const CodeLocation & loc = clause->location;
 | 
|---|
| 580 | 
 | 
|---|
| 581 |     // If we have a when_cond make the initialization conditional
 | 
|---|
| 582 |     if ( clause->when_cond )
 | 
|---|
| 583 |         currBody = new CompoundStmt( loc );
 | 
|---|
| 584 | 
 | 
|---|
| 585 |     // Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
 | 
|---|
| 586 |     currBody->push_back( new ExprStmt( loc,
 | 
|---|
| 587 |         new UntypedExpr ( loc,
 | 
|---|
| 588 |             new NameExpr( loc, "setup_clause" ),
 | 
|---|
| 589 |             {
 | 
|---|
| 590 |                 new NameExpr( loc, data->nodeName ),
 | 
|---|
| 591 |                 new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
 | 
|---|
| 592 |                 new AddressExpr( loc, new NameExpr( loc, pCountName ) )
 | 
|---|
| 593 |             }
 | 
|---|
| 594 |         )
 | 
|---|
| 595 |     ));
 | 
|---|
| 596 | 
 | 
|---|
| 597 |     // Generates: register_select(A, clause1);
 | 
|---|
| 598 |     currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
 | 
|---|
| 599 | 
 | 
|---|
| 600 |     // generates: if ( when_cond ) { ... currBody ... }
 | 
|---|
| 601 |     if ( clause->when_cond )
 | 
|---|
| 602 |         body->push_back( 
 | 
|---|
| 603 |             new IfStmt( loc,
 | 
|---|
| 604 |                 new NameExpr( loc, data->whenName ),
 | 
|---|
| 605 |                 currBody
 | 
|---|
| 606 |             )
 | 
|---|
| 607 |         );
 | 
|---|
| 608 | }
 | 
|---|
| 609 | 
 | 
|---|
| 610 | // Used to generate a call to one of the select trait routines
 | 
|---|
| 611 | Expr * GenerateWaitUntilCore::genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName ) {
 | 
|---|
| 612 |     const CodeLocation & loc = clause->location;
 | 
|---|
| 613 |     return new UntypedExpr ( loc,
 | 
|---|
| 614 |         new NameExpr( loc, fnName ),
 | 
|---|
| 615 |         {
 | 
|---|
| 616 |             new NameExpr( loc, data->targetName ),
 | 
|---|
| 617 |             new NameExpr( loc, data->nodeName )
 | 
|---|
| 618 |         }
 | 
|---|
| 619 |     );
 | 
|---|
| 620 | }
 | 
|---|
| 621 | 
 | 
|---|
| 622 | // Generates:
 | 
|---|
| 623 | /* on_selected( target_1, node_1 ); ... corresponding body of target_1 ... 
 | 
|---|
| 624 | */
 | 
|---|
| 625 | CompoundStmt * GenerateWaitUntilCore::genStmtBlock( const WhenClause * clause, const ClauseData * data ) {
 | 
|---|
| 626 |     const CodeLocation & cLoc = clause->location;
 | 
|---|
| 627 |     return new CompoundStmt( cLoc,
 | 
|---|
| 628 |         {
 | 
|---|
| 629 |             new IfStmt( cLoc,
 | 
|---|
| 630 |                 genSelectTraitCall( clause, data, "on_selected" ),
 | 
|---|
| 631 |                 ast::deepCopy( clause->stmt )
 | 
|---|
| 632 |             )
 | 
|---|
| 633 |         }
 | 
|---|
| 634 |     );
 | 
|---|
| 635 | }
 | 
|---|
| 636 | 
 | 
|---|
| 637 | // this routine generates and returns the following
 | 
|---|
| 638 | /*for ( int i = 0; i < numClauses; i++ ) {
 | 
|---|
| 639 |     if ( predName(clause_statuses) ) break;
 | 
|---|
| 640 |     if (clause_statuses[i] == __SELECT_SAT) {
 | 
|---|
| 641 |         switch (i) {
 | 
|---|
| 642 |             case 0:
 | 
|---|
| 643 |                 try {
 | 
|---|
| 644 |                     on_selected( target1, clause1 );
 | 
|---|
| 645 |                     dotarget1stmt();
 | 
|---|
| 646 |                 }
 | 
|---|
| 647 |                 finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
 | 
|---|
| 648 |                 break;
 | 
|---|
| 649 |             ...
 | 
|---|
| 650 |             case N:
 | 
|---|
| 651 |                 ...
 | 
|---|
| 652 |                 break;
 | 
|---|
| 653 |         }
 | 
|---|
| 654 |     }
 | 
|---|
| 655 | }*/
 | 
|---|
| 656 | CompoundStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {
 | 
|---|
| 657 |     CompoundStmt * ifBody = new CompoundStmt( stmt->location );
 | 
|---|
| 658 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 659 | 
 | 
|---|
| 660 |     string switchLabel = namer_label.newName();
 | 
|---|
| 661 | 
 | 
|---|
| 662 |     /* generates:
 | 
|---|
| 663 |     switch (i) {
 | 
|---|
| 664 |         case 0:
 | 
|---|
| 665 |             try {
 | 
|---|
| 666 |                 on_selected( target1, clause1 );
 | 
|---|
| 667 |                 dotarget1stmt();
 | 
|---|
| 668 |             }
 | 
|---|
| 669 |             finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
 | 
|---|
| 670 |             break;
 | 
|---|
| 671 |             ...
 | 
|---|
| 672 |         case N:
 | 
|---|
| 673 |             ...
 | 
|---|
| 674 |             break;
 | 
|---|
| 675 |     }*/
 | 
|---|
| 676 |     std::vector<ptr<CaseClause>> switchCases;
 | 
|---|
| 677 |     int idx = 0;
 | 
|---|
| 678 |     for ( const auto & clause: stmt->clauses ) {
 | 
|---|
| 679 |         const CodeLocation & cLoc = clause->location;
 | 
|---|
| 680 |         switchCases.push_back(
 | 
|---|
| 681 |             new CaseClause( cLoc,
 | 
|---|
| 682 |                 ConstantExpr::from_int( cLoc, idx ),
 | 
|---|
| 683 |                 {
 | 
|---|
| 684 |                     new CompoundStmt( cLoc,
 | 
|---|
| 685 |                         {
 | 
|---|
| 686 |                             new ast::TryStmt( cLoc,
 | 
|---|
| 687 |                                 genStmtBlock( clause, clauseData.at(idx) ),
 | 
|---|
| 688 |                                 {},
 | 
|---|
| 689 |                                 new ast::FinallyClause( cLoc, 
 | 
|---|
| 690 |                                     new CompoundStmt( cLoc,
 | 
|---|
| 691 |                                         {
 | 
|---|
| 692 |                                             new ExprStmt( loc,
 | 
|---|
| 693 |                                                 new UntypedExpr ( loc,
 | 
|---|
| 694 |                                                     new NameExpr( loc, "?=?" ),
 | 
|---|
| 695 |                                                     {
 | 
|---|
| 696 |                                                         new UntypedExpr ( loc, 
 | 
|---|
| 697 |                                                             new NameExpr( loc, "?[?]" ),
 | 
|---|
| 698 |                                                             {
 | 
|---|
| 699 |                                                                 new NameExpr( loc, clauseData.at(0)->statusName ),
 | 
|---|
| 700 |                                                                 new NameExpr( loc, idxName )
 | 
|---|
| 701 |                                                             }
 | 
|---|
| 702 |                                                         ),
 | 
|---|
| 703 |                                                         new NameExpr( loc, "__SELECT_RUN" )
 | 
|---|
| 704 |                                                     }
 | 
|---|
| 705 |                                                 )
 | 
|---|
| 706 |                                             ),
 | 
|---|
| 707 |                                             new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
 | 
|---|
| 708 |                                         }
 | 
|---|
| 709 |                                     )
 | 
|---|
| 710 |                                 )
 | 
|---|
| 711 |                             ),
 | 
|---|
| 712 |                             new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
 | 
|---|
| 713 |                         }
 | 
|---|
| 714 |                     )
 | 
|---|
| 715 |                 }
 | 
|---|
| 716 |             )
 | 
|---|
| 717 |         );
 | 
|---|
| 718 |         idx++;
 | 
|---|
| 719 |     }
 | 
|---|
| 720 | 
 | 
|---|
| 721 |     ifBody->push_back(
 | 
|---|
| 722 |         new SwitchStmt( loc,
 | 
|---|
| 723 |             new NameExpr( loc, idxName ),
 | 
|---|
| 724 |             std::move( switchCases ),
 | 
|---|
| 725 |             { Label( loc, switchLabel ) }
 | 
|---|
| 726 |         )
 | 
|---|
| 727 |     );
 | 
|---|
| 728 | 
 | 
|---|
| 729 |     // gens:
 | 
|---|
| 730 |     // if (clause_statuses[i] == __SELECT_SAT) {
 | 
|---|
| 731 |     //      ... ifBody  ...
 | 
|---|
| 732 |     // }
 | 
|---|
| 733 |     IfStmt * ifSwitch = new IfStmt( loc,
 | 
|---|
| 734 |         new UntypedExpr ( loc,
 | 
|---|
| 735 |             new NameExpr( loc, "?==?" ),
 | 
|---|
| 736 |             {
 | 
|---|
| 737 |                 new UntypedExpr ( loc, 
 | 
|---|
| 738 |                     new NameExpr( loc, "?[?]" ),
 | 
|---|
| 739 |                     {
 | 
|---|
| 740 |                         new NameExpr( loc, clauseData.at(0)->statusName ),
 | 
|---|
| 741 |                         new NameExpr( loc, idxName )
 | 
|---|
| 742 |                     }
 | 
|---|
| 743 |                 ),
 | 
|---|
| 744 |                 new NameExpr( loc, "__SELECT_SAT" )
 | 
|---|
| 745 |             }
 | 
|---|
| 746 |         ),      // condition
 | 
|---|
| 747 |         ifBody  // body
 | 
|---|
| 748 |     );
 | 
|---|
| 749 | 
 | 
|---|
| 750 |     string forLabel = namer_label.newName();
 | 
|---|
| 751 | 
 | 
|---|
| 752 |     // we hoist init here so that this pass can happen after hoistdecls pass
 | 
|---|
| 753 |     return new CompoundStmt( loc,
 | 
|---|
| 754 |         {
 | 
|---|
| 755 |             new DeclStmt( loc,
 | 
|---|
| 756 |                 new ObjectDecl( loc,
 | 
|---|
| 757 |                     idxName,
 | 
|---|
| 758 |                     new BasicType( BasicType::Kind::SignedInt ),
 | 
|---|
| 759 |                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
 | 
|---|
| 760 |                 )
 | 
|---|
| 761 |             ),
 | 
|---|
| 762 |             new ForStmt( loc,
 | 
|---|
| 763 |                 {},  // inits
 | 
|---|
| 764 |                 new UntypedExpr ( loc,
 | 
|---|
| 765 |                     new NameExpr( loc, "?<?" ),
 | 
|---|
| 766 |                     {
 | 
|---|
| 767 |                         new NameExpr( loc, idxName ),
 | 
|---|
| 768 |                         ConstantExpr::from_int( loc, stmt->clauses.size() )
 | 
|---|
| 769 |                     }
 | 
|---|
| 770 |                 ),  // cond
 | 
|---|
| 771 |                 new UntypedExpr ( loc,
 | 
|---|
| 772 |                     new NameExpr( loc, "?++" ),
 | 
|---|
| 773 |                     { new NameExpr( loc, idxName ) }
 | 
|---|
| 774 |                 ),  // inc
 | 
|---|
| 775 |                 new CompoundStmt( loc,
 | 
|---|
| 776 |                     {
 | 
|---|
| 777 |                         new IfStmt( loc,
 | 
|---|
| 778 |                             new UntypedExpr ( loc,
 | 
|---|
| 779 |                                 new NameExpr( loc, predName ),
 | 
|---|
| 780 |                                 { new NameExpr( loc, clauseData.at(0)->statusName ) }
 | 
|---|
| 781 |                             ),
 | 
|---|
| 782 |                             new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
 | 
|---|
| 783 |                         ),
 | 
|---|
| 784 |                         ifSwitch
 | 
|---|
| 785 |                     }
 | 
|---|
| 786 |                 ),   // body
 | 
|---|
| 787 |                 { Label( loc, forLabel ) }
 | 
|---|
| 788 |             )
 | 
|---|
| 789 |         }
 | 
|---|
| 790 |     );
 | 
|---|
| 791 | }
 | 
|---|
| 792 | 
 | 
|---|
| 793 | // Generates: !is_full_sat_n() / !is_run_sat_n()
 | 
|---|
| 794 | Expr * genNotSatExpr( const WaitUntilStmt * stmt, string & satName, string & arrName ) {
 | 
|---|
| 795 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 796 |     return new UntypedExpr ( loc,
 | 
|---|
| 797 |         new NameExpr( loc, "!?" ),
 | 
|---|
| 798 |         {
 | 
|---|
| 799 |             new UntypedExpr ( loc,
 | 
|---|
| 800 |                 new NameExpr( loc, satName ),
 | 
|---|
| 801 |                 { new NameExpr( loc, arrName ) }
 | 
|---|
| 802 |             )
 | 
|---|
| 803 |         }
 | 
|---|
| 804 |     );
 | 
|---|
| 805 | }
 | 
|---|
| 806 | 
 | 
|---|
| 807 | // Generates the code needed for waituntils with an else ( ... )
 | 
|---|
| 808 | // Checks clauses once after registering for completion and runs them if completes
 | 
|---|
| 809 | // If not enough have run to satisfy predicate after one pass then the else is run
 | 
|---|
| 810 | Stmt * GenerateWaitUntilCore::genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData ) {
 | 
|---|
| 811 |     return new CompoundStmt( stmt->else_stmt->location,
 | 
|---|
| 812 |         {
 | 
|---|
| 813 |             genStatusCheckFor( stmt, clauseData, runName ),
 | 
|---|
| 814 |             new IfStmt( stmt->else_stmt->location,
 | 
|---|
| 815 |                 genNotSatExpr( stmt, runName, arrName ),
 | 
|---|
| 816 |                 ast::deepCopy( stmt->else_stmt )
 | 
|---|
| 817 |             )
 | 
|---|
| 818 |         }
 | 
|---|
| 819 |     );
 | 
|---|
| 820 | }
 | 
|---|
| 821 | 
 | 
|---|
| 822 | Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {
 | 
|---|
| 823 |     CompoundStmt * whileBody = new CompoundStmt( stmt->location );
 | 
|---|
| 824 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 825 | 
 | 
|---|
| 826 |     // generates: __CFA_maybe_park( &park_counter );
 | 
|---|
| 827 |     whileBody->push_back(
 | 
|---|
| 828 |         new ExprStmt( loc,
 | 
|---|
| 829 |             new UntypedExpr ( loc,
 | 
|---|
| 830 |                 new NameExpr( loc, "__CFA_maybe_park" ),
 | 
|---|
| 831 |                 { new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
 | 
|---|
| 832 |             )
 | 
|---|
| 833 |         )
 | 
|---|
| 834 |     );
 | 
|---|
| 835 | 
 | 
|---|
| 836 |     whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
 | 
|---|
| 837 | 
 | 
|---|
| 838 |     return new CompoundStmt( loc,
 | 
|---|
| 839 |         {
 | 
|---|
| 840 |             new WhileDoStmt( loc,
 | 
|---|
| 841 |                 genNotSatExpr( stmt, runName, arrName ),
 | 
|---|
| 842 |                 whileBody,  // body
 | 
|---|
| 843 |                 {}          // no inits
 | 
|---|
| 844 |             )
 | 
|---|
| 845 |         }
 | 
|---|
| 846 |     );
 | 
|---|
| 847 | }
 | 
|---|
| 848 | 
 | 
|---|
| 849 | // generates the following decls for each clause to ensure the target expr and when_cond is only evaluated once
 | 
|---|
| 850 | // typeof(target) & __clause_target_0 = target;
 | 
|---|
| 851 | // bool __when_cond_0 = when_cond; // only generated if when_cond defined
 | 
|---|
| 852 | // select_node clause1;
 | 
|---|
| 853 | void GenerateWaitUntilCore::genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName ) {
 | 
|---|
| 854 |     ClauseData * currClause;
 | 
|---|
| 855 |     for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
 | 
|---|
| 856 |         currClause = new ClauseData( i, statusName );
 | 
|---|
| 857 |         currClause->nodeName = namer_node.newName();
 | 
|---|
| 858 |         currClause->targetName = namer_target.newName();
 | 
|---|
| 859 |         currClause->whenName = namer_when.newName();
 | 
|---|
| 860 |         clauseData.push_back(currClause);
 | 
|---|
| 861 |         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
 | 
|---|
| 862 | 
 | 
|---|
| 863 |         // typeof(target) & __clause_target_0 = target;
 | 
|---|
| 864 |         body->push_back(
 | 
|---|
| 865 |             new DeclStmt( cLoc,
 | 
|---|
| 866 |                 new ObjectDecl( cLoc,
 | 
|---|
| 867 |                     currClause->targetName,
 | 
|---|
| 868 |                     new ReferenceType( 
 | 
|---|
| 869 |                         new TypeofType( new UntypedExpr( cLoc,
 | 
|---|
| 870 |                             new NameExpr( cLoc, "__CFA_select_get_type" ),
 | 
|---|
| 871 |                             { ast::deepCopy( stmt->clauses.at(i)->target ) }
 | 
|---|
| 872 |                         ))
 | 
|---|
| 873 |                     ),
 | 
|---|
| 874 |                     new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
 | 
|---|
| 875 |                 )
 | 
|---|
| 876 |             )
 | 
|---|
| 877 |         );
 | 
|---|
| 878 | 
 | 
|---|
| 879 |         // bool __when_cond_0 = when_cond; // only generated if when_cond defined
 | 
|---|
| 880 |         if ( stmt->clauses.at(i)->when_cond )
 | 
|---|
| 881 |             body->push_back(
 | 
|---|
| 882 |                 new DeclStmt( cLoc,
 | 
|---|
| 883 |                     new ObjectDecl( cLoc,
 | 
|---|
| 884 |                         currClause->whenName,
 | 
|---|
| 885 |                         new BasicType( BasicType::Kind::Bool ),
 | 
|---|
| 886 |                         new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
 | 
|---|
| 887 |                     )
 | 
|---|
| 888 |                 )
 | 
|---|
| 889 |             );
 | 
|---|
| 890 |         
 | 
|---|
| 891 |         // select_node clause1;
 | 
|---|
| 892 |         body->push_back(
 | 
|---|
| 893 |             new DeclStmt( cLoc,
 | 
|---|
| 894 |                 new ObjectDecl( cLoc,
 | 
|---|
| 895 |                     currClause->nodeName,
 | 
|---|
| 896 |                     new StructInstType( selectNodeDecl )
 | 
|---|
| 897 |                 )
 | 
|---|
| 898 |             )
 | 
|---|
| 899 |         );
 | 
|---|
| 900 |     }
 | 
|---|
| 901 | 
 | 
|---|
| 902 |     if ( stmt->else_stmt && stmt->else_cond ) {
 | 
|---|
| 903 |         body->push_back(
 | 
|---|
| 904 |             new DeclStmt( stmt->else_cond->location,
 | 
|---|
| 905 |                 new ObjectDecl( stmt->else_cond->location,
 | 
|---|
| 906 |                     elseWhenName,
 | 
|---|
| 907 |                     new BasicType( BasicType::Kind::Bool ),
 | 
|---|
| 908 |                     new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
 | 
|---|
| 909 |                 )
 | 
|---|
| 910 |             )
 | 
|---|
| 911 |         );
 | 
|---|
| 912 |     }
 | 
|---|
| 913 | }
 | 
|---|
| 914 | 
 | 
|---|
| 915 | /*
 | 
|---|
| 916 | if ( clause_status == &clause1 ) ... clause 1 body ...
 | 
|---|
| 917 | ...
 | 
|---|
| 918 | elif ( clause_status == &clausen ) ... clause n body ...
 | 
|---|
| 919 | */
 | 
|---|
| 920 | Stmt * GenerateWaitUntilCore::buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data ) {
 | 
|---|
| 921 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 922 | 
 | 
|---|
| 923 |     IfStmt * outerIf = nullptr;
 | 
|---|
| 924 |         IfStmt * lastIf = nullptr;
 | 
|---|
| 925 | 
 | 
|---|
| 926 |         //adds an if/elif clause for each select clause address to run the corresponding clause stmt
 | 
|---|
| 927 |         for ( long unsigned int i = 0; i < data.size(); i++ ) {
 | 
|---|
| 928 |         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
 | 
|---|
| 929 | 
 | 
|---|
| 930 |                 IfStmt * currIf = new IfStmt( cLoc,
 | 
|---|
| 931 |                         new UntypedExpr( cLoc, 
 | 
|---|
| 932 |                 new NameExpr( cLoc, "?==?" ), 
 | 
|---|
| 933 |                 {
 | 
|---|
| 934 |                     new NameExpr( cLoc, statusName ),
 | 
|---|
| 935 |                     new CastExpr( cLoc, 
 | 
|---|
| 936 |                         new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
 | 
|---|
| 937 |                         new BasicType( BasicType::Kind::LongUnsignedInt ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 938 |                     )
 | 
|---|
| 939 |                 }
 | 
|---|
| 940 |             ),
 | 
|---|
| 941 |             genStmtBlock( stmt->clauses.at(i), data.at(i) )
 | 
|---|
| 942 |                 );
 | 
|---|
| 943 |                 
 | 
|---|
| 944 |                 if ( i == 0 ) {
 | 
|---|
| 945 |                         outerIf = currIf;
 | 
|---|
| 946 |                 } else {
 | 
|---|
| 947 |                         // add ifstmt to else of previous stmt
 | 
|---|
| 948 |                         lastIf->else_ = currIf;
 | 
|---|
| 949 |                 }
 | 
|---|
| 950 | 
 | 
|---|
| 951 |                 lastIf = currIf;
 | 
|---|
| 952 |         }
 | 
|---|
| 953 | 
 | 
|---|
| 954 |     return new CompoundStmt( loc,
 | 
|---|
| 955 |         {
 | 
|---|
| 956 |             new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
 | 
|---|
| 957 |             outerIf
 | 
|---|
| 958 |         }
 | 
|---|
| 959 |     );
 | 
|---|
| 960 | }
 | 
|---|
| 961 | 
 | 
|---|
| 962 | Stmt * GenerateWaitUntilCore::recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName ) {
 | 
|---|
| 963 |     if ( idx == data.size() ) {   // base case, gen last else
 | 
|---|
| 964 |         const CodeLocation & cLoc = stmt->else_stmt->location;
 | 
|---|
| 965 |         if ( !stmt->else_stmt ) // normal non-else gen
 | 
|---|
| 966 |             return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
 | 
|---|
| 967 | 
 | 
|---|
| 968 |         Expr * raceFnCall = new UntypedExpr( stmt->location,
 | 
|---|
| 969 |             new NameExpr( stmt->location, "__select_node_else_race" ),
 | 
|---|
| 970 |             { new NameExpr( stmt->location, data.at(0)->nodeName ) }
 | 
|---|
| 971 |         );
 | 
|---|
| 972 | 
 | 
|---|
| 973 |         if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
 | 
|---|
| 974 |             return new IfStmt( cLoc,
 | 
|---|
| 975 |                 new LogicalExpr( cLoc,
 | 
|---|
| 976 |                     new CastExpr( cLoc,
 | 
|---|
| 977 |                         new NameExpr( cLoc, elseWhenName ),
 | 
|---|
| 978 |                         new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 979 |                     ),
 | 
|---|
| 980 |                     new CastExpr( cLoc,
 | 
|---|
| 981 |                         raceFnCall,
 | 
|---|
| 982 |                         new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 983 |                     ),
 | 
|---|
| 984 |                     LogicalFlag::AndExpr
 | 
|---|
| 985 |                 ),
 | 
|---|
| 986 |                 ast::deepCopy( stmt->else_stmt ),
 | 
|---|
| 987 |                 buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
 | 
|---|
| 988 |             );
 | 
|---|
| 989 |         }
 | 
|---|
| 990 | 
 | 
|---|
| 991 |         // return else conditional on race
 | 
|---|
| 992 |         return new IfStmt( stmt->else_stmt->location,
 | 
|---|
| 993 |             raceFnCall,
 | 
|---|
| 994 |             ast::deepCopy( stmt->else_stmt ),
 | 
|---|
| 995 |             buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
 | 
|---|
| 996 |         );
 | 
|---|
| 997 |     }
 | 
|---|
| 998 |     const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
 | 
|---|
| 999 | 
 | 
|---|
| 1000 |     Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
 | 
|---|
| 1001 |     Expr * ifCond;
 | 
|---|
| 1002 | 
 | 
|---|
| 1003 |     // If we have a when_cond make the register call conditional on it
 | 
|---|
| 1004 |     if ( stmt->clauses.at(idx)->when_cond ) {
 | 
|---|
| 1005 |         ifCond = new LogicalExpr( cLoc,
 | 
|---|
| 1006 |             new CastExpr( cLoc,
 | 
|---|
| 1007 |                 new NameExpr( cLoc, data.at(idx)->whenName ), 
 | 
|---|
| 1008 |                 new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1009 |             ),
 | 
|---|
| 1010 |             new CastExpr( cLoc,
 | 
|---|
| 1011 |                 baseCond,
 | 
|---|
| 1012 |                 new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1013 |             ),
 | 
|---|
| 1014 |             LogicalFlag::AndExpr
 | 
|---|
| 1015 |         );
 | 
|---|
| 1016 |     } else ifCond = baseCond;
 | 
|---|
| 1017 | 
 | 
|---|
| 1018 |     return new CompoundStmt( cLoc,
 | 
|---|
| 1019 |         {   // gens: setup_clause( clause1, &status, 0p );
 | 
|---|
| 1020 |             new ExprStmt( cLoc,
 | 
|---|
| 1021 |                 new UntypedExpr ( cLoc,
 | 
|---|
| 1022 |                     new NameExpr( cLoc, "setup_clause" ),
 | 
|---|
| 1023 |                     {
 | 
|---|
| 1024 |                         new NameExpr( cLoc, data.at(idx)->nodeName ),
 | 
|---|
| 1025 |                         new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
 | 
|---|
| 1026 |                         ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicType::Kind::SignedInt ) ) )
 | 
|---|
| 1027 |                     }
 | 
|---|
| 1028 |                 )
 | 
|---|
| 1029 |             ),
 | 
|---|
| 1030 |             // gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
 | 
|---|
| 1031 |             new IfStmt( cLoc,
 | 
|---|
| 1032 |                 ifCond,
 | 
|---|
| 1033 |                 genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
 | 
|---|
| 1034 |                 recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
 | 
|---|
| 1035 |             )
 | 
|---|
| 1036 |         }
 | 
|---|
| 1037 |     );
 | 
|---|
| 1038 | }
 | 
|---|
| 1039 | 
 | 
|---|
| 1040 | // This gens the special case of an all OR waituntil:
 | 
|---|
| 1041 | /* 
 | 
|---|
| 1042 | int status = 0;
 | 
|---|
| 1043 | 
 | 
|---|
| 1044 | typeof(target) & __clause_target_0 = target;
 | 
|---|
| 1045 | bool __when_cond_0 = when_cond; // only generated if when_cond defined
 | 
|---|
| 1046 | select_node clause1;
 | 
|---|
| 1047 | ... generate above for rest of clauses ...
 | 
|---|
| 1048 | 
 | 
|---|
| 1049 | try {
 | 
|---|
| 1050 |     setup_clause( clause1, &status, 0p );
 | 
|---|
| 1051 |     if ( __when_cond_0 && register_select( 1 ) ) {
 | 
|---|
| 1052 |         ... clause 1 body ...
 | 
|---|
| 1053 |     } else {
 | 
|---|
| 1054 |         ... recursively gen for each of n clauses ...
 | 
|---|
| 1055 |         setup_clause( clausen, &status, 0p );
 | 
|---|
| 1056 |         if ( __when_cond_n-1 && register_select( n ) ) {
 | 
|---|
| 1057 |             ... clause n body ...
 | 
|---|
| 1058 |         } else {
 | 
|---|
| 1059 |             if ( else_when ) ... else clause body ...
 | 
|---|
| 1060 |             else {
 | 
|---|
| 1061 |                 park();
 | 
|---|
| 1062 | 
 | 
|---|
| 1063 |                 // after winning the race and before unpark() clause_status is set to be the winning clause index + 1 
 | 
|---|
| 1064 |                 if ( clause_status == &clause1) ... clause 1 body ...
 | 
|---|
| 1065 |                 ...
 | 
|---|
| 1066 |                 elif ( clause_status == &clausen ) ... clause n body ...
 | 
|---|
| 1067 |             }
 | 
|---|
| 1068 |         }
 | 
|---|
| 1069 |     }
 | 
|---|
| 1070 | }
 | 
|---|
| 1071 | finally { 
 | 
|---|
| 1072 |     if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
 | 
|---|
| 1073 |     ...
 | 
|---|
| 1074 |     if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
 | 
|---|
| 1075 | }
 | 
|---|
| 1076 | */
 | 
|---|
| 1077 | Stmt * GenerateWaitUntilCore::genAllOr( const WaitUntilStmt * stmt ) {
 | 
|---|
| 1078 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 1079 |     string statusName = namer_status.newName();
 | 
|---|
| 1080 |     string elseWhenName = namer_when.newName();
 | 
|---|
| 1081 |     int numClauses = stmt->clauses.size();
 | 
|---|
| 1082 |     CompoundStmt * body = new CompoundStmt( stmt->location );
 | 
|---|
| 1083 | 
 | 
|---|
| 1084 |     // Generates: unsigned long int status = 0;
 | 
|---|
| 1085 |     body->push_back( new DeclStmt( loc,
 | 
|---|
| 1086 |         new ObjectDecl( loc,
 | 
|---|
| 1087 |             statusName,
 | 
|---|
| 1088 |             new BasicType( BasicType::Kind::LongUnsignedInt ),
 | 
|---|
| 1089 |             new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
 | 
|---|
| 1090 |         )
 | 
|---|
| 1091 |     ));
 | 
|---|
| 1092 | 
 | 
|---|
| 1093 |     vector<ClauseData *> clauseData;
 | 
|---|
| 1094 |     genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
 | 
|---|
| 1095 | 
 | 
|---|
| 1096 |     vector<int> whenIndices; // track which clauses have whens
 | 
|---|
| 1097 | 
 | 
|---|
| 1098 |     CompoundStmt * unregisters = new CompoundStmt( loc );
 | 
|---|
| 1099 |     Expr * ifCond;
 | 
|---|
| 1100 |     for ( int i = 0; i < numClauses; i++ ) {
 | 
|---|
| 1101 |         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
 | 
|---|
| 1102 |         // Gens: node.status != 0p
 | 
|---|
| 1103 |         UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc, 
 | 
|---|
| 1104 |             new NameExpr( cLoc, "?!=?" ), 
 | 
|---|
| 1105 |             {
 | 
|---|
| 1106 |                 ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicType::Kind::LongUnsignedInt ) ) ),
 | 
|---|
| 1107 |                 new UntypedExpr( cLoc, 
 | 
|---|
| 1108 |                     new NameExpr( cLoc, "__get_clause_status" ), 
 | 
|---|
| 1109 |                     { new NameExpr( cLoc, clauseData.at(i)->nodeName ) } 
 | 
|---|
| 1110 |                 ) 
 | 
|---|
| 1111 |             }
 | 
|---|
| 1112 |         );
 | 
|---|
| 1113 | 
 | 
|---|
| 1114 |         // If we have a when_cond make the unregister call conditional on it
 | 
|---|
| 1115 |         if ( stmt->clauses.at(i)->when_cond ) {
 | 
|---|
| 1116 |             whenIndices.push_back(i);
 | 
|---|
| 1117 |             ifCond = new LogicalExpr( cLoc,
 | 
|---|
| 1118 |                 new CastExpr( cLoc,
 | 
|---|
| 1119 |                     new NameExpr( cLoc, clauseData.at(i)->whenName ), 
 | 
|---|
| 1120 |                     new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1121 |                 ),
 | 
|---|
| 1122 |                 new CastExpr( cLoc,
 | 
|---|
| 1123 |                     statusPtrCheck,
 | 
|---|
| 1124 |                     new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1125 |                 ),
 | 
|---|
| 1126 |                 LogicalFlag::AndExpr
 | 
|---|
| 1127 |             );
 | 
|---|
| 1128 |         } else ifCond = statusPtrCheck;
 | 
|---|
| 1129 |         
 | 
|---|
| 1130 |         unregisters->push_back(
 | 
|---|
| 1131 |             new IfStmt( cLoc,
 | 
|---|
| 1132 |                 ifCond,
 | 
|---|
| 1133 |                 new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) ) 
 | 
|---|
| 1134 |             )
 | 
|---|
| 1135 |         );
 | 
|---|
| 1136 |     }
 | 
|---|
| 1137 | 
 | 
|---|
| 1138 |     if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
 | 
|---|
| 1139 |         body->push_back(
 | 
|---|
| 1140 |                 new ast::TryStmt( loc,
 | 
|---|
| 1141 |                 new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
 | 
|---|
| 1142 |                 {},
 | 
|---|
| 1143 |                 new ast::FinallyClause( loc, unregisters )
 | 
|---|
| 1144 |             )
 | 
|---|
| 1145 |         );
 | 
|---|
| 1146 |     } else { // If all clauses have whens, we need to skip the waituntil if they are all false
 | 
|---|
| 1147 |         Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
 | 
|---|
| 1148 |         Expr * lastExpr = outerIfCond;
 | 
|---|
| 1149 | 
 | 
|---|
| 1150 |         for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
 | 
|---|
| 1151 |             outerIfCond = new LogicalExpr( loc,
 | 
|---|
| 1152 |                 new CastExpr( loc,
 | 
|---|
| 1153 |                     new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ), 
 | 
|---|
| 1154 |                     new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1155 |                 ),
 | 
|---|
| 1156 |                 new CastExpr( loc,
 | 
|---|
| 1157 |                     lastExpr,
 | 
|---|
| 1158 |                     new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1159 |                 ),
 | 
|---|
| 1160 |                 LogicalFlag::OrExpr
 | 
|---|
| 1161 |             );
 | 
|---|
| 1162 |             lastExpr = outerIfCond;
 | 
|---|
| 1163 |         }
 | 
|---|
| 1164 | 
 | 
|---|
| 1165 |         body->push_back(
 | 
|---|
| 1166 |                 new ast::TryStmt( loc,
 | 
|---|
| 1167 |                 new CompoundStmt( loc, 
 | 
|---|
| 1168 |                     {
 | 
|---|
| 1169 |                         new IfStmt( loc,
 | 
|---|
| 1170 |                             outerIfCond,
 | 
|---|
| 1171 |                             recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
 | 
|---|
| 1172 |                         )
 | 
|---|
| 1173 |                     }
 | 
|---|
| 1174 |                 ),
 | 
|---|
| 1175 |                 {},
 | 
|---|
| 1176 |                 new ast::FinallyClause( loc, unregisters )
 | 
|---|
| 1177 |             )
 | 
|---|
| 1178 |         );
 | 
|---|
| 1179 |     }
 | 
|---|
| 1180 | 
 | 
|---|
| 1181 |     for ( ClauseData * datum : clauseData )
 | 
|---|
| 1182 |         delete datum;
 | 
|---|
| 1183 | 
 | 
|---|
| 1184 |     return body;
 | 
|---|
| 1185 | }
 | 
|---|
| 1186 | 
 | 
|---|
| 1187 | Stmt * GenerateWaitUntilCore::postvisit( const WaitUntilStmt * stmt ) {
 | 
|---|
| 1188 |     if ( !selectNodeDecl )
 | 
|---|
| 1189 |         SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
 | 
|---|
| 1190 | 
 | 
|---|
| 1191 |     // Prep clause tree to figure out how to set initial statuses
 | 
|---|
| 1192 |     // setTreeSizes( stmt->predicateTree );
 | 
|---|
| 1193 |     if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
 | 
|---|
| 1194 |         return genAllOr( stmt );
 | 
|---|
| 1195 | 
 | 
|---|
| 1196 |     CompoundStmt * tryBody = new CompoundStmt( stmt->location );
 | 
|---|
| 1197 |     CompoundStmt * body = new CompoundStmt( stmt->location );
 | 
|---|
| 1198 |     string statusArrName = namer_status.newName();
 | 
|---|
| 1199 |     string pCountName = namer_park.newName();
 | 
|---|
| 1200 |     string satName = namer_sat.newName();
 | 
|---|
| 1201 |     string runName = namer_run.newName();
 | 
|---|
| 1202 |     string elseWhenName = namer_when.newName();
 | 
|---|
| 1203 |     int numClauses = stmt->clauses.size();
 | 
|---|
| 1204 |     addPredicates( stmt, satName, runName );
 | 
|---|
| 1205 | 
 | 
|---|
| 1206 |     const CodeLocation & loc = stmt->location;
 | 
|---|
| 1207 | 
 | 
|---|
| 1208 |     // Generates: int park_counter = 0;
 | 
|---|
| 1209 |     body->push_back( new DeclStmt( loc,
 | 
|---|
| 1210 |         new ObjectDecl( loc,
 | 
|---|
| 1211 |             pCountName,
 | 
|---|
| 1212 |             new BasicType( BasicType::Kind::SignedInt ),
 | 
|---|
| 1213 |             new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
 | 
|---|
| 1214 |         )
 | 
|---|
| 1215 |     ));
 | 
|---|
| 1216 | 
 | 
|---|
| 1217 |     // Generates: int clause_statuses[3] = { 0 };
 | 
|---|
| 1218 |     body->push_back( new DeclStmt( loc,
 | 
|---|
| 1219 |         new ObjectDecl( loc,
 | 
|---|
| 1220 |             statusArrName,
 | 
|---|
| 1221 |             new ArrayType( new BasicType( BasicType::Kind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
 | 
|---|
| 1222 |             new ListInit( loc,
 | 
|---|
| 1223 |                 {
 | 
|---|
| 1224 |                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
 | 
|---|
| 1225 |                 }
 | 
|---|
| 1226 |             )
 | 
|---|
| 1227 |         )
 | 
|---|
| 1228 |     ));
 | 
|---|
| 1229 | 
 | 
|---|
| 1230 |     vector<ClauseData *> clauseData;
 | 
|---|
| 1231 |     genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
 | 
|---|
| 1232 | 
 | 
|---|
| 1233 |     vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
 | 
|---|
| 1234 |     vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
 | 
|---|
| 1235 | 
 | 
|---|
| 1236 |     collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
 | 
|---|
| 1237 | 
 | 
|---|
| 1238 |     // This is only needed for clauses that have AND as a parent and a when_cond defined
 | 
|---|
| 1239 |     // generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
 | 
|---|
| 1240 |     for ( int idx : andWhenClauses ) {
 | 
|---|
| 1241 |         const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
 | 
|---|
| 1242 |         body->push_back( 
 | 
|---|
| 1243 |             new IfStmt( cLoc,
 | 
|---|
| 1244 |                 new UntypedExpr ( cLoc,
 | 
|---|
| 1245 |                     new NameExpr( cLoc, "!?" ),
 | 
|---|
| 1246 |                     { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
 | 
|---|
| 1247 |                 ),  // IfStmt cond
 | 
|---|
| 1248 |                 new ExprStmt( cLoc,
 | 
|---|
| 1249 |                     new UntypedExpr ( cLoc,
 | 
|---|
| 1250 |                         new NameExpr( cLoc, "?=?" ),
 | 
|---|
| 1251 |                         {
 | 
|---|
| 1252 |                             new UntypedExpr ( cLoc, 
 | 
|---|
| 1253 |                                 new NameExpr( cLoc, "?[?]" ),
 | 
|---|
| 1254 |                                 {
 | 
|---|
| 1255 |                                     new NameExpr( cLoc, statusArrName ),
 | 
|---|
| 1256 |                                     ConstantExpr::from_int( cLoc, idx )
 | 
|---|
| 1257 |                                 }
 | 
|---|
| 1258 |                             ),
 | 
|---|
| 1259 |                             new NameExpr( cLoc, "__SELECT_RUN" )
 | 
|---|
| 1260 |                         }
 | 
|---|
| 1261 |                     )
 | 
|---|
| 1262 |                 )  // IfStmt then
 | 
|---|
| 1263 |             )
 | 
|---|
| 1264 |         );
 | 
|---|
| 1265 |     }
 | 
|---|
| 1266 | 
 | 
|---|
| 1267 |     // Only need to generate conditional initial state setting for ambiguous when clauses
 | 
|---|
| 1268 |     if ( !ambiguousClauses.empty() ) {
 | 
|---|
| 1269 |         body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
 | 
|---|
| 1270 |     }
 | 
|---|
| 1271 | 
 | 
|---|
| 1272 |     // generates the following for each clause:
 | 
|---|
| 1273 |     // setup_clause( clause1, &clause_statuses[0], &park_counter );
 | 
|---|
| 1274 |     // register_select(A, clause1);
 | 
|---|
| 1275 |     for ( int i = 0; i < numClauses; i++ ) {
 | 
|---|
| 1276 |         setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
 | 
|---|
| 1277 |     }
 | 
|---|
| 1278 | 
 | 
|---|
| 1279 |     // generate satisfy logic based on if there is an else clause and if it is conditional
 | 
|---|
| 1280 |     if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
 | 
|---|
| 1281 |         tryBody->push_back(
 | 
|---|
| 1282 |             new IfStmt( stmt->else_cond->location,
 | 
|---|
| 1283 |                 new NameExpr( stmt->else_cond->location, elseWhenName ),
 | 
|---|
| 1284 |                 genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
 | 
|---|
| 1285 |                 genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
 | 
|---|
| 1286 |             )
 | 
|---|
| 1287 |         );
 | 
|---|
| 1288 |     } else if ( !stmt->else_stmt ) { // normal gen
 | 
|---|
| 1289 |         tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
 | 
|---|
| 1290 |     } else { // generate just else
 | 
|---|
| 1291 |         tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
 | 
|---|
| 1292 |     }
 | 
|---|
| 1293 | 
 | 
|---|
| 1294 |     // Collection of unregister calls on resources to be put in finally clause
 | 
|---|
| 1295 |     // for each clause: 
 | 
|---|
| 1296 |     // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
 | 
|---|
| 1297 |     // OR if when( ... ) defined on resource
 | 
|---|
| 1298 |     // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
 | 
|---|
| 1299 |     CompoundStmt * unregisters = new CompoundStmt( loc );
 | 
|---|
| 1300 | 
 | 
|---|
| 1301 |     Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
 | 
|---|
| 1302 |     for ( int i = 0; i < numClauses; i++ ) {
 | 
|---|
| 1303 |         const CodeLocation & cLoc = stmt->clauses.at(i)->location;
 | 
|---|
| 1304 | 
 | 
|---|
| 1305 |         // Generates: !__CFA_has_clause_run( clause_statuses[i] )
 | 
|---|
| 1306 |         statusExpr = new UntypedExpr ( cLoc,
 | 
|---|
| 1307 |             new NameExpr( cLoc, "!?" ),
 | 
|---|
| 1308 |             {
 | 
|---|
| 1309 |                 new UntypedExpr ( cLoc, 
 | 
|---|
| 1310 |                     new NameExpr( cLoc, "__CFA_has_clause_run" ),
 | 
|---|
| 1311 |                     {
 | 
|---|
| 1312 |                         genArrAccessExpr( cLoc, i, statusArrName )
 | 
|---|
| 1313 |                     }
 | 
|---|
| 1314 |                 )
 | 
|---|
| 1315 |             }
 | 
|---|
| 1316 |         );
 | 
|---|
| 1317 |         
 | 
|---|
| 1318 |         // Generates:
 | 
|---|
| 1319 |         // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
 | 
|---|
| 1320 |         statusExpr = new LogicalExpr( cLoc,
 | 
|---|
| 1321 |             new CastExpr( cLoc,
 | 
|---|
| 1322 |                 statusExpr, 
 | 
|---|
| 1323 |                 new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1324 |             ),
 | 
|---|
| 1325 |             new CastExpr( cLoc,
 | 
|---|
| 1326 |                 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
 | 
|---|
| 1327 |                 new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1328 |             ),
 | 
|---|
| 1329 |             LogicalFlag::AndExpr
 | 
|---|
| 1330 |         );
 | 
|---|
| 1331 |         
 | 
|---|
| 1332 |         // if when cond defined generates:
 | 
|---|
| 1333 |         // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
 | 
|---|
| 1334 |         if ( stmt->clauses.at(i)->when_cond )
 | 
|---|
| 1335 |             statusExpr = new LogicalExpr( cLoc,
 | 
|---|
| 1336 |                 new CastExpr( cLoc,
 | 
|---|
| 1337 |                     new NameExpr( cLoc, clauseData.at(i)->whenName ), 
 | 
|---|
| 1338 |                     new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1339 |                 ),
 | 
|---|
| 1340 |                 new CastExpr( cLoc,
 | 
|---|
| 1341 |                     statusExpr,
 | 
|---|
| 1342 |                     new BasicType( BasicType::Kind::Bool ), GeneratedFlag::ExplicitCast 
 | 
|---|
| 1343 |                 ),
 | 
|---|
| 1344 |                 LogicalFlag::AndExpr
 | 
|---|
| 1345 |             );
 | 
|---|
| 1346 | 
 | 
|---|
| 1347 |         // generates:
 | 
|---|
| 1348 |         // if ( statusExpr ) { ... clausei stmt ... }
 | 
|---|
| 1349 |         unregisters->push_back( 
 | 
|---|
| 1350 |             new IfStmt( cLoc,
 | 
|---|
| 1351 |                 statusExpr,
 | 
|---|
| 1352 |                 new CompoundStmt( cLoc,
 | 
|---|
| 1353 |                     {
 | 
|---|
| 1354 |                         new IfStmt( cLoc,
 | 
|---|
| 1355 |                             genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
 | 
|---|
| 1356 |                             ast::deepCopy( stmt->clauses.at(i)->stmt )
 | 
|---|
| 1357 |                         )
 | 
|---|
| 1358 |                     }
 | 
|---|
| 1359 |                 )
 | 
|---|
| 1360 |             )
 | 
|---|
| 1361 |         );
 | 
|---|
| 1362 | 
 | 
|---|
| 1363 |         // // generates:
 | 
|---|
| 1364 |         // // if ( statusExpr ) { ... clausei stmt ... }
 | 
|---|
| 1365 |         // unregisters->push_back( 
 | 
|---|
| 1366 |         //     new IfStmt( cLoc,
 | 
|---|
| 1367 |         //         statusExpr,
 | 
|---|
| 1368 |         //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
 | 
|---|
| 1369 |         //     )
 | 
|---|
| 1370 |         // );
 | 
|---|
| 1371 |     }
 | 
|---|
| 1372 | 
 | 
|---|
| 1373 |     body->push_back( 
 | 
|---|
| 1374 |         new ast::TryStmt(
 | 
|---|
| 1375 |             loc,
 | 
|---|
| 1376 |             tryBody,
 | 
|---|
| 1377 |             {},
 | 
|---|
| 1378 |             new ast::FinallyClause( loc, unregisters )
 | 
|---|
| 1379 |         )
 | 
|---|
| 1380 |     );
 | 
|---|
| 1381 | 
 | 
|---|
| 1382 |     for ( ClauseData * datum : clauseData )
 | 
|---|
| 1383 |         delete datum;
 | 
|---|
| 1384 | 
 | 
|---|
| 1385 |     return body;
 | 
|---|
| 1386 | }
 | 
|---|
| 1387 | 
 | 
|---|
| 1388 | // To add the predicates at global scope we need to do it in a second pass
 | 
|---|
| 1389 | // Predicates are added after "struct select_node { ... };"
 | 
|---|
| 1390 | class AddPredicateDecls final : public WithDeclsToAdd<> {
 | 
|---|
| 1391 |     vector<FunctionDecl *> & satFns;
 | 
|---|
| 1392 |     const StructDecl * selectNodeDecl = nullptr;
 | 
|---|
| 1393 | 
 | 
|---|
| 1394 |   public:
 | 
|---|
| 1395 |     void previsit( const StructDecl * decl ) {
 | 
|---|
| 1396 |         if ( !decl->body ) {
 | 
|---|
| 1397 |             return;
 | 
|---|
| 1398 |         } else if ( "select_node" == decl->name ) {
 | 
|---|
| 1399 |             assert( !selectNodeDecl );
 | 
|---|
| 1400 |             selectNodeDecl = decl;
 | 
|---|
| 1401 |             for ( FunctionDecl * fn : satFns )
 | 
|---|
| 1402 |                 declsToAddAfter.push_back(fn);            
 | 
|---|
| 1403 |         }
 | 
|---|
| 1404 |     }
 | 
|---|
| 1405 |     AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
 | 
|---|
| 1406 | };
 | 
|---|
| 1407 | 
 | 
|---|
| 1408 | void generateWaitUntil( TranslationUnit & translationUnit ) {
 | 
|---|
| 1409 |     vector<FunctionDecl *> satFns;
 | 
|---|
| 1410 |         Pass<GenerateWaitUntilCore>::run( translationUnit, satFns );
 | 
|---|
| 1411 |     Pass<AddPredicateDecls>::run( translationUnit, satFns );
 | 
|---|
| 1412 | }
 | 
|---|
| 1413 | 
 | 
|---|
| 1414 | } // namespace Concurrency
 | 
|---|
| 1415 | 
 | 
|---|
| 1416 | // Local Variables: //
 | 
|---|
| 1417 | // tab-width: 4 //
 | 
|---|
| 1418 | // mode: c++ //
 | 
|---|
| 1419 | // compile-command: "make install" //
 | 
|---|
| 1420 | // End: //
 | 
|---|