source: src/Concurrency/Waitfor.cc @ 1dcd9554

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 1dcd9554 was 1dcd9554, checked in by Thierry Delisle <tdelisle@…>, 7 years ago

First "working" implementation of waitfor

  • Property mode set to 100644
File size: 12.4 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
208
209        //=============================================================================================
210        // Generate waitfor implementation
211        //=============================================================================================
212
213        void GenerateWaitForPass::premutate( FunctionDecl * decl) {
214                if( decl->name != "__accept_internal" ) return;
215
216                decl_waitfor = decl;
217        }
218
219        void GenerateWaitForPass::premutate( StructDecl   * decl ) {
220                if( ! decl->body ) return;
221
222                if( decl->name == "__acceptable_t" ) {
223                        assert( !decl_acceptable );
224                        decl_acceptable = decl;
225                }
226                else if( decl->name == "monitor_desc" ) {
227                        assert( !decl_monitor );
228                        decl_monitor = decl;
229                }
230        }
231
232        Statement * GenerateWaitForPass::postmutate( WaitForStmt * waitfor ) {
233                if( !decl_monitor || !decl_acceptable ) throw SemanticError( "waitfor keyword requires monitors to be in scope, add #include <monitor>", waitfor );
234
235                CompoundStmt * stmt = new CompoundStmt( noLabels );
236
237                ObjectDecl * acceptables = declare( waitfor->clauses.size(), stmt );
238
239                int index = 0;
240                for( auto & clause : waitfor->clauses ) {
241                        init( acceptables, index, clause, stmt );
242
243                        index++;
244                }
245
246                Expression * timeout = init_timeout(
247                        waitfor->timeout.time,
248                        waitfor->timeout.condition,
249                        waitfor->orelse .statement,
250                        waitfor->orelse .condition,
251                        stmt
252                );
253
254                Expression * result = call( waitfor->clauses.size(), acceptables, timeout, stmt );
255
256                choose( waitfor, result, stmt );
257
258                return stmt;
259        }
260
261        ObjectDecl * GenerateWaitForPass::declare( unsigned long count, CompoundStmt * stmt )
262        {
263                ObjectDecl * acceptables = ObjectDecl::newObject(
264                        namer_acc.newName(),
265                        new ArrayType(
266                                noQualifiers,
267                                new StructInstType(
268                                        noQualifiers,
269                                        decl_acceptable
270                                ),
271                                new ConstantExpr( Constant::from_ulong( count ) ),
272                                false,
273                                false
274                        ),
275                        nullptr
276                );
277
278                stmt->push_back( new DeclStmt( noLabels, acceptables) );
279
280                return acceptables;
281        }
282
283        ObjectDecl * GenerateWaitForPass::declMon( WaitForStmt::Clause & clause, CompoundStmt * stmt ) {
284
285                ObjectDecl * mon = ObjectDecl::newObject(
286                        namer_mon.newName(),
287                        new ArrayType(
288                                noQualifiers,
289                                new StructInstType(
290                                        noQualifiers,
291                                        decl_monitor
292                                ),
293                                new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ),
294                                false,
295                                false
296                        ),
297                        new ListInit(
298                                map_range < std::list<Initializer*> > ( clause.target.arguments, [this](Expression * expr ){
299                                        return new SingleInit( expr );
300                                })
301                        )
302                );
303
304                stmt->push_back( new DeclStmt( noLabels, mon) );
305
306                return mon;
307        }
308
309        void GenerateWaitForPass::init( ObjectDecl * acceptables, int index, WaitForStmt::Clause & clause, CompoundStmt * stmt ) {
310
311                ObjectDecl * monitors = declMon( clause, stmt );
312
313                Type * fptr_t = new PointerType( noQualifiers, new FunctionType( noQualifiers, true ) );
314
315                CompoundStmt * compound = new CompoundStmt( noLabels );
316                compound->push_back( makeAccStatement( acceptables, index, "func"    , new CastExpr( clause.target.function, fptr_t )                            , indexer ) );
317                compound->push_back( makeAccStatement( acceptables, index, "count"   , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ) );
318                compound->push_back( makeAccStatement( acceptables, index, "monitors", new VariableExpr( monitors )                                              , indexer ) );
319                compound->push_back( makeAccStatement( acceptables, index, "is_dtor" , new ConstantExpr( Constant::from_bool( true ) )                           , indexer ) );
320
321                stmt->push_back( new IfStmt(
322                        noLabels,
323                        safeCond( clause.condition ),
324                        compound,
325                        nullptr
326                ));
327
328                clause.target.function = nullptr;
329                clause.target.arguments.empty();
330                clause.condition = nullptr;
331        }
332
333        Expression * GenerateWaitForPass::init_timeout(
334                Expression *& time,
335                Expression *& time_cond,
336                bool has_else,
337                Expression *& else_cond,
338                CompoundStmt * stmt
339        ) {
340                ObjectDecl * timeout = ObjectDecl::newObject(
341                        namer_tim.newName(),
342                        new BasicType(
343                                noQualifiers,
344                                BasicType::LongLongUnsignedInt
345                        ),
346                        new SingleInit(
347                                new ConstantExpr( Constant::from_int( -1 ) )
348                        )
349                );
350
351                stmt->push_back( new DeclStmt( noLabels, timeout ) );
352
353                if( time ) {
354                        stmt->push_back( new IfStmt(
355                                noLabels,
356                                safeCond( time_cond ),
357                                new ExprStmt(
358                                        noLabels,
359                                        makeOpAssign(
360                                                new VariableExpr( timeout ),
361                                                time
362                                        )
363                                ),
364                                nullptr
365                        ));
366
367                        time = time_cond = nullptr;
368                }
369
370                if( has_else ) {
371                        stmt->push_back( new IfStmt(
372                                noLabels,
373                                safeCond( else_cond ),
374                                new ExprStmt(
375                                        noLabels,
376                                        makeOpAssign(
377                                                new VariableExpr( timeout ),
378                                                new ConstantExpr( Constant::from_ulong( 0 ) )
379                                        )
380                                ),
381                                nullptr
382                        ));
383
384                        else_cond = nullptr;
385                }
386
387                return new VariableExpr( timeout );
388        }
389
390        Expression * GenerateWaitForPass::call(
391                size_t count,
392                ObjectDecl * acceptables,
393                Expression * timeout,
394                CompoundStmt * stmt
395        ) {
396                ObjectDecl * decl = ObjectDecl::newObject(
397                        namer_ret.newName(),
398                        new BasicType(
399                                noQualifiers,
400                                BasicType::LongLongUnsignedInt
401                        ),
402                        new SingleInit(
403                                new UntypedExpr(
404                                        VariableExpr::functionPointer( decl_waitfor ),
405                                        {
406                                                new ConstantExpr( Constant::from_ulong( count ) ),
407                                                new VariableExpr( acceptables ),
408                                                timeout
409                                        }
410                                )
411                        )
412                );
413
414                stmt->push_back( new DeclStmt( noLabels, decl ) );
415
416                return new VariableExpr( decl );
417        }
418
419        void GenerateWaitForPass::choose(
420                WaitForStmt * waitfor,
421                Expression  * result,
422                CompoundStmt * stmt
423        ) {
424                SwitchStmt * swtch = new SwitchStmt(
425                        noLabels,
426                        result,
427                        std::list<Statement *>()
428                );
429
430                unsigned long i = 0;
431                for( auto & clause : waitfor->clauses ) {
432                        swtch->statements.push_back(
433                                new CaseStmt(
434                                        noLabels,
435                                        new ConstantExpr( Constant::from_ulong( i++ ) ),
436                                        {
437                                                clause.statement,
438                                                new BranchStmt(
439                                                        noLabels,
440                                                        "",
441                                                        BranchStmt::Break
442                                                )
443                                        }
444                                )
445                        );
446                }
447
448                if(waitfor->timeout.statement) {
449                        swtch->statements.push_back(
450                                new CaseStmt(
451                                        noLabels,
452                                        new ConstantExpr( Constant::from_ulong( i++ ) ),
453                                        {
454                                                waitfor->timeout.statement,
455                                                new BranchStmt(
456                                                        noLabels,
457                                                        "",
458                                                        BranchStmt::Break
459                                                )
460                                        }
461                                )
462                        );
463                }
464
465                if(waitfor->orelse.statement) {
466                        swtch->statements.push_back(
467                                new CaseStmt(
468                                        noLabels,
469                                        new ConstantExpr( Constant::from_ulong( i++ ) ),
470                                        {
471                                                waitfor->orelse.statement,
472                                                new BranchStmt(
473                                                        noLabels,
474                                                        "",
475                                                        BranchStmt::Break
476                                                )
477                                        }
478                                )
479                        );
480                }
481
482                stmt->push_back( swtch );
483        }
484};
485
486// Local Variables: //
487// mode: c //
488// tab-width: 4 //
489// End: //
Note: See TracBrowser for help on using the repository browser.