source: src/Concurrency/KeywordsNew.cpp@ 03c56f6

ADT ast-experimental
Last change on this file since 03c56f6 was e01eb4a, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Moved some functions from InitTweak to Inspect.

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