source: src/Concurrency/Actors.cpp @ c042d79

ADTast-experimental
Last change on this file since c042d79 was 3dd8f42, checked in by caparsons <caparson@…>, 19 months ago

added actor support to the compiler

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[3dd8f42]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
76        void postvisit( const FunctionDecl * decl ) {
77        // return if not of the form receive( param1, param2 )
78        if ( decl->name != "receive" || decl->params.size() != 2 ) return;
79
80        // the params should be references
81        const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
82        const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
83        if ( !derivedActorRef || !derivedMsgRef ) return;
84
85        // the references should be to struct instances
86        const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
87        const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
88        if ( !arg1InstType || !arg2InstType ) return;
89
90        // If the struct instances are derived actor and message types then generate the message send routine
91        if ( actorStructDecls.count( arg1InstType->aggr() ) && messageStructDecls.count( arg2InstType->aggr() ) ) {
92
93            // check that we have found all the decls we need from <actor.hfa>
94            if ( !*allocationDecl || !*requestDecl ) 
95                SemanticError( decl->location, "using actors requires a header, add #include <actor.hfa>\n" );
96
97            //////////////////////////////////////////////////////////////////////
98            // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
99            /*
100                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
101                    request * new_req = alloc();
102                    Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
103                    __receive_fn fn = (__receive_fn)my_work_fn;
104                    (*new_req){ &receiver, &msg, fn };
105                    send( receiver, *new_req );
106                    return receiver;
107                }
108            */
109            CompoundStmt * sendBody = new CompoundStmt( decl->location );
110
111            // Generates: request * new_req = alloc();
112            sendBody->push_back( new DeclStmt(
113                decl->location,
114                new ObjectDecl(
115                    decl->location,
116                    "new_req",
117                    new PointerType( new StructInstType( *requestDecl ) ),
118                    new SingleInit( decl->location, new UntypedExpr( decl->location, new NameExpr( decl->location, "alloc" ), {} ) )
119                )
120            ));
121           
122            // Function type is: Allocation (*)( derived_actor &, derived_msg & )
123            FunctionType * derivedReceive = new FunctionType();
124            derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
125            derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
126            derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
127
128            // Generates: Allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
129            sendBody->push_back( new DeclStmt(
130                decl->location,
131                new ObjectDecl(
132                    decl->location,
133                    "my_work_fn",
134                    new PointerType( derivedReceive ),
135                    new SingleInit( decl->location, new NameExpr( decl->location, "receive" ) )
136                )
137            ));
138
139            // Function type is: Allocation (*)( actor &, messsage & )
140            FunctionType * genericReceive = new FunctionType();
141            genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
142            genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
143            genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
144
145            // Generates: Allocation (*fn)( actor &, messsage & ) = (Allocation (*)( actor &, messsage & ))my_work_fn;
146            // More readable synonymous code:
147            //     typedef Allocation (*__receive_fn)(actor &, message &);
148            //     __receive_fn fn = (__receive_fn)my_work_fn;
149            sendBody->push_back( new DeclStmt(
150                decl->location,
151                new ObjectDecl(
152                    decl->location,
153                    "fn",
154                    new PointerType( genericReceive ),
155                    new SingleInit( decl->location, 
156                        new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
157                    )
158                )
159            ));
160
161            // Generates: (*new_req){ &receiver, &msg, fn };
162            sendBody->push_back( new ExprStmt(
163                decl->location,
164                                new UntypedExpr (
165                    decl->location, 
166                                        new NameExpr( decl->location, "?{}" ),
167                                        {
168                                                new UntypedExpr( decl->location, new NameExpr( decl->location, "*?" ), {  new NameExpr( decl->location, "new_req" ) } ),
169                        new AddressExpr( new NameExpr( decl->location, "receiver" ) ),
170                        new AddressExpr( new NameExpr( decl->location, "msg" ) ),
171                        new NameExpr( decl->location, "fn" )
172                                        }
173                                )
174                        ));
175
176            // Generates: send( receiver, *new_req );
177            sendBody->push_back( new ExprStmt(
178                decl->location,
179                                new UntypedExpr (
180                    decl->location,
181                                        new NameExpr( decl->location, "send" ),
182                                        {
183                                                {
184                            new NameExpr( decl->location, "receiver" ),
185                            new UntypedExpr( decl->location, new NameExpr( decl->location, "*?" ), {  new NameExpr( decl->location, "new_req" ) } )
186                        }
187                                        }
188                                )
189                        ));
190           
191            // Generates: return receiver;
192            sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
193
194            // put it all together into the complete function decl from above
195            declsToAddAfter.push_back( new FunctionDecl(
196                decl->location,
197                "?|?",
198                {},                     // forall
199                {
200                    new ObjectDecl(
201                        decl->location,
202                        "receiver",
203                        ast::deepCopy( derivedActorRef )
204                    ),
205                    new ObjectDecl(
206                        decl->location,
207                        "msg",
208                        ast::deepCopy( derivedMsgRef )
209                    )
210                },                      // params
211                { 
212                    new ObjectDecl(
213                        decl->location,
214                        "receiver_ret",
215                        ast::deepCopy( derivedActorRef )
216                    )
217                },
218                sendBody,               // body
219                { Storage::Static },    // storage
220                Linkage::Cforall,       // linkage
221                {},                     // attributes
222                { Function::Inline }
223            ));
224        }
225        }
226
227  public:
228    GenReceiveDecls( std::map<const StructDecl *, int> & actorStructDecls, std::map<const StructDecl *, int> & messageStructDecls,
229        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl ) 
230        : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ), 
231        allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
232};
233
234void implementActors( TranslationUnit & translationUnit ) {
235    // maps to collect all derived actor and message types
236    std::map<const StructDecl *, int> actorStructDecls;
237    std::map<const StructDecl *, int> messageStructDecls;
238
239    // for setting through the passes
240    const StructDecl * requestDeclPtr = nullptr;
241    const EnumDecl * allocationDeclPtr = nullptr;
242    const StructDecl * actorDeclPtr = nullptr;
243    const StructDecl * msgDeclPtr = nullptr;
244
245    // double pointer to modify local ptrs above
246    const StructDecl ** requestDecl = &requestDeclPtr;
247    const EnumDecl ** allocationDecl = &allocationDeclPtr;
248    const StructDecl ** actorDecl = &actorDeclPtr;
249    const StructDecl ** msgDecl = &msgDeclPtr;
250
251    // first pass collects ptrs to Allocation enum, request type, and generic receive fn typedef
252    // also populates maps of all derived actors and messages
253    Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, 
254        allocationDecl, actorDecl, msgDecl );
255       
256    // second pass locates all receive() routines that overload the generic receive fn
257    // it then generates the appropriate operator '|' send routines for the receive routines
258    Pass<GenReceiveDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl, 
259        allocationDecl, actorDecl, msgDecl );
260}
261
262
263} // namespace Concurrency
264
265// Local Variables: //
266// tab-width: 4 //
267// mode: c++ //
268// compile-command: "make install" //
269// End: //
270
Note: See TracBrowser for help on using the repository browser.