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
RevLine 
[64adb03]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 :
[07de76b]13// Update Count : 10
[64adb03]14//
15
16#include "Concurrency/Keywords.h"
17
[427854b]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
[bf2438c]36
37class Attribute;
[64adb03]38
39namespace Concurrency {
40 //=============================================================================================
[2065609]41 // Pass declarations
[64adb03]42 //=============================================================================================
43
[bcda04c]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 //
[2065609]53 class ConcurrentSueKeyword : public WithDeclsToAdd {
[bcda04c]54 public:
55
[312029a]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 ) :
[9a705dc8]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 ) {}
[bcda04c]58
59 virtual ~ConcurrentSueKeyword() {}
60
[9a705dc8]61 Declaration * postmutate( StructDecl * decl );
[6c3a5ac1]62 DeclarationWithType * postmutate( FunctionDecl * decl );
[bcda04c]63
64 void handle( StructDecl * );
65 FunctionDecl * forwardDeclare( StructDecl * );
66 ObjectDecl * addField( StructDecl * );
[2f9a722]67 void addRoutines( ObjectDecl *, FunctionDecl * );
[bcda04c]68
69 virtual bool is_target( StructDecl * decl ) = 0;
70
[9a705dc8]71 Expression * postmutate( KeywordCastExpr * cast );
72
[bcda04c]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;
[bd4d011]78 bool needs_main;
[312029a]79 AggregateDecl::Aggregate cast_target;
[bcda04c]80
[6c3a5ac1]81 StructDecl * type_decl = nullptr;
82 FunctionDecl * dtor_decl = nullptr;
[bcda04c]83 };
84
85
[64adb03]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;
[ac2b598]91 // => $thread __thrd_d;
[64adb03]92 // }; };
[ac2b598]93 // static inline $thread * get_thread( MyThread * this ) { return &this->__thrd_d; }
[64adb03]94 //
[bcda04c]95 class ThreadKeyword final : public ConcurrentSueKeyword {
[64adb03]96 public:
97
[bcda04c]98 ThreadKeyword() : ConcurrentSueKeyword(
[ac2b598]99 "$thread",
[bcda04c]100 "__thrd",
101 "get_thread",
[6c3a5ac1]102 "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
[9a705dc8]103 true,
[312029a]104 AggregateDecl::Thread
[bcda04c]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 ) {
[2065609]113 PassVisitor< ThreadKeyword > impl;
[9a705dc8]114 mutateAll( translationUnit, impl );
[bcda04c]115 }
[64adb03]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;
[ac2b598]123 // => $coroutine __cor_d;
[64adb03]124 // }; };
[ac2b598]125 // static inline $coroutine * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
[64adb03]126 //
[bcda04c]127 class CoroutineKeyword final : public ConcurrentSueKeyword {
[64adb03]128 public:
129
[bcda04c]130 CoroutineKeyword() : ConcurrentSueKeyword(
[ac2b598]131 "$coroutine",
[bcda04c]132 "__cor",
133 "get_coroutine",
[6c3a5ac1]134 "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
[9a705dc8]135 true,
[312029a]136 AggregateDecl::Coroutine
[bcda04c]137 )
138 {}
[b32ada31]139
[bcda04c]140 virtual ~CoroutineKeyword() {}
141
142 virtual bool is_target( StructDecl * decl ) override final { return decl->is_coroutine(); }
[b32ada31]143
144 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]145 PassVisitor< CoroutineKeyword > impl;
[9a705dc8]146 mutateAll( translationUnit, impl );
[b32ada31]147 }
[64adb03]148 };
149
[427854b]150
151
[64adb03]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;
[ac2b598]157 // => $monitor __mon_d;
[64adb03]158 // }; };
[ac2b598]159 // static inline $monitor * get_coroutine( MyMonitor * this ) { return &this->__cor_d; }
[64adb03]160 //
[bcda04c]161 class MonitorKeyword final : public ConcurrentSueKeyword {
[64adb03]162 public:
163
[bcda04c]164 MonitorKeyword() : ConcurrentSueKeyword(
[ac2b598]165 "$monitor",
[bcda04c]166 "__mon",
167 "get_monitor",
[6c3a5ac1]168 "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
[9a705dc8]169 false,
[312029a]170 AggregateDecl::Monitor
[bcda04c]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 ) {
[2065609]179 PassVisitor< MonitorKeyword > impl;
[9a705dc8]180 mutateAll( translationUnit, impl );
[bcda04c]181 }
[64adb03]182 };
183
[427854b]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
[64adb03]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 ) {
[ac2b598]258 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[64adb03]259 // monitor_guard_t __guard = { __monitors, 2 };
260 // /*Some code*/ => /*Some code*/
261 // } }
262 //
[2065609]263 class MutexKeyword final {
[64adb03]264 public:
265
[2065609]266 void postvisit( FunctionDecl * decl );
267 void postvisit( StructDecl * decl );
[64adb03]268
[db4d8e3]269 std::list<DeclarationWithType*> findMutexArgs( FunctionDecl*, bool & first );
[64adb03]270 void validate( DeclarationWithType * );
[549c006]271 void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
[97e3296]272 void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
[64adb03]273
274 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]275 PassVisitor< MutexKeyword > impl;
[64adb03]276 acceptAll( translationUnit, impl );
277 }
[9243cc91]278
279 private:
280 StructDecl* monitor_decl = nullptr;
[ef42b143]281 StructDecl* guard_decl = nullptr;
[549c006]282 StructDecl* dtor_guard_decl = nullptr;
[97e3296]283
284 static std::unique_ptr< Type > generic_func;
[64adb03]285 };
286
[97e3296]287 std::unique_ptr< Type > MutexKeyword::generic_func = std::unique_ptr< Type >(
288 new FunctionType(
289 noQualifiers,
290 true
291 )
292 );
293
[bd4d011]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 ) {
[ac2b598]297 // $monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[bd4d011]298 // monitor_guard_t __guard = { __monitors, 2 };
299 // /*Some code*/ => /*Some code*/
300 // } }
301 //
[2065609]302 class ThreadStarter final {
[bd4d011]303 public:
304
[2065609]305 void postvisit( FunctionDecl * decl );
[549c006]306 void previsit ( StructDecl * decl );
[bd4d011]307
308 void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
309
310 static void implement( std::list< Declaration * > & translationUnit ) {
[2065609]311 PassVisitor< ThreadStarter > impl;
[bd4d011]312 acceptAll( translationUnit, impl );
313 }
[549c006]314
315 private :
316 bool thread_ctor_seen = false;
317 StructDecl * thread_decl = nullptr;
[bd4d011]318 };
319
[64adb03]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 );
[427854b]327 GeneratorKeyword ::implement( translationUnit );
328 SuspendKeyword ::implement( translationUnit );
[bcda04c]329 }
330
331 void implementMutexFuncs( std::list< Declaration * > & translationUnit ) {
[64adb03]332 MutexKeyword ::implement( translationUnit );
333 }
334
[bcda04c]335 void implementThreadStarter( std::list< Declaration * > & translationUnit ) {
[bd4d011]336 ThreadStarter ::implement( translationUnit );
[bcda04c]337 }
338
[b32ada31]339 //=============================================================================================
[bcda04c]340 // Generic keyword implementation
[b32ada31]341 //=============================================================================================
[2db79e5]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
[9a705dc8]353 Declaration * ConcurrentSueKeyword::postmutate(StructDecl * decl) {
[9f5ecf5]354 if( decl->name == type_name && decl->body ) {
[bcda04c]355 assert( !type_decl );
356 type_decl = decl;
[b32ada31]357 }
[bcda04c]358 else if ( is_target(decl) ) {
[b32ada31]359 handle( decl );
360 }
[9a705dc8]361 return decl;
[b32ada31]362 }
363
[6c3a5ac1]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
[9a705dc8]382 Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
383 if ( cast_target == cast->target ) {
[ac2b598]384 // convert (thread &)t to ($thread &)*get_thread(t), etc.
[9a705dc8]385 if( !type_decl ) SemanticError( cast, context_error );
[6c3a5ac1]386 if( !dtor_decl ) SemanticError( cast, context_error );
[3b0c8cb]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;
[9a705dc8]391 }
392 return cast;
393 }
394
395
[bcda04c]396 void ConcurrentSueKeyword::handle( StructDecl * decl ) {
[9f5ecf5]397 if( ! decl->body ) return;
[b32ada31]398
[a16764a6]399 if( !type_decl ) SemanticError( decl, context_error );
[6c3a5ac1]400 if( !dtor_decl ) SemanticError( decl, context_error );
[b32ada31]401
[bcda04c]402 FunctionDecl * func = forwardDeclare( decl );
403 ObjectDecl * field = addField( decl );
[2f9a722]404 addRoutines( field, func );
[b32ada31]405 }
406
[bcda04c]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
[bd4d011]414 FunctionType * get_type = new FunctionType( noQualifiers, false );
[bcda04c]415 ObjectDecl * this_decl = new ObjectDecl(
416 "this",
[ba3706f]417 noStorageClasses,
[b32ada31]418 LinkageSpec::Cforall,
419 nullptr,
[83a071f9]420 new ReferenceType(
[b32ada31]421 noQualifiers,
[bcda04c]422 new StructInstType(
423 noQualifiers,
424 decl
425 )
[b32ada31]426 ),
427 nullptr
428 );
429
[2db79e5]430 get_type->get_parameters().push_back( this_decl->clone() );
[bd4d011]431 get_type->get_returnVals().push_back(
[e04b636]432 new ObjectDecl(
433 "ret",
[ba3706f]434 noStorageClasses,
[e04b636]435 LinkageSpec::Cforall,
436 nullptr,
437 new PointerType(
438 noQualifiers,
439 new StructInstType(
440 noQualifiers,
[bcda04c]441 type_decl
[e04b636]442 )
443 ),
444 nullptr
445 )
446 );
[2db79e5]447 fixupGenerics(get_type, decl);
[b32ada31]448
[bcda04c]449 FunctionDecl * get_decl = new FunctionDecl(
450 getter_name,
451 Type::Static,
452 LinkageSpec::Cforall,
[bd4d011]453 get_type,
[bcda04c]454 nullptr,
[a8078ee]455 { new Attribute("const") },
[bcda04c]456 Type::Inline
457 );
458
[bd4d011]459 FunctionDecl * main_decl = nullptr;
460
461 if( needs_main ) {
462 FunctionType * main_type = new FunctionType( noQualifiers, false );
[bf2438c]463
[bd4d011]464 main_type->get_parameters().push_back( this_decl->clone() );
465
466 main_decl = new FunctionDecl(
467 "main",
[ba3706f]468 noStorageClasses,
[bd4d011]469 LinkageSpec::Cforall,
470 main_type,
471 nullptr
472 );
[2db79e5]473 fixupGenerics(main_type, decl);
[bd4d011]474 }
475
[2db79e5]476 delete this_decl;
477
[2065609]478 declsToAddBefore.push_back( forward );
479 if( needs_main ) declsToAddBefore.push_back( main_decl );
480 declsToAddBefore.push_back( get_decl );
[bcda04c]481
482 return get_decl;
483 }
484
485 ObjectDecl * ConcurrentSueKeyword::addField( StructDecl * decl ) {
486 ObjectDecl * field = new ObjectDecl(
487 field_name,
[ba3706f]488 noStorageClasses,
[bcda04c]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
[2f9a722]503 void ConcurrentSueKeyword::addRoutines( ObjectDecl * field, FunctionDecl * func ) {
[ba3706f]504 CompoundStmt * statement = new CompoundStmt();
[bf2438c]505 statement->push_back(
[b32ada31]506 new ReturnStmt(
[e04b636]507 new AddressExpr(
[bcda04c]508 new MemberExpr(
509 field,
[2db79e5]510 new CastExpr(
511 new VariableExpr( func->get_functionType()->get_parameters().front() ),
512 func->get_functionType()->get_parameters().front()->get_type()->stripReferences()->clone()
513 )
[e04b636]514 )
[b32ada31]515 )
516 )
517 );
518
[bcda04c]519 FunctionDecl * get_decl = func->clone();
520
521 get_decl->set_statements( statement );
[e04b636]522
523 declsToAddAfter.push_back( get_decl );
[427854b]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;
[e04b636]537
[427854b]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;
[b32ada31]553 }
554
[427854b]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 ) );
[e6cfa8ff]747 expr->location = loc;
[427854b]748
749 // Change this statement into a regular expr
750 assert(expr);
751 auto nstmt = new ExprStmt( expr );
[e6cfa8ff]752 nstmt->location = loc;
[427854b]753 return nstmt;
754 }
755
756
[64adb03]757 //=============================================================================================
758 // Mutex keyword implementation
759 //=============================================================================================
[97e3296]760
[2065609]761 void MutexKeyword::postvisit(FunctionDecl* decl) {
[102a58b]762
[db4d8e3]763 bool first = false;
764 std::list<DeclarationWithType*> mutexArgs = findMutexArgs( decl, first );
[ceedde6]765 bool isDtor = CodeGen::isDestructor( decl->name );
[64adb03]766
[ceedde6]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 }
[549c006]792
[ceedde6]793 // Monitors can't be constructed with mutual exclusion
794 if( CodeGen::isConstructor(decl->name) && !first ) SemanticError( decl, "constructors cannot have mutex parameters" );
[549c006]795
[ceedde6]796 // It makes no sense to have multiple mutex parameters for the destructor
[a16764a6]797 if( isDtor && mutexArgs.size() != 1 ) SemanticError( decl, "destructors can only have 1 mutex argument" );
[549c006]798
[ceedde6]799 // Make sure all the mutex arguments are monitors
[64adb03]800 for(auto arg : mutexArgs) {
801 validate( arg );
802 }
803
[ceedde6]804 // Check if we need to instrument the body
[64adb03]805 CompoundStmt* body = decl->get_statements();
806 if( ! body ) return;
807
[ceedde6]808 // Do we have the required headers
[a16764a6]809 if( !monitor_decl || !guard_decl || !dtor_guard_decl )
[73abe95]810 SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
[b32ada31]811
[ceedde6]812 // Instrument the body
[549c006]813 if( isDtor ) {
814 addDtorStatments( decl, body, mutexArgs );
815 }
816 else {
817 addStatments( decl, body, mutexArgs );
818 }
[64adb03]819 }
820
[2065609]821 void MutexKeyword::postvisit(StructDecl* decl) {
[102a58b]822
[ac2b598]823 if( decl->name == "$monitor" && decl->body ) {
[9243cc91]824 assert( !monitor_decl );
825 monitor_decl = decl;
826 }
[88d955f]827 else if( decl->name == "monitor_guard_t" && decl->body ) {
[ef42b143]828 assert( !guard_decl );
829 guard_decl = decl;
830 }
[88d955f]831 else if( decl->name == "monitor_dtor_guard_t" && decl->body ) {
[549c006]832 assert( !dtor_guard_decl );
833 dtor_guard_decl = decl;
834 }
[9243cc91]835 }
836
[db4d8e3]837 std::list<DeclarationWithType*> MutexKeyword::findMutexArgs( FunctionDecl* decl, bool & first ) {
[64adb03]838 std::list<DeclarationWithType*> mutexArgs;
839
[db4d8e3]840 bool once = true;
[64adb03]841 for( auto arg : decl->get_functionType()->get_parameters()) {
842 //Find mutex arguments
843 Type* ty = arg->get_type();
[615a096]844 if( ! ty->get_mutex() ) continue;
[64adb03]845
[db4d8e3]846 if(once) {first = true;}
847 once = false;
848
[64adb03]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
[870d1f0]860 ReferenceType* rty = dynamic_cast< ReferenceType * >( ty );
[a16764a6]861 if( ! rty ) SemanticError( arg, "Mutex argument must be of reference type " );
[64adb03]862
863 //Make sure the we are pointing directly to a type
[83a071f9]864 Type* base = rty->get_base();
[a16764a6]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 " );
[64adb03]867
868 //Make sure that typed isn't mutex
[a16764a6]869 if( base->get_mutex() ) SemanticError( arg, "mutex keyword may only appear once per argument " );
[64adb03]870 }
871
[549c006]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",
[ba3706f]878 noStorageClasses,
[549c006]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 :
[2bf7ef6]897 // monitor_dtor_guard_t __guard = { __monitors, func };
[549c006]898 body->push_front(
[ba3706f]899 new DeclStmt( new ObjectDecl(
[549c006]900 "__guard",
[ba3706f]901 noStorageClasses,
[549c006]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
[ac2b598]919 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[ba3706f]920 body->push_front( new DeclStmt( monitors) );
[549c006]921 }
922
[97e3296]923 void MutexKeyword::addStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
[9243cc91]924 ObjectDecl * monitors = new ObjectDecl(
925 "__monitors",
[ba3706f]926 noStorageClasses,
[9243cc91]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(
[bd41764]943 map_range < std::list<Initializer*> > ( args, [](DeclarationWithType * var ){
[cb0e6de]944 Type * type = var->get_type()->clone();
945 type->set_mutex( false );
[9243cc91]946 return new SingleInit( new UntypedExpr(
947 new NameExpr( "get_monitor" ),
[cb0e6de]948 { new CastExpr( new VariableExpr( var ), type ) }
[9243cc91]949 ) );
950 })
951 )
952 );
953
[97e3296]954 assert(generic_func);
955
[2bf7ef6]956 // in reverse order :
[97e3296]957 // monitor_guard_t __guard = { __monitors, #, func };
[64adb03]958 body->push_front(
[ba3706f]959 new DeclStmt( new ObjectDecl(
[64adb03]960 "__guard",
[ba3706f]961 noStorageClasses,
[64adb03]962 LinkageSpec::Cforall,
963 nullptr,
964 new StructInstType(
965 noQualifiers,
[ef42b143]966 guard_decl
[64adb03]967 ),
968 new ListInit(
969 {
[9243cc91]970 new SingleInit( new VariableExpr( monitors ) ),
[97e3296]971 new SingleInit( new ConstantExpr( Constant::from_ulong( args.size() ) ) ),
972 new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
[ef42b143]973 },
974 noDesignators,
975 true
[64adb03]976 )
977 ))
978 );
979
[ac2b598]980 //$monitor * __monitors[] = { get_monitor(a), get_monitor(b) };
[ba3706f]981 body->push_front( new DeclStmt( monitors) );
[64adb03]982 }
[bd4d011]983
984 //=============================================================================================
985 // General entry routine
986 //=============================================================================================
[549c006]987 void ThreadStarter::previsit( StructDecl * decl ) {
[ac2b598]988 if( decl->name == "$thread" && decl->body ) {
[549c006]989 assert( !thread_decl );
990 thread_decl = decl;
991 }
992 }
993
[2065609]994 void ThreadStarter::postvisit(FunctionDecl * decl) {
[9f5ecf5]995 if( ! CodeGen::isConstructor(decl->name) ) return;
[bd4d011]996
[549c006]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
[bd4d011]1003 DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
[ce8c12f]1004 auto type = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
[bd4d011]1005 if( type && type->get_baseStruct()->is_thread() ) {
[549c006]1006 if( !thread_decl || !thread_ctor_seen ) {
[73abe95]1007 SemanticError( type->get_baseStruct()->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>");
[549c006]1008 }
1009
[bd4d011]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
[bf2438c]1019 stmt->push_back(
[bd4d011]1020 new ExprStmt(
1021 new UntypedExpr(
1022 new NameExpr( "__thrd_start" ),
[09f357ec]1023 { new VariableExpr( param ), new NameExpr("main") }
[bd4d011]1024 )
1025 )
1026 );
1027 }
[68fe077a]1028};
[6b0b624]1029
1030// Local Variables: //
1031// mode: c //
1032// tab-width: 4 //
1033// End: //
Note: See TracBrowser for help on using the repository browser.