source: src/Concurrency/Actors.cpp @ 8a97248

ADTast-experimental
Last change on this file since 8a97248 was 34ed17b, checked in by caparsons <caparson@…>, 17 months 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.