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