- File:
-
- 1 edited
-
src/ResolvExpr/ConversionCost.cc (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/ConversionCost.cc
rc6b4432 r251ce80 21 21 22 22 #include "ResolvExpr/Cost.h" // for Cost 23 #include "ResolvExpr/TypeEnvironment.h" // for EqvClass, TypeEnvironment 23 24 #include "ResolvExpr/Unify.h" // for typesCompatibleIgnoreQualifiers 24 25 #include "ResolvExpr/PtrsAssignable.hpp" // for ptrsAssignable 26 #include "SymTab/Indexer.h" // for Indexer 27 #include "SynTree/Declaration.h" // for TypeDecl, NamedTypeDecl 28 #include "SynTree/Type.h" // for Type, BasicType, TypeInstType 29 25 30 26 31 namespace ResolvExpr { 32 #if 0 33 const Cost Cost::zero = Cost{ 0, 0, 0, 0, 0, 0, 0 }; 34 const Cost Cost::infinity = Cost{ -1, -1, -1, -1, -1, 1, -1 }; 35 const Cost Cost::unsafe = Cost{ 1, 0, 0, 0, 0, 0, 0 }; 36 const Cost Cost::poly = Cost{ 0, 1, 0, 0, 0, 0, 0 }; 37 const Cost Cost::safe = Cost{ 0, 0, 1, 0, 0, 0, 0 }; 38 const Cost Cost::sign = Cost{ 0, 0, 0, 1, 0, 0, 0 }; 39 const Cost Cost::var = Cost{ 0, 0, 0, 0, 1, 0, 0 }; 40 const Cost Cost::spec = Cost{ 0, 0, 0, 0, 0, -1, 0 }; 41 const Cost Cost::reference = Cost{ 0, 0, 0, 0, 0, 0, 1 }; 42 #endif 27 43 28 44 #if 0 … … 31 47 #define PRINT(x) 32 48 #endif 49 50 Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue, 51 const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 52 if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) { 53 PRINT( std::cerr << "type inst " << destAsTypeInst->name; ) 54 if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) { 55 if ( eqvClass->type ) { 56 return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env ); 57 } else { 58 return Cost::infinity; 59 } 60 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) { 61 PRINT( std::cerr << " found" << std::endl; ) 62 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType ); 63 // all typedefs should be gone by this point 64 assert( type ); 65 if ( type->base ) { 66 return conversionCost( src, type->base, srcIsLvalue, indexer, env ) 67 + Cost::safe; 68 } // if 69 } // if 70 PRINT( std::cerr << " not found" << std::endl; ) 71 } // if 72 PRINT( 73 std::cerr << "src is "; 74 src->print( std::cerr ); 75 std::cerr << std::endl << "dest is "; 76 dest->print( std::cerr ); 77 std::cerr << std::endl << "env is" << std::endl; 78 env.print( std::cerr, 8 ); 79 ) 80 if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) { 81 PRINT( std::cerr << "compatible!" << std::endl; ) 82 return Cost::zero; 83 } else if ( dynamic_cast< const VoidType * >( dest ) ) { 84 return Cost::safe; 85 } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) { 86 PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; ) 87 return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){ 88 return ptrsAssignable( t1, t2, env ); 89 }); 90 } else { 91 PassVisitor<ConversionCost> converter( 92 dest, srcIsLvalue, indexer, env, 93 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&)) 94 conversionCost ); 95 src->accept( converter ); 96 if ( converter.pass.get_cost() == Cost::infinity ) { 97 return Cost::infinity; 98 } else { 99 return converter.pass.get_cost() + Cost::zero; 100 } // if 101 } // if 102 } 103 104 static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue, 105 int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) { 106 PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; ) 107 if ( diff > 0 ) { 108 // TODO: document this 109 Cost cost = convertToReferenceCost( 110 strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue, 111 diff-1, indexer, env, func ); 112 cost.incReference(); 113 return cost; 114 } else if ( diff < -1 ) { 115 // TODO: document this 116 Cost cost = convertToReferenceCost( 117 src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue, 118 diff+1, indexer, env, func ); 119 cost.incReference(); 120 return cost; 121 } else if ( diff == 0 ) { 122 const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src ); 123 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest ); 124 if ( srcAsRef && destAsRef ) { // pointer-like conversions between references 125 PRINT( std::cerr << "converting between references" << std::endl; ) 126 Type::Qualifiers tq1 = srcAsRef->base->tq; 127 Type::Qualifiers tq2 = destAsRef->base->tq; 128 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) { 129 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; ) 130 if ( tq1 == tq2 ) { 131 // types are the same 132 return Cost::zero; 133 } else { 134 // types are the same, except otherPointer has more qualifiers 135 return Cost::safe; 136 } 137 } else { // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right? 138 int assignResult = func( srcAsRef->base, destAsRef->base, indexer, env ); 139 PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; ) 140 if ( assignResult > 0 ) { 141 return Cost::safe; 142 } else if ( assignResult < 0 ) { 143 return Cost::unsafe; 144 } // if 145 } // if 146 } else { 147 PRINT( std::cerr << "reference to rvalue conversion" << std::endl; ) 148 PassVisitor<ConversionCost> converter( 149 dest, srcIsLvalue, indexer, env, 150 (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&)) 151 conversionCost ); 152 src->accept( converter ); 153 return converter.pass.get_cost(); 154 } // if 155 } else { 156 const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest ); 157 assert( diff == -1 && destAsRef ); 158 PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; ) 159 if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) { 160 PRINT( std::cerr << "converting compatible base type" << std::endl; ) 161 if ( srcIsLvalue ) { 162 PRINT( 163 std::cerr << "lvalue to reference conversion" << std::endl; 164 std::cerr << src << " => " << destAsRef << std::endl; 165 ) 166 // lvalue-to-reference conversion: cv lvalue T => cv T & 167 if ( src->tq == destAsRef->base->tq ) { 168 return Cost::reference; // cost needs to be non-zero to add cast 169 } if ( src->tq < destAsRef->base->tq ) { 170 return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same 171 } else { 172 return Cost::unsafe; 173 } // if 174 } else if ( destAsRef->base->get_const() ) { 175 PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; ) 176 // rvalue-to-const-reference conversion: T => const T & 177 return Cost::safe; 178 } else { 179 PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; ) 180 // rvalue-to-reference conversion: T => T & 181 return Cost::unsafe; 182 } // if 183 } // if 184 PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; ) 185 } 186 return Cost::infinity; 187 } 188 189 Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue, 190 const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) { 191 int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth(); 192 Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func ); 193 PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; ) 194 return cost; 195 } 196 197 ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc ) 198 : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) { 199 } 33 200 34 201 // GENERATED START, DO NOT EDIT … … 59 226 // GENERATED START, DO NOT EDIT 60 227 // GENERATED BY BasicTypes-gen.cc 61 static const int costMatrix[ ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node228 static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node 62 229 /* B C SC UC SI SUI I UI LI LUI LLI LLUI IB UIB _FH _FH _F _FC F FC _FX _FXC FD _FDC D DC F80X_FDXC F80 _FB_FLDC FB LD LDC _FBX_FLDXC */ 63 230 /* B */ { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17, 16, 18, 17, }, … … 101 268 // GENERATED END 102 269 static_assert( 103 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,270 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES, 104 271 "Missing row in the cost matrix" 105 272 ); … … 107 274 // GENERATED START, DO NOT EDIT 108 275 // GENERATED BY BasicTypes-gen.cc 109 static const int signMatrix[ ast::BasicType::NUMBER_OF_BASIC_TYPES][ast::BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion276 static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion 110 277 /* B C SC UC SI SUI I UI LI LUI LLI LLUI IB UIB _FH _FH _F _FC F FC _FX _FXC FD _FDC D DC F80X_FDXC F80 _FB_FLDC FB LD LDC _FBX_FLDXC */ 111 278 /* B */ { 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, … … 148 315 // GENERATED END 149 316 static_assert( 150 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == ast::BasicType::NUMBER_OF_BASIC_TYPES * ast::BasicType::NUMBER_OF_BASIC_TYPES,317 sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES, 151 318 "Missing row in the sign matrix" 152 319 ); 320 321 void ConversionCost::postvisit( const VoidType * ) { 322 cost = Cost::infinity; 323 } 324 325 // refactor for code resue 326 void ConversionCost::conversionCostFromBasicToBasic(const BasicType * src, const BasicType * dest) { 327 int tableResult = costMatrix[ src->kind ][ dest->kind ]; 328 if ( tableResult == -1 ) { 329 cost = Cost::unsafe; 330 } else { 331 cost = Cost::zero; 332 cost.incSafe( tableResult ); 333 cost.incSign( signMatrix[ src->kind ][ dest->kind ] ); 334 } // if 335 } // ConversionCost::conversionCostFromBasicToBasic 336 337 void ConversionCost::postvisit(const BasicType * basicType) { 338 if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 339 conversionCostFromBasicToBasic(basicType, destAsBasic); 340 } else if ( const EnumInstType * enumInst = dynamic_cast< const EnumInstType * >( dest ) ) { 341 const EnumDecl * base_enum = enumInst->baseEnum; 342 if ( const Type * base = base_enum->base ) { 343 if ( const BasicType * enumBaseAstBasic = dynamic_cast< const BasicType *> (base) ) { 344 conversionCostFromBasicToBasic(basicType, enumBaseAstBasic); 345 } else { 346 cost = Cost::infinity; 347 } // if 348 } else { 349 cost = Cost::unsafe; 350 } // if 351 } // if 352 // no cases for zero_t/one_t because it should not be possible to convert int, etc. to zero_t/one_t. 353 } 354 355 void ConversionCost::postvisit( const PointerType * pointerType ) { 356 if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) { 357 PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; ) 358 Type::Qualifiers tq1 = pointerType->base->tq; 359 Type::Qualifiers tq2 = destAsPtr->base->tq; 360 if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) { 361 PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; ) 362 if ( tq1 == tq2 ) { 363 // types are the same 364 cost = Cost::zero; 365 } else { 366 // types are the same, except otherPointer has more qualifiers 367 cost = Cost::safe; 368 } // if 369 } else { 370 int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env ); 371 PRINT( std::cerr << " :: " << assignResult << std::endl; ) 372 if ( assignResult > 0 && tq1 <= tq2 ) { 373 // xxx - want the case where qualifiers are added to be more expensive than the case where qualifiers are the same. Is 1 safe vs. 2 safe correct? 374 if ( tq1 == tq2 ) { 375 cost = Cost::safe; 376 } else if ( tq1 < tq2 ) { 377 cost = Cost::safe+Cost::safe; 378 } 379 } else if ( assignResult < 0 ) { 380 cost = Cost::unsafe; 381 } // if 382 // assignResult == 0 means Cost::Infinity 383 } // if 384 // case case for zero_t because it should not be possible to convert pointers to zero_t. 385 } // if 386 } 387 388 void ConversionCost::postvisit( const ArrayType * ) {} 389 390 void ConversionCost::postvisit( const ReferenceType * refType ) { 391 // Note: dest can never be a reference, since it would have been caught in an earlier check 392 assert( ! dynamic_cast< const ReferenceType * >( dest ) ); 393 // convert reference to rvalue: cv T1 & => T2 394 // recursively compute conversion cost from T1 to T2. 395 // cv can be safely dropped because of 'implicit dereference' behavior. 396 cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env ); 397 if ( refType->base->tq == dest->tq ) { 398 cost.incReference(); // prefer exact qualifiers 399 } else if ( refType->base->tq < dest->tq ) { 400 cost.incSafe(); // then gaining qualifiers 401 } else { 402 cost.incUnsafe(); // lose qualifiers as last resort 403 } 404 PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; ) 405 } 406 407 void ConversionCost::postvisit( const FunctionType * ) {} 408 409 void ConversionCost::postvisit( const EnumInstType * enumInst) { 410 const EnumDecl * enumDecl = enumInst -> baseEnum; 411 if ( const Type * enumType = enumDecl -> base ) { // if it is a typed enum 412 cost = costFunc( enumType, dest, srcIsLvalue, indexer, env ); 413 } else { 414 static Type::Qualifiers q; 415 static BasicType integer( q, BasicType::SignedInt ); 416 cost = costFunc( &integer, dest, srcIsLvalue, indexer, env ); // safe if dest >= int 417 } // if 418 if ( cost < Cost::unsafe ) { 419 cost.incSafe(); 420 } // if 421 } 422 423 void ConversionCost::postvisit( const TraitInstType * ) {} 424 425 void ConversionCost::postvisit( const TypeInstType * inst ) { 426 if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) { 427 cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env ); 428 } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) { 429 if ( inst->name == destAsInst->name ) { 430 cost = Cost::zero; 431 } 432 } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) { 433 const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType ); 434 // all typedefs should be gone by this point 435 assert( type ); 436 if ( type->base ) { 437 cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe; 438 } // if 439 } // if 440 } 441 442 void ConversionCost::postvisit( const TupleType * tupleType ) { 443 Cost c = Cost::zero; 444 if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) { 445 std::list< Type * >::const_iterator srcIt = tupleType->types.begin(); 446 std::list< Type * >::const_iterator destIt = destAsTuple->types.begin(); 447 while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) { 448 Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env ); 449 if ( newCost == Cost::infinity ) { 450 return; 451 } // if 452 c += newCost; 453 } // while 454 if ( destIt != destAsTuple->types.end() ) { 455 cost = Cost::infinity; 456 } else { 457 cost = c; 458 } // if 459 } // if 460 } 461 462 void ConversionCost::postvisit( const VarArgsType * ) { 463 if ( dynamic_cast< const VarArgsType * >( dest ) ) { 464 cost = Cost::zero; 465 } 466 } 467 468 void ConversionCost::postvisit( const ZeroType * ) { 469 if ( dynamic_cast< const ZeroType * >( dest ) ) { 470 cost = Cost::zero; 471 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 472 // copied from visit(BasicType *) for signed int, but +1 for safe conversions 473 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ]; 474 if ( tableResult == -1 ) { 475 cost = Cost::unsafe; 476 } else { 477 cost = Cost::zero; 478 cost.incSafe( tableResult + 1 ); 479 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] ); 480 } // if 481 } else if ( dynamic_cast< const PointerType * >( dest ) ) { 482 cost = Cost::zero; 483 cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation 484 } // if 485 } 486 487 void ConversionCost::postvisit( const OneType * ) { 488 if ( dynamic_cast< const OneType * >( dest ) ) { 489 cost = Cost::zero; 490 } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) { 491 // copied from visit(BasicType *) for signed int, but +1 for safe conversions 492 int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ]; 493 if ( tableResult == -1 ) { 494 cost = Cost::unsafe; 495 } else { 496 cost = Cost::zero; 497 cost.incSafe( tableResult + 1 ); 498 cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] ); 499 } // if 500 } // if 501 } 153 502 154 503 namespace { … … 353 702 354 703 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 355 356 // xxx - should qualifiers be considered in pass-by-value?357 /*358 704 if ( refType->base->qualifiers == dst->qualifiers ) { 359 705 cost.incReference(); … … 363 709 cost.incUnsafe(); 364 710 } 365 */366 cost.incReference();367 711 } 368 712 … … 448 792 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 449 793 } 450 // this has the effect of letting any expr such as x+0, x+1 to be typed451 // the same as x, instead of at least int. are we willing to sacrifice this little452 // bit of coherence with C?453 // TODO: currently this does not work when no zero/one overloads exist. Find a fix for it.454 // cost = Cost::zero;455 794 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 456 795 cost = Cost::zero; 457 796 // +1 for zero_t ->, +1 for disambiguation 458 797 cost.incSafe( maxIntCost + 2 ); 459 // assuming 0p is supposed to be used for pointers?460 798 } 461 799 } … … 466 804 cost = Cost::zero; 467 805 } else if ( const ast::BasicType * dstAsBasic = 468 dynamic_cast< const ast::BasicType * >( dst ) ) { 806 dynamic_cast< const ast::BasicType * >( dst ) ) { 469 807 int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ]; 470 808 if ( -1 == tableResult ) { … … 475 813 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 476 814 } 477 478 // cost = Cost::zero;479 815 } 480 816 }
Note:
See TracChangeset
for help on using the changeset viewer.