Changes in src/GenPoly/Specialize.cc [6c3a988f:b3b2077]
- File:
-
- 1 edited
-
src/GenPoly/Specialize.cc (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/GenPoly/Specialize.cc
r6c3a988f rb3b2077 32 32 #include "Common/utility.h" 33 33 #include "InitTweak/InitTweak.h" 34 #include "Tuples/Tuples.h"35 34 36 35 namespace GenPoly { 37 c lass Specializer;38 class Specialize final : public PolyMutator { 39 friend class Specializer;36 const std::list<Label> noLabels; 37 38 class Specialize : public PolyMutator { 40 39 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 ); 45 45 // virtual Expression * mutate( LogicalExpr *logicalExpr ); 46 46 // virtual Expression * mutate( ConditionalExpr *conditionalExpr ); 47 47 // virtual Expression * mutate( CommaExpr *commaExpr ); 48 48 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 ); 50 52 void handleExplicitParams( ApplicationExpr *appExpr ); 53 54 UniqueName thunkNamer; 55 std::string paramPrefix; 51 56 }; 52 57 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 } 82 66 83 67 /// 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 ) { 85 69 if ( env ) { 86 70 using namespace ResolvExpr; … … 107 91 108 92 /// 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 ) { 112 94 FunctionType *newType = funType->clone(); 113 95 if ( env ) { 96 TypeSubstitution newEnv( *env ); 114 97 // it is important to replace only occurrences of type variables that occur free in the 115 98 // thunk's type 116 env->applyFree( newType );99 newEnv.applyFree( newType ); 117 100 } // if 118 101 // create new thunk with same signature as formal type (C linkage, empty body) … … 141 124 std::list< Statement* > oldStmts; 142 125 oldStmts.splice( oldStmts.end(), stmtsToAdd ); 143 spec.handleExplicitParams( appExpr );126 handleExplicitParams( appExpr ); 144 127 paramPrefix = oldParamPrefix; 145 128 // write any statements added for recursive specializations into the thunk body … … 163 146 } 164 147 165 Expression * Specialize r::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {148 Expression * Specialize::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) { 166 149 assertf( actual->has_result(), "attempting to specialize an untyped expression" ); 167 150 if ( needsSpecialization( formalType, actual->get_result(), env ) ) { 168 if ( FunctionType *funType = getFunctionType( formalType ) ) { 151 FunctionType *funType; 152 if ( ( funType = getFunctionType( formalType ) ) ) { 169 153 ApplicationExpr *appExpr; 170 154 VariableExpr *varExpr; … … 185 169 } 186 170 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 assertion214 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 the230 // thunk's type231 env->applyFree( newType );232 } // if233 // 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 attribute238 thunkFunc->get_attributes().push_back( new Attribute( "unused" ) );239 240 // thread thunk parameters into call to actual function, naming thunk parameters as we go241 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 polymorphic247 env->apply( actualType );248 }249 std::unique_ptr< FunctionType > actualTypeManager( actualType ); // for RAII250 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 } // for270 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 } // if276 277 // handle any specializations that may still be present278 std::string oldParamPrefix = paramPrefix;279 paramPrefix += "p";280 // save stmtsToAdd in oldStmts281 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 body286 thunkFunc->get_statements()->get_kids().splice( thunkFunc->get_statements()->get_kids().end(), stmtsToAdd );287 // restore oldStmts into stmtsToAdd288 stmtsToAdd.splice( stmtsToAdd.end(), oldStmts );289 290 // add return (or valueless expression) to the thunk291 Statement *appStmt;292 if ( funType->get_returnVals().empty() ) {293 appStmt = new ExprStmt( noLabels, appExpr );294 } else {295 appStmt = new ReturnStmt( noLabels, appExpr );296 } // if297 thunkFunc->get_statements()->get_kids().push_back( appStmt );298 299 // add thunk definition to queue of statements to add300 stmtsToAdd.push_back( new DeclStmt( noLabels, thunkFunc ) );301 // return address of thunk function as replacement expression302 return new AddressExpr( new VariableExpr( thunkFunc ) );303 }304 305 171 void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) { 306 172 // create thunks for the explicit parameters … … 311 177 std::list< Expression* >::iterator actual; 312 178 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() ); 314 180 } 315 181 } … … 323 189 // don't need to do this for intrinsic calls, because they aren't actually passed 324 190 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() ); 326 192 } 193 327 194 handleExplicitParams( appExpr ); 328 195 } 196 329 197 return appExpr; 330 198 } … … 333 201 addrExpr->get_arg()->acceptMutator( *this ); 334 202 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() ) ); 336 204 return addrExpr; 337 205 } … … 343 211 return castExpr; 344 212 } 345 Expression *specialized = specializer->doSpecialization( castExpr->get_result(), castExpr->get_arg() );213 Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() ); 346 214 if ( specialized != castExpr->get_arg() ) { 347 215 // assume here that the specialization incorporates the cast … … 367 235 // return commaExpr; 368 236 // } 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 }381 237 } // namespace GenPoly 382 238
Note:
See TracChangeset
for help on using the changeset viewer.