source: src/Concurrency/KeywordsNew.cpp @ f27331c

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since f27331c was 2cf3b87, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Translated valitate-E after much bug hunting.

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