source: src/GenPoly/Specialize.cc @ 0f8e4ac

aaron-thesisarm-ehcleanup-dtorsctordeferred_resndemanglergc_noraiijacob/cs343-translationjenkins-sandboxmemorynew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newwith_gc
Last change on this file since 0f8e4ac was 0f8e4ac, checked in by Rob Schluntz <rschlunt@…>, 6 years ago

change Label from a string typedef to a class

  • Property mode set to 100644
File size: 9.0 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// Specialize.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Mon May 18 07:44:20 2015
11// Last Modified By : Rob Schluntz
12// Last Modified On : Thu Apr 28 15:17:45 2016
13// Update Count     : 24
14//
15
16#include <cassert>
17
18#include "Specialize.h"
19#include "GenPoly.h"
20#include "PolyMutator.h"
21
22#include "Parser/ParseNode.h"
23
24#include "SynTree/Expression.h"
25#include "SynTree/Statement.h"
26#include "SynTree/Type.h"
27#include "SynTree/Attribute.h"
28#include "SynTree/TypeSubstitution.h"
29#include "SynTree/Mutator.h"
30#include "ResolvExpr/FindOpenVars.h"
31#include "Common/UniqueName.h"
32#include "Common/utility.h"
33
34namespace GenPoly {
35        const std::list<Label> noLabels;
36
37        class Specialize : public PolyMutator {
38          public:
39                Specialize( std::string paramPrefix = "_p" );
40
41                virtual Expression * mutate( ApplicationExpr *applicationExpr );
42                virtual Expression * mutate( AddressExpr *castExpr );
43                virtual Expression * mutate( CastExpr *castExpr );
44                // virtual Expression * mutate( LogicalExpr *logicalExpr );
45                // virtual Expression * mutate( ConditionalExpr *conditionalExpr );
46                // virtual Expression * mutate( CommaExpr *commaExpr );
47
48          private:
49                Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 );
50                Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
51                void handleExplicitParams( ApplicationExpr *appExpr );
52
53                UniqueName thunkNamer;
54                std::string paramPrefix;
55        };
56
57        void convertSpecializations( std::list< Declaration* >& translationUnit ) {
58                Specialize specializer;
59                mutateAll( translationUnit, specializer );
60        }
61
62        Specialize::Specialize( std::string paramPrefix )
63                : thunkNamer( "_thunk" ), paramPrefix( paramPrefix ) {
64        }
65
66        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
67        bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
68                if ( env ) {
69                        using namespace ResolvExpr;
70                        OpenVarSet openVars, closedVars;
71                        AssertionSet need, have;
72                        findOpenVars( formalType, openVars, closedVars, need, have, false );
73                        findOpenVars( actualType, openVars, closedVars, need, have, true );
74                        for ( OpenVarSet::const_iterator openVar = openVars.begin(); openVar != openVars.end(); ++openVar ) {
75                                Type *boundType = env->lookup( openVar->first );
76                                if ( ! boundType ) continue;
77                                if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( boundType ) ) {
78                                        if ( closedVars.find( typeInst->get_name() ) == closedVars.end() ) {
79                                                return true;
80                                        } // if
81                                } else {
82                                        return true;
83                                } // if
84                        } // for
85                        return false;
86                } else {
87                        return false;
88                } // if
89        }
90
91        /// Generates a thunk that calls `actual` with type `funType` and returns its address
92        Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
93                FunctionType *newType = funType->clone();
94                if ( env ) {
95                        TypeSubstitution newEnv( *env );
96                        // it is important to replace only occurrences of type variables that occur free in the
97                        // thunk's type
98                        newEnv.applyFree( newType );
99                } // if
100                // create new thunk with same signature as formal type (C linkage, empty body)
101                FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( noLabels ), false, false );
102                thunkFunc->fixUniqueId();
103
104                // thunks may be generated and not used - silence warning with attribute
105                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
106
107                // thread thunk parameters into call to actual function, naming thunk parameters as we go
108                UniqueName paramNamer( paramPrefix );
109                ApplicationExpr *appExpr = new ApplicationExpr( actual );
110                for ( std::list< DeclarationWithType* >::iterator param = thunkFunc->get_functionType()->get_parameters().begin(); param != thunkFunc->get_functionType()->get_parameters().end(); ++param ) {
111                        (*param )->set_name( paramNamer.newName() );
112                        appExpr->get_args().push_back( new VariableExpr( *param ) );
113                } // for
114                appExpr->set_env( maybeClone( env ) );
115                if ( inferParams ) {
116                        appExpr->get_inferParams() = *inferParams;
117                } // if
118
119                // handle any specializations that may still be present
120                std::string oldParamPrefix = paramPrefix;
121                paramPrefix += "p";
122                // save stmtsToAdd in oldStmts
123                std::list< Statement* > oldStmts;
124                oldStmts.splice( oldStmts.end(), stmtsToAdd );
125                handleExplicitParams( appExpr );
126                paramPrefix = oldParamPrefix;
127                // write any statements added for recursive specializations into the thunk body
128                thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
129                // restore oldStmts into stmtsToAdd
130                stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
131
132                // add return (or valueless expression) to the thunk
133                Statement *appStmt;
134                if ( funType->get_returnVals().empty() ) {
135                        appStmt = new ExprStmt( noLabels, appExpr );
136                } else {
137                        appStmt = new ReturnStmt( noLabels, appExpr );
138                } // if
139                thunkFunc->get_statements()->get_kids().push_back( appStmt );
140
141                // add thunk definition to queue of statements to add
142                stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
143                // return address of thunk function as replacement expression
144                return new AddressExpr( new VariableExpr( thunkFunc ) );
145        }
146
147        Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
148                assert( ! actual->get_results().empty() ); // using front, should have this assert
149                if ( needsSpecialization( formalType, actual->get_results().front(), env ) ) {
150                        FunctionType *funType;
151                        if ( ( funType = getFunctionType( formalType ) ) ) {
152                                ApplicationExpr *appExpr;
153                                VariableExpr *varExpr;
154                                if ( ( appExpr = dynamic_cast<ApplicationExpr*>( actual ) ) ) {
155                                        return createThunkFunction( funType, appExpr->get_function(), inferParams );
156                                } else if ( ( varExpr = dynamic_cast<VariableExpr*>( actual ) ) ) {
157                                        return createThunkFunction( funType, varExpr, inferParams );
158                                } else {
159                                        // This likely won't work, as anything that could build an ApplicationExpr probably hit one of the previous two branches
160                                        return createThunkFunction( funType, actual, inferParams );
161                                }
162                        } else {
163                                return actual;
164                        } // if
165                } else {
166                        return actual;
167                } // if
168        }
169
170        void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) {
171                // create thunks for the explicit parameters
172                assert( ! appExpr->get_function()->get_results().empty() );
173                FunctionType *function = getFunctionType( appExpr->get_function()->get_results().front() );
174                assert( function );
175                std::list< DeclarationWithType* >::iterator formal;
176                std::list< Expression* >::iterator actual;
177                for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) {
178                        *actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
179                }
180        }
181
182        Expression * Specialize::mutate( ApplicationExpr *appExpr ) {
183                appExpr->get_function()->acceptMutator( *this );
184                mutateAll( appExpr->get_args(), *this );
185
186                // create thunks for the inferred parameters
187                for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
188                        inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
189                }
190
191                handleExplicitParams( appExpr );
192
193                return appExpr;
194        }
195
196        Expression * Specialize::mutate( AddressExpr *addrExpr ) {
197                addrExpr->get_arg()->acceptMutator( *this );
198                assert( ! addrExpr->get_results().empty() );
199                addrExpr->set_arg( doSpecialization( addrExpr->get_results().front(), addrExpr->get_arg() ) );
200                return addrExpr;
201        }
202
203        Expression * Specialize::mutate( CastExpr *castExpr ) {
204                castExpr->get_arg()->acceptMutator( *this );
205                if ( castExpr->get_results().empty() ) {
206                        // can't specialize if we don't have a return value
207                        return castExpr;
208                }
209                Expression *specialized = doSpecialization( castExpr->get_results().front(), castExpr->get_arg() );
210                if ( specialized != castExpr->get_arg() ) {
211                        // assume here that the specialization incorporates the cast
212                        return specialized;
213                } else {
214                        return castExpr;
215                }
216        }
217
218        // Removing these for now. Richard put these in for some reason, but it's not clear why.
219        // In particular, copy constructors produce a comma expression, and with this code the parts
220        // of that comma expression are not specialized, which causes problems.
221
222        // Expression * Specialize::mutate( LogicalExpr *logicalExpr ) {
223        //      return logicalExpr;
224        // }
225
226        // Expression * Specialize::mutate( ConditionalExpr *condExpr ) {
227        //      return condExpr;
228        // }
229
230        // Expression * Specialize::mutate( CommaExpr *commaExpr ) {
231        //      return commaExpr;
232        // }
233} // namespace GenPoly
234
235// Local Variables: //
236// tab-width: 4 //
237// mode: c++ //
238// compile-command: "make install" //
239// End: //
Note: See TracBrowser for help on using the repository browser.