source: src/Concurrency/KeywordsNew.cpp@ a76202d

ADT ast-experimental enum pthread-emulation qualifiedEnum
Last change on this file since a76202d was 41d3c8d, checked in by caparsons <caparson@…>, 4 years ago

added check for mutex stmt header

  • Property mode set to 100644
File size: 48.7 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 : Fri Mar 11 10:40:00 2022
13// Update Count : 2
14//
15
16#include <iostream>
17
18#include "Concurrency/Keywords.h"
19
20#include "AST/Copy.hpp"
21#include "AST/Decl.hpp"
22#include "AST/Expr.hpp"
23#include "AST/Pass.hpp"
24#include "AST/Stmt.hpp"
25#include "AST/DeclReplacer.hpp"
26#include "AST/TranslationUnit.hpp"
27#include "CodeGen/OperatorTable.h"
28#include "Common/Examine.h"
29#include "Common/utility.h"
30#include "Common/UniqueName.h"
31#include "ControlStruct/LabelGeneratorNew.hpp"
32#include "InitTweak/InitTweak.h"
33#include "Virtual/Tables.h"
34
35namespace Concurrency {
36
37namespace {
38
39// --------------------------------------------------------------------------
40// Loose Helper Functions:
41
42/// Detect threads constructed with the keyword thread.
43bool isThread( const ast::DeclWithType * decl ) {
44 auto baseType = decl->get_type()->stripDeclarator();
45 auto instType = dynamic_cast<const ast::StructInstType *>( baseType );
46 if ( nullptr == instType ) { return false; }
47 return instType->base->is_thread();
48}
49
50/// Get the virtual type id if given a type name.
51std::string typeIdType( std::string const & exception_name ) {
52 return exception_name.empty() ? std::string()
53 : Virtual::typeIdType( exception_name );
54}
55
56/// Get the vtable type name if given a type name.
57std::string vtableTypeName( std::string const & exception_name ) {
58 return exception_name.empty() ? std::string()
59 : Virtual::vtableTypeName( exception_name );
60}
61
62static ast::Type * mutate_under_references( ast::ptr<ast::Type>& type ) {
63 ast::Type * mutType = type.get_and_mutate();
64 for ( ast::ReferenceType * mutRef
65 ; (mutRef = dynamic_cast<ast::ReferenceType *>( mutType ))
66 ; mutType = mutRef->base.get_and_mutate() );
67 return mutType;
68}
69
70// Describe that it adds the generic parameters and the uses of the generic
71// parameters on the function and first "this" argument.
72ast::FunctionDecl * fixupGenerics(
73 const ast::FunctionDecl * func, const ast::StructDecl * decl ) {
74 const CodeLocation & location = decl->location;
75 // We have to update both the declaration
76 auto mutFunc = ast::mutate( func );
77 auto mutType = mutFunc->type.get_and_mutate();
78
79 if ( decl->params.empty() ) {
80 return mutFunc;
81 }
82
83 assert( 0 != mutFunc->params.size() );
84 assert( 0 != mutType->params.size() );
85
86 // Add the "forall" clause information.
87 for ( const ast::ptr<ast::TypeDecl> & typeParam : decl->params ) {
88 auto typeDecl = ast::deepCopy( typeParam );
89 mutFunc->type_params.push_back( typeDecl );
90 mutType->forall.push_back(
91 new ast::TypeInstType( typeDecl->name, typeDecl ) );
92 for ( auto & assertion : typeDecl->assertions ) {
93 mutFunc->assertions.push_back( assertion );
94 mutType->assertions.emplace_back(
95 new ast::VariableExpr( location, assertion ) );
96 }
97 typeDecl->assertions.clear();
98 }
99
100 // Even chain_mutate is not powerful enough for this:
101 ast::ptr<ast::Type>& paramType = strict_dynamic_cast<ast::ObjectDecl *>(
102 mutFunc->params[0].get_and_mutate() )->type;
103 auto paramTypeInst = strict_dynamic_cast<ast::StructInstType *>(
104 mutate_under_references( paramType ) );
105 auto typeParamInst = strict_dynamic_cast<ast::StructInstType *>(
106 mutate_under_references( mutType->params[0] ) );
107
108 for ( const ast::ptr<ast::TypeDecl> & typeDecl : mutFunc->type_params ) {
109 paramTypeInst->params.push_back(
110 new ast::TypeExpr( location,
111 new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
112 typeParamInst->params.push_back(
113 new ast::TypeExpr( location,
114 new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
115 }
116
117 return mutFunc;
118}
119
120// --------------------------------------------------------------------------
121struct ConcurrentSueKeyword : public ast::WithDeclsToAdd<> {
122 ConcurrentSueKeyword(
123 std::string&& type_name, std::string&& field_name,
124 std::string&& getter_name, std::string&& context_error,
125 std::string&& exception_name,
126 bool needs_main, ast::AggregateDecl::Aggregate cast_target
127 ) :
128 type_name( type_name ), field_name( field_name ),
129 getter_name( getter_name ), context_error( context_error ),
130 exception_name( exception_name ),
131 typeid_name( typeIdType( exception_name ) ),
132 vtable_name( vtableTypeName( exception_name ) ),
133 needs_main( needs_main ), cast_target( cast_target )
134 {}
135
136 virtual ~ConcurrentSueKeyword() {}
137
138 const ast::Decl * postvisit( const ast::StructDecl * decl );
139 const ast::DeclWithType * postvisit( const ast::FunctionDecl * decl );
140 const ast::Expr * postvisit( const ast::KeywordCastExpr * expr );
141
142 struct StructAndField {
143 const ast::StructDecl * decl;
144 const ast::ObjectDecl * field;
145 };
146
147 const ast::StructDecl * handleStruct( const ast::StructDecl * );
148 void handleMain( const ast::FunctionDecl *, const ast::StructInstType * );
149 void addTypeId( const ast::StructDecl * );
150 void addVtableForward( const ast::StructDecl * );
151 const ast::FunctionDecl * forwardDeclare( const ast::StructDecl * );
152 StructAndField addField( const ast::StructDecl * );
153 void addGetRoutines( const ast::ObjectDecl *, const ast::FunctionDecl * );
154 void addLockUnlockRoutines( const ast::StructDecl * );
155
156private:
157 const std::string type_name;
158 const std::string field_name;
159 const std::string getter_name;
160 const std::string context_error;
161 const std::string exception_name;
162 const std::string typeid_name;
163 const std::string vtable_name;
164 const bool needs_main;
165 const ast::AggregateDecl::Aggregate cast_target;
166
167 const ast::StructDecl * type_decl = nullptr;
168 const ast::FunctionDecl * dtor_decl = nullptr;
169 const ast::StructDecl * except_decl = nullptr;
170 const ast::StructDecl * typeid_decl = nullptr;
171 const ast::StructDecl * vtable_decl = nullptr;
172
173};
174
175// Handles thread type declarations:
176//
177// thread Mythread { struct MyThread {
178// int data; int data;
179// a_struct_t more_data; a_struct_t more_data;
180// => thread$ __thrd_d;
181// }; };
182// static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; }
183//
184struct ThreadKeyword final : public ConcurrentSueKeyword {
185 ThreadKeyword() : ConcurrentSueKeyword(
186 "thread$",
187 "__thrd",
188 "get_thread",
189 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
190 "ThreadCancelled",
191 true,
192 ast::AggregateDecl::Thread )
193 {}
194
195 virtual ~ThreadKeyword() {}
196};
197
198// Handles coroutine type declarations:
199//
200// coroutine MyCoroutine { struct MyCoroutine {
201// int data; int data;
202// a_struct_t more_data; a_struct_t more_data;
203// => coroutine$ __cor_d;
204// }; };
205// static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
206//
207struct CoroutineKeyword final : public ConcurrentSueKeyword {
208 CoroutineKeyword() : ConcurrentSueKeyword(
209 "coroutine$",
210 "__cor",
211 "get_coroutine",
212 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
213 "CoroutineCancelled",
214 true,
215 ast::AggregateDecl::Coroutine )
216 {}
217
218 virtual ~CoroutineKeyword() {}
219};
220
221// Handles monitor type declarations:
222//
223// monitor MyMonitor { struct MyMonitor {
224// int data; int data;
225// a_struct_t more_data; a_struct_t more_data;
226// => monitor$ __mon_d;
227// }; };
228// static inline monitor$ * get_coroutine( MyMonitor * this ) {
229// return &this->__cor_d;
230// }
231// void lock(MyMonitor & this) {
232// lock(get_monitor(this));
233// }
234// void unlock(MyMonitor & this) {
235// unlock(get_monitor(this));
236// }
237//
238struct MonitorKeyword final : public ConcurrentSueKeyword {
239 MonitorKeyword() : ConcurrentSueKeyword(
240 "monitor$",
241 "__mon",
242 "get_monitor",
243 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
244 "",
245 false,
246 ast::AggregateDecl::Monitor )
247 {}
248
249 virtual ~MonitorKeyword() {}
250};
251
252// Handles generator type declarations:
253//
254// generator MyGenerator { struct MyGenerator {
255// int data; int data;
256// a_struct_t more_data; a_struct_t more_data;
257// => int __generator_state;
258// }; };
259//
260struct GeneratorKeyword final : public ConcurrentSueKeyword {
261 GeneratorKeyword() : ConcurrentSueKeyword(
262 "generator$",
263 "__generator_state",
264 "get_generator",
265 "Unable to find builtin type generator$\n",
266 "",
267 true,
268 ast::AggregateDecl::Generator )
269 {}
270
271 virtual ~GeneratorKeyword() {}
272};
273
274const ast::Decl * ConcurrentSueKeyword::postvisit(
275 const ast::StructDecl * decl ) {
276 if ( !decl->body ) {
277 return decl;
278 } else if ( cast_target == decl->kind ) {
279 return handleStruct( decl );
280 } else if ( type_name == decl->name ) {
281 assert( !type_decl );
282 type_decl = decl;
283 } else if ( exception_name == decl->name ) {
284 assert( !except_decl );
285 except_decl = decl;
286 } else if ( typeid_name == decl->name ) {
287 assert( !typeid_decl );
288 typeid_decl = decl;
289 } else if ( vtable_name == decl->name ) {
290 assert( !vtable_decl );
291 vtable_decl = decl;
292 }
293 return decl;
294}
295
296// Try to get the full definition, but raise an error on conflicts.
297const ast::FunctionDecl * getDefinition(
298 const ast::FunctionDecl * old_decl,
299 const ast::FunctionDecl * new_decl ) {
300 if ( !new_decl->stmts ) {
301 return old_decl;
302 } else if ( !old_decl->stmts ) {
303 return new_decl;
304 } else {
305 assert( !old_decl->stmts || !new_decl->stmts );
306 return nullptr;
307 }
308}
309
310const ast::DeclWithType * ConcurrentSueKeyword::postvisit(
311 const ast::FunctionDecl * decl ) {
312 if ( type_decl && isDestructorFor( decl, type_decl ) ) {
313 // Check for forward declarations, try to get the full definition.
314 dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl;
315 } else if ( !vtable_name.empty() && decl->has_body() ) {
316 if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) {
317 if ( !vtable_decl ) {
318 SemanticError( decl, context_error );
319 }
320 // Should be safe because of isMainFor.
321 const ast::StructInstType * struct_type =
322 static_cast<const ast::StructInstType *>(
323 static_cast<const ast::ReferenceType *>(
324 param->get_type() )->base.get() );
325
326 handleMain( decl, struct_type );
327 }
328 }
329 return decl;
330}
331
332const ast::Expr * ConcurrentSueKeyword::postvisit(
333 const ast::KeywordCastExpr * expr ) {
334 if ( cast_target == expr->target ) {
335 // Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc.
336 if ( !type_decl || !dtor_decl ) {
337 SemanticError( expr, context_error );
338 }
339 assert( nullptr == expr->result );
340 auto cast = ast::mutate( expr );
341 cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) );
342 cast->concrete_target.field = field_name;
343 cast->concrete_target.getter = getter_name;
344 return cast;
345 }
346 return expr;
347}
348
349const ast::StructDecl * ConcurrentSueKeyword::handleStruct(
350 const ast::StructDecl * decl ) {
351 assert( decl->body );
352
353 if ( !type_decl || !dtor_decl ) {
354 SemanticError( decl, context_error );
355 }
356
357 if ( !exception_name.empty() ) {
358 if( !typeid_decl || !vtable_decl ) {
359 SemanticError( decl, context_error );
360 }
361 addTypeId( decl );
362 addVtableForward( decl );
363 }
364
365 const ast::FunctionDecl * func = forwardDeclare( decl );
366 StructAndField addFieldRet = addField( decl );
367 decl = addFieldRet.decl;
368 const ast::ObjectDecl * field = addFieldRet.field;
369
370 addGetRoutines( field, func );
371 // Add routines to monitors for use by mutex stmt.
372 if ( ast::AggregateDecl::Monitor == cast_target ) {
373 addLockUnlockRoutines( decl );
374 }
375
376 return decl;
377}
378
379void ConcurrentSueKeyword::handleMain(
380 const ast::FunctionDecl * decl, const ast::StructInstType * type ) {
381 assert( vtable_decl );
382 assert( except_decl );
383
384 const CodeLocation & location = decl->location;
385
386 std::vector<ast::ptr<ast::Expr>> poly_args = {
387 new ast::TypeExpr( location, type ),
388 };
389 ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance(
390 location,
391 "_default_vtable_object_declaration",
392 new ast::StructInstType( vtable_decl, copy( poly_args ) ),
393 type,
394 nullptr
395 );
396 declsToAddAfter.push_back( vtable_object );
397 declsToAddAfter.push_back(
398 new ast::ObjectDecl(
399 location,
400 Virtual::concurrentDefaultVTableName(),
401 new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
402 new ast::SingleInit( location,
403 new ast::VariableExpr( location, vtable_object ) ),
404 ast::Storage::Classes(),
405 ast::Linkage::Cforall
406 )
407 );
408 declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
409 location,
410 vtable_object,
411 new ast::StructInstType( except_decl, copy( poly_args ) )
412 ) );
413}
414
415void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) {
416 assert( typeid_decl );
417 const CodeLocation & location = decl->location;
418
419 ast::StructInstType * typeid_type =
420 new ast::StructInstType( typeid_decl, ast::CV::Const );
421 typeid_type->params.push_back(
422 new ast::TypeExpr( location, new ast::StructInstType( decl ) ) );
423 declsToAddBefore.push_back(
424 Virtual::makeTypeIdInstance( location, typeid_type ) );
425 // If the typeid_type is going to be kept, the other reference will have
426 // been made by now, but we also get to avoid extra mutates.
427 ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type;
428}
429
430void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) {
431 assert( vtable_decl );
432 const CodeLocation& location = decl->location;
433
434 std::vector<ast::ptr<ast::Expr>> poly_args = {
435 new ast::TypeExpr( location, new ast::StructInstType( decl ) ),
436 };
437 declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
438 location,
439 new ast::StructInstType( vtable_decl, copy( poly_args ) ),
440 new ast::StructInstType( except_decl, copy( poly_args ) )
441 ) );
442 ast::ObjectDecl * vtable_object = Virtual::makeVtableForward(
443 location,
444 "_default_vtable_object_declaration",
445 new ast::StructInstType( vtable_decl, std::move( poly_args ) )
446 );
447 declsToAddBefore.push_back( vtable_object );
448 declsToAddBefore.push_back(
449 new ast::ObjectDecl(
450 location,
451 Virtual::concurrentDefaultVTableName(),
452 new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
453 nullptr,
454 ast::Storage::Extern,
455 ast::Linkage::Cforall
456 )
457 );
458}
459
460const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare(
461 const ast::StructDecl * decl ) {
462 const CodeLocation & location = decl->location;
463
464 ast::StructDecl * forward = ast::deepCopy( decl );
465 {
466 // If removing members makes ref-count go to zero, do not free.
467 ast::ptr<ast::StructDecl> forward_ptr = forward;
468 forward->body = false;
469 forward->members.clear();
470 forward_ptr.release();
471 }
472
473 ast::ObjectDecl * this_decl = new ast::ObjectDecl(
474 location,
475 "this",
476 new ast::ReferenceType( new ast::StructInstType( decl ) ),
477 nullptr,
478 ast::Storage::Classes(),
479 ast::Linkage::Cforall
480 );
481
482 ast::ObjectDecl * ret_decl = new ast::ObjectDecl(
483 location,
484 "ret",
485 new ast::PointerType( new ast::StructInstType( type_decl ) ),
486 nullptr,
487 ast::Storage::Classes(),
488 ast::Linkage::Cforall
489 );
490
491 ast::FunctionDecl * get_decl = new ast::FunctionDecl(
492 location,
493 getter_name,
494 {}, // forall
495 { this_decl }, // params
496 { ret_decl }, // returns
497 nullptr, // stmts
498 ast::Storage::Static,
499 ast::Linkage::Cforall,
500 { new ast::Attribute( "const" ) },
501 ast::Function::Inline
502 );
503 get_decl = fixupGenerics( get_decl, decl );
504
505 ast::FunctionDecl * main_decl = nullptr;
506 if ( needs_main ) {
507 // `this_decl` is copied here because the original was used above.
508 main_decl = new ast::FunctionDecl(
509 location,
510 "main",
511 {},
512 { ast::deepCopy( this_decl ) },
513 {},
514 nullptr,
515 ast::Storage::Classes(),
516 ast::Linkage::Cforall
517 );
518 main_decl = fixupGenerics( main_decl, decl );
519 }
520
521 declsToAddBefore.push_back( forward );
522 if ( needs_main ) declsToAddBefore.push_back( main_decl );
523 declsToAddBefore.push_back( get_decl );
524
525 return get_decl;
526}
527
528ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField(
529 const ast::StructDecl * decl ) {
530 const CodeLocation & location = decl->location;
531
532 ast::ObjectDecl * field = new ast::ObjectDecl(
533 location,
534 field_name,
535 new ast::StructInstType( type_decl ),
536 nullptr,
537 ast::Storage::Classes(),
538 ast::Linkage::Cforall
539 );
540
541 auto mutDecl = ast::mutate( decl );
542 mutDecl->members.push_back( field );
543
544 return {mutDecl, field};
545}
546
547void ConcurrentSueKeyword::addGetRoutines(
548 const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) {
549 // Say it is generated at the "same" places as the forward declaration.
550 const CodeLocation & location = forward->location;
551
552 const ast::DeclWithType * param = forward->params.front();
553 ast::Stmt * stmt = new ast::ReturnStmt( location,
554 new ast::AddressExpr( location,
555 new ast::MemberExpr( location,
556 field,
557 new ast::CastExpr( location,
558 new ast::VariableExpr( location, param ),
559 ast::deepCopy( param->get_type()->stripReferences() ),
560 ast::ExplicitCast
561 )
562 )
563 )
564 );
565
566 ast::FunctionDecl * decl = ast::deepCopy( forward );
567 decl->stmts = new ast::CompoundStmt( location, { stmt } );
568 declsToAddAfter.push_back( decl );
569}
570
571void ConcurrentSueKeyword::addLockUnlockRoutines(
572 const ast::StructDecl * decl ) {
573 // This should only be used on monitors.
574 assert( ast::AggregateDecl::Monitor == cast_target );
575
576 const CodeLocation & location = decl->location;
577
578 // The parameter for both routines.
579 ast::ObjectDecl * this_decl = new ast::ObjectDecl(
580 location,
581 "this",
582 new ast::ReferenceType( new ast::StructInstType( decl ) ),
583 nullptr,
584 ast::Storage::Classes(),
585 ast::Linkage::Cforall
586 );
587
588 ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
589 location,
590 "lock",
591 { /* forall */ },
592 {
593 // Copy the declaration of this.
594 ast::deepCopy( this_decl ),
595 },
596 { /* returns */ },
597 nullptr,
598 ast::Storage::Static,
599 ast::Linkage::Cforall,
600 { /* attributes */ },
601 ast::Function::Inline
602 );
603 lock_decl = fixupGenerics( lock_decl, decl );
604
605 lock_decl->stmts = new ast::CompoundStmt( location, {
606 new ast::ExprStmt( location,
607 new ast::UntypedExpr( location,
608 new ast::NameExpr( location, "lock" ),
609 {
610 new ast::UntypedExpr( location,
611 new ast::NameExpr( location, "get_monitor" ),
612 { new ast::VariableExpr( location,
613 InitTweak::getParamThis( lock_decl ) ) }
614 )
615 }
616 )
617 )
618 } );
619
620 ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
621 location,
622 "unlock",
623 { /* forall */ },
624 {
625 // Last use, consume the declaration of this.
626 this_decl,
627 },
628 { /* returns */ },
629 nullptr,
630 ast::Storage::Static,
631 ast::Linkage::Cforall,
632 { /* attributes */ },
633 ast::Function::Inline
634 );
635 unlock_decl = fixupGenerics( unlock_decl, decl );
636
637 unlock_decl->stmts = new ast::CompoundStmt( location, {
638 new ast::ExprStmt( location,
639 new ast::UntypedExpr( location,
640 new ast::NameExpr( location, "unlock" ),
641 {
642 new ast::UntypedExpr( location,
643 new ast::NameExpr( location, "get_monitor" ),
644 { new ast::VariableExpr( location,
645 InitTweak::getParamThis( unlock_decl ) ) }
646 )
647 }
648 )
649 )
650 } );
651
652 declsToAddAfter.push_back( lock_decl );
653 declsToAddAfter.push_back( unlock_decl );
654}
655
656
657// --------------------------------------------------------------------------
658struct SuspendKeyword final :
659 public ast::WithStmtsToAdd<>, public ast::WithGuards {
660 SuspendKeyword() = default;
661 virtual ~SuspendKeyword() = default;
662
663 void previsit( const ast::FunctionDecl * );
664 const ast::DeclWithType * postvisit( const ast::FunctionDecl * );
665 const ast::Stmt * postvisit( const ast::SuspendStmt * );
666
667private:
668 bool is_real_suspend( const ast::FunctionDecl * );
669
670 const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * );
671 const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * );
672
673 struct LabelPair {
674 ast::Label obj;
675 int idx;
676 };
677
678 LabelPair make_label(const ast::Stmt * stmt ) {
679 labels.push_back( ControlStruct::newLabel( "generator", stmt ) );
680 return { labels.back(), int(labels.size()) };
681 }
682
683 const ast::DeclWithType * in_generator = nullptr;
684 const ast::FunctionDecl * decl_suspend = nullptr;
685 std::vector<ast::Label> labels;
686};
687
688void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) {
689 GuardValue( in_generator ); in_generator = nullptr;
690
691 // If it is the real suspend, grab it if we don't have one already.
692 if ( is_real_suspend( decl ) ) {
693 decl_suspend = decl_suspend ? decl_suspend : decl;
694 return;
695 }
696
697 // Otherwise check if this is a generator main and, if so, handle it.
698 auto param = isMainFor( decl, ast::AggregateDecl::Generator );
699 if ( !param ) return;
700
701 if ( 0 != decl->returns.size() ) {
702 SemanticError( decl->location, "Generator main must return void" );
703 }
704
705 in_generator = param;
706 GuardValue( labels ); labels.clear();
707}
708
709const ast::DeclWithType * SuspendKeyword::postvisit(
710 const ast::FunctionDecl * decl ) {
711 // Only modify a full definition of a generator with states.
712 if ( !decl->stmts || !in_generator || labels.empty() ) return decl;
713
714 const CodeLocation & location = decl->location;
715
716 // Create a new function body:
717 // static void * __generator_labels[] = {&&s0, &&s1, ...};
718 // void * __generator_label = __generator_labels[GEN.__generator_state];
719 // goto * __generator_label;
720 // s0: ;
721 // OLD_BODY
722
723 // This is the null statement inserted right before the body.
724 ast::NullStmt * noop = new ast::NullStmt( location );
725 noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) );
726 const ast::Label & first_label = noop->labels.back();
727
728 // Add each label to the init, starting with the first label.
729 std::vector<ast::ptr<ast::Init>> inits = {
730 new ast::SingleInit( location,
731 new ast::LabelAddressExpr( location, copy( first_label ) ) ) };
732 // Then go through all the stored labels, and clear the store.
733 for ( auto && label : labels ) {
734 inits.push_back( new ast::SingleInit( label.location,
735 new ast::LabelAddressExpr( label.location, std::move( label )
736 ) ) );
737 }
738 labels.clear();
739 // Then construct the initializer itself.
740 auto init = new ast::ListInit( location, std::move( inits ) );
741
742 ast::ObjectDecl * generatorLabels = new ast::ObjectDecl(
743 location,
744 "__generator_labels",
745 new ast::ArrayType(
746 new ast::PointerType( new ast::VoidType() ),
747 nullptr,
748 ast::FixedLen,
749 ast::DynamicDim
750 ),
751 init,
752 ast::Storage::Classes(),
753 ast::Linkage::AutoGen
754 );
755
756 ast::ObjectDecl * generatorLabel = new ast::ObjectDecl(
757 location,
758 "__generator_label",
759 new ast::PointerType( new ast::VoidType() ),
760 new ast::SingleInit( location,
761 new ast::UntypedExpr( location,
762 new ast::NameExpr( location, "?[?]" ),
763 {
764 // TODO: Could be a variable expr.
765 new ast::NameExpr( location, "__generator_labels" ),
766 new ast::UntypedMemberExpr( location,
767 new ast::NameExpr( location, "__generator_state" ),
768 new ast::VariableExpr( location, in_generator )
769 )
770 }
771 )
772 ),
773 ast::Storage::Classes(),
774 ast::Linkage::AutoGen
775 );
776
777 ast::BranchStmt * theGoTo = new ast::BranchStmt(
778 location, new ast::VariableExpr( location, generatorLabel )
779 );
780
781 // The noop goes here in order.
782
783 ast::CompoundStmt * body = new ast::CompoundStmt( location, {
784 { new ast::DeclStmt( location, generatorLabels ) },
785 { new ast::DeclStmt( location, generatorLabel ) },
786 { theGoTo },
787 { noop },
788 { decl->stmts },
789 } );
790
791 auto mutDecl = ast::mutate( decl );
792 mutDecl->stmts = body;
793 return mutDecl;
794}
795
796const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
797 switch ( stmt->type ) {
798 case ast::SuspendStmt::None:
799 // Use the context to determain the implicit target.
800 if ( in_generator ) {
801 return make_generator_suspend( stmt );
802 } else {
803 return make_coroutine_suspend( stmt );
804 }
805 case ast::SuspendStmt::Coroutine:
806 return make_coroutine_suspend( stmt );
807 case ast::SuspendStmt::Generator:
808 // Generator suspends must be directly in a generator.
809 if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." );
810 return make_generator_suspend( stmt );
811 }
812 assert( false );
813 return stmt;
814}
815
816/// Find the real/official suspend declaration.
817bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) {
818 return ( !decl->linkage.is_mangled
819 && 0 == decl->params.size()
820 && 0 == decl->returns.size()
821 && "__cfactx_suspend" == decl->name );
822}
823
824const ast::Stmt * SuspendKeyword::make_generator_suspend(
825 const ast::SuspendStmt * stmt ) {
826 assert( in_generator );
827 // Target code is:
828 // GEN.__generator_state = X;
829 // THEN
830 // return;
831 // __gen_X:;
832
833 const CodeLocation & location = stmt->location;
834
835 LabelPair label = make_label( stmt );
836
837 // This is the context saving statement.
838 stmtsToAddBefore.push_back( new ast::ExprStmt( location,
839 new ast::UntypedExpr( location,
840 new ast::NameExpr( location, "?=?" ),
841 {
842 new ast::UntypedMemberExpr( location,
843 new ast::NameExpr( location, "__generator_state" ),
844 new ast::VariableExpr( location, in_generator )
845 ),
846 ast::ConstantExpr::from_int( location, label.idx ),
847 }
848 )
849 ) );
850
851 // The THEN component is conditional (return is not).
852 if ( stmt->then ) {
853 stmtsToAddBefore.push_back( stmt->then.get() );
854 }
855 stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) );
856
857 // The null statement replaces the old suspend statement.
858 return new ast::NullStmt( location, { label.obj } );
859}
860
861const ast::Stmt * SuspendKeyword::make_coroutine_suspend(
862 const ast::SuspendStmt * stmt ) {
863 // The only thing we need from the old statement is the location.
864 const CodeLocation & location = stmt->location;
865
866 if ( !decl_suspend ) {
867 SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" );
868 }
869 if ( stmt->then ) {
870 SemanticError( location, "Compound statement following coroutines is not implemented." );
871 }
872
873 return new ast::ExprStmt( location,
874 new ast::UntypedExpr( location,
875 ast::VariableExpr::functionPointer( location, decl_suspend ) )
876 );
877}
878
879// --------------------------------------------------------------------------
880struct MutexKeyword final : public ast::WithDeclsToAdd<> {
881 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
882 void postvisit( const ast::StructDecl * decl );
883 const ast::Stmt * postvisit( const ast::MutexStmt * stmt );
884
885 static std::vector<const ast::DeclWithType *> findMutexArgs(
886 const ast::FunctionDecl * decl, bool & first );
887 static void validate( const ast::DeclWithType * decl );
888
889 ast::CompoundStmt * addDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
890 ast::CompoundStmt * addStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
891 ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args );
892 ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args );
893 ast::ExprStmt * genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param);
894 ast::IfStmt * genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam );
895private:
896 const ast::StructDecl * monitor_decl = nullptr;
897 const ast::StructDecl * guard_decl = nullptr;
898 const ast::StructDecl * dtor_guard_decl = nullptr;
899 const ast::StructDecl * thread_guard_decl = nullptr;
900 const ast::StructDecl * lock_guard_decl = nullptr;
901
902 static ast::ptr<ast::Type> generic_func;
903
904 UniqueName mutex_func_namer = UniqueName("__lock_unlock_curr");
905};
906
907const ast::FunctionDecl * MutexKeyword::postvisit(
908 const ast::FunctionDecl * decl ) {
909 bool is_first_argument_mutex = false;
910 const std::vector<const ast::DeclWithType *> mutexArgs =
911 findMutexArgs( decl, is_first_argument_mutex );
912 bool const isDtor = CodeGen::isDestructor( decl->name );
913
914 // Does this function have any mutex arguments that connect to monitors?
915 if ( mutexArgs.empty() ) {
916 // If this is the destructor for a monitor it must be mutex.
917 if ( isDtor ) {
918 // This reflects MutexKeyword::validate, but no error messages.
919 const ast::Type * type = decl->type->params.front();
920
921 // If it's a copy, it's not a mutex.
922 const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
923 if ( nullptr == refType ) {
924 return decl;
925 }
926
927 // If it is not pointing directly to a type, it's not a mutex.
928 auto base = refType->base;
929 if ( base.as<ast::ReferenceType>() ) return decl;
930 if ( base.as<ast::PointerType>() ) return decl;
931
932 // If it is not a struct, it's not a mutex.
933 auto baseStruct = base.as<ast::StructInstType>();
934 if ( nullptr == baseStruct ) return decl;
935
936 // If it is a monitor, then it is a monitor.
937 if( baseStruct->base->is_monitor() || baseStruct->base->is_thread() ) {
938 SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
939 }
940 }
941 return decl;
942 }
943
944 // Monitors can't be constructed with mutual exclusion.
945 if ( CodeGen::isConstructor( decl->name ) && is_first_argument_mutex ) {
946 SemanticError( decl, "constructors cannot have mutex parameters\n" );
947 }
948
949 // It makes no sense to have multiple mutex parameters for the destructor.
950 if ( isDtor && mutexArgs.size() != 1 ) {
951 SemanticError( decl, "destructors can only have 1 mutex argument\n" );
952 }
953
954 // Make sure all the mutex arguments are monitors.
955 for ( auto arg : mutexArgs ) {
956 validate( arg );
957 }
958
959 // Check to see if the body needs to be instrument the body.
960 const ast::CompoundStmt * body = decl->stmts;
961 if ( !body ) return decl;
962
963 // Check to if the required headers have been seen.
964 if ( !monitor_decl || !guard_decl || !dtor_guard_decl ) {
965 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
966 }
967
968 // Instrument the body.
969 ast::CompoundStmt * newBody = nullptr;
970 if ( isDtor && isThread( mutexArgs.front() ) ) {
971 if ( !thread_guard_decl ) {
972 SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
973 }
974 newBody = addThreadDtorStatements( decl, body, mutexArgs );
975 } else if ( isDtor ) {
976 newBody = addDtorStatements( decl, body, mutexArgs );
977 } else {
978 newBody = addStatements( decl, body, mutexArgs );
979 }
980 assert( newBody );
981 return ast::mutate_field( decl, &ast::FunctionDecl::stmts, newBody );
982}
983
984void MutexKeyword::postvisit( const ast::StructDecl * decl ) {
985 if ( !decl->body ) {
986 return;
987 } else if ( decl->name == "monitor$" ) {
988 assert( !monitor_decl );
989 monitor_decl = decl;
990 } else if ( decl->name == "monitor_guard_t" ) {
991 assert( !guard_decl );
992 guard_decl = decl;
993 } else if ( decl->name == "monitor_dtor_guard_t" ) {
994 assert( !dtor_guard_decl );
995 dtor_guard_decl = decl;
996 } else if ( decl->name == "thread_dtor_guard_t" ) {
997 assert( !thread_guard_decl );
998 thread_guard_decl = decl;
999 } else if ( decl->name == "__mutex_stmt_lock_guard" ) {
1000 assert( !lock_guard_decl );
1001 lock_guard_decl = decl;
1002 }
1003}
1004
1005const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) {
1006 if ( !lock_guard_decl ) {
1007 SemanticError( stmt->location, "mutex stmt requires a header, add #include <mutex_stmt.hfa>\n" );
1008 }
1009 ast::CompoundStmt * body =
1010 new ast::CompoundStmt( stmt->location, { stmt->stmt } );
1011
1012 return addStatements( body, stmt->mutexObjs );;
1013}
1014
1015std::vector<const ast::DeclWithType *> MutexKeyword::findMutexArgs(
1016 const ast::FunctionDecl * decl, bool & first ) {
1017 std::vector<const ast::DeclWithType *> mutexArgs;
1018
1019 bool once = true;
1020 for ( auto arg : decl->params ) {
1021 const ast::Type * type = arg->get_type();
1022 if ( type->is_mutex() ) {
1023 if ( once ) first = true;
1024 mutexArgs.push_back( arg.get() );
1025 }
1026 once = false;
1027 }
1028 return mutexArgs;
1029}
1030
1031void MutexKeyword::validate( const ast::DeclWithType * decl ) {
1032 const ast::Type * type = decl->get_type();
1033
1034 // If it's a copy, it's not a mutex.
1035 const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
1036 if ( nullptr == refType ) {
1037 SemanticError( decl, "Mutex argument must be of reference type " );
1038 }
1039
1040 // If it is not pointing directly to a type, it's not a mutex.
1041 auto base = refType->base;
1042 if ( base.as<ast::ReferenceType>() || base.as<ast::PointerType>() ) {
1043 SemanticError( decl, "Mutex argument have exactly one level of indirection " );
1044 }
1045
1046 // If it is not a struct, it's not a mutex.
1047 auto baseStruct = base.as<ast::StructInstType>();
1048 if ( nullptr == baseStruct ) return;
1049
1050 // Make sure that only the outer reference is mutex.
1051 if( baseStruct->is_mutex() ) {
1052 SemanticError( decl, "mutex keyword may only appear once per argument " );
1053 }
1054}
1055
1056ast::CompoundStmt * MutexKeyword::addDtorStatements(
1057 const ast::FunctionDecl* func, const ast::CompoundStmt * body,
1058 const std::vector<const ast::DeclWithType *> & args ) {
1059 ast::Type * argType = ast::shallowCopy( args.front()->get_type() );
1060 argType->set_mutex( false );
1061
1062 ast::CompoundStmt * mutBody = ast::mutate( body );
1063
1064 // Generated code goes near the beginning of body:
1065 const CodeLocation & location = mutBody->location;
1066
1067 const ast::ObjectDecl * monitor = new ast::ObjectDecl(
1068 location,
1069 "__monitor",
1070 new ast::PointerType( new ast::StructInstType( monitor_decl ) ),
1071 new ast::SingleInit(
1072 location,
1073 new ast::UntypedExpr(
1074 location,
1075 new ast::NameExpr( location, "get_monitor" ),
1076 { new ast::CastExpr(
1077 location,
1078 new ast::VariableExpr( location, args.front() ),
1079 argType, ast::ExplicitCast
1080 ) }
1081 )
1082 ),
1083 ast::Storage::Classes(),
1084 ast::Linkage::Cforall
1085 );
1086
1087 assert( generic_func );
1088
1089 // In reverse order:
1090 // monitor_dtor_guard_t __guard = { __monitor, func, false };
1091 mutBody->push_front(
1092 new ast::DeclStmt( location, new ast::ObjectDecl(
1093 location,
1094 "__guard",
1095 new ast::StructInstType( dtor_guard_decl ),
1096 new ast::ListInit(
1097 location,
1098 {
1099 new ast::SingleInit( location,
1100 new ast::AddressExpr( location,
1101 new ast::VariableExpr( location, monitor ) ) ),
1102 new ast::SingleInit( location,
1103 new ast::CastExpr( location,
1104 new ast::VariableExpr( location, func ),
1105 generic_func,
1106 ast::ExplicitCast ) ),
1107 new ast::SingleInit( location,
1108 ast::ConstantExpr::from_bool( location, false ) ),
1109 },
1110 {},
1111 ast::MaybeConstruct
1112 ),
1113 ast::Storage::Classes(),
1114 ast::Linkage::Cforall
1115 ))
1116 );
1117
1118 // monitor$ * __monitor = get_monitor(a);
1119 mutBody->push_front( new ast::DeclStmt( location, monitor ) );
1120
1121 return mutBody;
1122}
1123
1124ast::CompoundStmt * MutexKeyword::addStatements(
1125 const ast::FunctionDecl* func, const ast::CompoundStmt * body,
1126 const std::vector<const ast::DeclWithType * > & args ) {
1127 ast::CompoundStmt * mutBody = ast::mutate( body );
1128
1129 // Code is generated near the beginning of the compound statement.
1130 const CodeLocation & location = mutBody->location;
1131
1132 // Make pointer to the monitors.
1133 ast::ObjectDecl * monitors = new ast::ObjectDecl(
1134 location,
1135 "__monitors",
1136 new ast::ArrayType(
1137 new ast::PointerType(
1138 new ast::StructInstType( monitor_decl )
1139 ),
1140 ast::ConstantExpr::from_ulong( location, args.size() ),
1141 ast::FixedLen,
1142 ast::DynamicDim
1143 ),
1144 new ast::ListInit(
1145 location,
1146 map_range<std::vector<ast::ptr<ast::Init>>>(
1147 args,
1148 []( const ast::DeclWithType * decl ) {
1149 return new ast::SingleInit(
1150 decl->location,
1151 new ast::UntypedExpr(
1152 decl->location,
1153 new ast::NameExpr( decl->location, "get_monitor" ),
1154 {
1155 new ast::CastExpr(
1156 decl->location,
1157 new ast::VariableExpr( decl->location, decl ),
1158 decl->get_type(),
1159 ast::ExplicitCast
1160 )
1161 }
1162 )
1163 );
1164 }
1165 )
1166 ),
1167 ast::Storage::Classes(),
1168 ast::Linkage::Cforall
1169 );
1170
1171 assert( generic_func );
1172
1173 // In Reverse Order:
1174 mutBody->push_front(
1175 new ast::DeclStmt( location, new ast::ObjectDecl(
1176 location,
1177 "__guard",
1178 new ast::StructInstType( guard_decl ),
1179 new ast::ListInit(
1180 location,
1181 {
1182 new ast::SingleInit( location,
1183 new ast::VariableExpr( location, monitors ) ),
1184 new ast::SingleInit( location,
1185 ast::ConstantExpr::from_ulong( location, args.size() ) ),
1186 new ast::SingleInit( location, new ast::CastExpr(
1187 location,
1188 new ast::VariableExpr( location, func ),
1189 generic_func,
1190 ast::ExplicitCast
1191 ) ),
1192 },
1193 {},
1194 ast::MaybeConstruct
1195 ),
1196 ast::Storage::Classes(),
1197 ast::Linkage::Cforall
1198 ))
1199 );
1200
1201 // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
1202 mutBody->push_front( new ast::DeclStmt( location, monitors ) );
1203
1204 return mutBody;
1205}
1206
1207// generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
1208// used to undo the type erasure done by storing all the lock pointers as void
1209ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
1210 return new ast::ExprStmt( location,
1211 new ast::UntypedExpr( location,
1212 new ast::NameExpr( location, fnName ), {
1213 ast::UntypedExpr::createDeref(
1214 location,
1215 new ast::CastExpr( location,
1216 param,
1217 new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
1218 expr->location,
1219 new ast::NameExpr( expr->location, "__get_mutexstmt_lock_type" ),
1220 { expr }
1221 ) ) ),
1222 ast::GeneratedFlag::ExplicitCast
1223 )
1224 )
1225 }
1226 )
1227 );
1228}
1229
1230ast::IfStmt * MutexKeyword::genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ) {
1231 ast::IfStmt * outerLockIf = nullptr;
1232 ast::IfStmt * lastLockIf = nullptr;
1233
1234 //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
1235 for ( long unsigned int i = 0; i < args.size(); i++ ) {
1236
1237 ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
1238 new ast::NameExpr( location, "?==?" ), {
1239 ast::deepCopy( thisParam ),
1240 new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
1241 }
1242 );
1243
1244 ast::IfStmt * currLockIf = new ast::IfStmt(
1245 location,
1246 ifCond,
1247 genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
1248 );
1249
1250 if ( i == 0 ) {
1251 outerLockIf = currLockIf;
1252 } else {
1253 // add ifstmt to else of previous stmt
1254 lastLockIf->else_ = currLockIf;
1255 }
1256
1257 lastLockIf = currLockIf;
1258 }
1259 return outerLockIf;
1260}
1261
1262ast::CompoundStmt * MutexKeyword::addStatements(
1263 const ast::CompoundStmt * body,
1264 const std::vector<ast::ptr<ast::Expr>> & args ) {
1265
1266 // Code is generated near the beginning of the compound statement.
1267 const CodeLocation & location = body->location;
1268
1269 // final body to return
1270 ast::CompoundStmt * newBody = new ast::CompoundStmt( location );
1271
1272 // std::string lockFnName = mutex_func_namer.newName();
1273 // std::string unlockFnName = mutex_func_namer.newName();
1274
1275 // Make pointer to the monitors.
1276 ast::ObjectDecl * monitors = new ast::ObjectDecl(
1277 location,
1278 "__monitors",
1279 new ast::ArrayType(
1280 new ast::PointerType(
1281 new ast::VoidType()
1282 ),
1283 ast::ConstantExpr::from_ulong( location, args.size() ),
1284 ast::FixedLen,
1285 ast::DynamicDim
1286 ),
1287 new ast::ListInit(
1288 location,
1289 map_range<std::vector<ast::ptr<ast::Init>>>(
1290 args, [](const ast::Expr * expr) {
1291 return new ast::SingleInit(
1292 expr->location,
1293 new ast::UntypedExpr(
1294 expr->location,
1295 new ast::NameExpr( expr->location, "__get_mutexstmt_lock_ptr" ),
1296 { expr }
1297 )
1298 );
1299 }
1300 )
1301 ),
1302 ast::Storage::Classes(),
1303 ast::Linkage::Cforall
1304 );
1305
1306 ast::StructInstType * lock_guard_struct =
1307 new ast::StructInstType( lock_guard_decl );
1308
1309 // use try stmts to lock and finally to unlock
1310 ast::TryStmt * outerTry = nullptr;
1311 ast::TryStmt * currentTry;
1312 ast::CompoundStmt * lastBody = nullptr;
1313
1314 // adds a nested try stmt for each lock we are locking
1315 for ( long unsigned int i = 0; i < args.size(); i++ ) {
1316 ast::UntypedExpr * innerAccess = new ast::UntypedExpr(
1317 location,
1318 new ast::NameExpr( location,"?[?]" ), {
1319 new ast::NameExpr( location, "__monitors" ),
1320 ast::ConstantExpr::from_int( location, i )
1321 }
1322 );
1323
1324 // make the try body
1325 ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location );
1326 ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess );
1327 currTryBody->push_back( lockCall );
1328
1329 // make the finally stmt
1330 ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location );
1331 ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess );
1332 currFinallyBody->push_back( unlockCall );
1333
1334 // construct the current try
1335 currentTry = new ast::TryStmt(
1336 location,
1337 currTryBody,
1338 {},
1339 new ast::FinallyStmt( location, currFinallyBody )
1340 );
1341 if ( i == 0 ) outerTry = currentTry;
1342 else {
1343 // pushback try into the body of the outer try
1344 lastBody->push_back( currentTry );
1345 }
1346 lastBody = currTryBody;
1347 }
1348
1349 // push body into innermost try body
1350 if ( lastBody != nullptr ) {
1351 lastBody->push_back( body );
1352 newBody->push_front( outerTry );
1353 }
1354
1355 // monitor_guard_t __guard = { __monitors, # };
1356 newBody->push_front(
1357 new ast::DeclStmt(
1358 location,
1359 new ast::ObjectDecl(
1360 location,
1361 "__guard",
1362 lock_guard_struct,
1363 new ast::ListInit(
1364 location,
1365 {
1366 new ast::SingleInit(
1367 location,
1368 new ast::VariableExpr( location, monitors ) ),
1369 new ast::SingleInit(
1370 location,
1371 ast::ConstantExpr::from_ulong( location, args.size() ) ),
1372 },
1373 {},
1374 ast::MaybeConstruct
1375 ),
1376 ast::Storage::Classes(),
1377 ast::Linkage::Cforall
1378 )
1379 )
1380 );
1381
1382 // monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
1383 newBody->push_front( new ast::DeclStmt( location, monitors ) );
1384
1385 // // The parameter for both __lock_curr/__unlock_curr routines.
1386 // ast::ObjectDecl * this_decl = new ast::ObjectDecl(
1387 // location,
1388 // "this",
1389 // new ast::PointerType( new ast::VoidType() ),
1390 // nullptr,
1391 // {},
1392 // ast::Linkage::Cforall
1393 // );
1394
1395 // ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
1396 // location,
1397 // lockFnName,
1398 // { /* forall */ },
1399 // {
1400 // // Copy the declaration of this.
1401 // this_decl,
1402 // },
1403 // { /* returns */ },
1404 // nullptr,
1405 // 0,
1406 // ast::Linkage::Cforall,
1407 // { /* attributes */ },
1408 // ast::Function::Inline
1409 // );
1410
1411 // ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
1412 // location,
1413 // unlockFnName,
1414 // { /* forall */ },
1415 // {
1416 // // Copy the declaration of this.
1417 // ast::deepCopy( this_decl ),
1418 // },
1419 // { /* returns */ },
1420 // nullptr,
1421 // 0,
1422 // ast::Linkage::Cforall,
1423 // { /* attributes */ },
1424 // ast::Function::Inline
1425 // );
1426
1427 // ast::IfStmt * outerLockIf = nullptr;
1428 // ast::IfStmt * outerUnlockIf = nullptr;
1429 // ast::IfStmt * lastLockIf = nullptr;
1430 // ast::IfStmt * lastUnlockIf = nullptr;
1431
1432 // //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
1433 // for ( long unsigned int i = 0; i < args.size(); i++ ) {
1434 // ast::VariableExpr * thisParam = new ast::VariableExpr( location, InitTweak::getParamThis( lock_decl ) );
1435 // ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
1436 // new ast::NameExpr( location, "?==?" ), {
1437 // thisParam,
1438 // new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
1439 // }
1440 // );
1441
1442 // ast::IfStmt * currLockIf = new ast::IfStmt(
1443 // location,
1444 // ast::deepCopy( ifCond ),
1445 // genVirtLockUnlockExpr( "lock", args.at(i), location, ast::deepCopy( thisParam ) )
1446 // );
1447
1448 // ast::IfStmt * currUnlockIf = new ast::IfStmt(
1449 // location,
1450 // ifCond,
1451 // genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
1452 // );
1453
1454 // if ( i == 0 ) {
1455 // outerLockIf = currLockIf;
1456 // outerUnlockIf = currUnlockIf;
1457 // } else {
1458 // // add ifstmt to else of previous stmt
1459 // lastLockIf->else_ = currLockIf;
1460 // lastUnlockIf->else_ = currUnlockIf;
1461 // }
1462
1463 // lastLockIf = currLockIf;
1464 // lastUnlockIf = currUnlockIf;
1465 // }
1466
1467 // // add pointer typing if/elifs to body of routines
1468 // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
1469 // unlock_decl->stmts = new ast::CompoundStmt( location, { outerUnlockIf } );
1470
1471 // // add routines to scope
1472 // declsToAddBefore.push_back( lock_decl );
1473 // declsToAddBefore.push_back( unlock_decl );
1474
1475 // newBody->push_front(new ast::DeclStmt( location, lock_decl ));
1476 // newBody->push_front(new ast::DeclStmt( location, unlock_decl ));
1477
1478 return newBody;
1479}
1480
1481ast::CompoundStmt * MutexKeyword::addThreadDtorStatements(
1482 const ast::FunctionDecl*, const ast::CompoundStmt * body,
1483 const std::vector<const ast::DeclWithType * > & args ) {
1484 assert( args.size() == 1 );
1485 const ast::DeclWithType * arg = args.front();
1486 const ast::Type * argType = arg->get_type();
1487 assert( argType->is_mutex() );
1488
1489 ast::CompoundStmt * mutBody = ast::mutate( body );
1490
1491 // The code is generated near the front of the body.
1492 const CodeLocation & location = mutBody->location;
1493
1494 // thread_dtor_guard_t __guard = { this, intptr( 0 ) };
1495 mutBody->push_front( new ast::DeclStmt(
1496 location,
1497 new ast::ObjectDecl(
1498 location,
1499 "__guard",
1500 new ast::StructInstType( thread_guard_decl ),
1501 new ast::ListInit(
1502 location,
1503 {
1504 new ast::SingleInit( location,
1505 new ast::CastExpr( location,
1506 new ast::VariableExpr( location, arg ), argType ) ),
1507 new ast::SingleInit(
1508 location,
1509 new ast::UntypedExpr(
1510 location,
1511 new ast::NameExpr( location, "intptr" ), {
1512 ast::ConstantExpr::from_int( location, 0 ),
1513 }
1514 ) ),
1515 },
1516 {},
1517 ast::MaybeConstruct
1518 ),
1519 ast::Storage::Classes(),
1520 ast::Linkage::Cforall
1521 )
1522 ));
1523
1524 return mutBody;
1525}
1526
1527ast::ptr<ast::Type> MutexKeyword::generic_func =
1528 new ast::FunctionType( ast::VariableArgs );
1529
1530// --------------------------------------------------------------------------
1531struct ThreadStarter final {
1532 void previsit( const ast::StructDecl * decl );
1533 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
1534
1535private:
1536 bool thread_ctor_seen = false;
1537 const ast::StructDecl * thread_decl = nullptr;
1538};
1539
1540void ThreadStarter::previsit( const ast::StructDecl * decl ) {
1541 if ( decl->body && decl->name == "thread$" ) {
1542 assert( !thread_decl );
1543 thread_decl = decl;
1544 }
1545}
1546
1547const ast::FunctionDecl * ThreadStarter::postvisit( const ast::FunctionDecl * decl ) {
1548 if ( !CodeGen::isConstructor( decl->name ) ) return decl;
1549
1550 // Seach for the thread constructor.
1551 // (Are the "prefixes" of these to blocks the same?)
1552 const ast::Type * typeof_this = InitTweak::getTypeofThis( decl->type );
1553 auto ctored_type = dynamic_cast<const ast::StructInstType *>( typeof_this );
1554 if ( ctored_type && ctored_type->base == thread_decl ) {
1555 thread_ctor_seen = true;
1556 }
1557
1558 // Modify this declaration, the extra checks to see if we will are first.
1559 const ast::ptr<ast::DeclWithType> & param = decl->params.front();
1560 auto type = dynamic_cast<const ast::StructInstType *>(
1561 InitTweak::getPointerBase( param->get_type() ) );
1562 if ( nullptr == type ) return decl;
1563 if ( !type->base->is_thread() ) return decl;
1564 if ( !thread_decl || !thread_ctor_seen ) {
1565 SemanticError( type->base->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>" );
1566 }
1567 const ast::CompoundStmt * stmt = decl->stmts;
1568 if ( nullptr == stmt ) return decl;
1569
1570 // Now do the actual modification:
1571 ast::CompoundStmt * mutStmt = ast::mutate( stmt );
1572 const CodeLocation & location = mutStmt->location;
1573 mutStmt->push_back(
1574 new ast::ExprStmt(
1575 location,
1576 new ast::UntypedExpr(
1577 location,
1578 new ast::NameExpr( location, "__thrd_start" ),
1579 {
1580 new ast::VariableExpr( location, param ),
1581 new ast::NameExpr( location, "main" ),
1582 }
1583 )
1584 )
1585 );
1586
1587 return ast::mutate_field( decl, &ast::FunctionDecl::stmts, mutStmt );
1588}
1589
1590} // namespace
1591
1592// --------------------------------------------------------------------------
1593// Interface Functions:
1594
1595void implementKeywords( ast::TranslationUnit & translationUnit ) {
1596 ast::Pass<ThreadKeyword>::run( translationUnit );
1597 ast::Pass<CoroutineKeyword>::run( translationUnit );
1598 ast::Pass<MonitorKeyword>::run( translationUnit );
1599 ast::Pass<GeneratorKeyword>::run( translationUnit );
1600 ast::Pass<SuspendKeyword>::run( translationUnit );
1601}
1602
1603void implementMutex( ast::TranslationUnit & translationUnit ) {
1604 ast::Pass<MutexKeyword>::run( translationUnit );
1605}
1606
1607void implementThreadStarter( ast::TranslationUnit & translationUnit ) {
1608 ast::Pass<ThreadStarter>::run( translationUnit );
1609}
1610
1611}
1612
1613// Local Variables: //
1614// tab-width: 4 //
1615// mode: c++ //
1616// compile-command: "make install" //
1617// End: //
Note: See TracBrowser for help on using the repository browser.