Changeset 2e9b59b for src/Concurrency/KeywordsNew.cpp
- Timestamp:
- Apr 19, 2022, 3:00:04 PM (3 years ago)
- Branches:
- ADT, ast-experimental, master, pthread-emulation, qualifiedEnum
- Children:
- 5b84a321
- Parents:
- ba897d21 (diff), bb7c77d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Concurrency/KeywordsNew.cpp
rba897d21 r2e9b59b 10 10 // Created On : Tue Nov 16 9:53:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Dec 1 11:24:00 202113 // Update Count : 112 // Last Modified On : Fri Mar 11 10:40:00 2022 13 // Update Count : 2 14 14 // 15 16 #include <iostream> 15 17 16 18 #include "Concurrency/Keywords.h" … … 18 20 #include "AST/Copy.hpp" 19 21 #include "AST/Decl.hpp" 22 #include "AST/Expr.hpp" 20 23 #include "AST/Pass.hpp" 21 24 #include "AST/Stmt.hpp" 25 #include "AST/DeclReplacer.hpp" 22 26 #include "AST/TranslationUnit.hpp" 23 27 #include "CodeGen/OperatorTable.h" 28 #include "Common/Examine.h" 24 29 #include "Common/utility.h" 30 #include "Common/UniqueName.h" 31 #include "ControlStruct/LabelGeneratorNew.hpp" 25 32 #include "InitTweak/InitTweak.h" 33 #include "Virtual/Tables.h" 26 34 27 35 namespace Concurrency { … … 29 37 namespace { 30 38 31 inline static bool isThread( const ast::DeclWithType * decl ) { 39 // -------------------------------------------------------------------------- 40 // Loose Helper Functions: 41 42 /// Detect threads constructed with the keyword thread. 43 bool isThread( const ast::DeclWithType * decl ) { 32 44 auto baseType = decl->get_type()->stripDeclarator(); 33 45 auto instType = dynamic_cast<const ast::StructInstType *>( baseType ); … … 36 48 } 37 49 50 /// Get the virtual type id if given a type name. 51 std::string typeIdType( std::string const & exception_name ) { 52 return exception_name.empty() ? std::string() 53 : Virtual::typeIdType( exception_name ); 54 } 55 56 /// Get the vtable type name if given a type name. 57 std::string vtableTypeName( std::string const & exception_name ) { 58 return exception_name.empty() ? std::string() 59 : Virtual::vtableTypeName( exception_name ); 60 } 61 62 static ast::Type * mutate_under_references( ast::ptr<ast::Type>& type ) { 63 ast::Type * mutType = type.get_and_mutate(); 64 for ( ast::ReferenceType * mutRef 65 ; (mutRef = dynamic_cast<ast::ReferenceType *>( mutType )) 66 ; mutType = mutRef->base.get_and_mutate() ); 67 return mutType; 68 } 69 70 // Describe that it adds the generic parameters and the uses of the generic 71 // parameters on the function and first "this" argument. 72 ast::FunctionDecl * fixupGenerics( 73 const ast::FunctionDecl * func, const ast::StructDecl * decl ) { 74 const CodeLocation & location = decl->location; 75 // We have to update both the declaration 76 auto mutFunc = ast::mutate( func ); 77 auto mutType = mutFunc->type.get_and_mutate(); 78 79 if ( decl->params.empty() ) { 80 return mutFunc; 81 } 82 83 assert( 0 != mutFunc->params.size() ); 84 assert( 0 != mutType->params.size() ); 85 86 // Add the "forall" clause information. 87 for ( const ast::ptr<ast::TypeDecl> & typeParam : decl->params ) { 88 auto typeDecl = ast::deepCopy( typeParam ); 89 mutFunc->type_params.push_back( typeDecl ); 90 mutType->forall.push_back( new ast::TypeInstType( typeDecl ) ); 91 for ( auto & assertion : typeDecl->assertions ) { 92 mutFunc->assertions.push_back( assertion ); 93 mutType->assertions.emplace_back( 94 new ast::VariableExpr( location, assertion ) ); 95 } 96 typeDecl->assertions.clear(); 97 } 98 99 // Even chain_mutate is not powerful enough for this: 100 ast::ptr<ast::Type>& paramType = strict_dynamic_cast<ast::ObjectDecl *>( 101 mutFunc->params[0].get_and_mutate() )->type; 102 auto paramTypeInst = strict_dynamic_cast<ast::StructInstType *>( 103 mutate_under_references( paramType ) ); 104 auto typeParamInst = strict_dynamic_cast<ast::StructInstType *>( 105 mutate_under_references( mutType->params[0] ) ); 106 107 for ( const ast::ptr<ast::TypeDecl> & typeDecl : mutFunc->type_params ) { 108 paramTypeInst->params.push_back( 109 new ast::TypeExpr( location, new ast::TypeInstType( typeDecl ) ) ); 110 typeParamInst->params.push_back( 111 new ast::TypeExpr( location, new ast::TypeInstType( typeDecl ) ) ); 112 } 113 114 return mutFunc; 115 } 116 38 117 // -------------------------------------------------------------------------- 39 struct MutexKeyword final { 118 struct ConcurrentSueKeyword : public ast::WithDeclsToAdd<> { 119 ConcurrentSueKeyword( 120 std::string&& type_name, std::string&& field_name, 121 std::string&& getter_name, std::string&& context_error, 122 std::string&& exception_name, 123 bool needs_main, ast::AggregateDecl::Aggregate cast_target 124 ) : 125 type_name( type_name ), field_name( field_name ), 126 getter_name( getter_name ), context_error( context_error ), 127 exception_name( exception_name ), 128 typeid_name( typeIdType( exception_name ) ), 129 vtable_name( vtableTypeName( exception_name ) ), 130 needs_main( needs_main ), cast_target( cast_target ) 131 {} 132 133 virtual ~ConcurrentSueKeyword() {} 134 135 const ast::Decl * postvisit( const ast::StructDecl * decl ); 136 const ast::DeclWithType * postvisit( const ast::FunctionDecl * decl ); 137 const ast::Expr * postvisit( const ast::KeywordCastExpr * expr ); 138 139 struct StructAndField { 140 const ast::StructDecl * decl; 141 const ast::ObjectDecl * field; 142 }; 143 144 const ast::StructDecl * handleStruct( const ast::StructDecl * ); 145 void handleMain( const ast::FunctionDecl *, const ast::StructInstType * ); 146 void addTypeId( const ast::StructDecl * ); 147 void addVtableForward( const ast::StructDecl * ); 148 const ast::FunctionDecl * forwardDeclare( const ast::StructDecl * ); 149 StructAndField addField( const ast::StructDecl * ); 150 void addGetRoutines( const ast::ObjectDecl *, const ast::FunctionDecl * ); 151 void addLockUnlockRoutines( const ast::StructDecl * ); 152 153 private: 154 const std::string type_name; 155 const std::string field_name; 156 const std::string getter_name; 157 const std::string context_error; 158 const std::string exception_name; 159 const std::string typeid_name; 160 const std::string vtable_name; 161 const bool needs_main; 162 const ast::AggregateDecl::Aggregate cast_target; 163 164 const ast::StructDecl * type_decl = nullptr; 165 const ast::FunctionDecl * dtor_decl = nullptr; 166 const ast::StructDecl * except_decl = nullptr; 167 const ast::StructDecl * typeid_decl = nullptr; 168 const ast::StructDecl * vtable_decl = nullptr; 169 170 }; 171 172 // Handles thread type declarations: 173 // 174 // thread Mythread { struct MyThread { 175 // int data; int data; 176 // a_struct_t more_data; a_struct_t more_data; 177 // => thread$ __thrd_d; 178 // }; }; 179 // static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; } 180 // 181 struct ThreadKeyword final : public ConcurrentSueKeyword { 182 ThreadKeyword() : ConcurrentSueKeyword( 183 "thread$", 184 "__thrd", 185 "get_thread", 186 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n", 187 "ThreadCancelled", 188 true, 189 ast::AggregateDecl::Thread ) 190 {} 191 192 virtual ~ThreadKeyword() {} 193 }; 194 195 // Handles coroutine type declarations: 196 // 197 // coroutine MyCoroutine { struct MyCoroutine { 198 // int data; int data; 199 // a_struct_t more_data; a_struct_t more_data; 200 // => coroutine$ __cor_d; 201 // }; }; 202 // static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; } 203 // 204 struct CoroutineKeyword final : public ConcurrentSueKeyword { 205 CoroutineKeyword() : ConcurrentSueKeyword( 206 "coroutine$", 207 "__cor", 208 "get_coroutine", 209 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n", 210 "CoroutineCancelled", 211 true, 212 ast::AggregateDecl::Coroutine ) 213 {} 214 215 virtual ~CoroutineKeyword() {} 216 }; 217 218 // Handles monitor type declarations: 219 // 220 // monitor MyMonitor { struct MyMonitor { 221 // int data; int data; 222 // a_struct_t more_data; a_struct_t more_data; 223 // => monitor$ __mon_d; 224 // }; }; 225 // static inline monitor$ * get_coroutine( MyMonitor * this ) { 226 // return &this->__cor_d; 227 // } 228 // void lock(MyMonitor & this) { 229 // lock(get_monitor(this)); 230 // } 231 // void unlock(MyMonitor & this) { 232 // unlock(get_monitor(this)); 233 // } 234 // 235 struct MonitorKeyword final : public ConcurrentSueKeyword { 236 MonitorKeyword() : ConcurrentSueKeyword( 237 "monitor$", 238 "__mon", 239 "get_monitor", 240 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n", 241 "", 242 false, 243 ast::AggregateDecl::Monitor ) 244 {} 245 246 virtual ~MonitorKeyword() {} 247 }; 248 249 // Handles generator type declarations: 250 // 251 // generator MyGenerator { struct MyGenerator { 252 // int data; int data; 253 // a_struct_t more_data; a_struct_t more_data; 254 // => int __generator_state; 255 // }; }; 256 // 257 struct GeneratorKeyword final : public ConcurrentSueKeyword { 258 GeneratorKeyword() : ConcurrentSueKeyword( 259 "generator$", 260 "__generator_state", 261 "get_generator", 262 "Unable to find builtin type generator$\n", 263 "", 264 true, 265 ast::AggregateDecl::Generator ) 266 {} 267 268 virtual ~GeneratorKeyword() {} 269 }; 270 271 const ast::Decl * ConcurrentSueKeyword::postvisit( 272 const ast::StructDecl * decl ) { 273 if ( !decl->body ) { 274 return decl; 275 } else if ( cast_target == decl->kind ) { 276 return handleStruct( decl ); 277 } else if ( type_name == decl->name ) { 278 assert( !type_decl ); 279 type_decl = decl; 280 } else if ( exception_name == decl->name ) { 281 assert( !except_decl ); 282 except_decl = decl; 283 } else if ( typeid_name == decl->name ) { 284 assert( !typeid_decl ); 285 typeid_decl = decl; 286 } else if ( vtable_name == decl->name ) { 287 assert( !vtable_decl ); 288 vtable_decl = decl; 289 } 290 return decl; 291 } 292 293 // Try to get the full definition, but raise an error on conflicts. 294 const ast::FunctionDecl * getDefinition( 295 const ast::FunctionDecl * old_decl, 296 const ast::FunctionDecl * new_decl ) { 297 if ( !new_decl->stmts ) { 298 return old_decl; 299 } else if ( !old_decl->stmts ) { 300 return new_decl; 301 } else { 302 assert( !old_decl->stmts || !new_decl->stmts ); 303 return nullptr; 304 } 305 } 306 307 const ast::DeclWithType * ConcurrentSueKeyword::postvisit( 308 const ast::FunctionDecl * decl ) { 309 if ( type_decl && isDestructorFor( decl, type_decl ) ) { 310 // Check for forward declarations, try to get the full definition. 311 dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl; 312 } else if ( !vtable_name.empty() && decl->has_body() ) { 313 if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) { 314 if ( !vtable_decl ) { 315 SemanticError( decl, context_error ); 316 } 317 // Should be safe because of isMainFor. 318 const ast::StructInstType * struct_type = 319 static_cast<const ast::StructInstType *>( 320 static_cast<const ast::ReferenceType *>( 321 param->get_type() )->base.get() ); 322 323 handleMain( decl, struct_type ); 324 } 325 } 326 return decl; 327 } 328 329 const ast::Expr * ConcurrentSueKeyword::postvisit( 330 const ast::KeywordCastExpr * expr ) { 331 if ( cast_target == expr->target ) { 332 // Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc. 333 if ( !type_decl || !dtor_decl ) { 334 SemanticError( expr, context_error ); 335 } 336 assert( nullptr == expr->result ); 337 auto cast = ast::mutate( expr ); 338 cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) ); 339 cast->concrete_target.field = field_name; 340 cast->concrete_target.getter = getter_name; 341 return cast; 342 } 343 return expr; 344 } 345 346 const ast::StructDecl * ConcurrentSueKeyword::handleStruct( 347 const ast::StructDecl * decl ) { 348 assert( decl->body ); 349 350 if ( !type_decl || !dtor_decl ) { 351 SemanticError( decl, context_error ); 352 } 353 354 if ( !exception_name.empty() ) { 355 if( !typeid_decl || !vtable_decl ) { 356 SemanticError( decl, context_error ); 357 } 358 addTypeId( decl ); 359 addVtableForward( decl ); 360 } 361 362 const ast::FunctionDecl * func = forwardDeclare( decl ); 363 StructAndField addFieldRet = addField( decl ); 364 decl = addFieldRet.decl; 365 const ast::ObjectDecl * field = addFieldRet.field; 366 367 addGetRoutines( field, func ); 368 // Add routines to monitors for use by mutex stmt. 369 if ( ast::AggregateDecl::Monitor == cast_target ) { 370 addLockUnlockRoutines( decl ); 371 } 372 373 return decl; 374 } 375 376 void ConcurrentSueKeyword::handleMain( 377 const ast::FunctionDecl * decl, const ast::StructInstType * type ) { 378 assert( vtable_decl ); 379 assert( except_decl ); 380 381 const CodeLocation & location = decl->location; 382 383 std::vector<ast::ptr<ast::Expr>> poly_args = { 384 new ast::TypeExpr( location, type ), 385 }; 386 ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance( 387 location, 388 "_default_vtable_object_declaration", 389 new ast::StructInstType( vtable_decl, copy( poly_args ) ), 390 type, 391 nullptr 392 ); 393 declsToAddAfter.push_back( vtable_object ); 394 declsToAddAfter.push_back( 395 new ast::ObjectDecl( 396 location, 397 Virtual::concurrentDefaultVTableName(), 398 new ast::ReferenceType( vtable_object->type, ast::CV::Const ), 399 new ast::SingleInit( location, 400 new ast::VariableExpr( location, vtable_object ) ), 401 ast::Storage::Classes(), 402 ast::Linkage::Cforall 403 ) 404 ); 405 declsToAddAfter.push_back( Virtual::makeGetExceptionFunction( 406 location, 407 vtable_object, 408 new ast::StructInstType( except_decl, copy( poly_args ) ) 409 ) ); 410 } 411 412 void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) { 413 assert( typeid_decl ); 414 const CodeLocation & location = decl->location; 415 416 ast::StructInstType * typeid_type = 417 new ast::StructInstType( typeid_decl, ast::CV::Const ); 418 typeid_type->params.push_back( 419 new ast::TypeExpr( location, new ast::StructInstType( decl ) ) ); 420 declsToAddBefore.push_back( 421 Virtual::makeTypeIdInstance( location, typeid_type ) ); 422 // If the typeid_type is going to be kept, the other reference will have 423 // been made by now, but we also get to avoid extra mutates. 424 ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type; 425 } 426 427 void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) { 428 assert( vtable_decl ); 429 const CodeLocation& location = decl->location; 430 431 std::vector<ast::ptr<ast::Expr>> poly_args = { 432 new ast::TypeExpr( location, new ast::StructInstType( decl ) ), 433 }; 434 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 435 location, 436 new ast::StructInstType( vtable_decl, copy( poly_args ) ), 437 new ast::StructInstType( except_decl, copy( poly_args ) ) 438 ) ); 439 ast::ObjectDecl * vtable_object = Virtual::makeVtableForward( 440 location, 441 "_default_vtable_object_declaration", 442 new ast::StructInstType( vtable_decl, std::move( poly_args ) ) 443 ); 444 declsToAddBefore.push_back( vtable_object ); 445 declsToAddBefore.push_back( 446 new ast::ObjectDecl( 447 location, 448 Virtual::concurrentDefaultVTableName(), 449 new ast::ReferenceType( vtable_object->type, ast::CV::Const ), 450 nullptr, 451 ast::Storage::Extern, 452 ast::Linkage::Cforall 453 ) 454 ); 455 } 456 457 const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare( 458 const ast::StructDecl * decl ) { 459 const CodeLocation & location = decl->location; 460 461 ast::StructDecl * forward = ast::deepCopy( decl ); 462 { 463 // If removing members makes ref-count go to zero, do not free. 464 ast::ptr<ast::StructDecl> forward_ptr = forward; 465 forward->body = false; 466 forward->members.clear(); 467 forward_ptr.release(); 468 } 469 470 ast::ObjectDecl * this_decl = new ast::ObjectDecl( 471 location, 472 "this", 473 new ast::ReferenceType( new ast::StructInstType( decl ) ), 474 nullptr, 475 ast::Storage::Classes(), 476 ast::Linkage::Cforall 477 ); 478 479 ast::ObjectDecl * ret_decl = new ast::ObjectDecl( 480 location, 481 "ret", 482 new ast::PointerType( new ast::StructInstType( type_decl ) ), 483 nullptr, 484 ast::Storage::Classes(), 485 ast::Linkage::Cforall 486 ); 487 488 ast::FunctionDecl * get_decl = new ast::FunctionDecl( 489 location, 490 getter_name, 491 {}, // forall 492 { this_decl }, // params 493 { ret_decl }, // returns 494 nullptr, // stmts 495 ast::Storage::Static, 496 ast::Linkage::Cforall, 497 { new ast::Attribute( "const" ) }, 498 ast::Function::Inline 499 ); 500 get_decl = fixupGenerics( get_decl, decl ); 501 502 ast::FunctionDecl * main_decl = nullptr; 503 if ( needs_main ) { 504 // `this_decl` is copied here because the original was used above. 505 main_decl = new ast::FunctionDecl( 506 location, 507 "main", 508 {}, 509 { ast::deepCopy( this_decl ) }, 510 {}, 511 nullptr, 512 ast::Storage::Classes(), 513 ast::Linkage::Cforall 514 ); 515 main_decl = fixupGenerics( main_decl, decl ); 516 } 517 518 declsToAddBefore.push_back( forward ); 519 if ( needs_main ) declsToAddBefore.push_back( main_decl ); 520 declsToAddBefore.push_back( get_decl ); 521 522 return get_decl; 523 } 524 525 ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField( 526 const ast::StructDecl * decl ) { 527 const CodeLocation & location = decl->location; 528 529 ast::ObjectDecl * field = new ast::ObjectDecl( 530 location, 531 field_name, 532 new ast::StructInstType( type_decl ), 533 nullptr, 534 ast::Storage::Classes(), 535 ast::Linkage::Cforall 536 ); 537 538 auto mutDecl = ast::mutate( decl ); 539 mutDecl->members.push_back( field ); 540 541 return {mutDecl, field}; 542 } 543 544 void ConcurrentSueKeyword::addGetRoutines( 545 const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) { 546 // Say it is generated at the "same" places as the forward declaration. 547 const CodeLocation & location = forward->location; 548 549 const ast::DeclWithType * param = forward->params.front(); 550 ast::Stmt * stmt = new ast::ReturnStmt( location, 551 new ast::AddressExpr( location, 552 new ast::MemberExpr( location, 553 field, 554 new ast::CastExpr( location, 555 new ast::VariableExpr( location, param ), 556 ast::deepCopy( param->get_type()->stripReferences() ), 557 ast::ExplicitCast 558 ) 559 ) 560 ) 561 ); 562 563 ast::FunctionDecl * decl = ast::deepCopy( forward ); 564 decl->stmts = new ast::CompoundStmt( location, { stmt } ); 565 declsToAddAfter.push_back( decl ); 566 } 567 568 void ConcurrentSueKeyword::addLockUnlockRoutines( 569 const ast::StructDecl * decl ) { 570 // This should only be used on monitors. 571 assert( ast::AggregateDecl::Monitor == cast_target ); 572 573 const CodeLocation & location = decl->location; 574 575 // The parameter for both routines. 576 ast::ObjectDecl * this_decl = new ast::ObjectDecl( 577 location, 578 "this", 579 new ast::ReferenceType( new ast::StructInstType( decl ) ), 580 nullptr, 581 ast::Storage::Classes(), 582 ast::Linkage::Cforall 583 ); 584 585 ast::FunctionDecl * lock_decl = new ast::FunctionDecl( 586 location, 587 "lock", 588 { /* forall */ }, 589 { 590 // Copy the declaration of this. 591 ast::deepCopy( this_decl ), 592 }, 593 { /* returns */ }, 594 nullptr, 595 ast::Storage::Static, 596 ast::Linkage::Cforall, 597 { /* attributes */ }, 598 ast::Function::Inline 599 ); 600 lock_decl = fixupGenerics( lock_decl, decl ); 601 602 lock_decl->stmts = new ast::CompoundStmt( location, { 603 new ast::ExprStmt( location, 604 new ast::UntypedExpr( location, 605 new ast::NameExpr( location, "lock" ), 606 { 607 new ast::UntypedExpr( location, 608 new ast::NameExpr( location, "get_monitor" ), 609 { new ast::VariableExpr( location, 610 InitTweak::getParamThis( lock_decl ) ) } 611 ) 612 } 613 ) 614 ) 615 } ); 616 617 ast::FunctionDecl * unlock_decl = new ast::FunctionDecl( 618 location, 619 "unlock", 620 { /* forall */ }, 621 { 622 // Last use, consume the declaration of this. 623 this_decl, 624 }, 625 { /* returns */ }, 626 nullptr, 627 ast::Storage::Static, 628 ast::Linkage::Cforall, 629 { /* attributes */ }, 630 ast::Function::Inline 631 ); 632 unlock_decl = fixupGenerics( unlock_decl, decl ); 633 634 unlock_decl->stmts = new ast::CompoundStmt( location, { 635 new ast::ExprStmt( location, 636 new ast::UntypedExpr( location, 637 new ast::NameExpr( location, "unlock" ), 638 { 639 new ast::UntypedExpr( location, 640 new ast::NameExpr( location, "get_monitor" ), 641 { new ast::VariableExpr( location, 642 InitTweak::getParamThis( unlock_decl ) ) } 643 ) 644 } 645 ) 646 ) 647 } ); 648 649 declsToAddAfter.push_back( lock_decl ); 650 declsToAddAfter.push_back( unlock_decl ); 651 } 652 653 654 // -------------------------------------------------------------------------- 655 struct SuspendKeyword final : 656 public ast::WithStmtsToAdd<>, public ast::WithGuards { 657 SuspendKeyword() = default; 658 virtual ~SuspendKeyword() = default; 659 660 void previsit( const ast::FunctionDecl * ); 661 const ast::DeclWithType * postvisit( const ast::FunctionDecl * ); 662 const ast::Stmt * postvisit( const ast::SuspendStmt * ); 663 664 private: 665 bool is_real_suspend( const ast::FunctionDecl * ); 666 667 const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * ); 668 const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * ); 669 670 struct LabelPair { 671 ast::Label obj; 672 int idx; 673 }; 674 675 LabelPair make_label(const ast::Stmt * stmt ) { 676 labels.push_back( ControlStruct::newLabel( "generator", stmt ) ); 677 return { labels.back(), int(labels.size()) }; 678 } 679 680 const ast::DeclWithType * in_generator = nullptr; 681 const ast::FunctionDecl * decl_suspend = nullptr; 682 std::vector<ast::Label> labels; 683 }; 684 685 void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) { 686 GuardValue( in_generator ); in_generator = nullptr; 687 688 // If it is the real suspend, grab it if we don't have one already. 689 if ( is_real_suspend( decl ) ) { 690 decl_suspend = decl_suspend ? decl_suspend : decl; 691 return; 692 } 693 694 // Otherwise check if this is a generator main and, if so, handle it. 695 auto param = isMainFor( decl, ast::AggregateDecl::Generator ); 696 if ( !param ) return; 697 698 if ( 0 != decl->returns.size() ) { 699 SemanticError( decl->location, "Generator main must return void" ); 700 } 701 702 in_generator = param; 703 GuardValue( labels ); labels.clear(); 704 } 705 706 const ast::DeclWithType * SuspendKeyword::postvisit( 707 const ast::FunctionDecl * decl ) { 708 // Only modify a full definition of a generator with states. 709 if ( !decl->stmts || !in_generator || labels.empty() ) return decl; 710 711 const CodeLocation & location = decl->location; 712 713 // Create a new function body: 714 // static void * __generator_labels[] = {&&s0, &&s1, ...}; 715 // void * __generator_label = __generator_labels[GEN.__generator_state]; 716 // goto * __generator_label; 717 // s0: ; 718 // OLD_BODY 719 720 // This is the null statement inserted right before the body. 721 ast::NullStmt * noop = new ast::NullStmt( location ); 722 noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) ); 723 const ast::Label & first_label = noop->labels.back(); 724 725 // Add each label to the init, starting with the first label. 726 std::vector<ast::ptr<ast::Init>> inits = { 727 new ast::SingleInit( location, 728 new ast::LabelAddressExpr( location, copy( first_label ) ) ) }; 729 // Then go through all the stored labels, and clear the store. 730 for ( auto && label : labels ) { 731 inits.push_back( new ast::SingleInit( label.location, 732 new ast::LabelAddressExpr( label.location, std::move( label ) 733 ) ) ); 734 } 735 labels.clear(); 736 // Then construct the initializer itself. 737 auto init = new ast::ListInit( location, std::move( inits ) ); 738 739 ast::ObjectDecl * generatorLabels = new ast::ObjectDecl( 740 location, 741 "__generator_labels", 742 new ast::ArrayType( 743 new ast::PointerType( new ast::VoidType() ), 744 nullptr, 745 ast::FixedLen, 746 ast::DynamicDim 747 ), 748 init, 749 ast::Storage::Classes(), 750 ast::Linkage::AutoGen 751 ); 752 753 ast::ObjectDecl * generatorLabel = new ast::ObjectDecl( 754 location, 755 "__generator_label", 756 new ast::PointerType( new ast::VoidType() ), 757 new ast::SingleInit( location, 758 new ast::UntypedExpr( location, 759 new ast::NameExpr( location, "?[?]" ), 760 { 761 // TODO: Could be a variable expr. 762 new ast::NameExpr( location, "__generator_labels" ), 763 new ast::UntypedMemberExpr( location, 764 new ast::NameExpr( location, "__generator_state" ), 765 new ast::VariableExpr( location, in_generator ) 766 ) 767 } 768 ) 769 ), 770 ast::Storage::Classes(), 771 ast::Linkage::AutoGen 772 ); 773 774 ast::BranchStmt * theGoTo = new ast::BranchStmt( 775 location, new ast::VariableExpr( location, generatorLabel ) 776 ); 777 778 // The noop goes here in order. 779 780 ast::CompoundStmt * body = new ast::CompoundStmt( location, { 781 { new ast::DeclStmt( location, generatorLabels ) }, 782 { new ast::DeclStmt( location, generatorLabel ) }, 783 { theGoTo }, 784 { noop }, 785 { decl->stmts }, 786 } ); 787 788 auto mutDecl = ast::mutate( decl ); 789 mutDecl->stmts = body; 790 return mutDecl; 791 } 792 793 const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) { 794 switch ( stmt->type ) { 795 case ast::SuspendStmt::None: 796 // Use the context to determain the implicit target. 797 if ( in_generator ) { 798 return make_generator_suspend( stmt ); 799 } else { 800 return make_coroutine_suspend( stmt ); 801 } 802 case ast::SuspendStmt::Coroutine: 803 return make_coroutine_suspend( stmt ); 804 case ast::SuspendStmt::Generator: 805 // Generator suspends must be directly in a generator. 806 if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." ); 807 return make_generator_suspend( stmt ); 808 } 809 assert( false ); 810 return stmt; 811 } 812 813 /// Find the real/official suspend declaration. 814 bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) { 815 return ( !decl->linkage.is_mangled 816 && 0 == decl->params.size() 817 && 0 == decl->returns.size() 818 && "__cfactx_suspend" == decl->name ); 819 } 820 821 const ast::Stmt * SuspendKeyword::make_generator_suspend( 822 const ast::SuspendStmt * stmt ) { 823 assert( in_generator ); 824 // Target code is: 825 // GEN.__generator_state = X; 826 // THEN 827 // return; 828 // __gen_X:; 829 830 const CodeLocation & location = stmt->location; 831 832 LabelPair label = make_label( stmt ); 833 834 // This is the context saving statement. 835 stmtsToAddBefore.push_back( new ast::ExprStmt( location, 836 new ast::UntypedExpr( location, 837 new ast::NameExpr( location, "?=?" ), 838 { 839 new ast::UntypedMemberExpr( location, 840 new ast::NameExpr( location, "__generator_state" ), 841 new ast::VariableExpr( location, in_generator ) 842 ), 843 ast::ConstantExpr::from_int( location, label.idx ), 844 } 845 ) 846 ) ); 847 848 // The THEN component is conditional (return is not). 849 if ( stmt->then ) { 850 stmtsToAddBefore.push_back( stmt->then.get() ); 851 } 852 stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) ); 853 854 // The null statement replaces the old suspend statement. 855 return new ast::NullStmt( location, { label.obj } ); 856 } 857 858 const ast::Stmt * SuspendKeyword::make_coroutine_suspend( 859 const ast::SuspendStmt * stmt ) { 860 // The only thing we need from the old statement is the location. 861 const CodeLocation & location = stmt->location; 862 863 if ( !decl_suspend ) { 864 SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" ); 865 } 866 if ( stmt->then ) { 867 SemanticError( location, "Compound statement following coroutines is not implemented." ); 868 } 869 870 return new ast::ExprStmt( location, 871 new ast::UntypedExpr( location, 872 ast::VariableExpr::functionPointer( location, decl_suspend ) ) 873 ); 874 } 875 876 // -------------------------------------------------------------------------- 877 struct MutexKeyword final : public ast::WithDeclsToAdd<> { 40 878 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ); 41 879 void postvisit( const ast::StructDecl * decl ); … … 50 888 ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args ); 51 889 ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args ); 52 890 ast::ExprStmt * genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param); 891 ast::IfStmt * genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ); 53 892 private: 54 893 const ast::StructDecl * monitor_decl = nullptr; … … 59 898 60 899 static ast::ptr<ast::Type> generic_func; 900 901 UniqueName mutex_func_namer = UniqueName("__lock_unlock_curr"); 61 902 }; 62 903 … … 160 1001 161 1002 const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) { 1003 if ( !lock_guard_decl ) { 1004 SemanticError( stmt->location, "mutex stmt requires a header, add #include <mutex_stmt.hfa>\n" ); 1005 } 162 1006 ast::CompoundStmt * body = 163 1007 new ast::CompoundStmt( stmt->location, { stmt->stmt } ); 164 addStatements( body, stmt->mutexObjs );165 return body;1008 1009 return addStatements( body, stmt->mutexObjs );; 166 1010 } 167 1011 … … 251 1095 { 252 1096 new ast::SingleInit( location, 253 new ast::AddressExpr( 1097 new ast::AddressExpr( location, 254 1098 new ast::VariableExpr( location, monitor ) ) ), 255 1099 new ast::SingleInit( location, … … 358 1202 } 359 1203 1204 // generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it 1205 // used to undo the type erasure done by storing all the lock pointers as void 1206 ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) { 1207 return new ast::ExprStmt( location, 1208 new ast::UntypedExpr( location, 1209 new ast::NameExpr( location, fnName ), { 1210 ast::UntypedExpr::createDeref( 1211 location, 1212 new ast::CastExpr( location, 1213 param, 1214 new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr( 1215 expr->location, 1216 new ast::NameExpr( expr->location, "__get_mutexstmt_lock_type" ), 1217 { expr } 1218 ) ) ), 1219 ast::GeneratedFlag::ExplicitCast 1220 ) 1221 ) 1222 } 1223 ) 1224 ); 1225 } 1226 1227 ast::IfStmt * MutexKeyword::genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ) { 1228 ast::IfStmt * outerLockIf = nullptr; 1229 ast::IfStmt * lastLockIf = nullptr; 1230 1231 //adds an if/elif clause for each lock to assign type from void ptr based on ptr address 1232 for ( long unsigned int i = 0; i < args.size(); i++ ) { 1233 1234 ast::UntypedExpr * ifCond = new ast::UntypedExpr( location, 1235 new ast::NameExpr( location, "?==?" ), { 1236 ast::deepCopy( thisParam ), 1237 new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() )) 1238 } 1239 ); 1240 1241 ast::IfStmt * currLockIf = new ast::IfStmt( 1242 location, 1243 ifCond, 1244 genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) ) 1245 ); 1246 1247 if ( i == 0 ) { 1248 outerLockIf = currLockIf; 1249 } else { 1250 // add ifstmt to else of previous stmt 1251 lastLockIf->else_ = currLockIf; 1252 } 1253 1254 lastLockIf = currLockIf; 1255 } 1256 return outerLockIf; 1257 } 1258 360 1259 ast::CompoundStmt * MutexKeyword::addStatements( 361 1260 const ast::CompoundStmt * body, 362 1261 const std::vector<ast::ptr<ast::Expr>> & args ) { 363 ast::CompoundStmt * mutBody = ast::mutate( body );364 1262 365 1263 // Code is generated near the beginning of the compound statement. 366 const CodeLocation & location = mutBody->location; 1264 const CodeLocation & location = body->location; 1265 1266 // final body to return 1267 ast::CompoundStmt * newBody = new ast::CompoundStmt( location ); 1268 1269 // std::string lockFnName = mutex_func_namer.newName(); 1270 // std::string unlockFnName = mutex_func_namer.newName(); 367 1271 368 1272 // Make pointer to the monitors. … … 372 1276 new ast::ArrayType( 373 1277 new ast::PointerType( 374 new ast::TypeofType( 375 new ast::UntypedExpr( 376 location, 377 new ast::NameExpr( location, "__get_type" ), 378 { args.front() } 379 ) 380 ) 1278 new ast::VoidType() 381 1279 ), 382 1280 ast::ConstantExpr::from_ulong( location, args.size() ), … … 392 1290 new ast::UntypedExpr( 393 1291 expr->location, 394 new ast::NameExpr( expr->location, "__get_ ptr" ),1292 new ast::NameExpr( expr->location, "__get_mutexstmt_lock_ptr" ), 395 1293 { expr } 396 1294 ) … … 405 1303 ast::StructInstType * lock_guard_struct = 406 1304 new ast::StructInstType( lock_guard_decl ); 407 ast::TypeExpr * lock_type_expr = new ast::TypeExpr( 408 location, 409 new ast::TypeofType( 410 new ast::UntypedExpr( 411 location, 412 new ast::NameExpr( location, "__get_type" ), 413 { args.front() } 414 ) 415 ) 416 ); 417 418 lock_guard_struct->params.push_back( lock_type_expr ); 419 420 // In reverse order: 1305 1306 // use try stmts to lock and finally to unlock 1307 ast::TryStmt * outerTry = nullptr; 1308 ast::TryStmt * currentTry; 1309 ast::CompoundStmt * lastBody = nullptr; 1310 1311 // adds a nested try stmt for each lock we are locking 1312 for ( long unsigned int i = 0; i < args.size(); i++ ) { 1313 ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 1314 location, 1315 new ast::NameExpr( location,"?[?]" ), { 1316 new ast::NameExpr( location, "__monitors" ), 1317 ast::ConstantExpr::from_int( location, i ) 1318 } 1319 ); 1320 1321 // make the try body 1322 ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location ); 1323 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess ); 1324 currTryBody->push_back( lockCall ); 1325 1326 // make the finally stmt 1327 ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location ); 1328 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess ); 1329 currFinallyBody->push_back( unlockCall ); 1330 1331 // construct the current try 1332 currentTry = new ast::TryStmt( 1333 location, 1334 currTryBody, 1335 {}, 1336 new ast::FinallyClause( location, currFinallyBody ) 1337 ); 1338 if ( i == 0 ) outerTry = currentTry; 1339 else { 1340 // pushback try into the body of the outer try 1341 lastBody->push_back( currentTry ); 1342 } 1343 lastBody = currTryBody; 1344 } 1345 1346 // push body into innermost try body 1347 if ( lastBody != nullptr ) { 1348 lastBody->push_back( body ); 1349 newBody->push_front( outerTry ); 1350 } 1351 421 1352 // monitor_guard_t __guard = { __monitors, # }; 422 mutBody->push_front(1353 newBody->push_front( 423 1354 new ast::DeclStmt( 424 1355 location, … … 447 1378 448 1379 // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) }; 449 mutBody->push_front( new ast::DeclStmt( location, monitors ) ); 450 451 return mutBody; 1380 newBody->push_front( new ast::DeclStmt( location, monitors ) ); 1381 1382 // // The parameter for both __lock_curr/__unlock_curr routines. 1383 // ast::ObjectDecl * this_decl = new ast::ObjectDecl( 1384 // location, 1385 // "this", 1386 // new ast::PointerType( new ast::VoidType() ), 1387 // nullptr, 1388 // {}, 1389 // ast::Linkage::Cforall 1390 // ); 1391 1392 // ast::FunctionDecl * lock_decl = new ast::FunctionDecl( 1393 // location, 1394 // lockFnName, 1395 // { /* forall */ }, 1396 // { 1397 // // Copy the declaration of this. 1398 // this_decl, 1399 // }, 1400 // { /* returns */ }, 1401 // nullptr, 1402 // 0, 1403 // ast::Linkage::Cforall, 1404 // { /* attributes */ }, 1405 // ast::Function::Inline 1406 // ); 1407 1408 // ast::FunctionDecl * unlock_decl = new ast::FunctionDecl( 1409 // location, 1410 // unlockFnName, 1411 // { /* forall */ }, 1412 // { 1413 // // Copy the declaration of this. 1414 // ast::deepCopy( this_decl ), 1415 // }, 1416 // { /* returns */ }, 1417 // nullptr, 1418 // 0, 1419 // ast::Linkage::Cforall, 1420 // { /* attributes */ }, 1421 // ast::Function::Inline 1422 // ); 1423 1424 // ast::IfStmt * outerLockIf = nullptr; 1425 // ast::IfStmt * outerUnlockIf = nullptr; 1426 // ast::IfStmt * lastLockIf = nullptr; 1427 // ast::IfStmt * lastUnlockIf = nullptr; 1428 1429 // //adds an if/elif clause for each lock to assign type from void ptr based on ptr address 1430 // for ( long unsigned int i = 0; i < args.size(); i++ ) { 1431 // ast::VariableExpr * thisParam = new ast::VariableExpr( location, InitTweak::getParamThis( lock_decl ) ); 1432 // ast::UntypedExpr * ifCond = new ast::UntypedExpr( location, 1433 // new ast::NameExpr( location, "?==?" ), { 1434 // thisParam, 1435 // new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() )) 1436 // } 1437 // ); 1438 1439 // ast::IfStmt * currLockIf = new ast::IfStmt( 1440 // location, 1441 // ast::deepCopy( ifCond ), 1442 // genVirtLockUnlockExpr( "lock", args.at(i), location, ast::deepCopy( thisParam ) ) 1443 // ); 1444 1445 // ast::IfStmt * currUnlockIf = new ast::IfStmt( 1446 // location, 1447 // ifCond, 1448 // genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) ) 1449 // ); 1450 1451 // if ( i == 0 ) { 1452 // outerLockIf = currLockIf; 1453 // outerUnlockIf = currUnlockIf; 1454 // } else { 1455 // // add ifstmt to else of previous stmt 1456 // lastLockIf->else_ = currLockIf; 1457 // lastUnlockIf->else_ = currUnlockIf; 1458 // } 1459 1460 // lastLockIf = currLockIf; 1461 // lastUnlockIf = currUnlockIf; 1462 // } 1463 1464 // // add pointer typing if/elifs to body of routines 1465 // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } ); 1466 // unlock_decl->stmts = new ast::CompoundStmt( location, { outerUnlockIf } ); 1467 1468 // // add routines to scope 1469 // declsToAddBefore.push_back( lock_decl ); 1470 // declsToAddBefore.push_back( unlock_decl ); 1471 1472 // newBody->push_front(new ast::DeclStmt( location, lock_decl )); 1473 // newBody->push_front(new ast::DeclStmt( location, unlock_decl )); 1474 1475 return newBody; 452 1476 } 453 1477 … … 564 1588 565 1589 // -------------------------------------------------------------------------- 1590 // Interface Functions: 566 1591 567 1592 void implementKeywords( ast::TranslationUnit & translationUnit ) { 568 (void)translationUnit; 569 assertf(false, "Apply Keywords not implemented." ); 1593 ast::Pass<ThreadKeyword>::run( translationUnit ); 1594 ast::Pass<CoroutineKeyword>::run( translationUnit ); 1595 ast::Pass<MonitorKeyword>::run( translationUnit ); 1596 ast::Pass<GeneratorKeyword>::run( translationUnit ); 1597 ast::Pass<SuspendKeyword>::run( translationUnit ); 570 1598 } 571 1599
Note:
See TracChangeset
for help on using the changeset viewer.