Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Specialize.cc

    r8cbf8cd r698664b3  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Tue Sep 22 14:04:13 2015
    13 // Update Count     : 15
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jun 13 15:54:07 2015
     13// Update Count     : 6
    1414//
    1515
     
    4545
    4646          private:
     47                Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 );
    4748                Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
    4849                void handleExplicitParams( ApplicationExpr *appExpr );
     
    6162        }
    6263
     64        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
    6365        bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    6466                if ( env ) {
     
    8587        }
    8688
     89        /// Returns a pointer to the base FunctionType if ty is the type of a function (or pointer to one), NULL otherwise
     90        FunctionType * getFunctionType( Type *ty ) {
     91                PointerType *ptrType;
     92                if ( ( ptrType = dynamic_cast< PointerType* >( ty ) ) ) {
     93                        return dynamic_cast< FunctionType* >( ptrType->get_base() ); // pointer if FunctionType, NULL otherwise
     94                } else {
     95                        return dynamic_cast< FunctionType* >( ty ); // pointer if FunctionType, NULL otherwise
     96                }
     97        }
     98
     99        /// Generates a thunk that calls `actual` with type `funType` and returns its address
     100        Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     101                FunctionType *newType = funType->clone();
     102                if ( env ) {
     103                        TypeSubstitution newEnv( *env );
     104                        // it is important to replace only occurrences of type variables that occur free in the
     105                        // thunk's type
     106                        newEnv.applyFree( newType );
     107                } // if
     108                // create new thunk with same signature as formal type (C linkage, empty body)
     109                FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( std::list< std::string >() ), false, false );
     110                thunkFunc->fixUniqueId();
     111
     112                // thread thunk parameters into call to actual function, naming thunk parameters as we go
     113                UniqueName paramNamer( paramPrefix );
     114                ApplicationExpr *appExpr = new ApplicationExpr( actual );
     115                for ( std::list< DeclarationWithType* >::iterator param = thunkFunc->get_functionType()->get_parameters().begin(); param != thunkFunc->get_functionType()->get_parameters().end(); ++param ) {
     116                        (*param )->set_name( paramNamer.newName() );
     117                        appExpr->get_args().push_back( new VariableExpr( *param ) );
     118                } // for
     119                appExpr->set_env( maybeClone( env ) );
     120                if ( inferParams ) {
     121                        appExpr->get_inferParams() = *inferParams;
     122                } // if
     123
     124                // handle any specializations that may still be present
     125                std::string oldParamPrefix = paramPrefix;
     126                paramPrefix += "p";
     127                // save stmtsToAdd in oldStmts
     128                std::list< Statement* > oldStmts;
     129                oldStmts.splice( oldStmts.end(), stmtsToAdd );
     130                handleExplicitParams( appExpr );
     131                paramPrefix = oldParamPrefix;
     132                // write any statements added for recursive specializations into the thunk body
     133                thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
     134                // restore oldStmts into stmtsToAdd
     135                stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
     136
     137                // add return (or valueless expression) to the thunk
     138                Statement *appStmt;
     139                if ( funType->get_returnVals().empty() ) {
     140                        appStmt = new ExprStmt( noLabels, appExpr );
     141                } else {
     142                        appStmt = new ReturnStmt( noLabels, appExpr );
     143                } // if
     144                thunkFunc->get_statements()->get_kids().push_back( appStmt );
     145
     146                // add thunk definition to queue of statements to add
     147                stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
     148                // return address of thunk function as replacement expression
     149                return new AddressExpr( new VariableExpr( thunkFunc ) );
     150        }
     151       
    87152        Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
    88                 assert( ! actual->get_results().empty() );
    89153                if ( needsSpecialization( formalType, actual->get_results().front(), env ) ) {
    90                         PointerType *ptrType;
    91154                        FunctionType *funType;
    92                         if ( ( ptrType = dynamic_cast< PointerType* >( formalType ) ) && ( funType = dynamic_cast< FunctionType* >( ptrType->get_base() ) ) ) {
    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                                 FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( std::list< std::string >() ), false, false );
    101                                 thunkFunc->fixUniqueId();
    102 
    103                                 UniqueName paramNamer( paramPrefix );
    104                                 ApplicationExpr *appExpr = new ApplicationExpr( actual );
    105                                 for ( std::list< DeclarationWithType* >::iterator param = thunkFunc->get_functionType()->get_parameters().begin(); param != thunkFunc->get_functionType()->get_parameters().end(); ++param ) {
    106                                         (*param )->set_name( paramNamer.newName() );
    107                                         appExpr->get_args().push_back( new VariableExpr( *param ) );
    108                                 } // for
    109                                 appExpr->set_env( maybeClone( env ) );
    110                                 if ( inferParams ) {
    111                                         appExpr->get_inferParams() = *inferParams;
    112                                 } // if
    113 
    114                                 // handle any specializations that may still be present
    115                                 std::string oldParamPrefix = paramPrefix;
    116                                 paramPrefix += "p";
    117                                 std::list< Statement* > oldStmts;
    118                                 oldStmts.splice( oldStmts.end(), stmtsToAdd );
    119                                 handleExplicitParams( appExpr );
    120                                 paramPrefix = oldParamPrefix;
    121                                 thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
    122                                 stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
    123 
    124                                 Statement *appStmt;
    125                                 if ( funType->get_returnVals().empty() ) {
    126                                         appStmt = new ExprStmt( noLabels, appExpr );
     155                        if ( ( funType = getFunctionType( formalType ) ) ) {
     156                                ApplicationExpr *appExpr;
     157                                VariableExpr *varExpr;
     158                                if ( ( appExpr = dynamic_cast<ApplicationExpr*>( actual ) ) ) {
     159                                        return createThunkFunction( funType, appExpr->get_function(), inferParams );
     160                                } else if ( ( varExpr = dynamic_cast<VariableExpr*>( actual ) ) ) {
     161                                        return createThunkFunction( funType, varExpr, inferParams );
    127162                                } else {
    128                                         appStmt = new ReturnStmt( noLabels, appExpr );
    129                                 } // if
    130                                 thunkFunc->get_statements()->get_kids().push_back( appStmt );
    131                                 stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
    132                                 return new AddressExpr( new VariableExpr( thunkFunc ) );
     163                                        // This likely won't work, as anything that could build an ApplicationExpr probably hit one of the previous two branches
     164                                        return createThunkFunction( funType, actual, inferParams );
     165                                }
    133166                        } else {
    134167                                return actual;
     
    142175                // create thunks for the explicit parameters
    143176                assert( ! appExpr->get_function()->get_results().empty() );
    144                 PointerType *pointer = dynamic_cast< PointerType* >( appExpr->get_function()->get_results().front() );
    145                 assert( pointer );
    146                 FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() );
     177                FunctionType *function = getFunctionType( appExpr->get_function()->get_results().front() );
     178                assert( function );
    147179                std::list< DeclarationWithType* >::iterator formal;
    148180                std::list< Expression* >::iterator actual;
     
    168200        Expression * Specialize::mutate( AddressExpr *addrExpr ) {
    169201                addrExpr->get_arg()->acceptMutator( *this );
    170                 assert( ! addrExpr->get_results().empty() );
    171202                addrExpr->set_arg( doSpecialization( addrExpr->get_results().front(), addrExpr->get_arg() ) );
    172203                return addrExpr;
     
    175206        Expression * Specialize::mutate( CastExpr *castExpr ) {
    176207                castExpr->get_arg()->acceptMutator( *this );
    177                 if ( ! castExpr->get_results().empty() ) {
    178                         // this may not be the correct condition, but previously the next statement
    179                         // was happening unchecked, causing a crash on a cast to void
    180                         castExpr->set_arg( doSpecialization( castExpr->get_results().front(), castExpr->get_arg() ) );         
    181                 }
    182                 return castExpr;
     208                Expression *specialized = doSpecialization( castExpr->get_results().front(), castExpr->get_arg() );
     209                if ( specialized != castExpr->get_arg() ) {
     210                        // assume here that the specialization incorporates the cast
     211                        return specialized;
     212                } else {
     213                        return castExpr;
     214                }
    183215        }
    184216
Note: See TracChangeset for help on using the changeset viewer.