source: src/Concurrency/Waitfor.cpp@ 0497b6ba

Last change on this file since 0497b6ba was b6f2e7ab, checked in by Andrew Beach <ajbeach@…>, 12 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.