source: src/Concurrency/Keywords.cc@ f90d10f

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since f90d10f was e6cfa8ff, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

Fixed use after delete bug and regenerated stale tests

  • Property mode set to 100644
File size: 31.6 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// Keywords.cc --
8//
9// Author : Thierry Delisle
10// Created On : Mon Mar 13 12:41:22 2017
11// Last Modified By :
12// Last Modified On :
13// Update Count : 10
14//
15
16#include "Concurrency/Keywords.h"
17
18#include <cassert> // for assert
19#include <string> // for string, operator==
20
21#include "Common/PassVisitor.h" // for PassVisitor
22#include "Common/SemanticError.h" // for SemanticError
23#include "Common/utility.h" // for deleteAll, map_range
24#include "CodeGen/OperatorTable.h" // for isConstructor
25#include "ControlStruct/LabelGenerator.h" // for LebelGenerator
26#include "InitTweak/InitTweak.h" // for getPointerBase
27#include "SynTree/LinkageSpec.h" // for Cforall
28#include "SynTree/Constant.h" // for Constant
29#include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl
30#include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype...
31#include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ...
32#include "SynTree/Label.h" // for Label
33#include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt
34#include "SynTree/Type.h" // for StructInstType, Type, PointerType
35#include "SynTree/Visitor.h" // for Visitor, acceptAll
36
37class Attribute;
38
39namespace Concurrency {
40 //=============================================================================================
41 // Pass declarations
42 //=============================================================================================
43
44 //-----------------------------------------------------------------------------
45 //Handles sue type declarations :
46 // sue MyType { struct MyType {
47 // int data; int data;
48 // a_struct_t more_data; a_struct_t more_data;
49 // => NewField_t newField;
50 // }; };
51 // static inline NewField_t * getter_name( MyType * this ) { return &this->newField; }
52 //
53 class ConcurrentSueKeyword : public WithDeclsToAdd {
54 public:
55
56 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
57 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
58
59 virtual ~ConcurrentSueKeyword() {}
60
61 Declaration * postmutate( StructDecl * decl );
62 DeclarationWithType * postmutate( FunctionDecl * decl );
63
64 void handle( StructDecl * );
65 FunctionDecl * forwardDeclare( StructDecl * );
66 ObjectDecl * addField( StructDecl * );
67 void addRoutines( ObjectDecl *, FunctionDecl * );
68
69 virtual bool is_target( StructDecl * decl ) = 0;
70
71 Expression * postmutate( KeywordCastExpr * cast );
72
73 private:
74 const std::string type_name;
75 const std::string field_name;
76 const std::string getter_name;
77 const std::string context_error;
78 bool needs_main;
79 AggregateDecl::Aggregate cast_target;
80
81 StructDecl * type_decl = nullptr;
82 FunctionDecl * dtor_decl = nullptr;
83 };
84
85
86 //-----------------------------------------------------------------------------
87 //Handles thread type declarations :
88 // thread Mythread { struct MyThread {
89 // int data; int data;
90 // a_struct_t more_data; a_struct_t more_data;
91 // => $thread __thrd_d;
92 // }; };
93 // static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
94 //
95 class ThreadKeyword final : public ConcurrentSueKeyword {
96 public:
97
98 ThreadKeyword() : ConcurrentSueKeyword(
99 "$thread",
100 "__thrd",
101 "get_thread",
102 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
103 true,
104 AggregateDecl::Thread
105 )
106 {}
107
108 virtual ~ThreadKeyword() {}
109
110 virtual bool is_target( StructDecl * decl ) override final { return decl->is_thread(); }
111
112 static void implement( std::list< Declaration * > & translationUnit ) {
113 PassVisitor< ThreadKeyword > impl;
114 mutateAll( translationUnit, impl );
115 }
116 };
117
118 //-----------------------------------------------------------------------------
119 //Handles coroutine type declarations :
120 // coroutine MyCoroutine { struct MyCoroutine {
121 // int data; int data;
122 // a_struct_t more_data; a_struct_t more_data;
123 // => $coroutine __cor_d;
124 // }; };
125 // static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
126 //
127 class CoroutineKeyword final : public ConcurrentSueKeyword {
128 public:
129
130 CoroutineKeyword() : ConcurrentSueKeyword(
131 "$coroutine",
132 "__cor",
133 "get_coroutine",
134 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
135 true,
136 AggregateDecl::Coroutine
137 )
138 {}
139
140 virtual ~CoroutineKeyword() {}
141
142 virtual bool is_target( StructDecl * decl ) override final { return decl->is_coroutine(); }
143
144 static void implement( std::list< Declaration * > & translationUnit ) {
145 PassVisitor< CoroutineKeyword > impl;
146 mutateAll( translationUnit, impl );
147 }
148 };
149
150
151
152 //-----------------------------------------------------------------------------
153 //Handles monitor type declarations :
154 // monitor MyMonitor { struct MyMonitor {
155 // int data; int data;
156 // a_struct_t more_data; a_struct_t more_data;
157 // => $monitor __mon_d;
158 // }; };
159 // static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
160 //
161 class MonitorKeyword final : public ConcurrentSueKeyword {
162 public:
163
164 MonitorKeyword() : ConcurrentSueKeyword(
165 "$monitor",
166 "__mon",
167 "get_monitor",
168 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
169 false,
170 AggregateDecl::Monitor
171 )
172 {}
173
174 virtual ~MonitorKeyword() {}
175
176 virtual bool is_target( StructDecl * decl ) override final { return decl->is_monitor(); }
177
178 static void implement( std::list< Declaration * > & translationUnit ) {
179 PassVisitor< MonitorKeyword > impl;
180 mutateAll( translationUnit, impl );
181 }
182 };
183
184 //-----------------------------------------------------------------------------
185 //Handles generator type declarations :
186 // generator MyGenerator { struct MyGenerator {
187 // int data; int data;
188 // a_struct_t more_data; a_struct_t more_data;
189 // => int __gen_next;
190 // }; };
191 //
192 class GeneratorKeyword final : public ConcurrentSueKeyword {
193 public:
194
195 GeneratorKeyword() : ConcurrentSueKeyword(
196 "$generator",
197 "__generator_state",
198 "get_generator",
199 "Unable to find builtin type $generator\n",
200 true,
201 AggregateDecl::Generator
202 )
203 {}
204
205 virtual ~GeneratorKeyword() {}
206
207 virtual bool is_target( StructDecl * decl ) override final { return decl->is_generator(); }
208
209 static void implement( std::list< Declaration * > & translationUnit ) {
210 PassVisitor< GeneratorKeyword > impl;
211 mutateAll( translationUnit, impl );
212 }
213 };
214
215
216 //-----------------------------------------------------------------------------
217 class SuspendKeyword final : public WithStmtsToAdd, public WithGuards {
218 public:
219 SuspendKeyword() = default;
220 virtual ~SuspendKeyword() = default;
221
222 void premutate( FunctionDecl * );
223 DeclarationWithType * postmutate( FunctionDecl * );
224
225 Statement * postmutate( SuspendStmt * );
226
227 static void implement( std::list< Declaration * > & translationUnit ) {
228 PassVisitor< SuspendKeyword > impl;
229 mutateAll( translationUnit, impl );
230 }
231
232 private:
233 DeclarationWithType * is_main( FunctionDecl * );
234 bool is_real_suspend( FunctionDecl * );
235
236 Statement * make_generator_suspend( SuspendStmt * );
237 Statement * make_coroutine_suspend( SuspendStmt * );
238
239 struct LabelPair {
240 Label obj;
241 int idx;
242 };
243
244 LabelPair make_label() {
245 labels.push_back( gen.newLabel("generator") );
246 return { labels.back(), int(labels.size()) };
247 }
248
249 DeclarationWithType * in_generator = nullptr;
250 FunctionDecl * decl_suspend = nullptr;
251 std::vector<Label> labels;
252 ControlStruct::LabelGenerator & gen = *ControlStruct::LabelGenerator::getGenerator();
253 };
254
255 //-----------------------------------------------------------------------------
256 //Handles mutex routines definitions :
257 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) {
258 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
259 // monitor_guard_t __guard = { __monitors, 2 };
260 // /*Some code*/ => /*Some code*/
261 // } }
262 //
263 class MutexKeyword final {
264 public:
265
266 void postvisit( FunctionDecl * decl );
267 void postvisit( StructDecl * decl );
268
269 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
270 void validate( DeclarationWithType * );
271 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
272 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
273
274 static void implement( std::list< Declaration * > & translationUnit ) {
275 PassVisitor< MutexKeyword > impl;
276 acceptAll( translationUnit, impl );
277 }
278
279 private:
280 StructDecl* monitor_decl = nullptr;
281 StructDecl* guard_decl = nullptr;
282 StructDecl* dtor_guard_decl = nullptr;
283
284 static std::unique_ptr< Type > generic_func;
285 };
286
287 std::unique_ptr< Type > MutexKeyword::generic_func = std::unique_ptr< Type >(
288 new FunctionType(
289 noQualifiers,
290 true
291 )
292 );
293
294 //-----------------------------------------------------------------------------
295 //Handles mutex routines definitions :
296 // void foo( A * mutex a, B * mutex b, int i ) { void foo( A * a, B * b, int i ) {
297 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
298 // monitor_guard_t __guard = { __monitors, 2 };
299 // /*Some code*/ => /*Some code*/
300 // } }
301 //
302 class ThreadStarter final {
303 public:
304
305 void postvisit( FunctionDecl * decl );
306 void previsit ( StructDecl * decl );
307
308 void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
309
310 static void implement( std::list< Declaration * > & translationUnit ) {
311 PassVisitor< ThreadStarter > impl;
312 acceptAll( translationUnit, impl );
313 }
314
315 private :
316 bool thread_ctor_seen = false;
317 StructDecl * thread_decl = nullptr;
318 };
319
320 //=============================================================================================
321 // General entry routine
322 //=============================================================================================
323 void applyKeywords( std::list< Declaration * > & translationUnit ) {
324 ThreadKeyword ::implement( translationUnit );
325 CoroutineKeyword ::implement( translationUnit );
326 MonitorKeyword ::implement( translationUnit );
327 GeneratorKeyword ::implement( translationUnit );
328 SuspendKeyword ::implement( translationUnit );
329 }
330
331 void implementMutexFuncs( std::list< Declaration * > & translationUnit ) {
332 MutexKeyword ::implement( translationUnit );
333 }
334
335 void implementThreadStarter( std::list< Declaration * > & translationUnit ) {
336 ThreadStarter ::implement( translationUnit );
337 }
338
339 //=============================================================================================
340 // Generic keyword implementation
341 //=============================================================================================
342 void fixupGenerics(FunctionType * func, StructDecl * decl) {
343 cloneAll(decl->parameters, func->forall);
344 for ( TypeDecl * td : func->forall ) {
345 strict_dynamic_cast<StructInstType*>(
346 func->parameters.front()->get_type()->stripReferences()
347 )->parameters.push_back(
348 new TypeExpr( new TypeInstType( noQualifiers, td->name, td ) )
349 );
350 }
351 }
352
353 Declaration * ConcurrentSueKeyword::postmutate(StructDecl * decl) {
354 if( decl->name == type_name && decl->body ) {
355 assert( !type_decl );
356 type_decl = decl;
357 }
358 else if ( is_target(decl) ) {
359 handle( decl );
360 }
361 return decl;
362 }
363
364 DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
365 if( !type_decl ) return decl;
366 if( !CodeGen::isDestructor( decl->name ) ) return decl;
367
368 auto params = decl->type->parameters;
369 if( params.size() != 1 ) return decl;
370
371 auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
372 if( !type ) return decl;
373
374 auto stype = dynamic_cast<StructInstType*>( type->base );
375 if( !stype ) return decl;
376 if( stype->baseStruct != type_decl ) return decl;
377
378 if( !dtor_decl ) dtor_decl = decl;
379 return decl;
380 }
381
382 Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
383 if ( cast_target == cast->target ) {
384 // convert (thread &)t to ($thread &)*get_thread(t), etc.
385 if( !type_decl ) SemanticError( cast, context_error );
386 if( !dtor_decl ) SemanticError( cast, context_error );
387 assert( cast->result == nullptr );
388 cast->set_result( new ReferenceType( noQualifiers, new StructInstType( noQualifiers, type_decl ) ) );
389 cast->concrete_target.field = field_name;
390 cast->concrete_target.getter = getter_name;
391 }
392 return cast;
393 }
394
395
396 void ConcurrentSueKeyword::handle( StructDecl * decl ) {
397 if( ! decl->body ) return;
398
399 if( !type_decl ) SemanticError( decl, context_error );
400 if( !dtor_decl ) SemanticError( decl, context_error );
401
402 FunctionDecl * func = forwardDeclare( decl );
403 ObjectDecl * field = addField( decl );
404 addRoutines( field, func );
405 }
406
407 FunctionDecl * ConcurrentSueKeyword::forwardDeclare( StructDecl * decl ) {
408
409 StructDecl * forward = decl->clone();
410 forward->set_body( false );
411 deleteAll( forward->get_members() );
412 forward->get_members().clear();
413
414 FunctionType * get_type = new FunctionType( noQualifiers, false );
415 ObjectDecl * this_decl = new ObjectDecl(
416 "this",
417 noStorageClasses,
418 LinkageSpec::Cforall,
419 nullptr,
420 new ReferenceType(
421 noQualifiers,
422 new StructInstType(
423 noQualifiers,
424 decl
425 )
426 ),
427 nullptr
428 );
429
430 get_type->get_parameters().push_back( this_decl->clone() );
431 get_type->get_returnVals().push_back(
432 new ObjectDecl(
433 "ret",
434 noStorageClasses,
435 LinkageSpec::Cforall,
436 nullptr,
437 new PointerType(
438 noQualifiers,
439 new StructInstType(
440 noQualifiers,
441 type_decl
442 )
443 ),
444 nullptr
445 )
446 );
447 fixupGenerics(get_type, decl);
448
449 FunctionDecl * get_decl = new FunctionDecl(
450 getter_name,
451 Type::Static,
452 LinkageSpec::Cforall,
453 get_type,
454 nullptr,
455 { new Attribute("const") },
456 Type::Inline
457 );
458
459 FunctionDecl * main_decl = nullptr;
460
461 if( needs_main ) {
462 FunctionType * main_type = new FunctionType( noQualifiers, false );
463
464 main_type->get_parameters().push_back( this_decl->clone() );
465
466 main_decl = new FunctionDecl(
467 "main",
468 noStorageClasses,
469 LinkageSpec::Cforall,
470 main_type,
471 nullptr
472 );
473 fixupGenerics(main_type, decl);
474 }
475
476 delete this_decl;
477
478 declsToAddBefore.push_back( forward );
479 if( needs_main ) declsToAddBefore.push_back( main_decl );
480 declsToAddBefore.push_back( get_decl );
481
482 return get_decl;
483 }
484
485 ObjectDecl * ConcurrentSueKeyword::addField( StructDecl * decl ) {
486 ObjectDecl * field = new ObjectDecl(
487 field_name,
488 noStorageClasses,
489 LinkageSpec::Cforall,
490 nullptr,
491 new StructInstType(
492 noQualifiers,
493 type_decl
494 ),
495 nullptr
496 );
497
498 decl->get_members().push_back( field );
499
500 return field;
501 }
502
503 void ConcurrentSueKeyword::addRoutines( ObjectDecl * field, FunctionDecl * func ) {
504 CompoundStmt * statement = new CompoundStmt();
505 statement->push_back(
506 new ReturnStmt(
507 new AddressExpr(
508 new MemberExpr(
509 field,
510 new CastExpr(
511 new VariableExpr( func->get_functionType()->get_parameters().front() ),
512 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone()
513 )
514 )
515 )
516 )
517 );
518
519 FunctionDecl * get_decl = func->clone();
520
521 get_decl->set_statements( statement );
522
523 declsToAddAfter.push_back( get_decl );
524 }
525
526 //=============================================================================================
527 // Suspend keyword implementation
528 //=============================================================================================
529 DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) {
530 if(func->name != "main") return nullptr;
531 if(func->type->parameters.size() != 1) return nullptr;
532
533 auto param = func->type->parameters.front();
534
535 auto type = dynamic_cast<ReferenceType * >(param->get_type());
536 if(!type) return nullptr;
537
538 auto obj = dynamic_cast<StructInstType *>(type->base);
539 if(!obj) return nullptr;
540
541 if(!obj->baseStruct->is_generator()) return nullptr;
542
543 return param;
544 }
545
546 bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
547 if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
548 if(func->name != "__cfactx_suspend") return false; // the real suspend has a specific name
549 if(func->type->parameters.size() != 0) return false; // Too many parameters
550 if(func->type->returnVals.size() != 0) return false; // Too many return values
551
552 return true;
553 }
554
555 void SuspendKeyword::premutate( FunctionDecl * func ) {
556 GuardValue(in_generator);
557 in_generator = nullptr;
558
559 // Is this the real suspend?
560 if(is_real_suspend(func)) {
561 decl_suspend = decl_suspend ? decl_suspend : func;
562 return;
563 }
564
565 // Is this the main of a generator?
566 auto param = is_main( func );
567 if(!param) return;
568
569 if(func->type->returnVals.size() != 0) SemanticError(func->location, "Generator main must return void");
570
571 in_generator = param;
572 GuardValue(labels);
573 labels.clear();
574 }
575
576 DeclarationWithType * SuspendKeyword::postmutate( FunctionDecl * func ) {
577 if( !func->statements ) return func; // Not the actual definition, don't do anything
578 if( !in_generator ) return func; // Not in a generator, don't do anything
579 if( labels.empty() ) return func; // Generator has no states, nothing to do, could throw a warning
580
581 // This is a generator main, we need to add the following code to the top
582 // static void * __generator_labels[] = {&&s0, &&s1, ...};
583 // goto * __generator_labels[gen.__generator_state];
584 const auto & loc = func->location;
585
586 const auto first_label = gen.newLabel("generator");
587
588 // for each label add to declaration
589 std::list<Initializer*> inits = { new SingleInit( new LabelAddressExpr( first_label ) ) };
590 for(const auto & label : labels) {
591 inits.push_back(
592 new SingleInit(
593 new LabelAddressExpr( label )
594 )
595 );
596 }
597 auto init = new ListInit(std::move(inits), noDesignators, true);
598 labels.clear();
599
600 // create decl
601 auto decl = new ObjectDecl(
602 "__generator_labels",
603 Type::StorageClasses( Type::Static ),
604 LinkageSpec::AutoGen,
605 nullptr,
606 new ArrayType(
607 Type::Qualifiers(),
608 new PointerType(
609 Type::Qualifiers(),
610 new VoidType( Type::Qualifiers() )
611 ),
612 nullptr,
613 false, false
614 ),
615 init
616 );
617
618 // create the goto
619 assert(in_generator);
620
621 auto go_decl = new ObjectDecl(
622 "__generator_label",
623 noStorageClasses,
624 LinkageSpec::AutoGen,
625 nullptr,
626 new PointerType(
627 Type::Qualifiers(),
628 new VoidType( Type::Qualifiers() )
629 ),
630 new SingleInit(
631 new UntypedExpr(
632 new NameExpr("?[?]"),
633 {
634 new NameExpr("__generator_labels"),
635 new UntypedMemberExpr(
636 new NameExpr("__generator_state"),
637 new VariableExpr( in_generator )
638 )
639 }
640 )
641 )
642 );
643 go_decl->location = loc;
644
645 auto go = new BranchStmt(
646 new VariableExpr( go_decl ),
647 BranchStmt::Goto
648 );
649 go->location = loc;
650 go->computedTarget->location = loc;
651
652 auto noop = new NullStmt({ first_label });
653 noop->location = loc;
654
655 // wrap everything in a nice compound
656 auto body = new CompoundStmt({
657 new DeclStmt( decl ),
658 new DeclStmt( go_decl ),
659 go,
660 noop,
661 func->statements
662 });
663 body->location = loc;
664 func->statements = body;
665
666 return func;
667 }
668
669 Statement * SuspendKeyword::postmutate( SuspendStmt * stmt ) {
670 SuspendStmt::Type type = stmt->type;
671 if(type == SuspendStmt::None) {
672 // This suspend has a implicit target, find it
673 type = in_generator ? SuspendStmt::Generator : SuspendStmt::Coroutine;
674 }
675
676 // Check that the target makes sense
677 if(!in_generator && type == SuspendStmt::Generator) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type.");
678
679 // Act appropriately
680 switch(type) {
681 case SuspendStmt::Generator: return make_generator_suspend(stmt);
682 case SuspendStmt::Coroutine: return make_coroutine_suspend(stmt);
683 default: abort();
684 }
685 }
686
687 Statement * SuspendKeyword::make_generator_suspend( SuspendStmt * stmt ) {
688 assert(in_generator);
689 // Target code is :
690 // gen.__generator_state = X;
691 // { THEN }
692 // return;
693 // __gen_X:;
694
695 // Save the location and delete the old statement, we only need the location from this point on
696 auto loc = stmt->location;
697
698 // Build the label and get its index
699 auto label = make_label();
700
701 // Create the context saving statement
702 auto save = new ExprStmt( new UntypedExpr(
703 new NameExpr( "?=?" ),
704 {
705 new UntypedMemberExpr(
706 new NameExpr("__generator_state"),
707 new VariableExpr( in_generator )
708 ),
709 new ConstantExpr(
710 Constant::from_int( label.idx )
711 )
712 }
713 ));
714 assert(save->expr);
715 save->location = loc;
716 stmtsToAddBefore.push_back( save );
717
718 // if we have a then add it here
719 auto then = stmt->then;
720 stmt->then = nullptr;
721 delete stmt;
722 if(then) stmtsToAddBefore.push_back( then );
723
724 // Create the return statement
725 auto ret = new ReturnStmt( nullptr );
726 ret->location = loc;
727 stmtsToAddBefore.push_back( ret );
728
729 // Create the null statement with the created label
730 auto noop = new NullStmt({ label.obj });
731 noop->location = loc;
732
733 // Return the null statement to take the place of the previous statement
734 return noop;
735 }
736
737 Statement * SuspendKeyword::make_coroutine_suspend( SuspendStmt * stmt ) {
738 if(stmt->then) SemanticError( stmt->location, "Compound statement following coroutines is not implemented.");
739
740 // Save the location and delete the old statement, we only need the location from this point on
741 auto loc = stmt->location;
742 delete stmt;
743
744 // Create the call expression
745 if(!decl_suspend) SemanticError( loc, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n");
746 auto expr = new UntypedExpr( VariableExpr::functionPointer( decl_suspend ) );
747 expr->location = loc;
748
749 // Change this statement into a regular expr
750 assert(expr);
751 auto nstmt = new ExprStmt( expr );
752 nstmt->location = loc;
753 return nstmt;
754 }
755
756
757 //=============================================================================================
758 // Mutex keyword implementation
759 //=============================================================================================
760
761 void MutexKeyword::postvisit(FunctionDecl* decl) {
762
763 bool first = false;
764 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
765 bool isDtor = CodeGen::isDestructor( decl->name );
766
767 // Is this function relevant to monitors
768 if( mutexArgs.empty() ) {
769 // If this is the destructor for a monitor it must be mutex
770 if(isDtor) {
771 Type* ty = decl->get_functionType()->get_parameters().front()->get_type();
772
773 // If it's a copy, it's not a mutex
774 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
775 if( ! rty ) return;
776
777 // If we are not pointing directly to a type, it's not a mutex
778 Type* base = rty->get_base();
779 if( dynamic_cast< ReferenceType * >( base ) ) return;
780 if( dynamic_cast< PointerType * >( base ) ) return;
781
782 // Check if its a struct
783 StructInstType * baseStruct = dynamic_cast< StructInstType * >( base );
784 if( !baseStruct ) return;
785
786 // Check if its a monitor
787 if(baseStruct->baseStruct->is_monitor() || baseStruct->baseStruct->is_thread())
788 SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
789 }
790 return;
791 }
792
793 // Monitors can't be constructed with mutual exclusion
794 if( CodeGen::isConstructor(decl->name) && !first ) SemanticError( decl, "constructors cannot have mutex parameters" );
795
796 // It makes no sense to have multiple mutex parameters for the destructor
797 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" );
798
799 // Make sure all the mutex arguments are monitors
800 for(auto arg : mutexArgs) {
801 validate( arg );
802 }
803
804 // Check if we need to instrument the body
805 CompoundStmt* body = decl->get_statements();
806 if( ! body ) return;
807
808 // Do we have the required headers
809 if( !monitor_decl || !guard_decl || !dtor_guard_decl )
810 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
811
812 // Instrument the body
813 if( isDtor ) {
814 addDtorStatments( decl, body, mutexArgs );
815 }
816 else {
817 addStatments( decl, body, mutexArgs );
818 }
819 }
820
821 void MutexKeyword::postvisit(StructDecl* decl) {
822
823 if( decl->name == "$monitor" && decl->body ) {
824 assert( !monitor_decl );
825 monitor_decl = decl;
826 }
827 else if( decl->name == "monitor_guard_t" && decl->body ) {
828 assert( !guard_decl );
829 guard_decl = decl;
830 }
831 else if( decl->name == "monitor_dtor_guard_t" && decl->body ) {
832 assert( !dtor_guard_decl );
833 dtor_guard_decl = decl;
834 }
835 }
836
837 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl, bool & first ) {
838 std::list<DeclarationWithType*> mutexArgs;
839
840 bool once = true;
841 for( auto arg : decl->get_functionType()->get_parameters()) {
842 //Find mutex arguments
843 Type* ty = arg->get_type();
844 if( ! ty->get_mutex() ) continue;
845
846 if(once) {first = true;}
847 once = false;
848
849 //Append it to the list
850 mutexArgs.push_back( arg );
851 }
852
853 return mutexArgs;
854 }
855
856 void MutexKeyword::validate( DeclarationWithType * arg ) {
857 Type* ty = arg->get_type();
858
859 //Makes sure it's not a copy
860 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
861 if( ! rty ) SemanticError( arg, "Mutex argument must be of reference type " );
862
863 //Make sure the we are pointing directly to a type
864 Type* base = rty->get_base();
865 if( dynamic_cast< ReferenceType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
866 if( dynamic_cast< PointerType * >( base ) ) SemanticError( arg, "Mutex argument have exactly one level of indirection " );
867
868 //Make sure that typed isn't mutex
869 if( base->get_mutex() ) SemanticError( arg, "mutex keyword may only appear once per argument " );
870 }
871
872 void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
873 Type * arg_type = args.front()->get_type()->clone();
874 arg_type->set_mutex( false );
875
876 ObjectDecl * monitors = new ObjectDecl(
877 "__monitor",
878 noStorageClasses,
879 LinkageSpec::Cforall,
880 nullptr,
881 new PointerType(
882 noQualifiers,
883 new StructInstType(
884 noQualifiers,
885 monitor_decl
886 )
887 ),
888 new SingleInit( new UntypedExpr(
889 new NameExpr( "get_monitor" ),
890 { new CastExpr( new VariableExpr( args.front() ), arg_type ) }
891 ))
892 );
893
894 assert(generic_func);
895
896 //in reverse order :
897 // monitor_dtor_guard_t __guard = { __monitors, func };
898 body->push_front(
899 new DeclStmt( new ObjectDecl(
900 "__guard",
901 noStorageClasses,
902 LinkageSpec::Cforall,
903 nullptr,
904 new StructInstType(
905 noQualifiers,
906 dtor_guard_decl
907 ),
908 new ListInit(
909 {
910 new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
911 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
912 },
913 noDesignators,
914 true
915 )
916 ))
917 );
918
919 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
920 body->push_front( new DeclStmt( monitors) );
921 }
922
923 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
924 ObjectDecl * monitors = new ObjectDecl(
925 "__monitors",
926 noStorageClasses,
927 LinkageSpec::Cforall,
928 nullptr,
929 new ArrayType(
930 noQualifiers,
931 new PointerType(
932 noQualifiers,
933 new StructInstType(
934 noQualifiers,
935 monitor_decl
936 )
937 ),
938 new ConstantExpr( Constant::from_ulong( args.size() ) ),
939 false,
940 false
941 ),
942 new ListInit(
943 map_range < std::list<Initializer*> > ( args, [](DeclarationWithType * var ){
944 Type * type = var->get_type()->clone();
945 type->set_mutex( false );
946 return new SingleInit( new UntypedExpr(
947 new NameExpr( "get_monitor" ),
948 { new CastExpr( new VariableExpr( var ), type ) }
949 ) );
950 })
951 )
952 );
953
954 assert(generic_func);
955
956 // in reverse order :
957 // monitor_guard_t __guard = { __monitors, #, func };
958 body->push_front(
959 new DeclStmt( new ObjectDecl(
960 "__guard",
961 noStorageClasses,
962 LinkageSpec::Cforall,
963 nullptr,
964 new StructInstType(
965 noQualifiers,
966 guard_decl
967 ),
968 new ListInit(
969 {
970 new SingleInit( new VariableExpr( monitors ) ),
971 new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
972 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
973 },
974 noDesignators,
975 true
976 )
977 ))
978 );
979
980 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
981 body->push_front( new DeclStmt( monitors) );
982 }
983
984 //=============================================================================================
985 // General entry routine
986 //=============================================================================================
987 void ThreadStarter::previsit( StructDecl * decl ) {
988 if( decl->name == "$thread" && decl->body ) {
989 assert( !thread_decl );
990 thread_decl = decl;
991 }
992 }
993
994 void ThreadStarter::postvisit(FunctionDecl * decl) {
995 if( ! CodeGen::isConstructor(decl->name) ) return;
996
997 Type * typeof_this = InitTweak::getTypeofThis(decl->type);
998 StructInstType * ctored_type = dynamic_cast< StructInstType * >( typeof_this );
999 if( ctored_type && ctored_type->baseStruct == thread_decl ) {
1000 thread_ctor_seen = true;
1001 }
1002
1003 DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
1004 auto type = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
1005 if( type && type->get_baseStruct()->is_thread() ) {
1006 if( !thread_decl || !thread_ctor_seen ) {
1007 SemanticError( type->get_baseStruct()->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>");
1008 }
1009
1010 addStartStatement( decl, param );
1011 }
1012 }
1013
1014 void ThreadStarter::addStartStatement( FunctionDecl * decl, DeclarationWithType * param ) {
1015 CompoundStmt * stmt = decl->get_statements();
1016
1017 if( ! stmt ) return;
1018
1019 stmt->push_back(
1020 new ExprStmt(
1021 new UntypedExpr(
1022 new NameExpr( "__thrd_start" ),
1023 { new VariableExpr( param ), new NameExpr("main") }
1024 )
1025 )
1026 );
1027 }
1028};
1029
1030// Local Variables: //
1031// mode: c //
1032// tab-width: 4 //
1033// End: //
Note: See TracBrowser for help on using the repository browser.