Ignore:
Timestamp:
Apr 19, 2022, 3:00:04 PM (3 years ago)
Author:
m3zulfiq <m3zulfiq@…>
Branches:
ADT, ast-experimental, master, pthread-emulation, qualifiedEnum
Children:
5b84a321
Parents:
ba897d21 (diff), bb7c77d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

added benchmark and evaluations chapter to thesis

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Concurrency/KeywordsNew.cpp

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