source: src/Concurrency/KeywordsNew.cpp @ 41870a5

ADTast-experimentalenumpthread-emulationqualifiedEnum
Last change on this file since 41870a5 was 56f519b, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Clean-up of the last pass. Added a test for the constructor mutex argument test.

  • Property mode set to 100644
File size: 17.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// KeywordsNew.cpp -- Implement concurrency constructs from their keywords.
8//
9// Author           : Andrew Beach
10// Created On       : Tue Nov 16  9:53:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Wed Dec  1 11:24:00 2021
13// Update Count     : 1
14//
15
16#include "Concurrency/Keywords.h"
17
18#include "AST/Copy.hpp"
19#include "AST/Decl.hpp"
20#include "AST/Pass.hpp"
21#include "AST/Stmt.hpp"
22#include "AST/TranslationUnit.hpp"
23#include "CodeGen/OperatorTable.h"
24#include "Common/utility.h"
25#include "InitTweak/InitTweak.h"
26
27namespace Concurrency {
28
29namespace {
30
31inline static bool isThread( const ast::DeclWithType * decl ) {
32        auto baseType = decl->get_type()->stripDeclarator();
33        auto instType = dynamic_cast<const ast::StructInstType *>( baseType );
34        if ( nullptr == instType ) { return false; }
35        return instType->base->is_thread();
36}
37
38// --------------------------------------------------------------------------
39struct MutexKeyword final {
40        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
41        void postvisit( const ast::StructDecl * decl );
42        const ast::Stmt * postvisit( const ast::MutexStmt * stmt );
43
44        static std::vector<const ast::DeclWithType *> findMutexArgs(
45                        const ast::FunctionDecl * decl, bool & first );
46        static void validate( const ast::DeclWithType * decl );
47
48        ast::CompoundStmt * addDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
49        ast::CompoundStmt * addStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
50        ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args );
51        ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args );
52
53private:
54        const ast::StructDecl * monitor_decl = nullptr;
55        const ast::StructDecl * guard_decl = nullptr;
56        const ast::StructDecl * dtor_guard_decl = nullptr;
57        const ast::StructDecl * thread_guard_decl = nullptr;
58        const ast::StructDecl * lock_guard_decl = nullptr;
59
60        static ast::ptr<ast::Type> generic_func;
61};
62
63const ast::FunctionDecl * MutexKeyword::postvisit(
64                const ast::FunctionDecl * decl ) {
65        bool is_first_argument_mutex = false;
66        const std::vector<const ast::DeclWithType *> mutexArgs =
67                findMutexArgs( decl, is_first_argument_mutex );
68        bool const isDtor = CodeGen::isDestructor( decl->name );
69
70        // Does this function have any mutex arguments that connect to monitors?
71        if ( mutexArgs.empty() ) {
72                // If this is the destructor for a monitor it must be mutex.
73                if ( isDtor ) {
74                        // This reflects MutexKeyword::validate, but no error messages.
75                        const ast::Type * type = decl->type->params.front();
76
77                        // If it's a copy, it's not a mutex.
78                        const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
79                        if ( nullptr == refType ) {
80                                return decl;
81                        }
82
83                        // If it is not pointing directly to a type, it's not a mutex.
84                        auto base = refType->base;
85                        if ( base.as<ast::ReferenceType>() ) return decl;
86                        if ( base.as<ast::PointerType>() ) return decl;
87
88                        // If it is not a struct, it's not a mutex.
89                        auto baseStruct = base.as<ast::StructInstType>();
90                        if ( nullptr == baseStruct ) return decl;
91
92                        // If it is a monitor, then it is a monitor.
93                        if( baseStruct->base->is_monitor() || baseStruct->base->is_thread() ) {
94                                SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
95                        }
96                }
97                return decl;
98        }
99
100        // Monitors can't be constructed with mutual exclusion.
101        if ( CodeGen::isConstructor( decl->name ) && is_first_argument_mutex ) {
102                SemanticError( decl, "constructors cannot have mutex parameters\n" );
103        }
104
105        // It makes no sense to have multiple mutex parameters for the destructor.
106        if ( isDtor && mutexArgs.size() != 1 ) {
107                SemanticError( decl, "destructors can only have 1 mutex argument\n" );
108        }
109
110        // Make sure all the mutex arguments are monitors.
111        for ( auto arg : mutexArgs ) {
112                validate( arg );
113        }
114
115        // Check to see if the body needs to be instrument the body.
116        const ast::CompoundStmt * body = decl->stmts;
117        if ( !body ) return decl;
118
119        // Check to if the required headers have been seen.
120        if ( !monitor_decl || !guard_decl || !dtor_guard_decl ) {
121                SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
122        }
123
124        // Instrument the body.
125        ast::CompoundStmt * newBody = nullptr;
126        if ( isDtor && isThread( mutexArgs.front() ) ) {
127                if ( !thread_guard_decl ) {
128                        SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
129                }
130                newBody = addThreadDtorStatements( decl, body, mutexArgs );
131        } else if ( isDtor ) {
132                newBody = addDtorStatements( decl, body, mutexArgs );
133        } else {
134                newBody = addStatements( decl, body, mutexArgs );
135        }
136        assert( newBody );
137        return ast::mutate_field( decl, &ast::FunctionDecl::stmts, newBody );
138}
139
140void MutexKeyword::postvisit( const ast::StructDecl * decl ) {
141        if ( !decl->body ) {
142                return;
143        } else if ( decl->name == "monitor$" ) {
144                assert( !monitor_decl );
145                monitor_decl = decl;
146        } else if ( decl->name == "monitor_guard_t" ) {
147                assert( !guard_decl );
148                guard_decl = decl;
149        } else if ( decl->name == "monitor_dtor_guard_t" ) {
150                assert( !dtor_guard_decl );
151                dtor_guard_decl = decl;
152        } else if ( decl->name == "thread_dtor_guard_t" ) {
153                assert( !thread_guard_decl );
154                thread_guard_decl = decl;
155        } else if ( decl->name == "__mutex_stmt_lock_guard" ) {
156                assert( !lock_guard_decl );
157                lock_guard_decl = decl;
158        }
159}
160
161const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) {
162        ast::CompoundStmt * body =
163                        new ast::CompoundStmt( stmt->location, { stmt->stmt } );
164        addStatements( body, stmt->mutexObjs );
165        return body;
166}
167
168std::vector<const ast::DeclWithType *> MutexKeyword::findMutexArgs(
169                const ast::FunctionDecl * decl, bool & first ) {
170        std::vector<const ast::DeclWithType *> mutexArgs;
171
172        bool once = true;
173        for ( auto arg : decl->params ) {
174                const ast::Type * type = arg->get_type();
175                if ( type->is_mutex() ) {
176                        if ( once ) first = true;
177                        mutexArgs.push_back( arg.get() );
178                }
179                once = false;
180        }
181        return mutexArgs;
182}
183
184void MutexKeyword::validate( const ast::DeclWithType * decl ) {
185        const ast::Type * type = decl->get_type();
186
187        // If it's a copy, it's not a mutex.
188        const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
189        if ( nullptr == refType ) {
190                SemanticError( decl, "Mutex argument must be of reference type " );
191        }
192
193        // If it is not pointing directly to a type, it's not a mutex.
194        auto base = refType->base;
195        if ( base.as<ast::ReferenceType>() || base.as<ast::PointerType>() ) {
196                SemanticError( decl, "Mutex argument have exactly one level of indirection " );
197        }
198
199        // If it is not a struct, it's not a mutex.
200        auto baseStruct = base.as<ast::StructInstType>();
201        if ( nullptr == baseStruct ) return;
202
203        // Make sure that only the outer reference is mutex.
204        if( baseStruct->is_mutex() ) {
205                SemanticError( decl, "mutex keyword may only appear once per argument " );
206        }
207}
208
209ast::CompoundStmt * MutexKeyword::addDtorStatements(
210                const ast::FunctionDecl* func, const ast::CompoundStmt * body,
211                const std::vector<const ast::DeclWithType *> & args ) {
212        ast::Type * argType = ast::shallowCopy( args.front()->get_type() );
213        argType->set_mutex( false );
214
215        ast::CompoundStmt * mutBody = ast::mutate( body );
216
217        // Generated code goes near the beginning of body:
218        const CodeLocation & location = mutBody->location;
219
220        const ast::ObjectDecl * monitor = new ast::ObjectDecl(
221                location,
222                "__monitor",
223                new ast::PointerType( new ast::StructInstType( monitor_decl ) ),
224                new ast::SingleInit(
225                        location,
226                        new ast::UntypedExpr(
227                                location,
228                                new ast::NameExpr( location, "get_monitor" ),
229                                { new ast::CastExpr(
230                                        location,
231                                        new ast::VariableExpr( location, args.front() ),
232                                        argType, ast::ExplicitCast
233                                ) }
234                        )
235                ),
236                ast::Storage::Classes(),
237                ast::Linkage::Cforall
238        );
239
240        assert( generic_func );
241
242        // In reverse order:
243        // monitor_dtor_guard_t __guard = { __monitor, func, false };
244        mutBody->push_front(
245                new ast::DeclStmt( location, new ast::ObjectDecl(
246                        location,
247                        "__guard",
248                        new ast::StructInstType( dtor_guard_decl ),
249                        new ast::ListInit(
250                                location,
251                                {
252                                        new ast::SingleInit( location,
253                                                new ast::AddressExpr(
254                                                        new ast::VariableExpr( location, monitor ) ) ),
255                                        new ast::SingleInit( location,
256                                                new ast::CastExpr( location,
257                                                        new ast::VariableExpr( location, func ),
258                                                        generic_func,
259                                                        ast::ExplicitCast ) ),
260                                        new ast::SingleInit( location,
261                                                ast::ConstantExpr::from_bool( location, false ) ),
262                                },
263                                {},
264                                ast::MaybeConstruct
265                        ),
266                        ast::Storage::Classes(),
267                        ast::Linkage::Cforall
268                ))
269        );
270
271        // monitor$ * __monitor = get_monitor(a);
272        mutBody->push_front( new ast::DeclStmt( location, monitor ) );
273
274        return mutBody;
275}
276
277ast::CompoundStmt * MutexKeyword::addStatements(
278                const ast::FunctionDecl* func, const ast::CompoundStmt * body,
279                const std::vector<const ast::DeclWithType * > & args ) {
280        ast::CompoundStmt * mutBody = ast::mutate( body );
281
282        // Code is generated near the beginning of the compound statement.
283        const CodeLocation & location = mutBody->location;
284
285        // Make pointer to the monitors.
286        ast::ObjectDecl * monitors = new ast::ObjectDecl(
287                location,
288                "__monitors",
289                new ast::ArrayType(
290                        new ast::PointerType(
291                                new ast::StructInstType( monitor_decl )
292                        ),
293                        ast::ConstantExpr::from_ulong( location, args.size() ),
294                        ast::FixedLen,
295                        ast::DynamicDim
296                ),
297                new ast::ListInit(
298                        location,
299                        map_range<std::vector<ast::ptr<ast::Init>>>(
300                                args,
301                                []( const ast::DeclWithType * decl ) {
302                                        return new ast::SingleInit(
303                                                decl->location,
304                                                new ast::UntypedExpr(
305                                                        decl->location,
306                                                        new ast::NameExpr( decl->location, "get_monitor" ),
307                                                        {
308                                                                new ast::CastExpr(
309                                                                        decl->location,
310                                                                        new ast::VariableExpr( decl->location, decl ),
311                                                                        decl->get_type(),
312                                                                        ast::ExplicitCast
313                                                                )
314                                                        }
315                                                )
316                                        );
317                                }
318                        )
319                ),
320                ast::Storage::Classes(),
321                ast::Linkage::Cforall
322        );
323
324        assert( generic_func );
325
326        // In Reverse Order:
327        mutBody->push_front(
328                new ast::DeclStmt( location, new ast::ObjectDecl(
329                        location,
330                        "__guard",
331                        new ast::StructInstType( guard_decl ),
332                        new ast::ListInit(
333                                location,
334                                {
335                                        new ast::SingleInit( location,
336                                                new ast::VariableExpr( location, monitors ) ),
337                                        new ast::SingleInit( location,
338                                                ast::ConstantExpr::from_ulong( location, args.size() ) ),
339                                        new ast::SingleInit( location, new ast::CastExpr(
340                                                location,
341                                                new ast::VariableExpr( location, func ),
342                                                generic_func,
343                                                ast::ExplicitCast
344                                        ) ),
345                                },
346                                {},
347                                ast::MaybeConstruct
348                        ),
349                        ast::Storage::Classes(),
350                        ast::Linkage::Cforall
351                ))
352        );
353
354        // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
355        mutBody->push_front( new ast::DeclStmt( location, monitors ) );
356
357        return mutBody;
358}
359
360ast::CompoundStmt * MutexKeyword::addStatements(
361                const ast::CompoundStmt * body,
362                const std::vector<ast::ptr<ast::Expr>> & args ) {
363        ast::CompoundStmt * mutBody = ast::mutate( body );
364
365        // Code is generated near the beginning of the compound statement.
366        const CodeLocation & location = mutBody->location;
367
368        // Make pointer to the monitors.
369        ast::ObjectDecl * monitors = new ast::ObjectDecl(
370                location,
371                "__monitors",
372                new ast::ArrayType(
373                        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                                )
381                        ),
382                        ast::ConstantExpr::from_ulong( location, args.size() ),
383                        ast::FixedLen,
384                        ast::DynamicDim
385                ),
386                new ast::ListInit(
387                        location,
388                        map_range<std::vector<ast::ptr<ast::Init>>>(
389                                args, [](const ast::Expr * expr) {
390                                        return new ast::SingleInit(
391                                                expr->location,
392                                                new ast::UntypedExpr(
393                                                        expr->location,
394                                                        new ast::NameExpr( expr->location, "__get_ptr" ),
395                                                        { expr }
396                                                )
397                                        );
398                                }
399                        )
400                ),
401                ast::Storage::Classes(),
402                ast::Linkage::Cforall
403        );
404
405        ast::StructInstType * lock_guard_struct =
406                        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:
421        // monitor_guard_t __guard = { __monitors, # };
422        mutBody->push_front(
423                new ast::DeclStmt(
424                        location,
425                        new ast::ObjectDecl(
426                                location,
427                                "__guard",
428                                lock_guard_struct,
429                                new ast::ListInit(
430                                        location,
431                                        {
432                                                new ast::SingleInit(
433                                                        location,
434                                                        new ast::VariableExpr( location, monitors ) ),
435                                                new ast::SingleInit(
436                                                        location,
437                                                        ast::ConstantExpr::from_ulong( location, args.size() ) ),
438                                        },
439                                        {},
440                                        ast::MaybeConstruct
441                                ),
442                                ast::Storage::Classes(),
443                                ast::Linkage::Cforall
444                        )
445                )
446        );
447
448        // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
449        mutBody->push_front( new ast::DeclStmt( location, monitors ) );
450
451        return mutBody;
452}
453
454ast::CompoundStmt * MutexKeyword::addThreadDtorStatements(
455                const ast::FunctionDecl*, const ast::CompoundStmt * body,
456                const std::vector<const ast::DeclWithType * > & args ) {
457        assert( args.size() == 1 );
458        const ast::DeclWithType * arg = args.front();
459        const ast::Type * argType = arg->get_type();
460        assert( argType->is_mutex() );
461
462        ast::CompoundStmt * mutBody = ast::mutate( body );
463
464        // The code is generated near the front of the body.
465        const CodeLocation & location = mutBody->location;
466
467        // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
468        mutBody->push_front( new ast::DeclStmt(
469                location,
470                new ast::ObjectDecl(
471                        location,
472                        "__guard",
473                        new ast::StructInstType( thread_guard_decl ),
474                        new ast::ListInit(
475                                location,
476                                {
477                                        new ast::SingleInit( location,
478                                                new ast::CastExpr( location,
479                                                        new ast::VariableExpr( location, arg ), argType ) ),
480                                        new ast::SingleInit(
481                                                location,
482                                                new ast::UntypedExpr(
483                                                        location,
484                                                        new ast::NameExpr( location, "intptr" ), {
485                                                                ast::ConstantExpr::from_int( location, 0 ),
486                                                        }
487                                                ) ),
488                                },
489                                {},
490                                ast::MaybeConstruct
491                        ),
492                        ast::Storage::Classes(),
493                        ast::Linkage::Cforall
494                )
495        ));
496
497        return mutBody;
498}
499
500ast::ptr<ast::Type> MutexKeyword::generic_func =
501        new ast::FunctionType( ast::VariableArgs );
502
503// --------------------------------------------------------------------------
504struct ThreadStarter final {
505        void previsit( const ast::StructDecl * decl );
506        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
507
508private:
509        bool thread_ctor_seen = false;
510        const ast::StructDecl * thread_decl = nullptr;
511};
512
513void ThreadStarter::previsit( const ast::StructDecl * decl ) {
514        if ( decl->body && decl->name == "thread$" ) {
515                assert( !thread_decl );
516                thread_decl = decl;
517        }
518}
519
520const ast::FunctionDecl * ThreadStarter::postvisit( const ast::FunctionDecl * decl ) {
521        if ( !CodeGen::isConstructor( decl->name ) ) return decl;
522
523        // Seach for the thread constructor.
524        // (Are the "prefixes" of these to blocks the same?)
525        const ast::Type * typeof_this = InitTweak::getTypeofThis( decl->type );
526        auto ctored_type = dynamic_cast<const ast::StructInstType *>( typeof_this );
527        if ( ctored_type && ctored_type->base == thread_decl ) {
528                thread_ctor_seen = true;
529        }
530
531        // Modify this declaration, the extra checks to see if we will are first.
532        const ast::ptr<ast::DeclWithType> & param = decl->params.front();
533        auto type = dynamic_cast<const ast::StructInstType *>(
534                InitTweak::getPointerBase( param->get_type() ) );
535        if ( nullptr == type ) return decl;
536        if ( !type->base->is_thread() ) return decl;
537        if ( !thread_decl || !thread_ctor_seen ) {
538                SemanticError( type->base->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>" );
539        }
540        const ast::CompoundStmt * stmt = decl->stmts;
541        if ( nullptr == stmt ) return decl;
542
543        // Now do the actual modification:
544        ast::CompoundStmt * mutStmt = ast::mutate( stmt );
545        const CodeLocation & location = mutStmt->location;
546        mutStmt->push_back(
547                new ast::ExprStmt(
548                        location,
549                        new ast::UntypedExpr(
550                                location,
551                                new ast::NameExpr( location, "__thrd_start" ),
552                                {
553                                        new ast::VariableExpr( location, param ),
554                                        new ast::NameExpr( location, "main" ),
555                                }
556                        )
557                )
558        );
559
560        return ast::mutate_field( decl, &ast::FunctionDecl::stmts, mutStmt );
561}
562
563} // namespace
564
565// --------------------------------------------------------------------------
566
567void implementKeywords( ast::TranslationUnit & translationUnit ) {
568        (void)translationUnit;
569        assertf(false, "Apply Keywords not implemented." );
570}
571
572void implementMutex( ast::TranslationUnit & translationUnit ) {
573        ast::Pass<MutexKeyword>::run( translationUnit );
574}
575
576void implementThreadStarter( ast::TranslationUnit & translationUnit ) {
577        ast::Pass<ThreadStarter>::run( translationUnit );
578}
579
580}
581
582// Local Variables: //
583// tab-width: 4 //
584// mode: c++ //
585// compile-command: "make install" //
586// End: //
Note: See TracBrowser for help on using the repository browser.