source: src/Concurrency/Waitfor.cc @ 0895cba

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 0895cba was b18830e, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

Refactoring monitor code in prevision for proper waitfor support

  • added monitor group struct
  • else and timeout now return negative results
  • Property mode set to 100644
File size: 13.3 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// Waitfor.cc --
8//
9// Author           : Thierry Delisle
10// Created On       : Mon Aug 28 11:06:52 2017
11// Last Modified By :
12// Last Modified On :
13// Update Count     : 5
14//
15
16#include "Concurrency/Keywords.h"
17
18#include <cassert>                 // for assert
19#include <string>                  // for string, operator==
20
21using namespace std::string_literals;
22
23#include "Common/PassVisitor.h"    // for PassVisitor
24#include "Common/SemanticError.h"  // for SemanticError
25#include "Common/utility.h"        // for deleteAll, map_range
26#include "CodeGen/OperatorTable.h" // for isConstructor
27#include "InitTweak/InitTweak.h"   // for getPointerBase
28#include "Parser/LinkageSpec.h"    // for Cforall
29#include "ResolvExpr/Resolver.h"   // for findVoidExpression
30#include "SynTree/Constant.h"      // for Constant
31#include "SynTree/Declaration.h"   // for StructDecl, FunctionDecl, ObjectDecl
32#include "SynTree/Expression.h"    // for VariableExpr, ConstantExpr, Untype...
33#include "SynTree/Initializer.h"   // for SingleInit, ListInit, Initializer ...
34#include "SynTree/Label.h"         // for Label
35#include "SynTree/Statement.h"     // for CompoundStmt, DeclStmt, ExprStmt
36#include "SynTree/Type.h"          // for StructInstType, Type, PointerType
37#include "SynTree/Visitor.h"       // for Visitor, acceptAll
38
39class Attribute;
40/*
41void foo() {
42        while( true ) {
43                when( a < 1 ) waitfor( f, a ) { bar(); }
44                or timeout( swagl() );
45                or waitfor( g, a ) { baz(); }
46                or waitfor( ^?{}, a ) { break; }
47                or waitfor( ^?{} ) { break; }
48        }
49}
50
51void f(int i, float f, A & mutex b, struct foo *  );
52void f(int );
53
54
55                      |  |
56                      |  |
57                            |  |
58                      |  |
59                      |  |
60                    \ |  | /
61                     \    /
62                      \  /
63                       \/
64
65
66void foo() {
67        while( true ) {
68
69                acceptable_t acceptables[3];
70                if( a < 1 ) {
71                        acceptables[0].func = f;
72                        acceptables[0].mon = a;
73                }
74                acceptables[1].func = g;
75                acceptables[1].mon = a;
76
77                acceptables[2].func = f;
78                acceptables[2].mon = a;
79                acceptables[2].is_dtor = true;
80
81                int ret = waitfor_internal( acceptables, swagl() );
82
83                switch( ret ) {
84                        case 0:
85                        {
86                                bar();
87                        }
88                        case 1:
89                        {
90                                baz();
91                        }
92                        case 2:
93                                signal(a);
94                                {
95                                        break;
96                                }
97                }
98        }
99}*/
100
101namespace Concurrency {
102
103        namespace {
104                const std::list<Label> noLabels;
105                const std::list< Attribute * > noAttributes;
106                Type::StorageClasses noStorage;
107                Type::Qualifiers noQualifiers;
108        }
109
110        //=============================================================================================
111        // Pass declarations
112        //=============================================================================================
113
114        class GenerateWaitForPass final : public WithIndexer {
115          public:
116
117                void premutate( FunctionDecl * decl );
118                void premutate( StructDecl   * decl );
119
120                Statement * postmutate( WaitForStmt * stmt );
121
122                static void generate( std::list< Declaration * > & translationUnit ) {
123                        PassVisitor< GenerateWaitForPass > impl;
124                        acceptAll( translationUnit, impl );
125                }
126
127                ObjectDecl * declare( unsigned long count, CompoundStmt * stmt );
128                ObjectDecl * declMon( WaitForStmt::Clause & clause, CompoundStmt * stmt );
129                void         init( ObjectDecl * acceptables, int index, WaitForStmt::Clause & clause, CompoundStmt * stmt );
130                Expression * init_timeout( Expression *& time, Expression *& time_cond, bool has_else, Expression *& else_cond, CompoundStmt * stmt );
131                Expression * call(size_t count, ObjectDecl * acceptables, Expression * timeout, CompoundStmt * stmt);
132                void         choose( WaitForStmt * waitfor, Expression  * result, CompoundStmt * stmt );
133
134                static void implement( std::list< Declaration * > & translationUnit ) {
135                        PassVisitor< GenerateWaitForPass > impl;
136                        mutateAll( translationUnit, impl );
137                }
138
139
140          private:
141                FunctionDecl        * decl_waitfor    = nullptr;
142                StructDecl          * decl_acceptable = nullptr;
143                StructDecl          * decl_monitor    = nullptr;
144
145                static std::unique_ptr< Type > generic_func;
146
147                UniqueName namer_mon = "__monitors_"s;
148                UniqueName namer_acc = "__acceptables_"s;
149                UniqueName namer_tim = "__timeout_"s;
150                UniqueName namer_ret = "__return_"s;
151        };
152
153        //=============================================================================================
154        // General entry routine
155        //=============================================================================================
156        void generateWaitFor( std::list< Declaration * > & translationUnit ) {
157                GenerateWaitForPass     ::implement( translationUnit );
158        }
159
160        //=============================================================================================
161        // Generic helper routine
162        //=============================================================================================
163
164        namespace {
165                Expression * makeOpIndex( DeclarationWithType * array, unsigned long index ) {
166                        return new UntypedExpr(
167                                new NameExpr( "?[?]" ),
168                                {
169                                        new VariableExpr( array ),
170                                        new ConstantExpr( Constant::from_ulong( index ) )
171                                }
172                        );
173                }
174
175                Expression * makeOpAssign( Expression * lhs, Expression * rhs ) {
176                        return new UntypedExpr(
177                                        new NameExpr( "?=?" ),
178                                        { lhs, rhs }
179                        );
180                }
181
182                Expression * makeOpMember( Expression * sue, const std::string & mem ) {
183                        return new UntypedMemberExpr( new NameExpr( mem ), sue );
184                }
185
186                Statement * makeAccStatement( DeclarationWithType * object, unsigned long index, const std::string & member, Expression * value, const SymTab::Indexer & indexer ) {
187                        std::unique_ptr< Expression > expr( makeOpAssign(
188                                makeOpMember(
189                                        makeOpIndex(
190                                                object,
191                                                index
192                                        ),
193                                        member
194                                ),
195                                value
196                        ) );
197
198                        return new ExprStmt( noLabels, ResolvExpr::findVoidExpression( expr.get(), indexer ) );
199                }
200
201                Expression * safeCond( Expression * expr, bool ifnull = true ) {
202                        if( expr ) return expr;
203
204                        return new ConstantExpr( Constant::from_bool( ifnull ) );
205                }
206
207                VariableExpr * extractVariable( Expression * func ) {
208                        if( VariableExpr * var = dynamic_cast< VariableExpr * >( func ) ) {
209                                return var;
210                        }
211
212                        CastExpr * cast = strict_dynamic_cast< CastExpr * >( func );
213                        return strict_dynamic_cast< VariableExpr * >( cast->arg );
214                }
215
216                Expression * detectIsDtor( Expression * func ) {
217                        VariableExpr * typed_func = extractVariable( func );
218                        bool is_dtor = InitTweak::isDestructor( typed_func->var );
219                        return new ConstantExpr( Constant::from_bool( is_dtor ) );
220                }
221        };
222
223
224        //=============================================================================================
225        // Generate waitfor implementation
226        //=============================================================================================
227
228        void GenerateWaitForPass::premutate( FunctionDecl * decl) {
229                if( decl->name != "__waitfor_internal" ) return;
230
231                decl_waitfor = decl;
232        }
233
234        void GenerateWaitForPass::premutate( StructDecl   * decl ) {
235                if( ! decl->body ) return;
236
237                if( decl->name == "__acceptable_t" ) {
238                        assert( !decl_acceptable );
239                        decl_acceptable = decl;
240                }
241                else if( decl->name == "monitor_desc" ) {
242                        assert( !decl_monitor );
243                        decl_monitor = decl;
244                }
245        }
246
247        Statement * GenerateWaitForPass::postmutate( WaitForStmt * waitfor ) {
248                if( !decl_monitor || !decl_acceptable ) throw SemanticError( "waitfor keyword requires monitors to be in scope, add #include <monitor>", waitfor );
249
250                CompoundStmt * stmt = new CompoundStmt( noLabels );
251
252                ObjectDecl * acceptables = declare( waitfor->clauses.size(), stmt );
253
254                int index = 0;
255                for( auto & clause : waitfor->clauses ) {
256                        init( acceptables, index, clause, stmt );
257
258                        index++;
259                }
260
261                Expression * timeout = init_timeout(
262                        waitfor->timeout.time,
263                        waitfor->timeout.condition,
264                        waitfor->orelse .statement,
265                        waitfor->orelse .condition,
266                        stmt
267                );
268
269                Expression * result = call( waitfor->clauses.size(), acceptables, timeout, stmt );
270
271                choose( waitfor, result, stmt );
272
273                return stmt;
274        }
275
276        ObjectDecl * GenerateWaitForPass::declare( unsigned long count, CompoundStmt * stmt )
277        {
278                ObjectDecl * acceptables = ObjectDecl::newObject(
279                        namer_acc.newName(),
280                        new ArrayType(
281                                noQualifiers,
282                                new StructInstType(
283                                        noQualifiers,
284                                        decl_acceptable
285                                ),
286                                new ConstantExpr( Constant::from_ulong( count ) ),
287                                false,
288                                false
289                        ),
290                        nullptr
291                );
292
293                stmt->push_back( new DeclStmt( noLabels, acceptables) );
294
295                return acceptables;
296        }
297
298        ObjectDecl * GenerateWaitForPass::declMon( WaitForStmt::Clause & clause, CompoundStmt * stmt ) {
299
300                ObjectDecl * mon = ObjectDecl::newObject(
301                        namer_mon.newName(),
302                        new ArrayType(
303                                noQualifiers,
304                                new PointerType(
305                                        noQualifiers,
306                                        new StructInstType(
307                                                noQualifiers,
308                                                decl_monitor
309                                        )
310                                ),
311                                new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ),
312                                false,
313                                false
314                        ),
315                        new ListInit(
316                                map_range < std::list<Initializer*> > ( clause.target.arguments, [this](Expression * expr ){
317                                        Expression * untyped = new CastExpr(
318                                                new UntypedExpr(
319                                                        new NameExpr( "get_monitor" ),
320                                                        { expr }
321                                                ),
322                                                new PointerType(
323                                                        noQualifiers,
324                                                        new StructInstType(
325                                                                noQualifiers,
326                                                                decl_monitor
327                                                        )
328                                                )
329                                        );
330
331                                        Expression * init = ResolvExpr::findSingleExpression( untyped, indexer );
332                                        delete untyped;
333                                        return new SingleInit( init );
334                                })
335                        )
336                );
337
338                stmt->push_back( new DeclStmt( noLabels, mon) );
339
340                return mon;
341        }
342
343        void GenerateWaitForPass::init( ObjectDecl * acceptables, int index, WaitForStmt::Clause & clause, CompoundStmt * stmt ) {
344
345                ObjectDecl * monitors = declMon( clause, stmt );
346
347                Type * fptr_t = new PointerType( noQualifiers, new FunctionType( noQualifiers, true ) );
348
349                CompoundStmt * compound = new CompoundStmt( noLabels );
350                compound->push_back( makeAccStatement( acceptables, index, "is_dtor" , detectIsDtor( clause.target.function )                                    , indexer ) );
351                compound->push_back( makeAccStatement( acceptables, index, "func"    , new CastExpr( clause.target.function, fptr_t )                            , indexer ) );
352                compound->push_back( makeAccStatement( acceptables, index, "monitors", new VariableExpr( monitors )                                              , indexer ) );
353                compound->push_back( makeAccStatement( acceptables, index, "count"   , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ) );
354
355                stmt->push_back( new IfStmt(
356                        noLabels,
357                        safeCond( clause.condition ),
358                        compound,
359                        nullptr
360                ));
361
362                clause.target.function = nullptr;
363                clause.target.arguments.empty();
364                clause.condition = nullptr;
365        }
366
367        Expression * GenerateWaitForPass::init_timeout(
368                Expression *& time,
369                Expression *& time_cond,
370                bool has_else,
371                Expression *& else_cond,
372                CompoundStmt * stmt
373        ) {
374                ObjectDecl * timeout = ObjectDecl::newObject(
375                        namer_tim.newName(),
376                        new BasicType(
377                                noQualifiers,
378                                BasicType::LongLongUnsignedInt
379                        ),
380                        new SingleInit(
381                                new ConstantExpr( Constant::from_int( -1 ) )
382                        )
383                );
384
385                stmt->push_back( new DeclStmt( noLabels, timeout ) );
386
387                if( time ) {
388                        stmt->push_back( new IfStmt(
389                                noLabels,
390                                safeCond( time_cond ),
391                                new ExprStmt(
392                                        noLabels,
393                                        makeOpAssign(
394                                                new VariableExpr( timeout ),
395                                                time
396                                        )
397                                ),
398                                nullptr
399                        ));
400
401                        time = time_cond = nullptr;
402                }
403
404                if( has_else ) {
405                        stmt->push_back( new IfStmt(
406                                noLabels,
407                                safeCond( else_cond ),
408                                new ExprStmt(
409                                        noLabels,
410                                        makeOpAssign(
411                                                new VariableExpr( timeout ),
412                                                new ConstantExpr( Constant::from_ulong( 0 ) )
413                                        )
414                                ),
415                                nullptr
416                        ));
417
418                        else_cond = nullptr;
419                }
420
421                return new VariableExpr( timeout );
422        }
423
424        Expression * GenerateWaitForPass::call(
425                size_t count,
426                ObjectDecl * acceptables,
427                Expression * timeout,
428                CompoundStmt * stmt
429        ) {
430                ObjectDecl * decl = ObjectDecl::newObject(
431                        namer_ret.newName(),
432                        new BasicType(
433                                noQualifiers,
434                                BasicType::LongLongUnsignedInt
435                        ),
436                        new SingleInit(
437                                new UntypedExpr(
438                                        VariableExpr::functionPointer( decl_waitfor ),
439                                        {
440                                                new ConstantExpr( Constant::from_ulong( count ) ),
441                                                new VariableExpr( acceptables ),
442                                                timeout
443                                        }
444                                )
445                        )
446                );
447
448                stmt->push_back( new DeclStmt( noLabels, decl ) );
449
450                return new VariableExpr( decl );
451        }
452
453        void GenerateWaitForPass::choose(
454                WaitForStmt * waitfor,
455                Expression  * result,
456                CompoundStmt * stmt
457        ) {
458                SwitchStmt * swtch = new SwitchStmt(
459                        noLabels,
460                        result,
461                        std::list<Statement *>()
462                );
463
464                unsigned long i = 0;
465                for( auto & clause : waitfor->clauses ) {
466                        swtch->statements.push_back(
467                                new CaseStmt(
468                                        noLabels,
469                                        new ConstantExpr( Constant::from_ulong( i++ ) ),
470                                        {
471                                                clause.statement,
472                                                new BranchStmt(
473                                                        noLabels,
474                                                        "",
475                                                        BranchStmt::Break
476                                                )
477                                        }
478                                )
479                        );
480                }
481
482                if(waitfor->timeout.statement) {
483                        swtch->statements.push_back(
484                                new CaseStmt(
485                                        noLabels,
486                                        new ConstantExpr( Constant::from_int( -2 ) ),
487                                        {
488                                                waitfor->timeout.statement,
489                                                new BranchStmt(
490                                                        noLabels,
491                                                        "",
492                                                        BranchStmt::Break
493                                                )
494                                        }
495                                )
496                        );
497                }
498
499                if(waitfor->orelse.statement) {
500                        swtch->statements.push_back(
501                                new CaseStmt(
502                                        noLabels,
503                                        new ConstantExpr( Constant::from_int( -1 ) ),
504                                        {
505                                                waitfor->orelse.statement,
506                                                new BranchStmt(
507                                                        noLabels,
508                                                        "",
509                                                        BranchStmt::Break
510                                                )
511                                        }
512                                )
513                        );
514                }
515
516                stmt->push_back( swtch );
517        }
518};
519
520// Local Variables: //
521// mode: c //
522// tab-width: 4 //
523// End: //
Note: See TracBrowser for help on using the repository browser.