Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Specialize.cc

    rb3b2077 r6c3a988f  
    3232#include "Common/utility.h"
    3333#include "InitTweak/InitTweak.h"
     34#include "Tuples/Tuples.h"
    3435
    3536namespace GenPoly {
    36         const std::list<Label> noLabels;
    37 
    38         class Specialize : public PolyMutator {
     37        class Specializer;
     38        class Specialize final : public PolyMutator {
     39                friend class Specializer;
    3940          public:
    40                 Specialize( std::string paramPrefix = "_p" );
    41 
    42                 virtual Expression * mutate( ApplicationExpr *applicationExpr );
    43                 virtual Expression * mutate( AddressExpr *castExpr );
    44                 virtual Expression * mutate( CastExpr *castExpr );
     41                using PolyMutator::mutate;
     42                virtual Expression * mutate( ApplicationExpr *applicationExpr ) override;
     43                virtual Expression * mutate( AddressExpr *castExpr ) override;
     44                virtual Expression * mutate( CastExpr *castExpr ) override;
    4545                // virtual Expression * mutate( LogicalExpr *logicalExpr );
    4646                // virtual Expression * mutate( ConditionalExpr *conditionalExpr );
    4747                // virtual Expression * mutate( CommaExpr *commaExpr );
    4848
    49           private:
    50                 Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 );
    51                 Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
     49                Specializer * specializer = nullptr;
    5250                void handleExplicitParams( ApplicationExpr *appExpr );
    53 
    54                 UniqueName thunkNamer;
    55                 std::string paramPrefix;
    5651        };
    5752
    58         void convertSpecializations( std::list< Declaration* >& translationUnit ) {
    59                 Specialize specializer;
    60                 mutateAll( translationUnit, specializer );
    61         }
    62 
    63         Specialize::Specialize( std::string paramPrefix )
    64                 : thunkNamer( "_thunk" ), paramPrefix( paramPrefix ) {
    65         }
     53        class Specializer {
     54          public:
     55                Specializer( Specialize & spec ) : spec( spec ), env( spec.env ), stmtsToAdd( spec.stmtsToAdd ) {}
     56                virtual bool needsSpecialization( Type * formalType, Type * actualType, TypeSubstitution * env ) = 0;
     57                virtual Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) = 0;
     58                virtual Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
     59
     60          protected:
     61                Specialize & spec;
     62                std::string paramPrefix = "_p";
     63                TypeSubstitution *& env;
     64                std::list< Statement * > & stmtsToAdd;
     65        };
     66
     67        // for normal polymorphic -> monomorphic function conversion
     68        class PolySpecializer : public Specializer {
     69          public:
     70                PolySpecializer( Specialize & spec ) : Specializer( spec ) {}
     71                virtual bool needsSpecialization( Type * formalType, Type * actualType, TypeSubstitution * env ) override;
     72                virtual Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) override;
     73        };
     74
     75        // // for tuple -> non-tuple function conversion
     76        class TupleSpecializer : public Specializer {
     77          public:
     78                TupleSpecializer( Specialize & spec ) : Specializer( spec ) {}
     79                virtual bool needsSpecialization( Type * formalType, Type * actualType, TypeSubstitution * env ) override;
     80                virtual Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) override;
     81        };
    6682
    6783        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
    68         bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     84        bool PolySpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    6985                if ( env ) {
    7086                        using namespace ResolvExpr;
     
    91107
    92108        /// Generates a thunk that calls `actual` with type `funType` and returns its address
    93         Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     109        Expression * PolySpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     110                static UniqueName thunkNamer( "_thunk" );
     111
    94112                FunctionType *newType = funType->clone();
    95113                if ( env ) {
    96                         TypeSubstitution newEnv( *env );
    97114                        // it is important to replace only occurrences of type variables that occur free in the
    98115                        // thunk's type
    99                         newEnv.applyFree( newType );
     116                        env->applyFree( newType );
    100117                } // if
    101118                // create new thunk with same signature as formal type (C linkage, empty body)
     
    124141                std::list< Statement* > oldStmts;
    125142                oldStmts.splice( oldStmts.end(), stmtsToAdd );
    126                 handleExplicitParams( appExpr );
     143                spec.handleExplicitParams( appExpr );
    127144                paramPrefix = oldParamPrefix;
    128145                // write any statements added for recursive specializations into the thunk body
     
    146163        }
    147164
    148         Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
     165        Expression * Specializer::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
    149166                assertf( actual->has_result(), "attempting to specialize an untyped expression" );
    150167                if ( needsSpecialization( formalType, actual->get_result(), env ) ) {
    151                         FunctionType *funType;
    152                         if ( ( funType = getFunctionType( formalType ) ) ) {
     168                        if ( FunctionType *funType = getFunctionType( formalType ) ) {
    153169                                ApplicationExpr *appExpr;
    154170                                VariableExpr *varExpr;
     
    169185        }
    170186
     187        bool TupleSpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     188                if ( FunctionType * ftype = getFunctionType( formalType ) ) {
     189                        return ftype->isTtype();
     190                }
     191                return false;
     192        }
     193
     194        /// restructures arg to match the structure of a single formal parameter. Assumes that atomic types are compatible (as the Resolver should have ensured this)
     195        template< typename OutIterator >
     196        void matchOneFormal( Expression * arg, unsigned & idx, Type * formal, OutIterator out ) {
     197                if ( TupleType * tupleType = dynamic_cast< TupleType * >( formal ) ) {
     198                        std::list< Expression * > exprs;
     199                        for ( Type * t : *tupleType ) {
     200                                matchOneFormal( arg, idx, t, back_inserter( exprs ) );
     201                        }
     202                        *out++ = new TupleExpr( exprs );
     203                } else {
     204                        *out++ = new TupleIndexExpr( arg->clone(), idx++ );
     205                }
     206        }
     207
     208        /// restructures the ttype argument to match the structure of the formal parameters of the actual function.
     209        // [begin, end) are the formal parameters.
     210        // args is the list of arguments currently given to the actual function, the last of which needs to be restructured.
     211        template< typename Iterator, typename OutIterator >
     212        void fixLastArg( Expression * last, Iterator begin, Iterator end, OutIterator out ) {
     213                // safe_dynamic_cast for the assertion
     214                safe_dynamic_cast< TupleType * >( last->get_result() );
     215                unsigned idx = 0;
     216                for ( ; begin != end; ++begin ) {
     217                        DeclarationWithType * formal = *begin;
     218                        Type * formalType = formal->get_type();
     219                        matchOneFormal( last, idx, formalType, out );
     220                }
     221                delete last;
     222        }
     223
     224        Expression * TupleSpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     225                static UniqueName thunkNamer( "_tupleThunk" );
     226
     227                FunctionType *newType = funType->clone();
     228                if ( env ) {
     229                        // it is important to replace only occurrences of type variables that occur free in the
     230                        // thunk's type
     231                        env->applyFree( newType );
     232                } // if
     233                // create new thunk with same signature as formal type (C linkage, empty body)
     234                FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( noLabels ), false, false );
     235                thunkFunc->fixUniqueId();
     236
     237                // thunks may be generated and not used - silence warning with attribute
     238                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
     239
     240                // thread thunk parameters into call to actual function, naming thunk parameters as we go
     241                UniqueName paramNamer( paramPrefix );
     242                ApplicationExpr *appExpr = new ApplicationExpr( actual );
     243
     244                FunctionType * actualType = getFunctionType( actual->get_result() )->clone();
     245                if ( env ) {
     246                        // need to apply the environment to the actual function's type, since it may itself be polymorphic
     247                        env->apply( actualType );
     248                }
     249                std::unique_ptr< FunctionType > actualTypeManager( actualType ); // for RAII
     250                std::list< DeclarationWithType * >::iterator actualBegin = actualType->get_parameters().begin();
     251                std::list< DeclarationWithType * >::iterator actualEnd = actualType->get_parameters().end();
     252                std::list< DeclarationWithType * >::iterator formalBegin = funType->get_parameters().begin();
     253                std::list< DeclarationWithType * >::iterator formalEnd = funType->get_parameters().end();
     254
     255                Expression * last = nullptr;
     256                for ( DeclarationWithType* param : thunkFunc->get_functionType()->get_parameters() ) {
     257                        // walk the parameters to the actual function alongside the parameters to the thunk to find the location where the ttype parameter begins to satisfy parameters in the actual function.
     258                        param->set_name( paramNamer.newName() );
     259                        assertf( formalBegin != formalEnd, "Reached end of formal parameters before finding ttype parameter" );
     260                        if ( Tuples::isTtype((*formalBegin)->get_type()) ) {
     261                                last = new VariableExpr( param );
     262                                break;
     263                        }
     264                        assertf( actualBegin != actualEnd, "reached end of actual function's arguments before finding ttype parameter" );
     265                        ++actualBegin;
     266                        ++formalBegin;
     267
     268                        appExpr->get_args().push_back( new VariableExpr( param ) );
     269                } // for
     270                assert( last );
     271                fixLastArg( last, actualBegin, actualEnd, back_inserter( appExpr->get_args() ) );
     272                appExpr->set_env( maybeClone( env ) );
     273                if ( inferParams ) {
     274                        appExpr->get_inferParams() = *inferParams;
     275                } // if
     276
     277                // handle any specializations that may still be present
     278                std::string oldParamPrefix = paramPrefix;
     279                paramPrefix += "p";
     280                // save stmtsToAdd in oldStmts
     281                std::list< Statement* > oldStmts;
     282                oldStmts.splice( oldStmts.end(), stmtsToAdd );
     283                spec.mutate( appExpr );
     284                paramPrefix = oldParamPrefix;
     285                // write any statements added for recursive specializations into the thunk body
     286                thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
     287                // restore oldStmts into stmtsToAdd
     288                stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
     289
     290                // add return (or valueless expression) to the thunk
     291                Statement *appStmt;
     292                if ( funType->get_returnVals().empty() ) {
     293                        appStmt = new ExprStmt( noLabels, appExpr );
     294                } else {
     295                        appStmt = new ReturnStmt( noLabels, appExpr );
     296                } // if
     297                thunkFunc->get_statements()->get_kids().push_back( appStmt );
     298
     299                // add thunk definition to queue of statements to add
     300                stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
     301                // return address of thunk function as replacement expression
     302                return new AddressExpr( new VariableExpr( thunkFunc ) );
     303        }
     304
    171305        void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) {
    172306                // create thunks for the explicit parameters
     
    177311                std::list< Expression* >::iterator actual;
    178312                for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) {
    179                         *actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
     313                        *actual = specializer->doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
    180314                }
    181315        }
     
    189323                        // don't need to do this for intrinsic calls, because they aren't actually passed
    190324                        for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
    191                                 inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
     325                                inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, inferParam->second.inferParams.get() );
    192326                        }
    193 
    194327                        handleExplicitParams( appExpr );
    195328                }
    196 
    197329                return appExpr;
    198330        }
     
    201333                addrExpr->get_arg()->acceptMutator( *this );
    202334                assert( addrExpr->has_result() );
    203                 addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
     335                addrExpr->set_arg( specializer->doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
    204336                return addrExpr;
    205337        }
     
    211343                        return castExpr;
    212344                }
    213                 Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );
     345                Expression *specialized = specializer->doSpecialization( castExpr->get_result(), castExpr->get_arg() );
    214346                if ( specialized != castExpr->get_arg() ) {
    215347                        // assume here that the specialization incorporates the cast
     
    235367        //      return commaExpr;
    236368        // }
     369
     370        void convertSpecializations( std::list< Declaration* >& translationUnit ) {
     371                Specialize spec;
     372
     373                TupleSpecializer tupleSpec( spec );
     374                spec.specializer = &tupleSpec;
     375                mutateAll( translationUnit, spec );
     376
     377                PolySpecializer polySpec( spec );
     378                spec.specializer = &polySpec;
     379                mutateAll( translationUnit, spec );
     380        }
    237381} // namespace GenPoly
    238382
Note: See TracChangeset for help on using the changeset viewer.