Changeset 5b544a6


Ignore:
Timestamp:
Mar 9, 2020, 11:09:52 AM (19 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr
Children:
6565321
Parents:
87f572e (diff), e6cfa8ff (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.
Message:

Merge branch 'generator'

Files:
9 added
38 edited
1 moved

Legend:

Unmodified
Added
Removed
  • benchmark/ctxswitch/cfa_cor.cfa

    r87f572e r5b544a6  
    77void main( __attribute__((unused)) C & ) {
    88        while () {
    9                 suspend();
     9                suspend;
    1010        }
    1111}
  • libcfa/prelude/builtins.c

    r87f572e r5b544a6  
    4848void exit( int status, const char fmt[], ... ) __attribute__ (( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));
    4949void abort( const char fmt[], ... ) __attribute__ (( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));
     50
     51forall(dtype T)
     52static inline T & identity(T & i) {
     53        return i;
     54}
     55
     56// generator support
     57struct $generator {
     58        inline int;
     59};
     60
     61static inline void  ?{}($generator & this) { ((int&)this) = 0; }
     62static inline void ^?{}($generator &) {}
     63
     64trait is_generator(dtype T) {
     65      void main(T & this);
     66      $generator * get_generator(T & this);
     67};
     68
     69forall(dtype T | is_generator(T))
     70static inline T & resume(T & gen) {
     71        main(gen);
     72        return gen;
     73}
    5074
    5175// implicit increment, decrement if += defined, and implicit not if != defined
  • libcfa/src/concurrency/coroutine.cfa

    r87f572e r5b544a6  
    208208
    209209                if(cor->state == Primed) {
    210                         suspend();
     210                        __cfactx_suspend();
    211211                }
    212212
  • libcfa/src/concurrency/coroutine.hfa

    r87f572e r5b544a6  
    4646//-----------------------------------------------------------------------------
    4747// 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 
    5348forall(dtype T | is_coroutine(T))
    5449void prime(T & cor);
     
    9691
    9792// Suspend implementation inlined for performance
    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;
     93extern "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;
    105101
    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 );
     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 );
    114110
    115         $ctx_switch( src, src->last );
     111                $ctx_switch( src, src->last );
     112        }
    116113}
    117114
  • src/AST/Convert.cpp

    r87f572e r5b544a6  
    493493        }
    494494
     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
    495507        const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    496508                if ( inCache( node ) ) return nullptr;
     
    18591871        }
    18601872
     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
    18611891        virtual void visit( const WaitForStmt * old ) override final {
    18621892                if ( inCache( old ) ) return;
  • src/AST/Decl.hpp

    r87f572e r5b544a6  
    259259
    260260        bool is_coroutine() { return kind == Coroutine; }
    261         bool is_monitor() { return kind == Monitor; }
    262         bool is_thread() { return kind == Thread; }
     261        bool is_generator() { return kind == Generator; }
     262        bool is_monitor  () { return kind == Monitor  ; }
     263        bool is_thread   () { return kind == Thread   ; }
    263264
    264265        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    r87f572e r5b544a6  
    5353class CatchStmt;
    5454class FinallyStmt;
     55class SuspendStmt;
    5556class WaitForStmt;
    5657class WithStmt;
  • src/AST/Pass.hpp

    r87f572e r5b544a6  
    111111        const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
    112112        const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
     113        const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
    113114        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    114115        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    r87f572e r5b544a6  
    823823
    824824//--------------------------------------------------------------------------
     825// FinallyStmt
     826template< typename pass_t >
     827const 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//--------------------------------------------------------------------------
    825838// WaitForStmt
    826839template< typename pass_t >
  • src/AST/Print.cpp

    r87f572e r5b544a6  
    674674                safe_print( node->body );
    675675                --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;
    676695
    677696                return node;
  • src/AST/Stmt.hpp

    r87f572e r5b544a6  
    342342};
    343343
     344/// Suspend statement
     345class SuspendStmt final : public Stmt {
     346public:
     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 ); }
     354private:
     355        SuspendStmt * clone() const override { return new SuspendStmt{ *this }; }
     356        MUTATE_FRIEND
     357};
     358
    344359/// Wait for concurrency statement `when (...) waitfor (... , ...) ... timeout(...) ... else ...`
    345360class WaitForStmt final : public Stmt {
  • src/AST/Visitor.hpp

    r87f572e r5b544a6  
    4747    virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) = 0;
    4848    virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) = 0;
     49    virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
    4950    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5051    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
  • src/Common/PassVisitor.h

    r87f572e r5b544a6  
    110110        virtual void visit( FinallyStmt * finallyStmt ) override final;
    111111        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;
    112114        virtual void visit( WaitForStmt * waitforStmt ) override final;
    113115        virtual void visit( const WaitForStmt * waitforStmt ) override final;
     
    276278        virtual Statement * mutate( CatchStmt * catchStmt ) override final;
    277279        virtual Statement * mutate( FinallyStmt * finallyStmt ) override final;
     280        virtual Statement * mutate( SuspendStmt * suspendStmt ) override final;
    278281        virtual Statement * mutate( WaitForStmt * waitforStmt ) override final;
    279282        virtual Declaration * mutate( WithStmt * withStmt ) override final;
  • src/Common/PassVisitor.impl.h

    r87f572e r5b544a6  
    15221522
    15231523//--------------------------------------------------------------------------
     1524// SuspendStmt
     1525template< typename pass_type >
     1526void PassVisitor< pass_type >::visit( SuspendStmt * node ) {
     1527        VISIT_START( node );
     1528
     1529        maybeAccept_impl( node->then  , *this );
     1530
     1531        VISIT_END( node );
     1532}
     1533
     1534template< typename pass_type >
     1535void 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
     1543template< typename pass_type >
     1544Statement * 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//--------------------------------------------------------------------------
    15241553// WaitForStmt
    15251554template< typename pass_type >
  • src/Concurrency/Keywords.cc

    r87f572e r5b544a6  
    1616#include "Concurrency/Keywords.h"
    1717
    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
     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
    3536
    3637class Attribute;
     
    147148        };
    148149
     150
     151
    149152        //-----------------------------------------------------------------------------
    150153        //Handles monitor type declarations :
     
    180183
    181184        //-----------------------------------------------------------------------------
     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::Generator
     202                )
     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        //-----------------------------------------------------------------------------
    182256        //Handles mutex routines definitions :
    183257        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
     
    251325                CoroutineKeyword        ::implement( translationUnit );
    252326                MonitorKeyword  ::implement( translationUnit );
     327                GeneratorKeyword  ::implement( translationUnit );
     328                SuspendKeyword    ::implement( translationUnit );
    253329        }
    254330
     
    446522
    447523                declsToAddAfter.push_back( get_decl );
    448 
    449                 // get_decl->fixUniqueId();
    450         }
     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
    451756
    452757        //=============================================================================================
  • src/Parser/ParseNode.h

    r87f572e r5b544a6  
    428428Statement * build_asm( bool voltile, Expression * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    429429Statement * build_directive( std::string * directive );
     430SuspendStmt * build_suspend( StatementNode *, SuspendStmt::Type = SuspendStmt::None);
    430431WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when );
    431432WaitForStmt * build_waitfor( ExpressionNode * target, StatementNode * stmt, ExpressionNode * when, WaitForStmt * existing );
  • src/Parser/StatementNode.cc

    r87f572e r5b544a6  
    249249} // build_finally
    250250
     251SuspendStmt * 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
    251266WaitForStmt * build_waitfor( ExpressionNode * targetExpr, StatementNode * stmt, ExpressionNode * when ) {
    252267        auto node = new WaitForStmt();
  • src/Parser/TypeData.cc

    r87f572e r5b544a6  
    769769          case AggregateDecl::Struct:
    770770          case AggregateDecl::Coroutine:
     771          case AggregateDecl::Generator:
    771772          case AggregateDecl::Monitor:
    772773          case AggregateDecl::Thread:
  • src/Parser/lex.ll

    r87f572e r5b544a6  
    6565#define FLOATXX(v) KEYWORD_RETURN(v);
    6666#else
    67 #define FLOATXX(v) IDENTIFIER_RETURN(); 
     67#define FLOATXX(v) IDENTIFIER_RETURN();
    6868#endif // HAVE_KEYWORDS_FLOATXX
    6969
     
    301301_Static_assert  { KEYWORD_RETURN(STATICASSERT); }               // C11
    302302struct                  { KEYWORD_RETURN(STRUCT); }
    303         /* suspend                      { KEYWORD_RETURN(SUSPEND); }                    // CFA */
     303suspend                 { KEYWORD_RETURN(SUSPEND); }                    // CFA
    304304switch                  { KEYWORD_RETURN(SWITCH); }
    305305thread                  { KEYWORD_RETURN(THREAD); }                             // C11
  • src/Parser/parser.yy

    r87f572e r5b544a6  
    278278%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    279279%token SIZEOF OFFSETOF
    280 // %token SUSPEND RESUME                                                                        // CFA
     280// %token RESUME                                                                        // CFA
     281%token SUSPEND                                                                  // CFA
    281282%token ATTRIBUTE EXTENSION                                                              // GCC
    282283%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
     
    12591260        | RETURN '{' initializer_list_opt comma_opt '}' ';'
    12601261                { SemanticError( yylloc, "Initializer return is currently unimplemented." ); $$ = nullptr; }
    1261         // | SUSPEND ';'
    1262         //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
    1263         // | SUSPEND compound_statement ';'
    1264         //      { SemanticError( yylloc, "Suspend expression is currently unimplemented." ); $$ = nullptr; }
     1262        | SUSPEND ';'
     1263                { $$ = new StatementNode( build_suspend( nullptr ) ); }
     1264        | SUSPEND compound_statement
     1265                { $$ = new StatementNode( build_suspend( $2 ) ); }
     1266        | SUSPEND COROUTINE ';'
     1267                { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Coroutine ) ); }
     1268        | SUSPEND COROUTINE compound_statement
     1269                { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Coroutine ) ); }
     1270        | SUSPEND GENERATOR ';'
     1271                { $$ = new StatementNode( build_suspend( nullptr, SuspendStmt::Generator ) ); }
     1272        | SUSPEND GENERATOR compound_statement
     1273                { $$ = new StatementNode( build_suspend( $3, SuspendStmt::Generator ) ); }
    12651274        | THROW assignment_expression_opt ';'                           // handles rethrow
    12661275                { $$ = new StatementNode( build_throw( $2 ) ); }
     
    20772086aggregate_control:                                                                              // CFA
    20782087        GENERATOR
    2079                 { SemanticError( yylloc, "generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2088                { yyy = true; $$ = AggregateDecl::Generator; }
    20802089        | MONITOR GENERATOR
    20812090                { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
  • src/SynTree/Declaration.h

    r87f572e r5b544a6  
    302302
    303303        bool is_coroutine() { return kind == Coroutine; }
    304         bool is_monitor() { return kind == Monitor; }
    305         bool is_thread() { return kind == Thread; }
     304        bool is_generator() { return kind == Generator; }
     305        bool is_monitor  () { return kind == Monitor  ; }
     306        bool is_thread   () { return kind == Thread   ; }
    306307
    307308        virtual StructDecl * clone() const override { return new StructDecl( *this ); }
  • src/SynTree/Mutator.h

    r87f572e r5b544a6  
    5151        virtual Statement * mutate( CatchStmt * catchStmt ) = 0;
    5252        virtual Statement * mutate( FinallyStmt * catchStmt ) = 0;
     53        virtual Statement * mutate( SuspendStmt * suspendStmt ) = 0;
    5354        virtual Statement * mutate( WaitForStmt * waitforStmt ) = 0;
    5455        virtual Declaration * mutate( WithStmt * withStmt ) = 0;
  • src/SynTree/Statement.cc

    r87f572e r5b544a6  
    420420}
    421421
     422SuspendStmt::SuspendStmt( const SuspendStmt & other )
     423        : Statement( other )
     424        , then( maybeClone(other.then) )
     425{}
     426
     427SuspendStmt::~SuspendStmt() {
     428        delete then;
     429}
     430
     431void 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
    422447WaitForStmt::WaitForStmt() : Statement() {
    423448        timeout.time      = nullptr;
  • src/SynTree/Statement.h

    r87f572e r5b544a6  
    422422};
    423423
     424class 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
    424440class WaitForStmt : public Statement {
    425441  public:
  • src/SynTree/SynTree.h

    r87f572e r5b544a6  
    5454class CatchStmt;
    5555class FinallyStmt;
     56class SuspendStmt;
    5657class WaitForStmt;
    5758class WithStmt;
  • src/SynTree/Visitor.h

    r87f572e r5b544a6  
    7878        virtual void visit( FinallyStmt * node ) { visit( const_cast<const FinallyStmt *>(node) ); }
    7979        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;
    8082        virtual void visit( WaitForStmt * node ) { visit( const_cast<const WaitForStmt *>(node) ); }
    8183        virtual void visit( const WaitForStmt * waitforStmt ) = 0;
  • tests/concurrent/coroutineYield.cfa

    r87f572e r5b544a6  
    3333                        sout | "Coroutine 2";
    3434                #endif
    35                 suspend();
     35                suspend;
    3636        }
    3737}
  • tests/concurrent/suspend_then.cfa

    r87f572e r5b544a6  
    11#include <fstream.hfa>
    22#include <kernel.hfa>
    3 #include <monitor.hfa>
    43#include <thread.hfa>
    54#include <time.hfa>
     
    109#include "long_tests.hfa"
    1110
    12 #ifndef PREEMPTION_RATE
    13 #define PREEMPTION_RATE 10`ms
    14 #endif
    15 
    1611Duration default_preemption() {
    17         return PREEMPTION_RATE;
     12        return 0;
    1813}
    1914
     
    2621#if !defined(TEST_FOREVER)
    2722        static inline void print(const char * const text ) {
    28                 write( STDERR_FILENO, text, strlen(text) );
     23                write( STDOUT_FILENO, text, strlen(text) );
    2924        }
    3025#else
     
    3227#endif
    3328
    34 coroutine Coroutine {};
     29generator Coroutine { int i; };
    3530
    3631volatile bool done = false;
     
    4944
    5045void main(Coroutine& this) {
    51         suspend();
    52         for(int i = 0; TEST(i < N); i++) {
     46        this.i = 0;
     47        suspend;
     48        for(;TEST(this.i < N); this.i++) {
    5349
    54                 print("C - Suspending");
    55                 void publish() {
    56                         print("C - Publishing");
     50                print("C - Suspending\n");
     51                suspend{
     52                        print("C - Publishing\n");
    5753                        assert(!the_cor);
    5854                        store( this );
    5955                }
    60                 suspend_then(publish);
    6156                assert(!the_cor);
    62                 print("Coroutine 2");
     57                print("C - Back\n");
    6358                KICK_WATCHDOG;
    6459                yield();
    6560        }
    6661        done = true;
    67         suspend();
     62        suspend;
    6863}
    6964
     
    7772                if(!mine) continue;
    7873
    79                 print("T - took");
     74                print("T - took\n");
    8075                resume(*mine);
    81                 print("T - back");
    8276        }
    8377}
  • tests/coroutine/.expect/fmtLines.txt

    r87f572e r5b544a6  
    4848{                                                         // f  or n  ewli 
    4949ne c  hara  cter  s                                     su 
    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:   //
     50spen  d;                                        i  f (   fmt. 
     51ch !  = '\  n' )   bre  ak;      
     52        //   igno  re n  ewli  ne                
     53                }   // f  or                            so  ut | 
     54 fmt  .ch;                                                      /  / pr 
     55int   char  acte  r                       } // 
     56 for                    s  out   | "    ";       
     57                                                        /  / pr  int   bloc 
     58k se  para  tor         } /  / fo 
     59r               s  out   | nl  ;                                                         
     60                //   pri  nt g  roup   sep 
     61arat  or        }   //   for}   //  
     62main  void   prt  ( Fo  rmat 
     63 & f  mt,   char   ch   ) {   
     64   f  mt.c  h =   ch;      r 
     65esum  e( f  mt )  ;} /  / pr 
     66tint   mai  n()   {     Fo  rmat 
     67 fmt  ; ch  ar c  h;    f  or ( 
     68 ;;   ) {               sin   | c  h;            
     69                                                                  // r  ead   one  
     70char  acte  r       if (   eof 
     71( si  n )   ) br  eak;                                   
     72                        /  / eo  f ?            prt  ( fm 
     73t, c  h );      } /  / fo  r} / 
     74/ ma  in//   Loc  al V  aria 
     75bles  : //  // t  ab-w  idth 
     76: 4   ////   com  pile  -com 
     77mand  : "c  fa f  mtLi  nes. 
     78cfa"   ///  / En  d: /  /
  • tests/coroutine/.in/fmtLines.txt

    r87f572e r5b544a6  
    3535                        for ( fmt.b = 0; fmt.b < 4; fmt.b += 1 ) {      // blocks of 4 characters
    3636                                for ( ;; ) {                                                    // for newline characters
    37                                         suspend();
     37                                        suspend;
    3838                                        if ( fmt.ch != '\n' ) break;            // ignore newline
    3939                                } // for
  • tests/coroutine/cntparens.cfa

    r87f572e r5b544a6  
    1 // 
     1//
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 // 
     6//
    77// cntparens.cfa -- match left/right parenthesis
    8 // 
     8//
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Apr 20 11:04:45 2019
     
    1212// Last Modified On : Sat Apr 20 11:06:21 2019
    1313// Update Count     : 1
    14 // 
     14//
    1515
    1616#include <fstream.hfa>
     
    2626void main( CntParens & cpns ) with( cpns ) {
    2727        for ( ; ch == '('; cnt += 1 ) {                                         // left parenthesis
    28                 suspend();
     28                suspend;
    2929        }
    3030        for ( ; ch == ')' && cnt > 1; cnt -= 1 ) {                      // right parenthesis
    31                 suspend();
     31                suspend;
    3232        }
    3333        status = ch == ')' ? Match : Error;
    3434} // main
    35        
     35
    3636void ?{}( CntParens & cpns ) with( cpns ) { status = Cont; cnt = 0; }
    3737
  • tests/coroutine/devicedriver.cfa

    r87f572e r5b544a6  
    1 // 
     1//
    22// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    44// The contents of this file are covered under the licence agreement in the
    55// file "LICENCE" distributed with Cforall.
    6 // 
    7 // devicedriver.cfa -- 
    8 // 
     6//
     7// devicedriver.cfa --
     8//
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Mar 16 15:30:34 2019
     
    1212// Last Modified On : Sat Apr 20 09:07:19 2019
    1313// Update Count     : 90
    14 // 
     14//
    1515
    1616#include <fstream.hfa>
     
    2929
    3030void checkCRC( Driver & d, unsigned int sum ) with( d ) {
    31         suspend();
     31        suspend;
    3232        unsigned short int crc = byte << 8;                                     // sign extension over written
    33         suspend();
     33        suspend;
    3434        // prevent sign extension for signed char
    3535        status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
     
    4141                status = CONT;
    4242                unsigned int lnth = 0, sum = 0;
    43                 while ( byte != STX ) suspend();
     43                while ( byte != STX ) suspend;
    4444          emsg: for () {
    45                         suspend();
     45                        suspend;
    4646                        choose ( byte ) {                                                       // process byte
    4747                          case STX:
    48                                 status = ESTX; suspend(); continue msg;
     48                                status = ESTX; suspend; continue msg;
    4949                          case ETX:
    5050                                break emsg;
    5151                          case ESC:
    52                                 suspend();
     52                                suspend;
    5353                        } // choose
    5454                        if ( lnth >= MaxMsg ) {                                         // buffer full ?
    55                                 status = ELNTH; suspend(); continue msg;
     55                                status = ELNTH; suspend; continue msg;
    5656                        } // if
    5757                        msg[lnth++] = byte;
     
    6060                msg[lnth] = '\0';                                                               // terminate string
    6161                checkCRC( d, sum );                                                             // refactor CRC check
    62                 suspend();
     62                suspend;
    6363        } // for
    6464} // main
  • tests/coroutine/fibonacci.cfa

    r87f572e r5b544a6  
    2222        int fn1, fn2;                                                                           // retained between resumes
    2323        fn = 0;  fn1 = fn;                                                                      // 1st case
    24         suspend();                                                                                      // restart last resume
     24        suspend;                                                                                        // restart last resume
    2525        fn = 1;  fn2 = fn1;  fn1 = fn;                                          // 2nd case
    26         suspend();                                                                                      // restart last resume
     26        suspend;                                                                                        // restart last resume
    2727        for () {
    2828                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    29                 suspend();                                                                              // restart last resume
     29                suspend;                                                                                // restart last resume
    3030        } // for
    3131}
  • tests/coroutine/fibonacci_1.cfa

    r87f572e r5b544a6  
    1212// Last Modified On : Thu Mar 21 08:10:45 2019
    1313// Update Count     : 25
    14 // 
     14//
    1515
    1616#include <fstream.hfa>
     
    2323        [fn1, fn] = [0, 1];                                                                     // precompute first two states
    2424        for () {
    25                 suspend();                                                                              // restart last resume
     25                suspend;                                                                                // restart last resume
    2626                [fn1, fn] = [fn, fn1 + fn];                                             // general case
    2727        } // for
  • tests/coroutine/fmtLines.cfa

    r87f572e r5b544a6  
    2727                        for ( b = 0; b < 4; b += 1 ) {                          // blocks of 4 characters
    2828                                for () {                                                                // for newline characters
    29                                         suspend();
     29                                        suspend;
    3030                                  if ( ch != '\n' ) break;                              // ignore newline
    3131                                } // for
  • tests/coroutine/raii.cfa

    r87f572e r5b544a6  
    3939        Raii raii = { "Coroutine" };
    4040        sout | "Before Suspend";
    41         suspend();
     41        suspend;
    4242        sout | "After Suspend";
    4343}
  • tests/coroutine/runningTotal.cfa

    r87f572e r5b544a6  
    2525void update( RunTotal & rntl, int input ) with( rntl ) { // helper
    2626        total += input;                                                                         // remember between activations
    27         suspend();                                                                                      // inactivate on stack
     27        suspend;                                                                                        // inactivate on stack
    2828}
    2929
  • tests/coroutine/suspend_then.cfa

    r87f572e r5b544a6  
    1515
    1616#include <fstream.hfa>
    17 #include <coroutine.hfa>
    1817
    19 void then() {
    20         sout | "Then!";
    21 }
    22 
    23 coroutine Fibonacci { int fn; };                                                // used for communication
     18generator Fibonacci {
     19        int fn;                                                                         // used for communication
     20        int fn1, fn2;                                                           // retained between resumes
     21};
    2422
    2523void main( Fibonacci & fib ) with( fib ) {                              // called on first resume
    26         int fn1, fn2;                                                           // retained between resumes
    2724        fn = 0;  fn1 = fn;                                                      // 1st case
    28         suspend_then(then);                                                     // restart last resume
     25        suspend { sout | "Then!"; }                                             // restart last resume
    2926        fn = 1;  fn2 = fn1;  fn1 = fn;                                  // 2nd case
    30         suspend_then(then);                                                     // restart last resume
     27        suspend { sout | "Then!"; }                                             // restart last resume
    3128        for () {
    3229                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    33                 suspend_then(then);                                             // restart last resume
     30                suspend { sout | "Then!"; }                                     // restart last resume
    3431        } // for
    3532}
  • tests/errors/.expect/completeType.txt

    r87f572e r5b544a6  
    2727    void
    2828  )
    29   Environment:( _83_4_DT ) -> instance of struct A with body 0 (no widening)
     29  Environment:( _85_4_DT ) -> instance of struct A with body 0 (no widening)
    3030
    3131
     
    5050    void
    5151  )
    52   Environment:( _83_4_DT ) -> instance of struct B with body 1 (no widening)
     52  Environment:( _85_4_DT ) -> instance of struct B with body 1 (no widening)
    5353
    5454
     
    127127          void
    128128        )
    129         Environment:( _102_0_T ) -> instance of type T (not function type) (no widening)
     129        Environment:( _104_0_T ) -> instance of type T (not function type) (no widening)
    130130
    131131      Could not satisfy assertion:
    132132?=?: pointer to function
    133133        ... with parameters
    134           reference to instance of type _102_0_T (not function type)
    135           instance of type _102_0_T (not function type)
     134          reference to instance of type _104_0_T (not function type)
     135          instance of type _104_0_T (not function type)
    136136        ... returning
    137           _retval__operator_assign: instance of type _102_0_T (not function type)
     137          _retval__operator_assign: instance of type _104_0_T (not function type)
    138138          ... with attributes:
    139139            Attribute with name: unused
Note: See TracChangeset for help on using the changeset viewer.