source: src/Concurrency/Keywords.cc@ 9f5a19fa

ADT ast-experimental enum forall-pointer-decay jacob/cs343-translation pthread-emulation qualifiedEnum
Last change on this file since 9f5a19fa was 6cebfef, checked in by caparsons <caparson@…>, 4 years ago

added mutex stmt monitor

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