source: src/Concurrency/KeywordsNew.cpp@ f27331c

ADT ast-experimental enum forall-pointer-decay pthread-emulation qualifiedEnum
Last change on this file since f27331c was 2cf3b87, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Translated valitate-E after much bug hunting.

  • Property mode set to 100644
File size: 17.0 KB
RevLine 
[2cf3b87]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.