source: src/Concurrency/Waitfor.cpp @ 2325b57

Last change on this file since 2325b57 was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 2 months ago

Removed SizeofExpr::expr and AlignofExpr::expr, expressions that would be stored there are wrapped in TypeofType? and stored in the type field. Some special cases to hide the typeof in code generation were added. In addition, initializer length is calculated in more cases so that the full type of more arrays is known sooner. Other than that, most of the code changes were just stripping out the conditional code and checks no longer needed. Some tests had to be updated, because the typeof is not hidden in dumps and the resolver replaces known typeof expressions with the type. The extension case caused some concern but it appears that just hides warnings in the expression which no longer exists.

  • 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.hpp"
17
18#include <string>
19
20#include "AST/Pass.hpp"
21#include "Common/UniqueName.hpp"
22#include "InitTweak/InitTweak.hpp"
23#include "ResolvExpr/Resolver.hpp"
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::TypeofType(
233                                        new ast::VariableExpr( location, acceptables ) ) ),
234                }
235        );
236        ResolveContext context{ symtab, transUnit().global };
237        auto result = ResolvExpr::findVoidExpression( set, context );
238        out->push_back( new ast::ExprStmt( location, result.get() ) );
239
240        return acceptables;
241}
242
243ast::ObjectDecl * GenerateWaitForCore::declareFlag(
244                ast::CompoundStmt * out, const CodeLocation & location ) {
245        ast::ObjectDecl * flag = new ast::ObjectDecl( location,
246                namer_flg.newName(),
247                new ast::BasicType( ast::BasicKind::Bool ),
248                new ast::SingleInit( location,
249                        ast::ConstantExpr::from_ulong( location, 0 )
250                )
251        );
252        out->push_back( new ast::DeclStmt( location, flag ) );
253        return flag;
254}
255
256ast::ExprStmt * GenerateWaitForCore::makeSetter(
257                const CodeLocation & location, ast::ObjectDecl * flag ) {
258        ast::Expr * expr = new ast::UntypedExpr( location,
259                new ast::NameExpr( location, "?=?" ),
260                {
261                        new ast::VariableExpr( location, flag ),
262                        ast::ConstantExpr::from_ulong( location, 1 ),
263                }
264        );
265        ResolveContext context{ symtab, transUnit().global };
266        auto result = ResolvExpr::findVoidExpression( expr, context );
267        return new ast::ExprStmt( location, result.get() );
268}
269
270ast::ObjectDecl * GenerateWaitForCore::declMonitors(
271                ast::CompoundStmt * out,
272                const ast::WaitForClause * clause ) {
273        const CodeLocation & location = clause->location;
274        ast::ObjectDecl * monitor = new ast::ObjectDecl( location,
275                namer_mon.newName(),
276                new ast::ArrayType(
277                        new ast::PointerType(
278                                new ast::StructInstType( decl_monitor )
279                        ),
280                        ast::ConstantExpr::from_ulong( location, clause->target_args.size() ),
281                        ast::FixedLen,
282                        ast::DynamicDim
283                ),
284                new ast::ListInit( location,
285                        map_range<std::vector<ast::ptr<ast::Init>>>(
286                                clause->target_args,
287                                []( const ast::Expr * expr ){
288                                        return new ast::SingleInit( expr->location, expr ); }
289                        )
290                )
291        );
292        out->push_back( new ast::DeclStmt( location, monitor ) );
293        return monitor;
294}
295
296void GenerateWaitForCore::init_clause(
297                ast::CompoundStmt * out,
298                ast::ObjectDecl * acceptables,
299                int index,
300                const ast::WaitForClause * clause,
301                ast::Stmt * setter ) {
302        const CodeLocation & location = clause->location;
303        const ast::ObjectDecl * monitors = declMonitors( out, clause );
304        ast::Type * fptr_t = new ast::PointerType(
305                        new ast::FunctionType( ast::FixedArgs ) );
306
307        const ast::VariableExpr * variableExpr =
308                clause->target.as<ast::VariableExpr>();
309        ast::Expr * castExpr = new ast::CastExpr(
310                location,
311                new ast::CastExpr(
312                        location,
313                        clause->target,
314                        ast::deepCopy( variableExpr->result.get() ),
315                        ast::GeneratedCast ),
316                fptr_t,
317                ast::GeneratedCast );
318
319        ast::ObjectDecl * funcDecl = new ast::ObjectDecl( location,
320                namer_fun.newName(),
321                ast::deepCopy( fptr_t ),
322                new ast::SingleInit( location, castExpr )
323                );
324        ast::Expr * funcExpr = new ast::VariableExpr( location, funcDecl );
325        out->push_back( new ast::DeclStmt( location, funcDecl ) );
326
327        ResolveContext context{ symtab, transUnit().global };
328        out->push_back( maybeCond( location, clause->when_cond.get(), {
329                makeAccStmt( location, acceptables, index, "is_dtor",
330                        detectIsDtor( location, clause->target ), context ),
331                makeAccStmt( location, acceptables, index, "func",
332                        funcExpr, context ),
333                makeAccStmt( location, acceptables, index, "data",
334                        new ast::VariableExpr( location, monitors ), context ),
335                makeAccStmt( location, acceptables, index, "size",
336                        ast::ConstantExpr::from_ulong( location,
337                                clause->target_args.size() ), context ),
338                ast::deepCopy( setter ),
339        } ) );
340}
341
342ast::Expr * GenerateWaitForCore::init_timeout(
343                ast::CompoundStmt * out,
344                const CodeLocation & topLocation,
345                const ast::Expr * timeout_time,
346                const ast::Expr * timeout_cond,
347                const ast::Stmt * else_stmt,
348                const ast::Expr * else_cond,
349                const ast::Stmt * setter ) {
350        ast::ObjectDecl * timeout = new ast::ObjectDecl( topLocation,
351                namer_tim.newName(),
352                new ast::BasicType( ast::BasicKind::LongLongUnsignedInt ),
353                new ast::SingleInit( topLocation,
354                        ast::ConstantExpr::from_int( topLocation, -1 )
355                )
356        );
357        out->push_back( new ast::DeclStmt( topLocation, timeout ) );
358
359        if ( timeout_time ) {
360                const CodeLocation & location = timeout_time->location;
361                out->push_back( maybeCond( location, timeout_cond, {
362                        new ast::ExprStmt( location,
363                                makeOpAssign(
364                                        location,
365                                        new ast::VariableExpr( location, timeout ),
366                                        timeout_time
367                                )
368                        ),
369                        ast::deepCopy( setter ),
370                } ) );
371        }
372
373        // We only care about the else_stmt's presence and location.
374        if ( else_stmt ) {
375                const CodeLocation & location = else_stmt->location;
376                out->push_back( maybeCond( location, else_cond, {
377                        new ast::ExprStmt( location,
378                                makeOpAssign(
379                                        location,
380                                        new ast::VariableExpr( location, timeout ),
381                                        ast::ConstantExpr::from_ulong( location, 0 )
382                                )
383                        ),
384                        ast::deepCopy( setter ),
385                } ) );
386        }
387
388        return new ast::VariableExpr( topLocation, timeout );
389}
390
391ast::Expr * GenerateWaitForCore::call(
392        ast::CompoundStmt * out,
393        const CodeLocation & location,
394        size_t numClauses,
395        ast::ObjectDecl * acceptables,
396        ast::Expr * timeout
397) {
398        ast::ObjectDecl * index = new ast::ObjectDecl( location,
399                namer_idx.newName(),
400                new ast::BasicType( ast::BasicKind::ShortSignedInt ),
401                new ast::SingleInit( location,
402                        ast::ConstantExpr::from_int( location, -1 )
403                )
404        );
405        out->push_back( new ast::DeclStmt( location, index ) );
406
407        ast::ObjectDecl * mask = new ast::ObjectDecl( location,
408                namer_msk.newName(),
409                new ast::StructInstType( decl_mask ),
410                new ast::ListInit( location, {
411                        new ast::SingleInit( location,
412                                new ast::AddressExpr( location,
413                                        new ast::VariableExpr( location, index )
414                                )
415                        ),
416                        new ast::ListInit( location, {
417                                new ast::SingleInit( location,
418                                        new ast::VariableExpr( location, acceptables )
419                                ),
420                                new ast::SingleInit( location,
421                                        ast::ConstantExpr::from_ulong( location, numClauses )
422                                ),
423                        }),
424                })
425        );
426        out->push_back( new ast::DeclStmt( location, mask ) );
427
428        ast::ApplicationExpr * waitforMask = new ast::ApplicationExpr( location,
429                ast::VariableExpr::functionPointer( location, decl_waitfor ),
430                {
431                        new ast::CastExpr(
432                                new ast::VariableExpr( location, mask ),
433                                new ast::ReferenceType(
434                                        new ast::StructInstType( decl_mask )
435                                )
436                        ),
437                        timeout
438                }
439        );
440        out->push_back( new ast::ExprStmt( location, waitforMask ) );
441
442        return new ast::VariableExpr( location, index );
443}
444
445ast::Stmt * choose( const ast::WaitForStmt * waitfor, ast::Expr * result ) {
446        const CodeLocation & location = waitfor->location;
447
448        ast::SwitchStmt * theSwitch = new ast::SwitchStmt( location,
449                result,
450                std::vector<ast::ptr<ast::CaseClause>>()
451        );
452
453        for ( const auto & [i, clause] : enumerate( waitfor->clauses ) ) {
454                theSwitch->cases.push_back(
455                        new ast::CaseClause( location,
456                                ast::ConstantExpr::from_ulong( location, i ),
457                                {
458                                        new ast::CompoundStmt( location, {
459                                                clause->stmt,
460                                                new ast::BranchStmt( location,
461                                                        ast::BranchStmt::Break,
462                                                        ast::Label( location )
463                                                )
464                                        })
465                                }
466                        )
467                );
468        }
469
470        if ( waitfor->timeout_stmt ) {
471                theSwitch->cases.push_back(
472                        new ast::CaseClause( location,
473                                ast::ConstantExpr::from_int( location, -2 ),
474                                {
475                                        new ast::CompoundStmt( location, {
476                                                waitfor->timeout_stmt,
477                                                new ast::BranchStmt( location,
478                                                        ast::BranchStmt::Break,
479                                                        ast::Label( location )
480                                                )
481                                        })
482                                }
483                        )
484                );
485        }
486
487        if ( waitfor->else_stmt ) {
488                theSwitch->cases.push_back(
489                        new ast::CaseClause( location,
490                                ast::ConstantExpr::from_int( location, -1 ),
491                                {
492                                        new ast::CompoundStmt( location, {
493                                                waitfor->else_stmt,
494                                                new ast::BranchStmt( location,
495                                                        ast::BranchStmt::Break,
496                                                        ast::Label( location )
497                                                )
498                                        })
499                                }
500                        )
501                );
502        }
503
504        return theSwitch;
505}
506
507void GenerateWaitForCore::previsit( const ast::FunctionDecl * decl ) {
508        if ( "__waitfor_internal" == decl->name ) {
509                decl_waitfor = decl;
510        }
511}
512
513void GenerateWaitForCore::previsit( const ast::StructDecl * decl ) {
514        if ( !decl->body ) {
515                return;
516        } else if ( "__acceptable_t" == decl->name ) {
517                assert( !decl_acceptable );
518                decl_acceptable = decl;
519        } else if ( "__waitfor_mask_t" == decl->name ) {
520                assert( !decl_mask );
521                decl_mask = decl;
522        } else if ( "monitor$" == decl->name ) {
523                assert( !decl_monitor );
524                decl_monitor = decl;
525        }
526}
527
528ast::Stmt * GenerateWaitForCore::postvisit( const ast::WaitForStmt * stmt ) {
529        if ( !decl_monitor || !decl_acceptable || !decl_mask ) {
530                SemanticError( stmt, "waitfor keyword requires monitors to be in scope, add #include <monitor.hfa>" );
531        }
532
533        const CodeLocation & location = stmt->location;
534        ast::CompoundStmt * comp = new ast::CompoundStmt( location );
535
536        ast::ObjectDecl * acceptables = declareAcceptables( comp, location, stmt->clauses.size() );
537        ast::ObjectDecl * flag        = declareFlag( comp, location );
538        ast::Stmt       * setter      = makeSetter( location, flag );
539
540        for ( const auto & [i, clause] : enumerate( stmt->clauses ) ) {
541                init_clause( comp, acceptables, i, clause, setter );
542        }
543
544        ast::Expr * timeout = init_timeout(
545                comp,
546                location,
547                stmt->timeout_time,
548                stmt->timeout_cond,
549                stmt->else_stmt,
550                stmt->else_cond,
551                setter
552        );
553
554        ast::CompoundStmt * compound = new ast::CompoundStmt( location );
555        comp->push_back( new ast::IfStmt( location,
556                new ast::VariableExpr( location, flag ),
557                compound,
558                nullptr
559        ));
560
561        ast::Expr * result = call(
562                compound, location, stmt->clauses.size(), acceptables, timeout );
563        compound->push_back( choose( stmt, result ) );
564        return comp;
565}
566
567} // namespace
568
569void generateWaitFor( ast::TranslationUnit & translationUnit ) {
570        ast::Pass<GenerateWaitForCore>::run( translationUnit );
571}
572
573} // namespace Concurrency
574
575// Local Variables: //
576// tab-width: 4 //
577// mode: c++ //
578// compile-command: "make install" //
579// End: //
Note: See TracBrowser for help on using the repository browser.