Changes in src/GenPoly/Specialize.cc [b3b2077:6c3a988f]
- File:
-
- 1 edited
-
src/GenPoly/Specialize.cc (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/GenPoly/Specialize.cc
rb3b2077 r6c3a988f 32 32 #include "Common/utility.h" 33 33 #include "InitTweak/InitTweak.h" 34 #include "Tuples/Tuples.h" 34 35 35 36 namespace GenPoly { 36 c onst std::list<Label> noLabels;37 38 class Specialize : public PolyMutator {37 class Specializer; 38 class Specialize final : public PolyMutator { 39 friend class Specializer; 39 40 public: 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 ); 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; 45 45 // virtual Expression * mutate( LogicalExpr *logicalExpr ); 46 46 // virtual Expression * mutate( ConditionalExpr *conditionalExpr ); 47 47 // virtual Expression * mutate( CommaExpr *commaExpr ); 48 48 49 private: 50 Expression *createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams = 0 ); 51 Expression *doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams = 0 ); 49 Specializer * specializer = nullptr; 52 50 void handleExplicitParams( ApplicationExpr *appExpr ); 53 54 UniqueName thunkNamer;55 std::string paramPrefix;56 51 }; 57 52 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 } 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 }; 66 82 67 83 /// Looks up open variables in actual type, returning true if any of them are bound in the environment or formal type. 68 bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {84 bool PolySpecializer::needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) { 69 85 if ( env ) { 70 86 using namespace ResolvExpr; … … 91 107 92 108 /// Generates a thunk that calls `actual` with type `funType` and returns its address 93 Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) { 109 Expression * PolySpecializer::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) { 110 static UniqueName thunkNamer( "_thunk" ); 111 94 112 FunctionType *newType = funType->clone(); 95 113 if ( env ) { 96 TypeSubstitution newEnv( *env );97 114 // it is important to replace only occurrences of type variables that occur free in the 98 115 // thunk's type 99 newEnv.applyFree( newType );116 env->applyFree( newType ); 100 117 } // if 101 118 // create new thunk with same signature as formal type (C linkage, empty body) … … 124 141 std::list< Statement* > oldStmts; 125 142 oldStmts.splice( oldStmts.end(), stmtsToAdd ); 126 handleExplicitParams( appExpr );143 spec.handleExplicitParams( appExpr ); 127 144 paramPrefix = oldParamPrefix; 128 145 // write any statements added for recursive specializations into the thunk body … … 146 163 } 147 164 148 Expression * Specialize ::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) {165 Expression * Specializer::doSpecialization( Type *formalType, Expression *actual, InferredParams *inferParams ) { 149 166 assertf( actual->has_result(), "attempting to specialize an untyped expression" ); 150 167 if ( needsSpecialization( formalType, actual->get_result(), env ) ) { 151 FunctionType *funType; 152 if ( ( funType = getFunctionType( formalType ) ) ) { 168 if ( FunctionType *funType = getFunctionType( formalType ) ) { 153 169 ApplicationExpr *appExpr; 154 170 VariableExpr *varExpr; … … 169 185 } 170 186 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 171 305 void Specialize::handleExplicitParams( ApplicationExpr *appExpr ) { 172 306 // create thunks for the explicit parameters … … 177 311 std::list< Expression* >::iterator actual; 178 312 for ( formal = function->get_parameters().begin(), actual = appExpr->get_args().begin(); formal != function->get_parameters().end() && actual != appExpr->get_args().end(); ++formal, ++actual ) { 179 *actual = doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() );313 *actual = specializer->doSpecialization( (*formal )->get_type(), *actual, &appExpr->get_inferParams() ); 180 314 } 181 315 } … … 189 323 // don't need to do this for intrinsic calls, because they aren't actually passed 190 324 for ( InferredParams::iterator inferParam = appExpr->get_inferParams().begin(); inferParam != appExpr->get_inferParams().end(); ++inferParam ) { 191 inferParam->second.expr = doSpecialization( inferParam->second.formalType, inferParam->second.expr, &appExpr->get_inferParams() );325 inferParam->second.expr = specializer->doSpecialization( inferParam->second.formalType, inferParam->second.expr, inferParam->second.inferParams.get() ); 192 326 } 193 194 327 handleExplicitParams( appExpr ); 195 328 } 196 197 329 return appExpr; 198 330 } … … 201 333 addrExpr->get_arg()->acceptMutator( *this ); 202 334 assert( addrExpr->has_result() ); 203 addrExpr->set_arg( doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) );335 addrExpr->set_arg( specializer->doSpecialization( addrExpr->get_result(), addrExpr->get_arg() ) ); 204 336 return addrExpr; 205 337 } … … 211 343 return castExpr; 212 344 } 213 Expression *specialized = doSpecialization( castExpr->get_result(), castExpr->get_arg() );345 Expression *specialized = specializer->doSpecialization( castExpr->get_result(), castExpr->get_arg() ); 214 346 if ( specialized != castExpr->get_arg() ) { 215 347 // assume here that the specialization incorporates the cast … … 235 367 // return commaExpr; 236 368 // } 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 } 237 381 } // namespace GenPoly 238 382
Note:
See TracChangeset
for help on using the changeset viewer.