source: src/Concurrency/Keywords.cc@ 40a1392

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since 40a1392 was 69c5c00, checked in by Andrew Beach <ajbeach@…>, 5 years ago

Rework exceptions mark_exception -> get_exception_vtable and the needed follow up.

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