source: src/Concurrency/Keywords.cc @ d0e80f61

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since d0e80f61 was 43cedfb1, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Fixed extra declaration of vtable on forwarded declarations of threads

  • Property mode set to 100644
File size: 35.0 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Keywords.cc --
8//
9// Author           : Thierry Delisle
10// Created On       : Mon Mar 13 12:41:22 2017
11// Last Modified By :
12// Last Modified On :
13// Update Count     : 10
14//
15
16#include "Concurrency/Keywords.h"
17
18#include <cassert>                        // for assert
19#include <string>                         // for string, operator==
20
21#include <iostream>
22
23#include "Common/Examine.h"               // for isMainFor
24#include "Common/PassVisitor.h"           // for PassVisitor
25#include "Common/SemanticError.h"         // for SemanticError
26#include "Common/utility.h"               // for deleteAll, map_range
27#include "CodeGen/OperatorTable.h"        // for isConstructor
28#include "ControlStruct/LabelGenerator.h" // for LebelGenerator
29#include "InitTweak/InitTweak.h"          // for getPointerBase
30#include "SynTree/LinkageSpec.h"          // for Cforall
31#include "SynTree/Constant.h"             // for Constant
32#include "SynTree/Declaration.h"          // for StructDecl, FunctionDecl, ObjectDecl
33#include "SynTree/Expression.h"           // for VariableExpr, ConstantExpr, Untype...
34#include "SynTree/Initializer.h"          // for SingleInit, ListInit, Initializer ...
35#include "SynTree/Label.h"                // for Label
36#include "SynTree/Statement.h"            // for CompoundStmt, DeclStmt, ExprStmt
37#include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
38#include "SynTree/Visitor.h"              // for Visitor, acceptAll
39#include "Virtual/Tables.h"
40
41class Attribute;
42
43namespace Concurrency {
44        inline static std::string getVTableName( std::string const & exception_name ) {
45                return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
46        }
47
48        // Only detects threads constructed with the keyword thread.
49        inline static bool isThread( DeclarationWithType * decl ) {
50                Type * baseType = decl->get_type()->stripDeclarator();
51                StructInstType * instType = dynamic_cast<StructInstType *>( baseType );
52                if ( nullptr == instType ) { return false; }
53                return instType->baseStruct->is_thread();
54        }
55
56        //=============================================================================================
57        // Pass declarations
58        //=============================================================================================
59
60        //-----------------------------------------------------------------------------
61        //Handles sue type declarations :
62        // sue MyType {                             struct MyType {
63        //      int data;                                  int data;
64        //      a_struct_t more_data;                      a_struct_t more_data;
65        //                                =>             NewField_t newField;
66        // };                                        };
67        //                                           static inline NewField_t * getter_name( MyType * this ) { return &this->newField; }
68        //
69        class ConcurrentSueKeyword : public WithDeclsToAdd {
70          public:
71
72                ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name,
73                        std::string&& getter_name, std::string&& context_error, std::string&& exception_name,
74                        bool needs_main, AggregateDecl::Aggregate cast_target ) :
75                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
76                  context_error( context_error ), exception_name( exception_name ),
77                  vtable_name( getVTableName( exception_name ) ),
78                  needs_main( needs_main ), cast_target( cast_target ) {}
79
80                virtual ~ConcurrentSueKeyword() {}
81
82                Declaration * postmutate( StructDecl * decl );
83                DeclarationWithType * postmutate( FunctionDecl * decl );
84
85                void handle( StructDecl * );
86                void addVtableForward( StructDecl * );
87                FunctionDecl * forwardDeclare( StructDecl * );
88                ObjectDecl * addField( StructDecl * );
89                void addRoutines( ObjectDecl *, FunctionDecl * );
90
91                virtual bool is_target( StructDecl * decl ) = 0;
92
93                Expression * postmutate( KeywordCastExpr * cast );
94
95          private:
96                const std::string type_name;
97                const std::string field_name;
98                const std::string getter_name;
99                const std::string context_error;
100                const std::string exception_name;
101                const std::string vtable_name;
102                bool needs_main;
103                AggregateDecl::Aggregate cast_target;
104
105                StructDecl   * type_decl = nullptr;
106                FunctionDecl * dtor_decl = nullptr;
107                StructDecl * except_decl = nullptr;
108                StructDecl * vtable_decl = nullptr;
109        };
110
111
112        //-----------------------------------------------------------------------------
113        //Handles thread type declarations :
114        // thread Mythread {                         struct MyThread {
115        //      int data;                                  int data;
116        //      a_struct_t more_data;                      a_struct_t more_data;
117        //                                =>             $thread __thrd_d;
118        // };                                        };
119        //                                           static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
120        //
121        class ThreadKeyword final : public ConcurrentSueKeyword {
122          public:
123
124                ThreadKeyword() : ConcurrentSueKeyword(
125                        "$thread",
126                        "__thrd",
127                        "get_thread",
128                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
129                        "ThreadCancelled",
130                        true,
131                        AggregateDecl::Thread
132                )
133                {}
134
135                virtual ~ThreadKeyword() {}
136
137                virtual bool is_target( StructDecl * decl ) override final { return decl->is_thread(); }
138
139                static void implement( std::list< Declaration * > & translationUnit ) {
140                        PassVisitor< ThreadKeyword > impl;
141                        mutateAll( translationUnit, impl );
142                }
143        };
144
145        //-----------------------------------------------------------------------------
146        //Handles coroutine type declarations :
147        // coroutine MyCoroutine {                   struct MyCoroutine {
148        //      int data;                                  int data;
149        //      a_struct_t more_data;                      a_struct_t more_data;
150        //                                =>             $coroutine __cor_d;
151        // };                                        };
152        //                                           static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
153        //
154        class CoroutineKeyword final : public ConcurrentSueKeyword {
155          public:
156
157                CoroutineKeyword() : ConcurrentSueKeyword(
158                        "$coroutine",
159                        "__cor",
160                        "get_coroutine",
161                        "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
162                        "CoroutineCancelled",
163                        true,
164                        AggregateDecl::Coroutine
165                )
166                {}
167
168                virtual ~CoroutineKeyword() {}
169
170                virtual bool is_target( StructDecl * decl ) override final { return decl->is_coroutine(); }
171
172                static void implement( std::list< Declaration * > & translationUnit ) {
173                        PassVisitor< CoroutineKeyword > impl;
174                        mutateAll( translationUnit, impl );
175                }
176        };
177
178
179
180        //-----------------------------------------------------------------------------
181        //Handles monitor type declarations :
182        // monitor MyMonitor {                       struct MyMonitor {
183        //      int data;                                  int data;
184        //      a_struct_t more_data;                      a_struct_t more_data;
185        //                                =>             $monitor __mon_d;
186        // };                                        };
187        //                                           static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
188        //
189        class MonitorKeyword final : public ConcurrentSueKeyword {
190          public:
191
192                MonitorKeyword() : ConcurrentSueKeyword(
193                        "$monitor",
194                        "__mon",
195                        "get_monitor",
196                        "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
197                        "",
198                        false,
199                        AggregateDecl::Monitor
200                )
201                {}
202
203                virtual ~MonitorKeyword() {}
204
205                virtual bool is_target( StructDecl * decl ) override final { return decl->is_monitor(); }
206
207                static void implement( std::list< Declaration * > & translationUnit ) {
208                        PassVisitor< MonitorKeyword > impl;
209                        mutateAll( translationUnit, impl );
210                }
211        };
212
213        //-----------------------------------------------------------------------------
214        //Handles generator type declarations :
215        // generator MyGenerator {                   struct MyGenerator {
216        //      int data;                                  int data;
217        //      a_struct_t more_data;                      a_struct_t more_data;
218        //                                =>             int __gen_next;
219        // };                                        };
220        //
221        class GeneratorKeyword final : public ConcurrentSueKeyword {
222          public:
223
224                GeneratorKeyword() : ConcurrentSueKeyword(
225                        "$generator",
226                        "__generator_state",
227                        "get_generator",
228                        "Unable to find builtin type $generator\n",
229                        "",
230                        true,
231                        AggregateDecl::Generator
232                )
233                {}
234
235                virtual ~GeneratorKeyword() {}
236
237                virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
238
239                static void implement( std::list< Declaration * > & translationUnit ) {
240                        PassVisitor< GeneratorKeyword > impl;
241                        mutateAll( translationUnit, impl );
242                }
243        };
244
245
246        //-----------------------------------------------------------------------------
247        class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
248        public:
249                SuspendKeyword() = default;
250                virtual ~SuspendKeyword() = default;
251
252                void  premutate( FunctionDecl * );
253                DeclarationWithType * postmutate( FunctionDecl * );
254
255                Statement * postmutate( SuspendStmt * );
256
257                static void implement( std::list< Declaration * > & translationUnit ) {
258                        PassVisitor< SuspendKeyword > impl;
259                        mutateAll( translationUnit, impl );
260                }
261
262        private:
263                bool is_real_suspend( FunctionDecl * );
264
265                Statement * make_generator_suspend( SuspendStmt * );
266                Statement * make_coroutine_suspend( SuspendStmt * );
267
268                struct LabelPair {
269                        Label obj;
270                        int   idx;
271                };
272
273                LabelPair make_label() {
274                        labels.push_back( gen.newLabel("generator") );
275                        return { labels.back(), int(labels.size()) };
276                }
277
278                DeclarationWithType * in_generator = nullptr;
279                FunctionDecl * decl_suspend = nullptr;
280                std::vector<Label> labels;
281                ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
282        };
283
284        //-----------------------------------------------------------------------------
285        //Handles mutex routines definitions :
286        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
287        //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
288        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
289        //    /*Some code*/                                       =>           /*Some code*/
290        // }                                                               }
291        //
292        class MutexKeyword final {
293          public:
294
295                void postvisit( FunctionDecl * decl );
296                void postvisit(   StructDecl * decl );
297
298                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
299                void validate( DeclarationWithType * );
300                void addDtorStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
301                void addStatements( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
302                void addThreadDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args );
303
304                static void implement( std::list< Declaration * > & translationUnit ) {
305                        PassVisitor< MutexKeyword > impl;
306                        acceptAll( translationUnit, impl );
307                }
308
309          private:
310                StructDecl* monitor_decl = nullptr;
311                StructDecl* guard_decl = nullptr;
312                StructDecl* dtor_guard_decl = nullptr;
313                StructDecl* thread_guard_decl = nullptr;
314
315                static std::unique_ptr< Type > generic_func;
316        };
317
318        std::unique_ptr< Type > MutexKeyword::generic_func = std::unique_ptr< Type >(
319                new FunctionType(
320                        noQualifiers,
321                        true
322                )
323        );
324
325        //-----------------------------------------------------------------------------
326        //Handles mutex routines definitions :
327        // void foo( A * mutex a, B * mutex b,  int i ) {                  void foo( A * a, B * b,  int i ) {
328        //                                                                       $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
329        //                                                                       monitor_guard_t __guard = { __monitors, 2 };
330        //    /*Some code*/                                       =>           /*Some code*/
331        // }                                                               }
332        //
333        class ThreadStarter final {
334          public:
335
336                void postvisit( FunctionDecl * decl );
337                void previsit ( StructDecl   * decl );
338
339                void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
340
341                static void implement( std::list< Declaration * > & translationUnit ) {
342                        PassVisitor< ThreadStarter > impl;
343                        acceptAll( translationUnit, impl );
344                }
345
346          private :
347                bool thread_ctor_seen = false;
348                StructDecl * thread_decl = nullptr;
349        };
350
351        //=============================================================================================
352        // General entry routine
353        //=============================================================================================
354        void applyKeywords( std::list< Declaration * > & translationUnit ) {
355                ThreadKeyword   ::implement( translationUnit );
356                CoroutineKeyword        ::implement( translationUnit );
357                MonitorKeyword  ::implement( translationUnit );
358                GeneratorKeyword  ::implement( translationUnit );
359                SuspendKeyword    ::implement( translationUnit );
360        }
361
362        void implementMutexFuncs( std::list< Declaration * > & translationUnit ) {
363                MutexKeyword    ::implement( translationUnit );
364        }
365
366        void implementThreadStarter( std::list< Declaration * > & translationUnit ) {
367                ThreadStarter   ::implement( translationUnit );
368        }
369
370        //=============================================================================================
371        // Generic keyword implementation
372        //=============================================================================================
373        void fixupGenerics(FunctionType * func, StructDecl * decl) {
374                cloneAll(decl->parameters, func->forall);
375                for ( TypeDecl * td : func->forall ) {
376                        strict_dynamic_cast<StructInstType*>(
377                                func->parameters.front()->get_type()->stripReferences()
378                        )->parameters.push_back(
379                                new TypeExpr( new TypeInstType( noQualifiers, td->name, td ) )
380                        );
381                }
382        }
383
384        Declaration * ConcurrentSueKeyword::postmutate(StructDecl * decl) {
385                if( decl->name == type_name && decl->body ) {
386                        assert( !type_decl );
387                        type_decl = decl;
388                }
389                else if ( is_target(decl) ) {
390                        handle( decl );
391                }
392                else if ( !except_decl && exception_name == decl->name && decl->body ) {
393                        except_decl = decl;
394                }
395                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
396                        vtable_decl = decl;
397                }
398                // Might be able to get ride of is target.
399                assert( is_target(decl) == (cast_target == decl->kind) );
400                return decl;
401        }
402
403        DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
404                if ( type_decl && isDestructorFor( decl, type_decl ) )
405                        dtor_decl = decl;
406                else if ( vtable_name.empty() )
407                        ;
408                else if( !decl->has_body() )
409                        ;
410                else if ( auto param = isMainFor( decl, cast_target ) ) {
411                        // This should never trigger.
412                        assert( vtable_decl );
413                        // Should be safe because of isMainFor.
414                        StructInstType * struct_type = static_cast<StructInstType *>(
415                                static_cast<ReferenceType *>( param->get_type() )->base );
416                        assert( struct_type );
417
418                        std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) };
419                        ObjectDecl * vtable_object = Virtual::makeVtableInstance(
420                                vtable_decl->makeInst( poly_args ), struct_type, nullptr );
421                        declsToAddAfter.push_back( vtable_object );
422                        declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
423                                vtable_object, except_decl->makeInst( std::move( poly_args ) )
424                        ) );
425                }
426
427                return decl;
428        }
429
430        Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
431                if ( cast_target == cast->target ) {
432                        // convert (thread &)t to ($thread &)*get_thread(t), etc.
433                        if( !type_decl ) SemanticError( cast, context_error );
434                        if( !dtor_decl ) SemanticError( cast, context_error );
435                        assert( cast->result == nullptr );
436                        cast->set_result( new ReferenceType( noQualifiers, new StructInstType( noQualifiers, type_decl ) ) );
437                        cast->concrete_target.field  = field_name;
438                        cast->concrete_target.getter = getter_name;
439                }
440                return cast;
441        }
442
443
444        void ConcurrentSueKeyword::handle( StructDecl * decl ) {
445                if( ! decl->body ) return;
446
447                if( !type_decl ) SemanticError( decl, context_error );
448                if( !dtor_decl ) SemanticError( decl, context_error );
449
450                addVtableForward( decl );
451                FunctionDecl * func = forwardDeclare( decl );
452                ObjectDecl * field = addField( decl );
453                addRoutines( field, func );
454        }
455
456        void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
457                if ( vtable_decl ) {
458                        std::list< Expression * > poly_args = {
459                                new TypeExpr( new StructInstType( noQualifiers, decl ) ),
460                        };
461                        declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
462                                vtable_decl->makeInst( poly_args ),
463                                except_decl->makeInst( poly_args )
464                        ) );
465                        declsToAddBefore.push_back( Virtual::makeVtableForward(
466                                vtable_decl->makeInst( move( poly_args ) ) ) );
467                // Its only an error if we want a vtable and don't have one.
468                } else if ( ! vtable_name.empty() ) {
469                        SemanticError( decl, context_error );
470                }
471        }
472
473        FunctionDecl * ConcurrentSueKeyword::forwardDeclare( StructDecl * decl ) {
474
475                StructDecl * forward = decl->clone();
476                forward->set_body( false );
477                deleteAll( forward->get_members() );
478                forward->get_members().clear();
479
480                FunctionType * get_type = new FunctionType( noQualifiers, false );
481                ObjectDecl * this_decl = new ObjectDecl(
482                        "this",
483                        noStorageClasses,
484                        LinkageSpec::Cforall,
485                        nullptr,
486                        new ReferenceType(
487                                noQualifiers,
488                                new StructInstType(
489                                        noQualifiers,
490                                        decl
491                                )
492                        ),
493                        nullptr
494                );
495
496                get_type->get_parameters().push_back( this_decl->clone() );
497                get_type->get_returnVals().push_back(
498                        new ObjectDecl(
499                                "ret",
500                                noStorageClasses,
501                                LinkageSpec::Cforall,
502                                nullptr,
503                                new PointerType(
504                                        noQualifiers,
505                                        new StructInstType(
506                                                noQualifiers,
507                                                type_decl
508                                        )
509                                ),
510                                nullptr
511                        )
512                );
513                fixupGenerics(get_type, decl);
514
515                FunctionDecl * get_decl = new FunctionDecl(
516                        getter_name,
517                        Type::Static,
518                        LinkageSpec::Cforall,
519                        get_type,
520                        nullptr,
521                        { new Attribute("const") },
522                        Type::Inline
523                );
524
525                FunctionDecl * main_decl = nullptr;
526
527                if( needs_main ) {
528                        FunctionType * main_type = new FunctionType( noQualifiers, false );
529
530                        main_type->get_parameters().push_back( this_decl->clone() );
531
532                        main_decl = new FunctionDecl(
533                                "main",
534                                noStorageClasses,
535                                LinkageSpec::Cforall,
536                                main_type,
537                                nullptr
538                        );
539                        fixupGenerics(main_type, decl);
540                }
541
542                delete this_decl;
543
544                declsToAddBefore.push_back( forward );
545                if( needs_main ) declsToAddBefore.push_back( main_decl );
546                declsToAddBefore.push_back( get_decl );
547
548                return get_decl;
549        }
550
551        ObjectDecl * ConcurrentSueKeyword::addField( StructDecl * decl ) {
552                ObjectDecl * field = new ObjectDecl(
553                        field_name,
554                        noStorageClasses,
555                        LinkageSpec::Cforall,
556                        nullptr,
557                        new StructInstType(
558                                noQualifiers,
559                                type_decl
560                        ),
561                        nullptr
562                );
563
564                decl->get_members().push_back( field );
565
566                return field;
567        }
568
569        void ConcurrentSueKeyword::addRoutines( ObjectDecl * field, FunctionDecl * func ) {
570                CompoundStmt * statement = new CompoundStmt();
571                statement->push_back(
572                        new ReturnStmt(
573                                new AddressExpr(
574                                        new MemberExpr(
575                                                field,
576                                                new CastExpr(
577                                                        new VariableExpr( func->get_functionType()->get_parameters().front() ),
578                                                        func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone(),
579                                                        false
580                                                )
581                                        )
582                                )
583                        )
584                );
585
586                FunctionDecl * get_decl = func->clone();
587
588                get_decl->set_statements( statement );
589
590                declsToAddAfter.push_back( get_decl );
591        }
592
593        //=============================================================================================
594        // Suspend keyword implementation
595        //=============================================================================================
596        bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
597                if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
598                if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
599                if(func->type->parameters.size() != 0) return false; // Too many parameters
600                if(func->type->returnVals.size() != 0) return false; // Too many return values
601
602                return true;
603        }
604
605        void SuspendKeyword::premutate( FunctionDecl * func ) {
606                GuardValue(in_generator);
607                in_generator = nullptr;
608
609                // Is this the real suspend?
610                if(is_real_suspend(func)) {
611                        decl_suspend = decl_suspend ? decl_suspend : func;
612                        return;
613                }
614
615                // Is this the main of a generator?
616                auto param = isMainFor( func, AggregateDecl::Aggregate::Generator );
617                if(!param) return;
618
619                if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
620
621                in_generator = param;
622                GuardValue(labels);
623                labels.clear();
624        }
625
626        DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
627                if( !func->statements ) return func; // Not the actual definition, don't do anything
628                if( !in_generator     ) return func; // Not in a generator, don't do anything
629                if( labels.empty()    ) return func; // Generator has no states, nothing to do, could throw a warning
630
631                // This is a generator main, we need to add the following code to the top
632                // static void * __generator_labels[] = {&&s0, &&s1, ...};
633                // goto * __generator_labels[gen.__generator_state];
634                const auto & loc = func->location;
635
636                const auto first_label = gen.newLabel("generator");
637
638                // for each label add to declaration
639                std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
640                for(const auto & label : labels) {
641                        inits.push_back(
642                                new SingleInit(
643                                        new LabelAddressExpr( label )
644                                )
645                        );
646                }
647                auto init = new ListInit(std::move(inits), noDesignators, true);
648                labels.clear();
649
650                // create decl
651                auto decl = new ObjectDecl(
652                        "__generator_labels",
653                        Type::StorageClasses( Type::Static ),
654                        LinkageSpec::AutoGen,
655                        nullptr,
656                        new ArrayType(
657                                Type::Qualifiers(),
658                                new PointerType(
659                                        Type::Qualifiers(),
660                                        new VoidType( Type::Qualifiers() )
661                                ),
662                                nullptr,
663                                false, false
664                        ),
665                        init
666                );
667
668                // create the goto
669                assert(in_generator);
670
671                auto go_decl = new ObjectDecl(
672                        "__generator_label",
673                        noStorageClasses,
674                        LinkageSpec::AutoGen,
675                        nullptr,
676                        new PointerType(
677                                Type::Qualifiers(),
678                                new VoidType( Type::Qualifiers() )
679                        ),
680                        new SingleInit(
681                                new UntypedExpr(
682                                        new NameExpr("?[?]"),
683                                        {
684                                                new NameExpr("__generator_labels"),
685                                                new UntypedMemberExpr(
686                                                        new NameExpr("__generator_state"),
687                                                        new VariableExpr( in_generator )
688                                                )
689                                        }
690                                )
691                        )
692                );
693                go_decl->location = loc;
694
695                auto go = new BranchStmt(
696                        new VariableExpr( go_decl ),
697                        BranchStmt::Goto
698                );
699                go->location = loc;
700                go->computedTarget->location = loc;
701
702                auto noop = new NullStmt({ first_label });
703                noop->location = loc;
704
705                // wrap everything in a nice compound
706                auto body = new CompoundStmt({
707                        new DeclStmt( decl ),
708                        new DeclStmt( go_decl ),
709                        go,
710                        noop,
711                        func->statements
712                });
713                body->location   = loc;
714                func->statements = body;
715
716                return func;
717        }
718
719        Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
720                SuspendStmt::Type type = stmt->type;
721                if(type == SuspendStmt::None) {
722                        // This suspend has a implicit target, find it
723                        type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
724                }
725
726                // Check that the target makes sense
727                if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
728
729                // Act appropriately
730                switch(type) {
731                        case SuspendStmt::Generator: return make_generator_suspend(stmt);
732                        case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
733                        default: abort();
734                }
735        }
736
737        Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
738                assert(in_generator);
739                // Target code is :
740                //   gen.__generator_state = X;
741                //   { THEN }
742                //   return;
743                //   __gen_X:;
744
745                // Save the location and delete the old statement, we only need the location from this point on
746                auto loc = stmt->location;
747
748                // Build the label and get its index
749                auto label = make_label();
750
751                // Create the context saving statement
752                auto save = new ExprStmt( new UntypedExpr(
753                        new NameExpr( "?=?" ),
754                        {
755                                new UntypedMemberExpr(
756                                        new NameExpr("__generator_state"),
757                                        new VariableExpr( in_generator )
758                                ),
759                                new ConstantExpr(
760                                        Constant::from_int( label.idx )
761                                )
762                        }
763                ));
764                assert(save->expr);
765                save->location = loc;
766                stmtsToAddBefore.push_back( save );
767
768                // if we have a then add it here
769                auto then = stmt->then;
770                stmt->then = nullptr;
771                delete stmt;
772                if(then) stmtsToAddBefore.push_back( then );
773
774                // Create the return statement
775                auto ret = new ReturnStmt( nullptr );
776                ret->location = loc;
777                stmtsToAddBefore.push_back( ret );
778
779                // Create the null statement with the created label
780                auto noop = new NullStmt({ label.obj });
781                noop->location = loc;
782
783                // Return the null statement to take the place of the previous statement
784                return noop;
785        }
786
787        Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
788                if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
789
790                // Save the location and delete the old statement, we only need the location from this point on
791                auto loc = stmt->location;
792                delete stmt;
793
794                // Create the call expression
795                if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
796                auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
797                expr->location = loc;
798
799                // Change this statement into a regular expr
800                assert(expr);
801                auto nstmt = new ExprStmt( expr );
802                nstmt->location = loc;
803                return nstmt;
804        }
805
806
807        //=============================================================================================
808        // Mutex keyword implementation
809        //=============================================================================================
810
811        void MutexKeyword::postvisit(FunctionDecl* decl) {
812
813                bool first = false;
814                std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
815                bool const isDtor = CodeGen::isDestructor( decl->name );
816
817                // Is this function relevant to monitors
818                if( mutexArgs.empty() ) {
819                        // If this is the destructor for a monitor it must be mutex
820                        if(isDtor) {
821                                Type* ty = decl->get_functionType()->get_parameters().front()->get_type();
822
823                                // If it's a copy, it's not a mutex
824                                ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
825                                if( ! rty ) return;
826
827                                // If we are not pointing directly to a type, it's not a mutex
828                                Type* base = rty->get_base();
829                                if( dynamic_cast< ReferenceType * >( base ) ) return;
830                                if( dynamic_cast< PointerType * >( base ) ) return;
831
832                                // Check if its a struct
833                                StructInstType * baseStruct = dynamic_cast< StructInstType * >( base );
834                                if( !baseStruct ) return;
835
836                                // Check if its a monitor
837                                if(baseStruct->baseStruct->is_monitor() || baseStruct->baseStruct->is_thread())
838                                        SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
839                        }
840                        return;
841                }
842
843                // Monitors can't be constructed with mutual exclusion
844                if( CodeGen::isConstructor(decl->name) && !first ) SemanticError( decl, "constructors cannot have mutex parameters" );
845
846                // It makes no sense to have multiple mutex parameters for the destructor
847                if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" );
848
849                // Make sure all the mutex arguments are monitors
850                for(auto arg : mutexArgs) {
851                        validate( arg );
852                }
853
854                // Check if we need to instrument the body
855                CompoundStmt* body = decl->get_statements();
856                if( ! body ) return;
857
858                // Do we have the required headers
859                if( !monitor_decl || !guard_decl || !dtor_guard_decl )
860                        SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
861
862                // Instrument the body
863                if ( isDtor && isThread( mutexArgs.front() ) ) {
864                        if( !thread_guard_decl ) {
865                                SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
866                        }
867                        addThreadDtorStatements( decl, body, mutexArgs );
868                }
869                else if ( isDtor ) {
870                        addDtorStatements( decl, body, mutexArgs );
871                }
872                else {
873                        addStatements( decl, body, mutexArgs );
874                }
875        }
876
877        void MutexKeyword::postvisit(StructDecl* decl) {
878
879                if( decl->name == "$monitor" && decl->body ) {
880                        assert( !monitor_decl );
881                        monitor_decl = decl;
882                }
883                else if( decl->name == "monitor_guard_t" && decl->body ) {
884                        assert( !guard_decl );
885                        guard_decl = decl;
886                }
887                else if( decl->name == "monitor_dtor_guard_t" && decl->body ) {
888                        assert( !dtor_guard_decl );
889                        dtor_guard_decl = decl;
890                }
891                else if( decl->name == "thread_dtor_guard_t" && decl->body ) {
892                        assert( !thread_guard_decl );
893                        thread_guard_decl = decl;
894                }
895        }
896
897        std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl, bool & first ) {
898                std::list<DeclarationWithType*> mutexArgs;
899
900                bool once = true;
901                for( auto arg : decl->get_functionType()->get_parameters()) {
902                        //Find mutex arguments
903                        Type* ty = arg->get_type();
904                        if( ! ty->get_mutex() ) continue;
905
906                        if(once) {first = true;}
907                        once = false;
908
909                        //Append it to the list
910                        mutexArgs.push_back( arg );
911                }
912
913                return mutexArgs;
914        }
915
916        void MutexKeyword::validate( DeclarationWithType * arg ) {
917                Type* ty = arg->get_type();
918
919                //Makes sure it's not a copy
920                ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
921                if( ! rty ) SemanticError( arg, "Mutex argument must be of reference type " );
922
923                //Make sure the we are pointing directly to a type
924                Type* base = rty->get_base();
925                if( dynamic_cast< ReferenceType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
926                if( dynamic_cast< PointerType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
927
928                //Make sure that typed isn't mutex
929                if( base->get_mutex() ) SemanticError( arg, "mutex keyword may only appear once per argument " );
930        }
931
932        void MutexKeyword::addDtorStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
933                Type * arg_type = args.front()->get_type()->clone();
934                arg_type->set_mutex( false );
935
936                ObjectDecl * monitors = new ObjectDecl(
937                        "__monitor",
938                        noStorageClasses,
939                        LinkageSpec::Cforall,
940                        nullptr,
941                        new PointerType(
942                                noQualifiers,
943                                new StructInstType(
944                                        noQualifiers,
945                                        monitor_decl
946                                )
947                        ),
948                        new SingleInit( new UntypedExpr(
949                                new NameExpr( "get_monitor" ),
950                                {  new CastExpr( new VariableExpr( args.front() ), arg_type, false ) }
951                        ))
952                );
953
954                assert(generic_func);
955
956                //in reverse order :
957                // monitor_dtor_guard_t __guard = { __monitors, func };
958                body->push_front(
959                        new DeclStmt( new ObjectDecl(
960                                "__guard",
961                                noStorageClasses,
962                                LinkageSpec::Cforall,
963                                nullptr,
964                                new StructInstType(
965                                        noQualifiers,
966                                        dtor_guard_decl
967                                ),
968                                new ListInit(
969                                        {
970                                                new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
971                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) ),
972                                                new SingleInit( new ConstantExpr( Constant::from_bool( false ) ) )
973                                        },
974                                        noDesignators,
975                                        true
976                                )
977                        ))
978                );
979
980                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
981                body->push_front( new DeclStmt( monitors ) );
982        }
983
984        void MutexKeyword::addThreadDtorStatements(
985                        FunctionDecl*, CompoundStmt * body,
986                        const std::list<DeclarationWithType * > & args ) {
987                assert( args.size() == 1 );
988                DeclarationWithType * arg = args.front();
989                Type * arg_type = arg->get_type()->clone();
990                assert( arg_type->get_mutex() );
991                arg_type->set_mutex( false );
992
993                // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
994                body->push_front(
995                        new DeclStmt( new ObjectDecl(
996                                "__guard",
997                                noStorageClasses,
998                                LinkageSpec::Cforall,
999                                nullptr,
1000                                new StructInstType(
1001                                        noQualifiers,
1002                                        thread_guard_decl
1003                                ),
1004                                new ListInit(
1005                                        {
1006                                                new SingleInit( new CastExpr( new VariableExpr( arg ), arg_type ) ),
1007                                                new SingleInit( new UntypedExpr(
1008                                                        new NameExpr( "intptr" ), {
1009                                                                new ConstantExpr( Constant::from_int( 0 ) ),
1010                                                        }
1011                                                ) ),
1012                                        },
1013                                        noDesignators,
1014                                        true
1015                                )
1016                        ))
1017                );
1018        }
1019
1020        void MutexKeyword::addStatements( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
1021                ObjectDecl * monitors = new ObjectDecl(
1022                        "__monitors",
1023                        noStorageClasses,
1024                        LinkageSpec::Cforall,
1025                        nullptr,
1026                        new ArrayType(
1027                                noQualifiers,
1028                                new PointerType(
1029                                        noQualifiers,
1030                                        new StructInstType(
1031                                                noQualifiers,
1032                                                monitor_decl
1033                                        )
1034                                ),
1035                                new ConstantExpr( Constant::from_ulong( args.size() ) ),
1036                                false,
1037                                false
1038                        ),
1039                        new ListInit(
1040                                map_range < std::list<Initializer*> > ( args, [](DeclarationWithType * var ){
1041                                        Type * type = var->get_type()->clone();
1042                                        type->set_mutex( false );
1043                                        return new SingleInit( new UntypedExpr(
1044                                                new NameExpr( "get_monitor" ),
1045                                                {  new CastExpr( new VariableExpr( var ), type, false ) }
1046                                        ) );
1047                                })
1048                        )
1049                );
1050
1051                assert(generic_func);
1052
1053                // in reverse order :
1054                // monitor_guard_t __guard = { __monitors, #, func };
1055                body->push_front(
1056                        new DeclStmt( new ObjectDecl(
1057                                "__guard",
1058                                noStorageClasses,
1059                                LinkageSpec::Cforall,
1060                                nullptr,
1061                                new StructInstType(
1062                                        noQualifiers,
1063                                        guard_decl
1064                                ),
1065                                new ListInit(
1066                                        {
1067                                                new SingleInit( new VariableExpr( monitors ) ),
1068                                                new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
1069                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone(), false ) )
1070                                        },
1071                                        noDesignators,
1072                                        true
1073                                )
1074                        ))
1075                );
1076
1077                //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
1078                body->push_front( new DeclStmt( monitors) );
1079        }
1080
1081        //=============================================================================================
1082        // General entry routine
1083        //=============================================================================================
1084        void ThreadStarter::previsit( StructDecl * decl ) {
1085                if( decl->name == "$thread" && decl->body ) {
1086                        assert( !thread_decl );
1087                        thread_decl = decl;
1088                }
1089        }
1090
1091        void ThreadStarter::postvisit(FunctionDecl * decl) {
1092                if( ! CodeGen::isConstructor(decl->name) ) return;
1093
1094                Type * typeof_this = InitTweak::getTypeofThis(decl->type);
1095                StructInstType * ctored_type = dynamic_cast< StructInstType * >( typeof_this );
1096                if( ctored_type && ctored_type->baseStruct == thread_decl ) {
1097                        thread_ctor_seen = true;
1098                }
1099
1100                DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
1101                auto type  = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
1102                if( type && type->get_baseStruct()->is_thread() ) {
1103                        if( !thread_decl || !thread_ctor_seen ) {
1104                                SemanticError( type->get_baseStruct()->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>");
1105                        }
1106
1107                        addStartStatement( decl, param );
1108                }
1109        }
1110
1111        void ThreadStarter::addStartStatement( FunctionDecl * decl, DeclarationWithType * param ) {
1112                CompoundStmt * stmt = decl->get_statements();
1113
1114                if( ! stmt ) return;
1115
1116                stmt->push_back(
1117                        new ExprStmt(
1118                                new UntypedExpr(
1119                                        new NameExpr( "__thrd_start" ),
1120                                        { new VariableExpr( param ), new NameExpr("main") }
1121                                )
1122                        )
1123                );
1124        }
1125};
1126
1127// Local Variables: //
1128// mode: c //
1129// tab-width: 4 //
1130// End: //
1131
Note: See TracBrowser for help on using the repository browser.