Ignore:
Timestamp:
Mar 21, 2022, 1:44:06 PM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, ast-experimental, enum, master, pthread-emulation, qualifiedEnum
Children:
a76202d
Parents:
ef3c383 (diff), dbe2533 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Concurrency/KeywordsNew.cpp

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