source: src/Concurrency/Waitfor.cpp @ 45d1ab9

Last change on this file since 45d1ab9 was 83fd57d, checked in by Andrew Beach <ajbeach@…>, 11 months ago

Removed 'New' suffixes, they are no longer needed for disambiguation.

  • Property mode set to 100644
File size: 15.9 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.cpp -- Expand waitfor clauses into code.
8//
9// Author           : Andrew Beach
10// Created On       : Fri May 27 10:31:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue Jun 13 13:30:00 2022
13// Update Count     : 0
14//
15
16#include "Waitfor.h"
17
18#include <string>
19
20#include "AST/Pass.hpp"
21#include "Common/UniqueName.h"
22#include "InitTweak/InitTweak.h"
23#include "ResolvExpr/Resolver.h"
24
25#include "AST/Print.hpp"
26
27using namespace std::string_literals;
28using ResolvExpr::ResolveContext;
29
30/* So this is what this file dones:
31
32void f(int i, float f, A & mutex b, struct foo *  );
33void f(int );
34
35...{
36        when ( a < 1 ) waitfor( f : a ) { fee(); }
37        or timeout( getWaitTime() ) { fy(); }
38        or waitfor( g : a ) { foe(); }
39        or waitfor( ^?{} : a ) { break; }
40        or waitfor( ^?{} ) { break; }
41        or when ( a < 1 ) else { fum(); }
42}...
43
44                 ||
45                 ||
46                \||/
47                 \/
48
49...{
50        {
51                __acceptable_t __acceptables_#[4 <num-clauses>];
52                bool __do_run_# = false;
53
54                monitor$ * __monitors_#[1 <num-monitors>] = { a };
55                if ( a < 1) {
56                        void (*__function_#)() = <casts> f;
57                        __acceptables_#[0].is_dtor = false;
58                        __acceptables_#[0].func = __function_#;
59                        __acceptables_#[0].data = __monitors_#;
60                        __acceptables_#[0].size = 1;
61                        __do_run_# = true;
62                }
63
64                // Remaining waitfor clauses go here.
65
66                long long unsigned int __timeout_# = -1;
67                if ( true ) {
68                        __timeout_# = getWaitTime();
69                        __do_run_# = true;
70                }
71
72                if ( a < 1 ) {
73                        __timeout_# = 0
74                        __do_run_# = true;
75                }
76
77                short int __index_# = -1;
78                __waitfor_mask_t __mask_# = {&__index_#, {__acceptables_#, ?}};
79                __waitfor_internal((__waitfor_mask_t&)__mask_#, __timeout_#);
80
81                switch (__index_#) {
82                case 0:
83                        { { fee(); } break; }
84                case 1:
85                        { { foe(); } break; }
86                case 2:
87                        { <modified-break> break; }
88                case 3:
89                        { <modified-break> break; }
90                case -2:
91                        { { fy(); } break; }
92                case -1:
93                        { { foe(); } break; }
94                }
95        }
96}...
97*/
98
99namespace Concurrency {
100
101namespace {
102
103class GenerateWaitForCore final :
104                public ast::WithSymbolTable, public ast::WithConstTranslationUnit {
105        const ast::FunctionDecl * decl_waitfor    = nullptr;
106        const ast::StructDecl   * decl_mask       = nullptr;
107        const ast::StructDecl   * decl_acceptable = nullptr;
108        const ast::StructDecl   * decl_monitor    = nullptr;
109
110        UniqueName namer_acc = "__acceptables_"s;
111        UniqueName namer_idx = "__index_"s;
112        UniqueName namer_flg = "__do_run_"s;
113        UniqueName namer_msk = "__mask_"s;
114        UniqueName namer_mon = "__monitors_"s;
115        UniqueName namer_tim = "__timeout_"s;
116        UniqueName namer_fun = "__function_"s;
117
118        ast::ObjectDecl * declareAcceptables( ast::CompoundStmt * out,
119                const CodeLocation & location, unsigned long numClauses );
120        ast::ObjectDecl * declareFlag(
121                ast::CompoundStmt * out, const CodeLocation & location );
122        ast::ExprStmt * makeSetter(
123                const CodeLocation & location, ast::ObjectDecl * flag );
124        ast::ObjectDecl * declMonitors(
125                ast::CompoundStmt * out, const ast::WaitForClause * clause );
126        void init_clause( ast::CompoundStmt * out, ast::ObjectDecl * acceptables,
127                int index, const ast::WaitForClause * clause, ast::Stmt * setter );
128        ast::Expr * init_timeout(
129                ast::CompoundStmt * out, const CodeLocation & topLocation,
130                const ast::Expr * timeout_time, const ast::Expr * timeout_cond,
131                const ast::Stmt * else_stmt, const ast::Expr * else_cond,
132                const ast::Stmt * setter );
133        ast::Expr * call(
134                ast::CompoundStmt * out, const CodeLocation & location,
135                size_t numClauses, ast::ObjectDecl * acceptables,
136                ast::Expr * timeout );
137public:
138        void previsit( const ast::FunctionDecl * decl );
139        void previsit( const ast::StructDecl * decl );
140        ast::Stmt * postvisit( const ast::WaitForStmt * stmt );
141};
142
143ast::Expr * makeOpIndex( const CodeLocation & location,
144                const ast::DeclWithType * array, unsigned long index ) {
145        return new ast::UntypedExpr( location,
146                new ast::NameExpr( location, "?[?]" ),
147                {
148                        new ast::VariableExpr( location, array ),
149                        ast::ConstantExpr::from_ulong( location, index ),
150                }
151        );
152}
153
154ast::Expr * makeOpAssign( const CodeLocation & location,
155                const ast::Expr * lhs, const ast::Expr * rhs ) {
156        return new ast::UntypedExpr( location,
157                new ast::NameExpr( location, "?=?" ),
158                { lhs, rhs }
159        );
160}
161
162ast::Expr * makeOpMember( const CodeLocation & location,
163                const std::string & mem, const ast::Expr * sue ) {
164        return new ast::UntypedMemberExpr( location,
165                new ast::NameExpr( location, mem ),
166                sue
167        );
168}
169
170ast::Stmt * makeAccStmt(
171                const CodeLocation & location, ast::DeclWithType * object,
172                unsigned long index, const std::string & member,
173                const ast::Expr * value, const ResolveContext & context
174) {
175        ast::Expr * expr = makeOpAssign( location,
176                makeOpMember( location,
177                        member,
178                        makeOpIndex( location,
179                                object,
180                                index
181                        )
182                ),
183                value
184        );
185
186        auto result = ResolvExpr::findVoidExpression( expr, context );
187        return new ast::ExprStmt( location, result.get() );
188}
189
190const ast::Stmt * maybeCond( const CodeLocation & location,
191                const ast::Expr * cond, std::list<ast::ptr<ast::Stmt>> && stmts ) {
192        ast::Stmt * block = new ast::CompoundStmt( location, std::move( stmts ) );
193        return (cond) ? new ast::IfStmt( location, cond, block ) : block;
194}
195
196const ast::VariableExpr * extractVariable( const ast::Expr * func ) {
197        if ( auto var = dynamic_cast<const ast::VariableExpr *>( func ) ) {
198                return var;
199        }
200        auto cast = strict_dynamic_cast<const ast::CastExpr *>( func );
201        return cast->arg.strict_as<ast::VariableExpr>();
202}
203
204const ast::Expr * detectIsDtor(
205                const CodeLocation & location, const ast::Expr * func ) {
206        const ast::VariableExpr * typed_func = extractVariable( func );
207        bool is_dtor = InitTweak::isDestructor(
208                typed_func->var.strict_as<ast::FunctionDecl>() );
209        return ast::ConstantExpr::from_bool( location, is_dtor );
210}
211
212ast::ObjectDecl * GenerateWaitForCore::declareAcceptables(
213                ast::CompoundStmt * out,
214                const CodeLocation & location, unsigned long numClauses ) {
215        ast::ObjectDecl * acceptables = new ast::ObjectDecl( location,
216                namer_acc.newName(),
217                new ast::ArrayType(
218                        new ast::StructInstType( decl_acceptable ),
219                        ast::ConstantExpr::from_ulong( location, numClauses ),
220                        ast::FixedLen,
221                        ast::DynamicDim
222                )
223        );
224        out->push_back( new ast::DeclStmt( location, acceptables ) );
225
226        ast::Expr * set = new ast::UntypedExpr( location,
227                new ast::NameExpr( location, "__builtin_memset" ),
228                {
229                        new ast::VariableExpr( location, acceptables ),
230                        ast::ConstantExpr::from_int( location, 0 ),
231                        new ast::SizeofExpr( location,
232                                new ast::VariableExpr( location, acceptables ) ),
233                }
234        );
235        ResolveContext context{ symtab, transUnit().global };
236        auto result = ResolvExpr::findVoidExpression( set, context );
237        out->push_back( new ast::ExprStmt( location, result.get() ) );
238
239        return acceptables;
240}
241
242ast::ObjectDecl * GenerateWaitForCore::declareFlag(
243                ast::CompoundStmt * out, const CodeLocation & location ) {
244        ast::ObjectDecl * flag = new ast::ObjectDecl( location,
245                namer_flg.newName(),
246                new ast::BasicType( ast::BasicType::Bool ),
247                new ast::SingleInit( location,
248                        ast::ConstantExpr::from_ulong( location, 0 )
249                )
250        );
251        out->push_back( new ast::DeclStmt( location, flag ) );
252        return flag;
253}
254
255ast::ExprStmt * GenerateWaitForCore::makeSetter(
256                const CodeLocation & location, ast::ObjectDecl * flag ) {
257        ast::Expr * expr = new ast::UntypedExpr( location,
258                new ast::NameExpr( location, "?=?" ),
259                {
260                        new ast::VariableExpr( location, flag ),
261                        ast::ConstantExpr::from_ulong( location, 1 ),
262                }
263        );
264        ResolveContext context{ symtab, transUnit().global };
265        auto result = ResolvExpr::findVoidExpression( expr, context );
266        return new ast::ExprStmt( location, result.get() );
267}
268
269ast::ObjectDecl * GenerateWaitForCore::declMonitors(
270                ast::CompoundStmt * out,
271                const ast::WaitForClause * clause ) {
272        const CodeLocation & location = clause->location;
273        ast::ObjectDecl * monitor = new ast::ObjectDecl( location,
274                namer_mon.newName(),
275                new ast::ArrayType(
276                        new ast::PointerType(
277                                new ast::StructInstType( decl_monitor )
278                        ),
279                        ast::ConstantExpr::from_ulong( location, clause->target_args.size() ),
280                        ast::FixedLen,
281                        ast::DynamicDim
282                ),
283                new ast::ListInit( location,
284                        map_range<std::vector<ast::ptr<ast::Init>>>(
285                                clause->target_args,
286                                []( const ast::Expr * expr ){
287                                        return new ast::SingleInit( expr->location, expr ); }
288                        )
289                )
290        );
291        out->push_back( new ast::DeclStmt( location, monitor ) );
292        return monitor;
293}
294
295void GenerateWaitForCore::init_clause(
296                ast::CompoundStmt * out,
297                ast::ObjectDecl * acceptables,
298                int index,
299                const ast::WaitForClause * clause,
300                ast::Stmt * setter ) {
301        const CodeLocation & location = clause->location;
302        const ast::ObjectDecl * monitors = declMonitors( out, clause );
303        ast::Type * fptr_t = new ast::PointerType(
304                        new ast::FunctionType( ast::VariableArgs ) );
305
306        const ast::VariableExpr * variableExpr =
307                clause->target.as<ast::VariableExpr>();
308        ast::Expr * castExpr = new ast::CastExpr(
309                location,
310                new ast::CastExpr(
311                        location,
312                        clause->target,
313                        ast::deepCopy( variableExpr->result.get() ),
314                        ast::GeneratedCast ),
315                fptr_t,
316                ast::GeneratedCast );
317
318        ast::ObjectDecl * funcDecl = new ast::ObjectDecl( location,
319                namer_fun.newName(),
320                ast::deepCopy( fptr_t ),
321                new ast::SingleInit( location, castExpr )
322                );
323        ast::Expr * funcExpr = new ast::VariableExpr( location, funcDecl );
324        out->push_back( new ast::DeclStmt( location, funcDecl ) );
325
326        ResolveContext context{ symtab, transUnit().global };
327        out->push_back( maybeCond( location, clause->when_cond.get(), {
328                makeAccStmt( location, acceptables, index, "is_dtor",
329                        detectIsDtor( location, clause->target ), context ),
330                makeAccStmt( location, acceptables, index, "func",
331                        funcExpr, context ),
332                makeAccStmt( location, acceptables, index, "data",
333                        new ast::VariableExpr( location, monitors ), context ),
334                makeAccStmt( location, acceptables, index, "size",
335                        ast::ConstantExpr::from_ulong( location,
336                                clause->target_args.size() ), context ),
337                ast::deepCopy( setter ),
338        } ) );
339}
340
341ast::Expr * GenerateWaitForCore::init_timeout(
342                ast::CompoundStmt * out,
343                const CodeLocation & topLocation,
344                const ast::Expr * timeout_time,
345                const ast::Expr * timeout_cond,
346                const ast::Stmt * else_stmt,
347                const ast::Expr * else_cond,
348                const ast::Stmt * setter ) {
349        ast::ObjectDecl * timeout = new ast::ObjectDecl( topLocation,
350                namer_tim.newName(),
351                new ast::BasicType( ast::BasicType::LongLongUnsignedInt ),
352                new ast::SingleInit( topLocation,
353                        ast::ConstantExpr::from_int( topLocation, -1 )
354                )
355        );
356        out->push_back( new ast::DeclStmt( topLocation, timeout ) );
357
358        if ( timeout_time ) {
359                const CodeLocation & location = timeout_time->location;
360                out->push_back( maybeCond( location, timeout_cond, {
361                        new ast::ExprStmt( location,
362                                makeOpAssign(
363                                        location,
364                                        new ast::VariableExpr( location, timeout ),
365                                        timeout_time
366                                )
367                        ),
368                        ast::deepCopy( setter ),
369                } ) );
370        }
371
372        // We only care about the else_stmt's presence and location.
373        if ( else_stmt ) {
374                const CodeLocation & location = else_stmt->location;
375                out->push_back( maybeCond( location, else_cond, {
376                        new ast::ExprStmt( location,
377                                makeOpAssign(
378                                        location,
379                                        new ast::VariableExpr( location, timeout ),
380                                        ast::ConstantExpr::from_ulong( location, 0 )
381                                )
382                        ),
383                        ast::deepCopy( setter ),
384                } ) );
385        }
386
387        return new ast::VariableExpr( topLocation, timeout );
388}
389
390ast::Expr * GenerateWaitForCore::call(
391        ast::CompoundStmt * out,
392        const CodeLocation & location,
393        size_t numClauses,
394        ast::ObjectDecl * acceptables,
395        ast::Expr * timeout
396) {
397        ast::ObjectDecl * index = new ast::ObjectDecl( location,
398                namer_idx.newName(),
399                new ast::BasicType( ast::BasicType::ShortSignedInt ),
400                new ast::SingleInit( location,
401                        ast::ConstantExpr::from_int( location, -1 )
402                )
403        );
404        out->push_back( new ast::DeclStmt( location, index ) );
405
406        ast::ObjectDecl * mask = new ast::ObjectDecl( location,
407                namer_msk.newName(),
408                new ast::StructInstType( decl_mask ),
409                new ast::ListInit( location, {
410                        new ast::SingleInit( location,
411                                new ast::AddressExpr( location,
412                                        new ast::VariableExpr( location, index )
413                                )
414                        ),
415                        new ast::ListInit( location, {
416                                new ast::SingleInit( location,
417                                        new ast::VariableExpr( location, acceptables )
418                                ),
419                                new ast::SingleInit( location,
420                                        ast::ConstantExpr::from_ulong( location, numClauses )
421                                ),
422                        }),
423                })
424        );
425        out->push_back( new ast::DeclStmt( location, mask ) );
426
427        ast::ApplicationExpr * waitforMask = new ast::ApplicationExpr( location,
428                ast::VariableExpr::functionPointer( location, decl_waitfor ),
429                {
430                        new ast::CastExpr(
431                                new ast::VariableExpr( location, mask ),
432                                new ast::ReferenceType(
433                                        new ast::StructInstType( decl_mask )
434                                )
435                        ),
436                        timeout
437                }
438        );
439        out->push_back( new ast::ExprStmt( location, waitforMask ) );
440
441        return new ast::VariableExpr( location, index );
442}
443
444ast::Stmt * choose( const ast::WaitForStmt * waitfor, ast::Expr * result ) {
445        const CodeLocation & location = waitfor->location;
446
447        ast::SwitchStmt * theSwitch = new ast::SwitchStmt( location,
448                result,
449                std::vector<ast::ptr<ast::CaseClause>>()
450        );
451
452        for ( const auto & [i, clause] : enumerate( waitfor->clauses ) ) {
453                theSwitch->cases.push_back(
454                        new ast::CaseClause( location,
455                                ast::ConstantExpr::from_ulong( location, i ),
456                                {
457                                        new ast::CompoundStmt( location, {
458                                                clause->stmt,
459                                                new ast::BranchStmt( location,
460                                                        ast::BranchStmt::Break,
461                                                        ast::Label( location )
462                                                )
463                                        })
464                                }
465                        )
466                );
467        }
468
469        if ( waitfor->timeout_stmt ) {
470                theSwitch->cases.push_back(
471                        new ast::CaseClause( location,
472                                ast::ConstantExpr::from_int( location, -2 ),
473                                {
474                                        new ast::CompoundStmt( location, {
475                                                waitfor->timeout_stmt,
476                                                new ast::BranchStmt( location,
477                                                        ast::BranchStmt::Break,
478                                                        ast::Label( location )
479                                                )
480                                        })
481                                }
482                        )
483                );
484        }
485
486        if ( waitfor->else_stmt ) {
487                theSwitch->cases.push_back(
488                        new ast::CaseClause( location,
489                                ast::ConstantExpr::from_int( location, -1 ),
490                                {
491                                        new ast::CompoundStmt( location, {
492                                                waitfor->else_stmt,
493                                                new ast::BranchStmt( location,
494                                                        ast::BranchStmt::Break,
495                                                        ast::Label( location )
496                                                )
497                                        })
498                                }
499                        )
500                );
501        }
502
503        return theSwitch;
504}
505
506void GenerateWaitForCore::previsit( const ast::FunctionDecl * decl ) {
507        if ( "__waitfor_internal" == decl->name ) {
508                decl_waitfor = decl;
509        }
510}
511
512void GenerateWaitForCore::previsit( const ast::StructDecl * decl ) {
513        if ( !decl->body ) {
514                return;
515        } else if ( "__acceptable_t" == decl->name ) {
516                assert( !decl_acceptable );
517                decl_acceptable = decl;
518        } else if ( "__waitfor_mask_t" == decl->name ) {
519                assert( !decl_mask );
520                decl_mask = decl;
521        } else if ( "monitor$" == decl->name ) {
522                assert( !decl_monitor );
523                decl_monitor = decl;
524        }
525}
526
527ast::Stmt * GenerateWaitForCore::postvisit( const ast::WaitForStmt * stmt ) {
528        if ( !decl_monitor || !decl_acceptable || !decl_mask ) {
529                SemanticError( stmt, "waitfor keyword requires monitors to be in scope, add #include <monitor.hfa>" );
530        }
531
532        const CodeLocation & location = stmt->location;
533        ast::CompoundStmt * comp = new ast::CompoundStmt( location );
534
535        ast::ObjectDecl * acceptables = declareAcceptables( comp, location, stmt->clauses.size() );
536        ast::ObjectDecl * flag        = declareFlag( comp, location );
537        ast::Stmt       * setter      = makeSetter( location, flag );
538
539        for ( const auto & [i, clause] : enumerate( stmt->clauses ) ) {
540                init_clause( comp, acceptables, i, clause, setter );
541        }
542
543        ast::Expr * timeout = init_timeout(
544                comp,
545                location,
546                stmt->timeout_time,
547                stmt->timeout_cond,
548                stmt->else_stmt,
549                stmt->else_cond,
550                setter
551        );
552
553        ast::CompoundStmt * compound = new ast::CompoundStmt( location );
554        comp->push_back( new ast::IfStmt( location,
555                new ast::VariableExpr( location, flag ),
556                compound,
557                nullptr
558        ));
559
560        ast::Expr * result = call(
561                compound, location, stmt->clauses.size(), acceptables, timeout );
562        compound->push_back( choose( stmt, result ) );
563        return comp;
564}
565
566} // namespace
567
568void generateWaitFor( ast::TranslationUnit & translationUnit ) {
569        ast::Pass<GenerateWaitForCore>::run( translationUnit );
570}
571
572} // namespace Concurrency
573
574// Local Variables: //
575// tab-width: 4 //
576// mode: c++ //
577// compile-command: "make install" //
578// End: //
Note: See TracBrowser for help on using the repository browser.