Changes in / [5ebb2fbc:c49bf54]


Ignore:
Files:
4 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/Specialize.cc

    r5ebb2fbc rc49bf54  
    3535
    3636namespace GenPoly {
     37        class Specializer;
    3738        class Specialize final : public PolyMutator {
     39                friend class Specializer;
    3840          public:
    3941                using PolyMutator::mutate;
     
    4547                // virtual Expression * mutate( CommaExpr *commaExpr );
    4648
     49                Specializer * specializer = nullptr;
    4750                void handleExplicitParams( ApplicationExpr *appExpr );
    48                 Expression * createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams );
    49                 Expression * doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = nullptr );
    50 
     51        };
     52
     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;
    5162                std::string paramPrefix = "_p";
     63                TypeSubstitution *& env;
     64                std::list< Statement * > & stmtsToAdd;
    5265        };
    5366
     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        };
     82
    5483        /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type.
    55         bool needsPolySpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
     84        bool PolySpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    5685                if ( env ) {
    5786                        using namespace ResolvExpr;
     
    77106        }
    78107
    79         bool needsTupleSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    80                 if ( FunctionType * ftype = getFunctionType( formalType ) ) {
    81                         return ftype->isTtype();
    82                 }
    83                 return false;
    84         }
    85 
    86         bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    87                 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType, env );
    88         }
    89 
    90         Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
     108        /// 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
     112                FunctionType *newType = funType->clone();
     113                if ( env ) {
     114                        // it is important to replace only occurrences of type variables that occur free in the
     115                        // thunk's type
     116                        env->applyFree( newType );
     117                } // if
     118                // create new thunk with same signature as formal type (C linkage, empty body)
     119                FunctionDecl *thunkFunc = new FunctionDecl( thunkNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, newType, new CompoundStmt( noLabels ), false, false );
     120                thunkFunc->fixUniqueId();
     121
     122                // thunks may be generated and not used - silence warning with attribute
     123                thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );
     124
     125                // thread thunk parameters into call to actual function, naming thunk parameters as we go
     126                UniqueName paramNamer( paramPrefix );
     127                ApplicationExpr *appExpr = new ApplicationExpr( actual );
     128                for ( std::list< DeclarationWithType* >::iterator param = thunkFunc->get_functionType()->get_parameters().begin(); param != thunkFunc->get_functionType()->get_parameters().end(); ++param ) {
     129                        (*param )->set_name( paramNamer.newName() );
     130                        appExpr->get_args().push_back( new VariableExpr( *param ) );
     131                } // for
     132                appExpr->set_env( maybeClone( env ) );
     133                if ( inferParams ) {
     134                        appExpr->get_inferParams() = *inferParams;
     135                } // if
     136
     137                // handle any specializations that may still be present
     138                std::string oldParamPrefix = paramPrefix;
     139                paramPrefix += "p";
     140                // save stmtsToAdd in oldStmts
     141                std::list< Statement* > oldStmts;
     142                oldStmts.splice( oldStmts.end(), stmtsToAdd );
     143                spec.handleExplicitParams( appExpr );
     144                paramPrefix = oldParamPrefix;
     145                // write any statements added for recursive specializations into the thunk body
     146                thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );
     147                // restore oldStmts into stmtsToAdd
     148                stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );
     149
     150                // add return (or valueless expression) to the thunk
     151                Statement *appStmt;
     152                if ( funType->get_returnVals().empty() ) {
     153                        appStmt = new ExprStmt( noLabels, appExpr );
     154                } else {
     155                        appStmt = new ReturnStmt( noLabels, appExpr );
     156                } // if
     157                thunkFunc->get_statements()->get_kids().push_back( appStmt );
     158
     159                // add thunk definition to queue of statements to add
     160                stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );
     161                // return address of thunk function as replacement expression
     162                return new AddressExpr( new VariableExpr( thunkFunc ) );
     163        }
     164
     165        Expression * Specializer::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {
    91166                assertf( actual->has_result(), "attempting to specialize an untyped expression" );
    92167                if ( needsSpecialization( formalType, actual->get_result(), env ) ) {
     
    110185        }
    111186
     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
    112194        /// restructures arg to match the structure of a single formal parameter. Assumes that atomic types are compatible (as the Resolver should have ensured this)
    113195        template< typename OutIterator >
     
    125207
    126208        /// restructures the ttype argument to match the structure of the formal parameters of the actual function.
    127         /// [begin, end) are the formal parameters.
    128         /// args is the list of arguments currently given to the actual function, the last of which needs to be restructured.
     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.
    129211        template< typename Iterator, typename OutIterator >
    130212        void fixLastArg( Expression * last, Iterator begin, Iterator end, OutIterator out ) {
    131                 if ( Tuples::isTtype( last->get_result() ) ) {
    132                         *out++ = last;
    133                 } else {
    134                         // safe_dynamic_cast for the assertion
    135                         safe_dynamic_cast< TupleType * >( last->get_result() );
    136                         unsigned idx = 0;
    137                         for ( ; begin != end; ++begin ) {
    138                                 DeclarationWithType * formal = *begin;
    139                                 Type * formalType = formal->get_type();
    140                                 matchOneFormal( last, idx, formalType, out );
    141                         }
    142                         delete last;
    143                 }
    144         }
    145 
    146         /// Generates a thunk that calls `actual` with type `funType` and returns its address
    147         Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
    148                 static UniqueName thunkNamer( "_thunk" );
     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" );
    149226
    150227                FunctionType *newType = funType->clone();
     
    176253                std::list< DeclarationWithType * >::iterator formalEnd = funType->get_parameters().end();
    177254
     255                Expression * last = nullptr;
    178256                for ( DeclarationWithType* param : thunkFunc->get_functionType()->get_parameters() ) {
    179257                        // 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.
     
    181259                        assertf( formalBegin != formalEnd, "Reached end of formal parameters before finding ttype parameter" );
    182260                        if ( Tuples::isTtype((*formalBegin)->get_type()) ) {
    183                                 fixLastArg( new VariableExpr( param ), actualBegin, actualEnd, back_inserter( appExpr->get_args() ) );
     261                                last = new VariableExpr( param );
    184262                                break;
    185263                        }
     
    190268                        appExpr->get_args().push_back( new VariableExpr( param ) );
    191269                } // for
     270                assert( last );
     271                fixLastArg( last, actualBegin, actualEnd, back_inserter( appExpr->get_args() ) );
    192272                appExpr->set_env( maybeClone( env ) );
    193273                if ( inferParams ) {
     
    201281                std::list< Statement* > oldStmts;
    202282                oldStmts.splice( oldStmts.end(), stmtsToAdd );
    203                 mutate( appExpr );
     283                spec.mutate( appExpr );
    204284                paramPrefix = oldParamPrefix;
    205285                // write any statements added for recursive specializations into the thunk body
     
    231311                std::list< Expression* >::iterator actual;
    232312                for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) {
    233                         *actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
     313                        *actual = specializer->doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );
    234314                }
    235315        }
     
    242322                        // create thunks for the inferred parameters
    243323                        // don't need to do this for intrinsic calls, because they aren't actually passed
    244                         // need to handle explicit params before inferred params so that explicit params do not recieve a changed set of inferParams (and change them again)
    245                         // alternatively, if order starts to matter then copy appExpr's inferParams and pass them to handleExplicitParams.
     324                        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() );
     326                        }
    246327                        handleExplicitParams( appExpr );
    247                         for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) {
    248                                 inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, inferParam->second.inferParams.get() );
    249                         }
    250328                }
    251329                return appExpr;
     
    255333                addrExpr->get_arg()->acceptMutator( *this );
    256334                assert( addrExpr->has_result() );
    257                 addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
     335                addrExpr->set_arg( specializer->doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );
    258336                return addrExpr;
    259337        }
     
    265343                        return castExpr;
    266344                }
    267                 Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );
     345                Expression *specialized = specializer->doSpecialization( castExpr->get_result(), castExpr->get_arg() );
    268346                if ( specialized != castExpr->get_arg() ) {
    269347                        // assume here that the specialization incorporates the cast
     
    292370        void convertSpecializations( std::list< Declaration* >& translationUnit ) {
    293371                Specialize spec;
     372
     373                TupleSpecializer tupleSpec( spec );
     374                spec.specializer = &tupleSpec;
     375                mutateAll( translationUnit, spec );
     376
     377                PolySpecializer polySpec( spec );
     378                spec.specializer = &polySpec;
    294379                mutateAll( translationUnit, spec );
    295380        }
  • src/InitTweak/InitTweak.cc

    r5ebb2fbc rc49bf54  
    327327                        } else if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( expr ) ) {
    328328                                return handleDerefCalledFunction( appExpr );
    329                         } else if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
    330                                 return getCalledFunction( addrExpr->get_arg() );
    331329                        }
    332330                        return nullptr;
     
    338336                if ( ! appExpr ) return NULL;
    339337                DeclarationWithType * function = getCalledFunction( appExpr->get_function() );
    340                 assertf( function, "getCalledFunction returned nullptr: %s", toString( appExpr->get_function() ).c_str() );
     338                assert( function );
    341339                // check for Intrinsic only - don't want to remove all overridable ctor/dtors because autogenerated ctor/dtor
    342340                // will call all member dtors, and some members may have a user defined dtor.
     
    388386                } else if ( UntypedExpr * untypedExpr = dynamic_cast< UntypedExpr * >( callExpr ) ) {
    389387                        return callArg( untypedExpr, pos );
    390                 } else if ( TupleAssignExpr * tupleExpr = dynamic_cast< TupleAssignExpr * > ( callExpr ) ) {
    391                         std::list< Statement * > & stmts = tupleExpr->get_stmtExpr()->get_statements()->get_kids();
    392                         assertf( ! stmts.empty(), "TupleAssignExpr somehow has no statements." );
    393                         ExprStmt * stmt = safe_dynamic_cast< ExprStmt * >( stmts.back() );
    394                         TupleExpr * tuple = safe_dynamic_cast< TupleExpr * >( stmt->get_expr() );
    395                         assertf( ! tuple->get_exprs().empty(), "TupleAssignExpr somehow has empty tuple expr." );
    396                         return getCallArg( tuple->get_exprs().front(), pos );
    397388                } else {
    398                         assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( callExpr ).c_str() );
     389                        assertf( false, "Unexpected expression type passed to getCallArg" );
    399390                }
    400391        }
  • src/ResolvExpr/Unify.cc

    r5ebb2fbc rc49bf54  
    163163                        case TypeDecl::Ttype:
    164164                        // ttype unifies with any tuple type
    165                         return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
     165                        return dynamic_cast< TupleType * >( type );
    166166                } // switch
    167167                return false;
     
    488488        }
    489489
    490         template< typename Iterator, typename Func >
    491         std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {
     490        template< typename Iterator >
     491        std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end ) {
    492492                std::list< Type * > types;
    493493                for ( ; begin != end; ++begin ) {
    494494                        // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
    495                         flatten( toType( *begin ), back_inserter( types ) );
     495                        flatten( (*begin)->get_type(), back_inserter( types ) );
    496496                }
    497497                return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
     
    500500        template< typename Iterator1, typename Iterator2 >
    501501        bool unifyDeclList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
    502                 auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
    503502                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    504503                        Type * t1 = (*list1Begin)->get_type();
     
    510509                        if ( isTtype1 && ! isTtype2 ) {
    511510                                // combine all of the things in list2, then unify
    512                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     511                                return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    513512                        } else if ( isTtype2 && ! isTtype1 ) {
    514513                                // combine all of the things in list1, then unify
    515                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     514                                return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    516515                        } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
    517516                                return false;
     
    523522                        Type * t1 = (*list1Begin)->get_type();
    524523                        if ( Tuples::isTtype( t1 ) ) {
    525                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     524                                return unifyExact( t1, combineTypes( list2Begin, list2End ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    526525                        } else return false;
    527526                } else if ( list2Begin != list2End ) {
     
    529528                        Type * t2 = (*list2Begin)->get_type();
    530529                        if ( Tuples::isTtype( t2 ) ) {
    531                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     530                                return unifyExact( combineTypes( list1Begin, list1End ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    532531                        } else return false;
    533532                } else {
     
    666665        template< typename Iterator1, typename Iterator2 >
    667666        bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    668                 auto get_type = [](Type * t) { return t; };
    669667                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
    670                         Type * t1 = *list1Begin;
    671                         Type * t2 = *list2Begin;
    672                         bool isTtype1 = Tuples::isTtype( t1 );
    673                         bool isTtype2 = Tuples::isTtype( t2 );
    674                         // xxx - assumes ttype must be last parameter
    675                         // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
    676                         if ( isTtype1 && ! isTtype2 ) {
    677                                 // combine all of the things in list2, then unify
    678                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    679                         } else if ( isTtype2 && ! isTtype1 ) {
    680                                 // combine all of the things in list1, then unify
    681                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    682                         } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
     668                        Type *commonType = 0;
     669                        if ( ! unifyInexact( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, widenMode, indexer, commonType ) ) {
    683670                                return false;
    684                         } // if
    685 
     671                        }
     672                        delete commonType;
    686673                } // for
    687                 if ( list1Begin != list1End ) {
    688                         // try unifying empty tuple type with ttype
    689                         Type * t1 = *list1Begin;
    690                         if ( Tuples::isTtype( t1 ) ) {
    691                                 return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    692                         } else return false;
    693                 } else if ( list2Begin != list2End ) {
    694                         // try unifying empty tuple type with ttype
    695                         Type * t2 = *list2Begin;
    696                         if ( Tuples::isTtype( t2 ) ) {
    697                                 return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    698                         } else return false;
     674                if ( list1Begin != list1End || list2Begin != list2End ) {
     675                        return false;
    699676                } else {
    700677                        return true;
    701                 } // if
     678                } //if
    702679        }
    703680
    704681        void Unify::visit(TupleType *tupleType) {
    705682                if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
    706                         std::unique_ptr<TupleType> flat1( tupleType->clone() );
    707                         std::unique_ptr<TupleType> flat2( otherTuple->clone() );
    708                         std::list<Type *> types1, types2;
    709 
    710                         TtypeExpander expander( env );
    711                         flat1->acceptMutator( expander );
    712                         flat2->acceptMutator( expander );
    713 
    714                         flatten( flat1.get(), back_inserter( types1 ) );
    715                         flatten( flat2.get(), back_inserter( types2 ) );
    716 
    717                         result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, widenMode, indexer );
     683                        result = unifyList( tupleType->get_types().begin(), tupleType->get_types().end(), otherTuple->get_types().begin(), otherTuple->get_types().end(), env, needAssertions, haveAssertions, openVars, widenMode, indexer );
    718684                } // if
    719685        }
Note: See TracChangeset for help on using the changeset viewer.