source: src/Concurrency/Actors.cpp@ 8728104

ADT ast-experimental
Last change on this file since 8728104 was 34ed17b, checked in by caparsons <caparson@…>, 3 years ago

Fixed decl before use issue with actors sending messages to other actors

  • Property mode set to 100644
File size: 14.1 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 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// Actors.cpp -- generate code needed by the actor system
8//
9// Author : Colby Parsons
10// Created On : Thurs Jan 19 15:34:00 2023
11// Last Modified By : Colby Parsons
12// Last Modified On : Thurs Jan 19 15:34:00 2023
13// Update Count : 0
14//
15
16#include "AST/Print.hpp"
17#include "AST/Decl.hpp"
18#include "AST/Pass.hpp"
19#include "AST/Type.hpp"
20#include "AST/Stmt.hpp"
21#include "AST/TranslationUnit.hpp"
22#include "AST/Expr.hpp"
23using namespace ast;
24
25namespace Concurrency {
26
27struct CollectactorStructDecls : public ast::WithGuards {
28 std::map<const StructDecl *, int> & actorStructDecls;
29 std::map<const StructDecl *, int> & messageStructDecls;
30 const StructDecl ** requestDecl;
31 const EnumDecl ** allocationDecl;
32 const StructDecl ** actorDecl;
33 const StructDecl ** msgDecl;
34 StructDecl * parentDecl;
35 bool insideStruct = false;
36
37 void previsit( const EnumDecl * decl ) {
38 if( decl->name == "Allocation" ) *allocationDecl = decl;
39 }
40
41 void previsit( const StructDecl * decl ) {
42 GuardValue(insideStruct);
43 insideStruct = true;
44 parentDecl = mutate( decl );
45 if( decl->name == "actor" ) *actorDecl = decl;
46 if( decl->name == "message" ) *msgDecl = decl;
47 if( decl->name == "request" ) *requestDecl = decl;
48 }
49
50 void postvisit( const StructInstType * node ) {
51 if ( ! *actorDecl || ! *msgDecl ) return;
52 if ( insideStruct ) {
53 if ( node->aggr() == *actorDecl ) {
54 actorStructDecls.insert({parentDecl, 1});
55 } else if ( node->aggr() == *msgDecl ) {
56 messageStructDecls.insert({parentDecl, 1});
57 }
58 }
59 }
60
61 public:
62 CollectactorStructDecls( std::map<const StructDecl *, int> & actorStructDecls, std::map<const StructDecl *, int> & messageStructDecls,
63 const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl )
64 : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ),
65 allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
66};
67
68struct GenReceiveDecls : public ast::WithDeclsToAdd<> {
69 std::map<const StructDecl *, int> & actorStructDecls;
70 std::map<const StructDecl *, int> & messageStructDecls;
71 const StructDecl ** requestDecl;
72 const EnumDecl ** allocationDecl;
73 const StructDecl ** actorDecl;
74 const StructDecl ** msgDecl;
75 std::vector<FunctionDecl *> & forwardDecls;
76
77 void postvisit( const FunctionDecl * decl ) {
78 // return if not of the form receive( param1, param2 ) or if it is a forward decl
79 if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
80
81 // the params should be references
82 const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
83 const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
84 if ( !derivedActorRef || !derivedMsgRef ) return;
85
86 // the references should be to struct instances
87 const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
88 const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
89 if ( !arg1InstType || !arg2InstType ) return;
90
91 // If the struct instances are derived actor and message types then generate the message send routine
92 if ( actorStructDecls.count( arg1InstType->aggr() ) && messageStructDecls.count( arg2InstType->aggr() ) ) {
93
94 // check that we have found all the decls we need from <actor.hfa>
95 if ( !*allocationDecl || !*requestDecl )
96 SemanticError( decl->location, "using actors requires a header, add #include <actor.hfa>\n" );
97
98 //////////////////////////////////////////////////////////////////////
99 // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
100 /*
101 static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
102 request * new_req = alloc();
103 Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
104 __receive_fn fn = (__receive_fn)my_work_fn;
105 (*new_req){ &receiver, &msg, fn };
106 send( receiver, *new_req );
107 return receiver;
108 }
109 */
110 CompoundStmt * sendBody = new CompoundStmt( decl->location );
111
112 // Generates: request * new_req = alloc();
113 sendBody->push_back( new DeclStmt(
114 decl->location,
115 new ObjectDecl(
116 decl->location,
117 "new_req",
118 new PointerType( new StructInstType( *requestDecl ) ),
119 new SingleInit( decl->location, new UntypedExpr( decl->location, new NameExpr( decl->location, "alloc" ), {} ) )
120 )
121 ));
122
123 // Function type is: Allocation (*)( derived_actor &, derived_msg & )
124 FunctionType * derivedReceive = new FunctionType();
125 derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
126 derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
127 derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
128
129 // Generates: Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
130 sendBody->push_back( new DeclStmt(
131 decl->location,
132 new ObjectDecl(
133 decl->location,
134 "my_work_fn",
135 new PointerType( derivedReceive ),
136 new SingleInit( decl->location, new NameExpr( decl->location, "receive" ) )
137 )
138 ));
139
140 // Function type is: Allocation (*)( actor &, messsage & )
141 FunctionType * genericReceive = new FunctionType();
142 genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
143 genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
144 genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
145
146 // Generates: Allocation (*fn)( actor &, messsage & ) = (Allocation (*)( actor &, messsage & ))my_work_fn;
147 // More readable synonymous code:
148 // typedef Allocation (*__receive_fn)(actor &, message &);
149 // __receive_fn fn = (__receive_fn)my_work_fn;
150 sendBody->push_back( new DeclStmt(
151 decl->location,
152 new ObjectDecl(
153 decl->location,
154 "fn",
155 new PointerType( genericReceive ),
156 new SingleInit( decl->location,
157 new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
158 )
159 )
160 ));
161
162 // Generates: (*new_req){ &receiver, &msg, fn };
163 sendBody->push_back( new ExprStmt(
164 decl->location,
165 new UntypedExpr (
166 decl->location,
167 new NameExpr( decl->location, "?{}" ),
168 {
169 new UntypedExpr( decl->location, new NameExpr( decl->location, "*?" ), { new NameExpr( decl->location, "new_req" ) } ),
170 new AddressExpr( new NameExpr( decl->location, "receiver" ) ),
171 new AddressExpr( new NameExpr( decl->location, "msg" ) ),
172 new NameExpr( decl->location, "fn" )
173 }
174 )
175 ));
176
177 // Generates: send( receiver, *new_req );
178 sendBody->push_back( new ExprStmt(
179 decl->location,
180 new UntypedExpr (
181 decl->location,
182 new NameExpr( decl->location, "send" ),
183 {
184 {
185 new NameExpr( decl->location, "receiver" ),
186 new UntypedExpr( decl->location, new NameExpr( decl->location, "*?" ), { new NameExpr( decl->location, "new_req" ) } )
187 }
188 }
189 )
190 ));
191
192 // Generates: return receiver;
193 sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
194
195 // put it all together into the complete function decl from above
196 FunctionDecl * sendOperatorFunction = new FunctionDecl(
197 decl->location,
198 "?|?",
199 {}, // forall
200 {
201 new ObjectDecl(
202 decl->location,
203 "receiver",
204 ast::deepCopy( derivedActorRef )
205 ),
206 new ObjectDecl(
207 decl->location,
208 "msg",
209 ast::deepCopy( derivedMsgRef )
210 )
211 }, // params
212 {
213 new ObjectDecl(
214 decl->location,
215 "receiver_ret",
216 ast::deepCopy( derivedActorRef )
217 )
218 },
219 nullptr, // body
220 { Storage::Static }, // storage
221 Linkage::Cforall, // linkage
222 {}, // attributes
223 { Function::Inline }
224 );
225
226 // forward decls to resolve use before decl problem for '|' routines
227 forwardDecls.push_back( ast::deepCopy( sendOperatorFunction ) );
228
229 sendOperatorFunction->stmts = sendBody;
230 declsToAddAfter.push_back( sendOperatorFunction );
231 }
232 }
233
234 public:
235 GenReceiveDecls( std::map<const StructDecl *, int> & actorStructDecls, std::map<const StructDecl *, int> & messageStructDecls,
236 const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
237 std::vector<FunctionDecl *> & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
238 requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
239};
240
241struct GenFwdDecls : public ast::WithDeclsToAdd<> {
242 std::map<const StructDecl *, int> & actorStructDecls;
243 std::map<const StructDecl *, int> & messageStructDecls;
244 std::vector<FunctionDecl *> & forwardDecls;
245 bool done;
246
247 void postvisit( const FunctionDecl * decl ) {
248 if ( done ) return;
249 // return if not of the form receive( param1, param2 ) or if it is a forward decl
250 if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
251
252 // the params should be references
253 const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
254 const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
255 if ( !derivedActorRef || !derivedMsgRef ) return;
256
257 // the references should be to struct instances
258 const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
259 const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
260 if ( !arg1InstType || !arg2InstType ) return;
261
262 // If the struct instances are derived actor and message types then generate the message send routine
263 if ( actorStructDecls.count( arg1InstType->aggr() ) && messageStructDecls.count( arg2InstType->aggr() ) ) {
264 done = true;
265 for ( const auto & func : forwardDecls ) {
266 declsToAddBefore.push_back( func );
267 }
268 }
269 }
270
271 public:
272 GenFwdDecls( std::map<const StructDecl *, int> & actorStructDecls, std::map<const StructDecl *, int> & messageStructDecls,
273 std::vector<FunctionDecl *> & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
274 forwardDecls(forwardDecls), done(false) {}
275};
276
277void implementActors( TranslationUnit & translationUnit ) {
278 // maps to collect all derived actor and message types
279 std::map<const StructDecl *, int> actorStructDecls;
280 std::map<const StructDecl *, int> messageStructDecls;
281 std::vector<FunctionDecl *> forwardDecls;
282
283 // for storing through the passes
284 // these are populated with various important struct decls
285 const StructDecl * requestDeclPtr = nullptr;
286 const EnumDecl * allocationDeclPtr = nullptr;
287 const StructDecl * actorDeclPtr = nullptr;
288 const StructDecl * msgDeclPtr = nullptr;
289
290 // double pointer to modify local ptrs above
291 const StructDecl ** requestDecl = &requestDeclPtr;
292 const EnumDecl ** allocationDecl = &allocationDeclPtr;
293 const StructDecl ** actorDecl = &actorDeclPtr;
294 const StructDecl ** msgDecl = &msgDeclPtr;
295
296 // first pass collects ptrs to Allocation enum, request type, and generic receive fn typedef
297 // also populates maps of all derived actors and messages
298 Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
299 allocationDecl, actorDecl, msgDecl );
300
301 // second pass locates all receive() routines that overload the generic receive fn
302 // it then generates the appropriate operator '|' send routines for the receive routines
303 Pass<GenReceiveDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
304 allocationDecl, actorDecl, msgDecl, forwardDecls );
305
306 // The third pass forward declares operator '|' send routines
307 Pass<GenFwdDecls>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
308}
309
310
311} // namespace Concurrency
312
313// Local Variables: //
314// tab-width: 4 //
315// mode: c++ //
316// compile-command: "make install" //
317// End: //
318
Note: See TracBrowser for help on using the repository browser.