Changeset 626dbc10


Ignore:
Timestamp:
Dec 21, 2016, 3:12:19 PM (5 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
aaron-thesis, arm-eh, cleanup-dtors, deferred_resn, demangler, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, resolv-new, with_gc
Children:
b940dc71
Parents:
e33f321
git-author:
Rob Schluntz <rschlunt@…> (12/21/16 15:07:41)
git-committer:
Rob Schluntz <rschlunt@…> (12/21/16 15:12:19)
Message:

major refactoring of specialization code, added code to generate thunks for ttype functions, move specialize pass to before tuple expansion

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Specialize.cc

    re33f321 r626dbc10  
    3434
    3535namespace GenPoly {
    36         const std::list<Label> noLabels;
    37 
     36        class Specializer;
    3837        class Specialize final : public PolyMutator {
     38                friend class Specializer;
    3939          public:
    40                 Specialize( std::string paramPrefix = "_p" );
    41 
    4240                using PolyMutator::mutate;
    4341                virtual Expression * mutate( ApplicationExpr *applicationExpr ) override;
     
    4846                // virtual Expression * mutate( CommaExpr *commaExpr );
    4947
    50           private:
    51                 Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 );
    52                 Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
     48                Specializer * specializer = nullptr;
    5349                void handleExplicitParams( ApplicationExpr *appExpr );
    54 
    55                 UniqueName thunkNamer;
    56                 std::string paramPrefix;
    5750        };
    5851
    59         void convertSpecializations( std::list< Declaration* >& translationUnit ) {
    60                 Specialize specializer;
    61                 mutateAll( translationUnit, specializer );
    62         }
    63 
    64         Specialize::Specialize( std::string paramPrefix )
    65                 : thunkNamer( "_thunk" ), paramPrefix( paramPrefix ) {
    66         }
     52        class Specializer {
     53          public:
     54                Specializer( Specialize & spec ) : spec( spec ), env( spec.env ), stmtsToAdd( spec.stmtsToAdd ) {}
     55                virtual bool needsSpecialization( Type * formalType, Type * actualType, TypeSubstitution * env ) = 0;
     56                virtual Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) = 0;
     57                virtual Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 );
     58
     59          protected:
     60                Specialize & spec;
     61                std::string paramPrefix = "_p";
     62                TypeSubstitution *& env;
     63                std::list< Statement * > & stmtsToAdd;
     64        };
     65
     66        // for normal polymorphic -> monomorphic function conversion
     67        class PolySpecializer : public Specializer {
     68          public:
     69                PolySpecializer( Specialize & spec ) : Specializer( spec ) {}
     70                virtual bool needsSpecialization( Type * formalType, Type * actualType, TypeSubstitution * env ) override;
     71                virtual Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) override;
     72        };
     73
     74        // // for tuple -> non-tuple function conversion
     75        class TupleSpecializer : public Specializer {
     76          public:
     77                TupleSpecializer( Specialize & spec ) : Specializer( spec ) {}
     78                virtual bool needsSpecialization( Type * formalType, Type * actualType, TypeSubstitution * env ) override;
     79                virtual Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) override;
     80        };
    6781
    6882        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
    69         bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     83        bool PolySpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    7084                if ( env ) {
    7185                        using namespace ResolvExpr;
     
    92106
    93107        /// Generates a thunk that calls `actual` with type `funType` and returns its address
    94         Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     108        Expression * PolySpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     109                static UniqueName thunkNamer( "_thunk" );
     110
    95111                FunctionType *newType = funType->clone();
    96112                if ( env ) {
     
    125141                std::list< Statement* > oldStmts;
    126142                oldStmts.splice( oldStmts.end(), stmtsToAdd );
    127                 handleExplicitParams( appExpr );
     143                spec.handleExplicitParams( appExpr );
    128144                paramPrefix = oldParamPrefix;
    129145                // write any statements added for recursive specializations into the thunk body
     
    147163        }
    148164
    149         Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
     165        Expression * Specializer::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
    150166                assertf( actual->has_result(), "attempting to specialize an untyped expression" );
    151167                if ( needsSpecialization( formalType, actual->get_result(), env ) ) {
     
    170186        }
    171187
     188        bool TupleSpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     189                // std::cerr << "asking if type needs tuple spec: " << formalType << std::endl;
     190                if ( FunctionType * ftype = getFunctionType( formalType ) ) {
     191                        return ftype->isTtype();
     192                }
     193                return false;
     194        }
     195
     196        template< typename Iterator >
     197        void fixLastArg( std::list< Expression * > & args, Iterator begin, Iterator end ) {
     198                assertf( ! args.empty(), "Somehow args to tuple function are empty" ); // xxx - it's quite possible this will trigger for the nullary case...
     199                Expression * last = args.back();
     200                // safe_dynamic_cast for the assertion
     201                safe_dynamic_cast< TupleType * >( last->get_result() ); // xxx - it's quite possible this will trigger for the unary case...
     202                args.pop_back(); // replace last argument in the call with
     203                unsigned idx = 0;
     204                for ( ; begin != end; ++begin ) {
     205                        // DeclarationWithType * formal = *begin;
     206                        // Type * formalType = formal->get_type();
     207                        args.push_back( new TupleIndexExpr( last->clone(), idx++ ) );
     208                }
     209                delete last;
     210        }
     211
     212        Expression * TupleSpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
     213                static UniqueName thunkNamer( "_tupleThunk" );
     214                // std::cerr << "creating tuple thunk for " << funType << std::endl;
     215
     216                FunctionType *newType = funType->clone();
     217                if ( env ) {
     218                        TypeSubstitution newEnv( *env );
     219                        // it is important to replace only occurrences of type variables that occur free in the
     220                        // thunk's type
     221                        newEnv.applyFree( newType );
     222                } // if
     223                // create new thunk with same signature as formal type (C linkage, empty body)
     224                FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( noLabels ), false, false );
     225                thunkFunc->fixUniqueId();
     226
     227                // thunks may be generated and not used - silence warning with attribute
     228                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
     229
     230                // thread thunk parameters into call to actual function, naming thunk parameters as we go
     231                UniqueName paramNamer( paramPrefix );
     232                ApplicationExpr *appExpr = new ApplicationExpr( actual );
     233                // std::cerr << actual << std::endl;
     234
     235                FunctionType * actualType = getFunctionType( actual->get_result() );
     236                std::list< DeclarationWithType * >::iterator begin = actualType->get_parameters().begin();
     237                std::list< DeclarationWithType * >::iterator end = actualType->get_parameters().end();
     238
     239                for ( DeclarationWithType* param : thunkFunc->get_functionType()->get_parameters() ) {
     240                        ++begin;
     241                        assert( begin != end );
     242
     243                        // std::cerr << "thunk param: " << param << std::endl;
     244                        // last param will always be a tuple type... expand it into the actual type(?)
     245                        param->set_name( paramNamer.newName() );
     246                        appExpr->get_args().push_back( new VariableExpr( param ) );
     247                } // for
     248                fixLastArg( appExpr->get_args(), --begin, end );
     249                appExpr->set_env( maybeClone( env ) );
     250                if ( inferParams ) {
     251                        appExpr->get_inferParams() = *inferParams;
     252                } // if
     253
     254                // handle any specializations that may still be present
     255                std::string oldParamPrefix = paramPrefix;
     256                paramPrefix += "p";
     257                // save stmtsToAdd in oldStmts
     258                std::list< Statement* > oldStmts;
     259                oldStmts.splice( oldStmts.end(), stmtsToAdd );
     260                spec.handleExplicitParams( appExpr );
     261                paramPrefix = oldParamPrefix;
     262                // write any statements added for recursive specializations into the thunk body
     263                thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
     264                // restore oldStmts into stmtsToAdd
     265                stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
     266
     267                // add return (or valueless expression) to the thunk
     268                Statement *appStmt;
     269                if ( funType->get_returnVals().empty() ) {
     270                        appStmt = new ExprStmt( noLabels, appExpr );
     271                } else {
     272                        appStmt = new ReturnStmt( noLabels, appExpr );
     273                } // if
     274                thunkFunc->get_statements()->get_kids().push_back( appStmt );
     275
     276                // std::cerr << "thunkFunc is: " << thunkFunc << std::endl;
     277
     278                // add thunk definition to queue of statements to add
     279                stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
     280                // return address of thunk function as replacement expression
     281                return new AddressExpr( new VariableExpr( thunkFunc ) );
     282        }
     283
    172284        void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) {
    173285                // create thunks for the explicit parameters
     
    178290                std::list< Expression* >::iterator actual;
    179291                for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) {
    180                         *actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
     292                        *actual = specializer->doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
    181293                }
    182294        }
     
    190302                        // don't need to do this for intrinsic calls, because they aren't actually passed
    191303                        for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
    192                                 inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
     304                                inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );
    193305                        }
    194 
    195306                        handleExplicitParams( appExpr );
    196307                }
    197 
    198308                return appExpr;
    199309        }
     
    202312                addrExpr->get_arg()->acceptMutator( *this );
    203313                assert( addrExpr->has_result() );
    204                 addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
     314                addrExpr->set_arg( specializer->doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
    205315                return addrExpr;
    206316        }
     
    212322                        return castExpr;
    213323                }
    214                 Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );
     324                Expression *specialized = specializer->doSpecialization( castExpr->get_result(), castExpr->get_arg() );
    215325                if ( specialized != castExpr->get_arg() ) {
    216326                        // assume here that the specialization incorporates the cast
     
    236346        //      return commaExpr;
    237347        // }
     348
     349        void convertSpecializations( std::list< Declaration* >& translationUnit ) {
     350                Specialize spec;
     351
     352                TupleSpecializer tupleSpec( spec );
     353                spec.specializer = &tupleSpec;
     354                mutateAll( translationUnit, spec );
     355
     356                PolySpecializer polySpec( spec );
     357                spec.specializer = &polySpec;
     358                mutateAll( translationUnit, spec );
     359        }
    238360} // namespace GenPoly
    239361
  • src/main.cc

    re33f321 r626dbc10  
    6969        symtabp = false,
    7070        treep = false,
     71        tuplep = false,
    7172        validp = false,
    7273        errorp = false,
     
    266267                OPTPRINT( "expandUniqueExpr" ); // xxx - is this the right place for this? want to expand ASAP so that subsequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    267268                Tuples::expandUniqueExpr( translationUnit );
     269
     270                OPTPRINT( "convertSpecializations" ) // needs to happen before tuple types are expanded
     271                GenPoly::convertSpecializations( translationUnit );
     272
    268273                OPTPRINT( "expandTuples" ); // xxx - is this the right place for this?
    269274                Tuples::expandTuples( translationUnit );
     275                if ( tuplep ) {
     276                        dump( translationUnit );
     277                        return 0;
     278                }
    270279
    271280                OPTPRINT("instantiateGenerics")
     
    273282                OPTPRINT( "copyParams" );
    274283                GenPoly::copyParams( translationUnit );
    275                 OPTPRINT( "convertSpecializations" )
    276                 GenPoly::convertSpecializations( translationUnit );
    277284                OPTPRINT( "convertLvalue" )
    278285                GenPoly::convertLvalue( translationUnit );
     
    327334
    328335void parse_cmdline( int argc, char * argv[], const char *& filename ) {
    329         enum { Ast, Bbox, Bresolver, CtorInitFix, Expr, ExprAlt, Grammar, LibCFA, Nopreamble, Parse, Prototypes, Resolver, Symbol, Tree, Validate, };
     336        enum { Ast, Bbox, Bresolver, CtorInitFix, Expr, ExprAlt, Grammar, LibCFA, Nopreamble, Parse, Prototypes, Resolver, Symbol, Tree, TupleExpansion, Validate, };
    330337
    331338        static struct option long_opts[] = {
     
    344351                { "symbol", no_argument, 0, Symbol },
    345352                { "tree", no_argument, 0, Tree },
     353                { "tuple-expansion", no_argument, 0, TupleExpansion },
    346354                { "validate", no_argument, 0, Validate },
    347355                { 0, 0, 0, 0 }
     
    352360
    353361        int c;
    354         while ( (c = getopt_long( argc, argv, "abBcefglnpqrstvyzD:F:", long_opts, &long_index )) != -1 ) {
     362        while ( (c = getopt_long( argc, argv, "abBcefglnpqrstTvyzD:F:", long_opts, &long_index )) != -1 ) {
    355363                switch ( c ) {
    356364                  case Ast:
     
    362370                        bresolvep = true;
    363371                        break;
    364                   case 'B':                                                                             // print before resolver steps
     372                  case 'B':                                                                             // print before box steps
    365373                        bboxp = true;
    366374                        break;
     
    408416                  case 't':                                                                             // build in tree
    409417                        treep = true;
     418                        break;
     419                  case TupleExpansion:
     420                  case 'T':                                                                             // print after tuple expansion
     421                        tuplep = true;
    410422                        break;
    411423                  case 'v':                                                                             // dump AST after decl validation pass
Note: See TracChangeset for help on using the changeset viewer.