Changes in / [ff489bf:9867cdb]
- Files:
-
- 1 added
- 10 deleted
- 41 edited
-
Jenkinsfile (modified) (1 diff)
-
benchmark/ctxswitch/cfa_cor.cfa (modified) (1 diff)
-
configure (modified) (1 diff)
-
configure.ac (modified) (1 diff)
-
libcfa/prelude/builtins.c (modified) (1 diff)
-
libcfa/src/concurrency/coroutine.cfa (modified) (1 diff)
-
libcfa/src/concurrency/coroutine.hfa (modified) (2 diffs)
-
src/AST/Convert.cpp (modified) (2 diffs)
-
src/AST/Decl.hpp (modified) (1 diff)
-
src/AST/Fwd.hpp (modified) (1 diff)
-
src/AST/Pass.hpp (modified) (1 diff)
-
src/AST/Pass.impl.hpp (modified) (1 diff)
-
src/AST/Print.cpp (modified) (1 diff)
-
src/AST/Stmt.hpp (modified) (1 diff)
-
src/AST/Visitor.hpp (modified) (1 diff)
-
src/Common/PassVisitor.h (modified) (2 diffs)
-
src/Common/PassVisitor.impl.h (modified) (1 diff)
-
src/Concurrency/Keywords.cc (modified) (5 diffs)
-
src/Parser/ParseNode.h (modified) (1 diff)
-
src/Parser/StatementNode.cc (modified) (1 diff)
-
src/Parser/TypeData.cc (modified) (1 diff)
-
src/Parser/lex.ll (modified) (2 diffs)
-
src/Parser/parser.yy (modified) (3 diffs)
-
src/SynTree/Declaration.h (modified) (1 diff)
-
src/SynTree/Mutator.h (modified) (1 diff)
-
src/SynTree/Statement.cc (modified) (1 diff)
-
src/SynTree/Statement.h (modified) (1 diff)
-
src/SynTree/SynTree.h (modified) (1 diff)
-
src/SynTree/Visitor.h (modified) (1 diff)
-
tests/concurrent/.expect/suspend_then.txt (deleted)
-
tests/concurrent/coroutineThen.cfa (added)
-
tests/concurrent/coroutineYield.cfa (modified) (1 diff)
-
tests/concurrent/suspend_then.cfa (deleted)
-
tests/coroutine/.expect/fmtLines.txt (modified) (1 diff)
-
tests/coroutine/.in/fmtLines.txt (modified) (1 diff)
-
tests/coroutine/cntparens.cfa (modified) (3 diffs)
-
tests/coroutine/devicedriver.cfa (modified) (5 diffs)
-
tests/coroutine/fibonacci.cfa (modified) (1 diff)
-
tests/coroutine/fibonacci_1.cfa (modified) (2 diffs)
-
tests/coroutine/fmtLines.cfa (modified) (1 diff)
-
tests/coroutine/raii.cfa (modified) (1 diff)
-
tests/coroutine/runningTotal.cfa (modified) (1 diff)
-
tests/coroutine/suspend_then.cfa (modified) (1 diff)
-
tests/errors/.expect/completeType.txt (modified) (3 diffs)
-
tests/errors/suspend.cfa (deleted)
-
tests/generator/.expect/fibonacci.txt (deleted)
-
tests/generator/.expect/fmtLines.txt (deleted)
-
tests/generator/.expect/suspend_then.txt (deleted)
-
tests/generator/.in/fmtLines.txt (deleted)
-
tests/generator/fibonacci.cfa (deleted)
-
tests/generator/fmtLines.cfa (deleted)
-
tests/generator/suspend_then.cfa (deleted)
Legend:
- Unmodified
- Added
- Removed
-
Jenkinsfile
rff489bf r9867cdb 126 126 } 127 127 128 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib CXXFLAGS='-flto=auto' CFAFLAGS='-flto=auto'${targets} --quiet"128 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} ${targets} --quiet" 129 129 130 130 // Configure libcfa -
benchmark/ctxswitch/cfa_cor.cfa
rff489bf r9867cdb 7 7 void main( __attribute__((unused)) C & ) { 8 8 while () { 9 suspend ;9 suspend(); 10 10 } 11 11 } -
configure
rff489bf r9867cdb 2557 2557 # don't use the default CFLAGS as they unconditonnaly add -O2 2558 2558 : ${CFLAGS=""} 2559 : ${CXXFLAGS=""}2560 2559 2561 2560 am__api_version='1.15' -
configure.ac
rff489bf r9867cdb 14 14 # don't use the default CFLAGS as they unconditonnaly add -O2 15 15 : ${CFLAGS=""} 16 : ${CXXFLAGS=""}17 16 18 17 AM_INIT_AUTOMAKE([subdir-objects]) -
libcfa/prelude/builtins.c
rff489bf r9867cdb 48 48 void exit( int status, const char fmt[], ... ) __attribute__ (( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )); 49 49 void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )); 50 51 forall(dtype T)52 static inline T & identity(T & i) {53 return i;54 }55 56 // generator support57 struct $generator {58 inline int;59 };60 61 static inline void ?{}($generator & this) { ((int&)this) = 0; }62 static inline void ^?{}($generator &) {}63 64 trait is_generator(dtype T) {65 void main(T & this);66 $generator * get_generator(T & this);67 };68 69 forall(dtype T | is_generator(T))70 static inline T & resume(T & gen) {71 main(gen);72 return gen;73 }74 50 75 51 // implicit increment, decrement if += defined, and implicit not if != defined -
libcfa/src/concurrency/coroutine.cfa
rff489bf r9867cdb 208 208 209 209 if(cor->state == Primed) { 210 __cfactx_suspend();210 suspend(); 211 211 } 212 212 -
libcfa/src/concurrency/coroutine.hfa
rff489bf r9867cdb 46 46 //----------------------------------------------------------------------------- 47 47 // Public coroutine API 48 static inline void suspend(void); 49 50 forall(dtype T | is_coroutine(T)) 51 static inline T & resume(T & cor); 52 48 53 forall(dtype T | is_coroutine(T)) 49 54 void prime(T & cor); … … 91 96 92 97 // Suspend implementation inlined for performance 93 extern "C" { 94 static inline void __cfactx_suspend(void) { 95 // optimization : read TLS once and reuse it 96 // Safety note: this is preemption safe since if 97 // preemption occurs after this line, the pointer 98 // will also migrate which means this value will 99 // stay in syn with the TLS 100 $coroutine * src = TL_GET( this_thread )->curr_cor; 98 static inline void suspend(void) { 99 // optimization : read TLS once and reuse it 100 // Safety note: this is preemption safe since if 101 // preemption occurs after this line, the pointer 102 // will also migrate which means this value will 103 // stay in syn with the TLS 104 $coroutine * src = TL_GET( this_thread )->curr_cor; 101 105 102 assertf( src->last != 0,103 "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"104 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",105 src->name, src );106 assertf( src->last->state != Halted,107 "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"108 "Possible cause is terminated coroutine's main routine has already returned.",109 src->name, src, src->last->name, src->last );106 assertf( src->last != 0, 107 "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n" 108 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 109 src->name, src ); 110 assertf( src->last->state != Halted, 111 "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n" 112 "Possible cause is terminated coroutine's main routine has already returned.", 113 src->name, src, src->last->name, src->last ); 110 114 111 $ctx_switch( src, src->last ); 112 } 115 $ctx_switch( src, src->last ); 113 116 } 114 117 -
src/AST/Convert.cpp
rff489bf r9867cdb 493 493 } 494 494 495 const ast::Stmt * visit(const ast::SuspendStmt * node ) override final {496 if ( inCache( node ) ) return nullptr;497 auto stmt = new SuspendStmt();498 stmt->then = get<CompoundStmt>().accept1( node->then );499 switch(node->type) {500 case ast::SuspendStmt::None : stmt->type = SuspendStmt::None ; break;501 case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;502 case ast::SuspendStmt::Generator: stmt->type = SuspendStmt::Generator; break;503 }504 return stmtPostamble( stmt, node );505 }506 507 495 const ast::Stmt * visit( const ast::WaitForStmt * node ) override final { 508 496 if ( inCache( node ) ) return nullptr; … … 1871 1859 } 1872 1860 1873 virtual void visit( const SuspendStmt * old ) override final {1874 if ( inCache( old ) ) return;1875 ast::SuspendStmt::Type type;1876 switch (old->type) {1877 case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;1878 case SuspendStmt::Generator: type = ast::SuspendStmt::Generator; break;1879 case SuspendStmt::None : type = ast::SuspendStmt::None ; break;1880 default: abort();1881 }1882 this->node = new ast::SuspendStmt(1883 old->location,1884 GET_ACCEPT_1(then , CompoundStmt),1885 type,1886 GET_LABELS_V(old->labels)1887 );1888 cache.emplace( old, this->node );1889 }1890 1891 1861 virtual void visit( const WaitForStmt * old ) override final { 1892 1862 if ( inCache( old ) ) return; -
src/AST/Decl.hpp
rff489bf r9867cdb 259 259 260 260 bool is_coroutine() { return kind == Coroutine; } 261 bool is_generator() { return kind == Generator; } 262 bool is_monitor () { return kind == Monitor ; } 263 bool is_thread () { return kind == Thread ; } 261 bool is_monitor() { return kind == Monitor; } 262 bool is_thread() { return kind == Thread; } 264 263 265 264 const Decl * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Fwd.hpp
rff489bf r9867cdb 53 53 class CatchStmt; 54 54 class FinallyStmt; 55 class SuspendStmt;56 55 class WaitForStmt; 57 56 class WithStmt; -
src/AST/Pass.hpp
rff489bf r9867cdb 111 111 const ast::Stmt * visit( const ast::CatchStmt * ) override final; 112 112 const ast::Stmt * visit( const ast::FinallyStmt * ) override final; 113 const ast::Stmt * visit( const ast::SuspendStmt * ) override final;114 113 const ast::Stmt * visit( const ast::WaitForStmt * ) override final; 115 114 const ast::Decl * visit( const ast::WithStmt * ) override final; -
src/AST/Pass.impl.hpp
rff489bf r9867cdb 823 823 824 824 //-------------------------------------------------------------------------- 825 // FinallyStmt826 template< typename pass_t >827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {828 VISIT_START( node );829 830 VISIT(831 maybe_accept( node, &SuspendStmt::then );832 )833 834 VISIT_END( Stmt, node );835 }836 837 //--------------------------------------------------------------------------838 825 // WaitForStmt 839 826 template< typename pass_t > -
src/AST/Print.cpp
rff489bf r9867cdb 674 674 safe_print( node->body ); 675 675 --indent; 676 677 return node;678 }679 680 virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {681 os << "Suspend Statement";682 switch (node->type) {683 case ast::SuspendStmt::None : os << " with implicit target"; break;684 case ast::SuspendStmt::Generator: os << " for generator"; break;685 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;686 }687 os << endl;688 689 ++indent;690 if(node->then) {691 os << indent << " with post statement :" << endl;692 safe_print( node->then );693 }694 ++indent;695 676 696 677 return node; -
src/AST/Stmt.hpp
rff489bf r9867cdb 342 342 }; 343 343 344 /// Suspend statement345 class SuspendStmt final : public Stmt {346 public:347 ptr<CompoundStmt> then;348 enum Type { None, Coroutine, Generator } type = None;349 350 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, std::vector<Label> && labels = {} )351 : Stmt(loc, std::move(labels)), then(then), type(type) {}352 353 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }354 private:355 SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }356 MUTATE_FRIEND357 };358 359 344 /// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...` 360 345 class WaitForStmt final : public Stmt { -
src/AST/Visitor.hpp
rff489bf r9867cdb 47 47 virtual const ast::Stmt * visit( const ast::CatchStmt * ) = 0; 48 48 virtual const ast::Stmt * visit( const ast::FinallyStmt * ) = 0; 49 virtual const ast::Stmt * visit( const ast::SuspendStmt * ) = 0;50 49 virtual const ast::Stmt * visit( const ast::WaitForStmt * ) = 0; 51 50 virtual const ast::Decl * visit( const ast::WithStmt * ) = 0; -
src/Common/PassVisitor.h
rff489bf r9867cdb 110 110 virtual void visit( FinallyStmt * finallyStmt ) override final; 111 111 virtual void visit( const FinallyStmt * finallyStmt ) override final; 112 virtual void visit( SuspendStmt * suspendStmt ) override final;113 virtual void visit( const SuspendStmt * suspendStmt ) override final;114 112 virtual void visit( WaitForStmt * waitforStmt ) override final; 115 113 virtual void visit( const WaitForStmt * waitforStmt ) override final; … … 278 276 virtual Statement * mutate( CatchStmt * catchStmt ) override final; 279 277 virtual Statement * mutate( FinallyStmt * finallyStmt ) override final; 280 virtual Statement * mutate( SuspendStmt * suspendStmt ) override final;281 278 virtual Statement * mutate( WaitForStmt * waitforStmt ) override final; 282 279 virtual Declaration * mutate( WithStmt * withStmt ) override final; -
src/Common/PassVisitor.impl.h
rff489bf r9867cdb 1522 1522 1523 1523 //-------------------------------------------------------------------------- 1524 // SuspendStmt1525 template< typename pass_type >1526 void PassVisitor< pass_type >::visit( SuspendStmt * node ) {1527 VISIT_START( node );1528 1529 maybeAccept_impl( node->then , *this );1530 1531 VISIT_END( node );1532 }1533 1534 template< typename pass_type >1535 void PassVisitor< pass_type >::visit( const SuspendStmt * node ) {1536 VISIT_START( node );1537 1538 maybeAccept_impl( node->then , *this );1539 1540 VISIT_END( node );1541 }1542 1543 template< typename pass_type >1544 Statement * PassVisitor< pass_type >::mutate( SuspendStmt * node ) {1545 MUTATE_START( node );1546 1547 maybeMutate_impl( node->then , *this );1548 1549 MUTATE_END( Statement, node );1550 }1551 1552 //--------------------------------------------------------------------------1553 1524 // WaitForStmt 1554 1525 template< typename pass_type > -
src/Concurrency/Keywords.cc
rff489bf r9867cdb 16 16 #include "Concurrency/Keywords.h" 17 17 18 #include <cassert> // for assert 19 #include <string> // for string, operator== 20 21 #include "Common/PassVisitor.h" // for PassVisitor 22 #include "Common/SemanticError.h" // for SemanticError 23 #include "Common/utility.h" // for deleteAll, map_range 24 #include "CodeGen/OperatorTable.h" // for isConstructor 25 #include "ControlStruct/LabelGenerator.h" // for LebelGenerator 26 #include "InitTweak/InitTweak.h" // for getPointerBase 27 #include "SynTree/LinkageSpec.h" // for Cforall 28 #include "SynTree/Constant.h" // for Constant 29 #include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl 30 #include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype... 31 #include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ... 32 #include "SynTree/Label.h" // for Label 33 #include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt 34 #include "SynTree/Type.h" // for StructInstType, Type, PointerType 35 #include "SynTree/Visitor.h" // for Visitor, acceptAll 18 #include <cassert> // for assert 19 #include <string> // for string, operator== 20 21 #include "Common/PassVisitor.h" // for PassVisitor 22 #include "Common/SemanticError.h" // for SemanticError 23 #include "Common/utility.h" // for deleteAll, map_range 24 #include "CodeGen/OperatorTable.h" // for isConstructor 25 #include "InitTweak/InitTweak.h" // for getPointerBase 26 #include "SynTree/LinkageSpec.h" // for Cforall 27 #include "SynTree/Constant.h" // for Constant 28 #include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl 29 #include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype... 30 #include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ... 31 #include "SynTree/Label.h" // for Label 32 #include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt 33 #include "SynTree/Type.h" // for StructInstType, Type, PointerType 34 #include "SynTree/Visitor.h" // for Visitor, acceptAll 36 35 37 36 class Attribute; … … 148 147 }; 149 148 150 151 152 149 //----------------------------------------------------------------------------- 153 150 //Handles monitor type declarations : … … 183 180 184 181 //----------------------------------------------------------------------------- 185 //Handles generator type declarations :186 // generator MyGenerator { struct MyGenerator {187 // int data; int data;188 // a_struct_t more_data; a_struct_t more_data;189 // => int __gen_next;190 // }; };191 //192 class GeneratorKeyword final : public ConcurrentSueKeyword {193 public:194 195 GeneratorKeyword() : ConcurrentSueKeyword(196 "$generator",197 "__generator_state",198 "get_generator",199 "Unable to find builtin type $generator\n",200 true,201 AggregateDecl::Generator202 )203 {}204 205 virtual ~GeneratorKeyword() {}206 207 virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }208 209 static void implement( std::list< Declaration * > & translationUnit ) {210 PassVisitor< GeneratorKeyword > impl;211 mutateAll( translationUnit, impl );212 }213 };214 215 216 //-----------------------------------------------------------------------------217 class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {218 public:219 SuspendKeyword() = default;220 virtual ~SuspendKeyword() = default;221 222 void premutate( FunctionDecl * );223 DeclarationWithType * postmutate( FunctionDecl * );224 225 Statement * postmutate( SuspendStmt * );226 227 static void implement( std::list< Declaration * > & translationUnit ) {228 PassVisitor< SuspendKeyword > impl;229 mutateAll( translationUnit, impl );230 }231 232 private:233 DeclarationWithType * is_main( FunctionDecl * );234 bool is_real_suspend( FunctionDecl * );235 236 Statement * make_generator_suspend( SuspendStmt * );237 Statement * make_coroutine_suspend( SuspendStmt * );238 239 struct LabelPair {240 Label obj;241 int idx;242 };243 244 LabelPair make_label() {245 labels.push_back( gen.newLabel("generator") );246 return { labels.back(), int(labels.size()) };247 }248 249 DeclarationWithType * in_generator = nullptr;250 FunctionDecl * decl_suspend = nullptr;251 std::vector<Label> labels;252 ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();253 };254 255 //-----------------------------------------------------------------------------256 182 //Handles mutex routines definitions : 257 183 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) { … … 325 251 CoroutineKeyword ::implement( translationUnit ); 326 252 MonitorKeyword ::implement( translationUnit ); 327 GeneratorKeyword ::implement( translationUnit );328 SuspendKeyword ::implement( translationUnit );329 253 } 330 254 … … 522 446 523 447 declsToAddAfter.push_back( get_decl ); 524 } 525 526 //============================================================================================= 527 // Suspend keyword implementation 528 //============================================================================================= 529 DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) { 530 if(func->name != "main") return nullptr; 531 if(func->type->parameters.size() != 1) return nullptr; 532 533 auto param = func->type->parameters.front(); 534 535 auto type = dynamic_cast<ReferenceType * >(param->get_type()); 536 if(!type) return nullptr; 537 538 auto obj = dynamic_cast<StructInstType *>(type->base); 539 if(!obj) return nullptr; 540 541 if(!obj->baseStruct->is_generator()) return nullptr; 542 543 return param; 544 } 545 546 bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) { 547 if(isMangled(func->linkage)) return false; // the real suspend isn't mangled 548 if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name 549 if(func->type->parameters.size() != 0) return false; // Too many parameters 550 if(func->type->returnVals.size() != 0) return false; // Too many return values 551 552 return true; 553 } 554 555 void SuspendKeyword::premutate( FunctionDecl * func ) { 556 GuardValue(in_generator); 557 in_generator = nullptr; 558 559 // Is this the real suspend? 560 if(is_real_suspend(func)) { 561 decl_suspend = decl_suspend ? decl_suspend : func; 562 return; 563 } 564 565 // Is this the main of a generator? 566 auto param = is_main( func ); 567 if(!param) return; 568 569 if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void"); 570 571 in_generator = param; 572 GuardValue(labels); 573 labels.clear(); 574 } 575 576 DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) { 577 if( !func->statements ) return func; // Not the actual definition, don't do anything 578 if( !in_generator ) return func; // Not in a generator, don't do anything 579 if( labels.empty() ) return func; // Generator has no states, nothing to do, could throw a warning 580 581 // This is a generator main, we need to add the following code to the top 582 // static void * __generator_labels[] = {&&s0, &&s1, ...}; 583 // goto * __generator_labels[gen.__generator_state]; 584 const auto & loc = func->location; 585 586 const auto first_label = gen.newLabel("generator"); 587 588 // for each label add to declaration 589 std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) }; 590 for(const auto & label : labels) { 591 inits.push_back( 592 new SingleInit( 593 new LabelAddressExpr( label ) 594 ) 595 ); 596 } 597 auto init = new ListInit(std::move(inits), noDesignators, true); 598 labels.clear(); 599 600 // create decl 601 auto decl = new ObjectDecl( 602 "__generator_labels", 603 Type::StorageClasses( Type::Static ), 604 LinkageSpec::AutoGen, 605 nullptr, 606 new ArrayType( 607 Type::Qualifiers(), 608 new PointerType( 609 Type::Qualifiers(), 610 new VoidType( Type::Qualifiers() ) 611 ), 612 nullptr, 613 false, false 614 ), 615 init 616 ); 617 618 // create the goto 619 assert(in_generator); 620 621 auto go_decl = new ObjectDecl( 622 "__generator_label", 623 noStorageClasses, 624 LinkageSpec::AutoGen, 625 nullptr, 626 new PointerType( 627 Type::Qualifiers(), 628 new VoidType( Type::Qualifiers() ) 629 ), 630 new SingleInit( 631 new UntypedExpr( 632 new NameExpr("?[?]"), 633 { 634 new NameExpr("__generator_labels"), 635 new UntypedMemberExpr( 636 new NameExpr("__generator_state"), 637 new VariableExpr( in_generator ) 638 ) 639 } 640 ) 641 ) 642 ); 643 go_decl->location = loc; 644 645 auto go = new BranchStmt( 646 new VariableExpr( go_decl ), 647 BranchStmt::Goto 648 ); 649 go->location = loc; 650 go->computedTarget->location = loc; 651 652 auto noop = new NullStmt({ first_label }); 653 noop->location = loc; 654 655 // wrap everything in a nice compound 656 auto body = new CompoundStmt({ 657 new DeclStmt( decl ), 658 new DeclStmt( go_decl ), 659 go, 660 noop, 661 func->statements 662 }); 663 body->location = loc; 664 func->statements = body; 665 666 return func; 667 } 668 669 Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) { 670 SuspendStmt::Type type = stmt->type; 671 if(type == SuspendStmt::None) { 672 // This suspend has a implicit target, find it 673 type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine; 674 } 675 676 // Check that the target makes sense 677 if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type."); 678 679 // Act appropriately 680 switch(type) { 681 case SuspendStmt::Generator: return make_generator_suspend(stmt); 682 case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt); 683 default: abort(); 684 } 685 } 686 687 Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) { 688 assert(in_generator); 689 // Target code is : 690 // gen.__generator_state = X; 691 // { THEN } 692 // return; 693 // __gen_X:; 694 695 // Save the location and delete the old statement, we only need the location from this point on 696 auto loc = stmt->location; 697 698 // Build the label and get its index 699 auto label = make_label(); 700 701 // Create the context saving statement 702 auto save = new ExprStmt( new UntypedExpr( 703 new NameExpr( "?=?" ), 704 { 705 new UntypedMemberExpr( 706 new NameExpr("__generator_state"), 707 new VariableExpr( in_generator ) 708 ), 709 new ConstantExpr( 710 Constant::from_int( label.idx ) 711 ) 712 } 713 )); 714 assert(save->expr); 715 save->location = loc; 716 stmtsToAddBefore.push_back( save ); 717 718 // if we have a then add it here 719 auto then = stmt->then; 720 stmt->then = nullptr; 721 delete stmt; 722 if(then) stmtsToAddBefore.push_back( then ); 723 724 // Create the return statement 725 auto ret = new ReturnStmt( nullptr ); 726 ret->location = loc; 727 stmtsToAddBefore.push_back( ret ); 728 729 // Create the null statement with the created label 730 auto noop = new NullStmt({ label.obj }); 731 noop->location = loc; 732 733 // Return the null statement to take the place of the previous statement 734 return noop; 735 } 736 737 Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) { 738 if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented."); 739 740 // Save the location and delete the old statement, we only need the location from this point on 741 auto loc = stmt->location; 742 delete stmt; 743 744 // Create the call expression 745 if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n"); 746 auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) ); 747 expr->location = loc; 748 749 // Change this statement into a regular expr 750 assert(expr); 751 auto nstmt = new ExprStmt( expr ); 752 nstmt->location = loc; 753 return nstmt; 754 } 755 448 449 // get_decl->fixUniqueId(); 450 } 756 451 757 452 //============================================================================================= -
src/Parser/ParseNode.h
rff489bf r9867cdb 428 428 Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr ); 429 429 Statement * build_directive( std::string * directive ); 430 SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);431 430 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when ); 432 431 WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing ); -
src/Parser/StatementNode.cc
rff489bf r9867cdb 249 249 } // build_finally 250 250 251 SuspendStmt * build_suspend( StatementNode * then, SuspendStmt::Type type ) {252 auto node = new SuspendStmt();253 254 node->type = type;255 256 std::list< Statement * > stmts;257 buildMoveList< Statement, StatementNode >( then, stmts );258 if(!stmts.empty()) {259 assert( stmts.size() == 1 );260 node->then = dynamic_cast< CompoundStmt * >( stmts.front() );261 }262 263 return node;264 }265 266 251 WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) { 267 252 auto node = new WaitForStmt(); -
src/Parser/TypeData.cc
rff489bf r9867cdb 769 769 case AggregateDecl::Struct: 770 770 case AggregateDecl::Coroutine: 771 case AggregateDecl::Generator:772 771 case AggregateDecl::Monitor: 773 772 case AggregateDecl::Thread: -
src/Parser/lex.ll
rff489bf r9867cdb 65 65 #define FLOATXX(v) KEYWORD_RETURN(v); 66 66 #else 67 #define FLOATXX(v) IDENTIFIER_RETURN(); 67 #define FLOATXX(v) IDENTIFIER_RETURN(); 68 68 #endif // HAVE_KEYWORDS_FLOATXX 69 69 … … 301 301 _Static_assert { KEYWORD_RETURN(STATICASSERT); } // C11 302 302 struct { KEYWORD_RETURN(STRUCT); } 303 suspend { KEYWORD_RETURN(SUSPEND); } // CFA 303 /* suspend { KEYWORD_RETURN(SUSPEND); } // CFA */ 304 304 switch { KEYWORD_RETURN(SWITCH); } 305 305 thread { KEYWORD_RETURN(THREAD); } // C11 -
src/Parser/parser.yy
rff489bf r9867cdb 278 278 %token OTYPE FTYPE DTYPE TTYPE TRAIT // CFA 279 279 %token SIZEOF OFFSETOF 280 // %token RESUME // CFA 281 %token SUSPEND // CFA 280 // %token SUSPEND RESUME // CFA 282 281 %token ATTRIBUTE EXTENSION // GCC 283 282 %token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN … … 1266 1265 | RETURN '{' initializer_list_opt comma_opt '}' ';' 1267 1266 { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; } 1268 | SUSPEND ';' 1269 { $$ = new StatementNode( build_suspend( nullptr ) ); } 1270 | SUSPEND compound_statement 1271 { $$ = new StatementNode( build_suspend( $2 ) ); } 1272 | SUSPEND COROUTINE ';' 1273 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); } 1274 | SUSPEND COROUTINE compound_statement 1275 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); } 1276 | SUSPEND GENERATOR ';' 1277 { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); } 1278 | SUSPEND GENERATOR compound_statement 1279 { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); } 1267 // | SUSPEND ';' 1268 // { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; } 1269 // | SUSPEND compound_statement ';' 1270 // { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; } 1280 1271 | THROW assignment_expression_opt ';' // handles rethrow 1281 1272 { $$ = new StatementNode( build_throw( $2 ) ); } … … 2092 2083 aggregate_control: // CFA 2093 2084 GENERATOR 2094 { yyy = true; $$ = AggregateDecl::Generator; }2085 { SemanticError( yylloc, "generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2095 2086 | MONITOR GENERATOR 2096 2087 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } -
src/SynTree/Declaration.h
rff489bf r9867cdb 302 302 303 303 bool is_coroutine() { return kind == Coroutine; } 304 bool is_generator() { return kind == Generator; } 305 bool is_monitor () { return kind == Monitor ; } 306 bool is_thread () { return kind == Thread ; } 304 bool is_monitor() { return kind == Monitor; } 305 bool is_thread() { return kind == Thread; } 307 306 308 307 virtual StructDecl * clone() const override { return new StructDecl( *this ); } -
src/SynTree/Mutator.h
rff489bf r9867cdb 51 51 virtual Statement * mutate( CatchStmt * catchStmt ) = 0; 52 52 virtual Statement * mutate( FinallyStmt * catchStmt ) = 0; 53 virtual Statement * mutate( SuspendStmt * suspendStmt ) = 0;54 53 virtual Statement * mutate( WaitForStmt * waitforStmt ) = 0; 55 54 virtual Declaration * mutate( WithStmt * withStmt ) = 0; -
src/SynTree/Statement.cc
rff489bf r9867cdb 420 420 } 421 421 422 SuspendStmt::SuspendStmt( const SuspendStmt & other )423 : Statement( other )424 , then( maybeClone(other.then) )425 {}426 427 SuspendStmt::~SuspendStmt() {428 delete then;429 }430 431 void SuspendStmt::print( std::ostream & os, Indenter indent ) const {432 os << "Suspend Statement";433 switch (type) {434 case None : os << " with implicit target"; break;435 case Generator: os << " for generator" ; break;436 case Coroutine: os << " for coroutine" ; break;437 }438 os << endl;439 indent += 1;440 441 if(then) {442 os << indent << " with post statement :" << endl;443 then->print( os, indent + 1);444 }445 }446 447 422 WaitForStmt::WaitForStmt() : Statement() { 448 423 timeout.time = nullptr; -
src/SynTree/Statement.h
rff489bf r9867cdb 422 422 }; 423 423 424 class SuspendStmt : public Statement {425 public:426 CompoundStmt * then = nullptr;427 enum Type { None, Coroutine, Generator } type = None;428 429 SuspendStmt() = default;430 SuspendStmt( const SuspendStmt & );431 virtual ~SuspendStmt();432 433 virtual SuspendStmt * clone() const override { return new SuspendStmt( *this ); }434 virtual void accept( Visitor & v ) override { v.visit( this ); }435 virtual void accept( Visitor & v ) const override { v.visit( this ); }436 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); }437 virtual void print( std::ostream & os, Indenter indent = {} ) const override;438 };439 440 424 class WaitForStmt : public Statement { 441 425 public: -
src/SynTree/SynTree.h
rff489bf r9867cdb 54 54 class CatchStmt; 55 55 class FinallyStmt; 56 class SuspendStmt;57 56 class WaitForStmt; 58 57 class WithStmt; -
src/SynTree/Visitor.h
rff489bf r9867cdb 78 78 virtual void visit( FinallyStmt * node ) { visit( const_cast<const FinallyStmt *>(node) ); } 79 79 virtual void visit( const FinallyStmt * finallyStmt ) = 0; 80 virtual void visit( SuspendStmt * node ) { visit( const_cast<const SuspendStmt *>(node) ); }81 virtual void visit( const SuspendStmt * suspendStmt ) = 0;82 80 virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); } 83 81 virtual void visit( const WaitForStmt * waitforStmt ) = 0; -
tests/concurrent/coroutineYield.cfa
rff489bf r9867cdb 33 33 sout | "Coroutine 2"; 34 34 #endif 35 suspend ;35 suspend(); 36 36 } 37 37 } -
tests/coroutine/.expect/fmtLines.txt
rff489bf r9867cdb 48 48 { // f or n ewli 49 49 ne c hara cter s su 50 spen d ; i f ( fmt.51 ch ! = '\ n' ) bre ak;52 // igno re n ewli ne53 } // f or so ut |54 fmt .ch; / / pr55 int char acte r } //56 for s out | " ";57 / / pr int bloc58 k se para tor } / / fo59 r s out | nl ;60 // pri nt g roup sep61 arat or } // for} //62 main void prt ( Fo rmat63 & f mt, char ch ) {64 f mt.c h = ch; r65 esum e( f mt ) ;} / / pr66 tint mai n() { Fo rmat67 fmt ; ch ar c h; f or (68 ;; ) { sin | c h;69 // r ead one70 char acte r if ( eof71 ( si n ) ) br eak;72 / / eo f ? prt ( fm73 t, c h ); } / / fo r} /74 / ma in// Loc al V aria75 bles : // // t ab-w idth76 : 4 //// com pile -com77 mand : "c fa f mtLi nes.78 cfa" /// / En d: //50 spen d(); if ( fm 51 t.ch != '\n' ) b reak 52 ; / / ig nore new line 53 } // for sout 54 | f mt.c h; // 55 prin t ch arac ter } 56 // f or sou t | " " 57 ; // prin t bl 58 ock sepa rato r } // 59 for sou t | nl; 60 // p rint gro up s 61 epar ator } / / fo r} / 62 / ma invo id p rt( Form 63 at & fmt , ch ar c h ) 64 { fmt .ch = ch ; 65 res ume( fmt );} // 66 prti nt m ain( ) { Form 67 at f mt; char ch; for 68 ( ; ; ) { s in | ch; 69 // rea d on 70 e ch arac ter if ( e 71 of( sin ) ) brea k; 72 // eof ? p rt( 73 fmt, ch ); } // for} 74 // main // L ocal Var 75 iabl es: //// tab -wid 76 th: 4 // // c ompi le-c 77 omma nd: "cfa fmt Line 78 s.cf a" / /// End: // -
tests/coroutine/.in/fmtLines.txt
rff489bf r9867cdb 35 35 for ( fmt.b = 0; fmt.b < 4; fmt.b += 1 ) { // blocks of 4 characters 36 36 for ( ;; ) { // for newline characters 37 suspend ;37 suspend(); 38 38 if ( fmt.ch != '\n' ) break; // ignore newline 39 39 } // for -
tests/coroutine/cntparens.cfa
rff489bf r9867cdb 1 // 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 3 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 // 6 // 7 7 // cntparens.cfa -- match left/right parenthesis 8 // 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Apr 20 11:04:45 2019 … … 12 12 // Last Modified On : Sat Apr 20 11:06:21 2019 13 13 // Update Count : 1 14 // 14 // 15 15 16 16 #include <fstream.hfa> … … 26 26 void main( CntParens & cpns ) with( cpns ) { 27 27 for ( ; ch == '('; cnt += 1 ) { // left parenthesis 28 suspend ;28 suspend(); 29 29 } 30 30 for ( ; ch == ')' && cnt > 1; cnt -= 1 ) { // right parenthesis 31 suspend ;31 suspend(); 32 32 } 33 33 status = ch == ')' ? Match : Error; 34 34 } // main 35 35 36 36 void ?{}( CntParens & cpns ) with( cpns ) { status = Cont; cnt = 0; } 37 37 -
tests/coroutine/devicedriver.cfa
rff489bf r9867cdb 1 // 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 3 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 // 7 // devicedriver.cfa -- 8 // 6 // 7 // devicedriver.cfa -- 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Sat Mar 16 15:30:34 2019 … … 12 12 // Last Modified On : Sat Apr 20 09:07:19 2019 13 13 // Update Count : 90 14 // 14 // 15 15 16 16 #include <fstream.hfa> … … 29 29 30 30 void checkCRC( Driver & d, unsigned int sum ) with( d ) { 31 suspend ;31 suspend(); 32 32 unsigned short int crc = byte << 8; // sign extension over written 33 suspend ;33 suspend(); 34 34 // prevent sign extension for signed char 35 35 status = (crc | (unsigned char)byte) == sum ? MSG : ECRC; … … 41 41 status = CONT; 42 42 unsigned int lnth = 0, sum = 0; 43 while ( byte != STX ) suspend ;43 while ( byte != STX ) suspend(); 44 44 emsg: for () { 45 suspend ;45 suspend(); 46 46 choose ( byte ) { // process byte 47 47 case STX: 48 status = ESTX; suspend ; continue msg;48 status = ESTX; suspend(); continue msg; 49 49 case ETX: 50 50 break emsg; 51 51 case ESC: 52 suspend ;52 suspend(); 53 53 } // choose 54 54 if ( lnth >= MaxMsg ) { // buffer full ? 55 status = ELNTH; suspend ; continue msg;55 status = ELNTH; suspend(); continue msg; 56 56 } // if 57 57 msg[lnth++] = byte; … … 60 60 msg[lnth] = '\0'; // terminate string 61 61 checkCRC( d, sum ); // refactor CRC check 62 suspend ;62 suspend(); 63 63 } // for 64 64 } // main -
tests/coroutine/fibonacci.cfa
rff489bf r9867cdb 22 22 int fn1, fn2; // retained between resumes 23 23 fn = 0; fn1 = fn; // 1st case 24 suspend ; // restart last resume24 suspend(); // restart last resume 25 25 fn = 1; fn2 = fn1; fn1 = fn; // 2nd case 26 suspend ; // restart last resume26 suspend(); // restart last resume 27 27 for () { 28 28 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; // general case 29 suspend ; // restart last resume29 suspend(); // restart last resume 30 30 } // for 31 31 } -
tests/coroutine/fibonacci_1.cfa
rff489bf r9867cdb 12 12 // Last Modified On : Thu Mar 21 08:10:45 2019 13 13 // Update Count : 25 14 // 14 // 15 15 16 16 #include <fstream.hfa> … … 23 23 [fn1, fn] = [0, 1]; // precompute first two states 24 24 for () { 25 suspend ; // restart last resume25 suspend(); // restart last resume 26 26 [fn1, fn] = [fn, fn1 + fn]; // general case 27 27 } // for -
tests/coroutine/fmtLines.cfa
rff489bf r9867cdb 27 27 for ( b = 0; b < 4; b += 1 ) { // blocks of 4 characters 28 28 for () { // for newline characters 29 suspend ;29 suspend(); 30 30 if ( ch != '\n' ) break; // ignore newline 31 31 } // for -
tests/coroutine/raii.cfa
rff489bf r9867cdb 39 39 Raii raii = { "Coroutine" }; 40 40 sout | "Before Suspend"; 41 suspend ;41 suspend(); 42 42 sout | "After Suspend"; 43 43 } -
tests/coroutine/runningTotal.cfa
rff489bf r9867cdb 25 25 void update( RunTotal & rntl, int input ) with( rntl ) { // helper 26 26 total += input; // remember between activations 27 suspend ; // inactivate on stack27 suspend(); // inactivate on stack 28 28 } 29 29 -
tests/coroutine/suspend_then.cfa
rff489bf r9867cdb 15 15 16 16 #include <fstream.hfa> 17 #include <coroutine.hfa> 17 18 18 generator Fibonacci { 19 int fn; // used for communication 20 int fn1, fn2; // retained between resumes 21 }; 19 void then() { 20 sout | "Then!"; 21 } 22 23 coroutine Fibonacci { int fn; }; // used for communication 22 24 23 25 void main( Fibonacci & fib ) with( fib ) { // called on first resume 26 int fn1, fn2; // retained between resumes 24 27 fn = 0; fn1 = fn; // 1st case 25 suspend { sout | "Then!"; }// restart last resume28 suspend_then(then); // restart last resume 26 29 fn = 1; fn2 = fn1; fn1 = fn; // 2nd case 27 suspend { sout | "Then!"; }// restart last resume30 suspend_then(then); // restart last resume 28 31 for () { 29 32 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; // general case 30 suspend { sout | "Then!"; }// restart last resume33 suspend_then(then); // restart last resume 31 34 } // for 32 35 } -
tests/errors/.expect/completeType.txt
rff489bf r9867cdb 27 27 void 28 28 ) 29 Environment:( _8 5_4_DT ) -> instance of struct A with body 0 (no widening)29 Environment:( _83_4_DT ) -> instance of struct A with body 0 (no widening) 30 30 31 31 … … 50 50 void 51 51 ) 52 Environment:( _8 5_4_DT ) -> instance of struct B with body 1 (no widening)52 Environment:( _83_4_DT ) -> instance of struct B with body 1 (no widening) 53 53 54 54 … … 127 127 void 128 128 ) 129 Environment:( _10 4_0_T ) -> instance of type T (not function type) (no widening)129 Environment:( _102_0_T ) -> instance of type T (not function type) (no widening) 130 130 131 131 Could not satisfy assertion: 132 132 ?=?: pointer to function 133 133 ... with parameters 134 reference to instance of type _10 4_0_T (not function type)135 instance of type _10 4_0_T (not function type)134 reference to instance of type _102_0_T (not function type) 135 instance of type _102_0_T (not function type) 136 136 ... returning 137 _retval__operator_assign: instance of type _10 4_0_T (not function type)137 _retval__operator_assign: instance of type _102_0_T (not function type) 138 138 ... with attributes: 139 139 Attribute with name: unused
Note:
See TracChangeset
for help on using the changeset viewer.