Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Specialize.cc

    r6c3a988f rb3b2077  
    3232#include "Common/utility.h"
    3333#include "InitTweak/InitTweak.h"
    34 #include "Tuples/Tuples.h"
    3534
    3635namespace GenPoly {
    37         class Specializer;
    38         class Specialize final : public PolyMutator {
    39                 friend class Specializer;
     36        const std::list<Label> noLabels;
     37
     38        class Specialize : public PolyMutator {
    4039          public:
    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;
     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 );
    4545                // virtual Expression * mutate( LogicalExpr *logicalExpr );
    4646                // virtual Expression * mutate( ConditionalExpr *conditionalExpr );
    4747                // virtual Expression * mutate( CommaExpr *commaExpr );
    4848
    49                 Specializer * specializer = nullptr;
     49          private:
     50                Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 );
     51                Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
    5052                void handleExplicitParams( ApplicationExpr *appExpr );
     53
     54                UniqueName thunkNamer;
     55                std::string paramPrefix;
    5156        };
    5257
    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         };
     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        }
    8266
    8367        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
    84         bool PolySpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     68        bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    8569                if ( env ) {
    8670                        using namespace ResolvExpr;
     
    10791
    10892        /// Generates a thunk that calls `actual` with type `funType` and returns its address
    109         Expression * PolySpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
    110                 static UniqueName thunkNamer( "_thunk" );
    111 
     93        Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
    11294                FunctionType *newType = funType->clone();
    11395                if ( env ) {
     96                        TypeSubstitution newEnv( *env );
    11497                        // it is important to replace only occurrences of type variables that occur free in the
    11598                        // thunk's type
    116                         env->applyFree( newType );
     99                        newEnv.applyFree( newType );
    117100                } // if
    118101                // create new thunk with same signature as formal type (C linkage, empty body)
     
    141124                std::list< Statement* > oldStmts;
    142125                oldStmts.splice( oldStmts.end(), stmtsToAdd );
    143                 spec.handleExplicitParams( appExpr );
     126                handleExplicitParams( appExpr );
    144127                paramPrefix = oldParamPrefix;
    145128                // write any statements added for recursive specializations into the thunk body
     
    163146        }
    164147
    165         Expression * Specializer::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
     148        Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
    166149                assertf( actual->has_result(), "attempting to specialize an untyped expression" );
    167150                if ( needsSpecialization( formalType, actual->get_result(), env ) ) {
    168                         if ( FunctionType *funType = getFunctionType( formalType ) ) {
     151                        FunctionType *funType;
     152                        if ( ( funType = getFunctionType( formalType ) ) ) {
    169153                                ApplicationExpr *appExpr;
    170154                                VariableExpr *varExpr;
     
    185169        }
    186170
    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 
    305171        void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) {
    306172                // create thunks for the explicit parameters
     
    311177                std::list< Expression* >::iterator actual;
    312178                for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) {
    313                         *actual = specializer->doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
     179                        *actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
    314180                }
    315181        }
     
    323189                        // don't need to do this for intrinsic calls, because they aren't actually passed
    324190                        for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
    325                                 inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, inferParam->second.inferParams.get() );
     191                                inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
    326192                        }
     193
    327194                        handleExplicitParams( appExpr );
    328195                }
     196
    329197                return appExpr;
    330198        }
     
    333201                addrExpr->get_arg()->acceptMutator( *this );
    334202                assert( addrExpr->has_result() );
    335                 addrExpr->set_arg( specializer->doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
     203                addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
    336204                return addrExpr;
    337205        }
     
    343211                        return castExpr;
    344212                }
    345                 Expression *specialized = specializer->doSpecialization( castExpr->get_result(), castExpr->get_arg() );
     213                Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );
    346214                if ( specialized != castExpr->get_arg() ) {
    347215                        // assume here that the specialization incorporates the cast
     
    367235        //      return commaExpr;
    368236        // }
    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         }
    381237} // namespace GenPoly
    382238
Note: See TracChangeset for help on using the changeset viewer.