Ignore:
Timestamp:
Aug 25, 2017, 10:38:34 AM (8 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
800d275
Parents:
af08051 (diff), 3eab308c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/ConversionCost.cc

    raf08051 r28e58fd  
    2828
    2929namespace ResolvExpr {
    30         const Cost Cost::zero = Cost( 0, 0, 0 );
    31         const Cost Cost::infinity = Cost( -1, -1, -1 );
     30        const Cost Cost::zero = Cost( 0, 0, 0, 0 );
     31        const Cost Cost::infinity = Cost( -1, -1, -1, -1 );
     32        const Cost Cost::unsafe = Cost( 1, 0, 0, 0 );
     33        const Cost Cost::poly = Cost( 0, 1, 0, 0 );
     34        const Cost Cost::safe = Cost( 0, 0, 1, 0 );
     35        const Cost Cost::reference = Cost( 0, 0, 0, 1 );
     36
     37#if 0
     38#define PRINT(x) x
     39#else
     40#define PRINT(x)
     41#endif
    3242
    3343        Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     
    3545                        EqvClass eqvClass;
    3646                        NamedTypeDecl *namedType;
    37 ///     std::cout << "type inst " << destAsTypeInst->get_name();
     47                        PRINT( std::cerr << "type inst " << destAsTypeInst->get_name(); )
    3848                        if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) {
    3949                                if ( eqvClass.type ) {
     
    4353                                }
    4454                        } else if ( ( namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) ) {
    45 ///       std::cout << " found" << std::endl;
     55                                PRINT( std::cerr << " found" << std::endl; )
    4656                                TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
    4757                                // all typedefs should be gone by this point
    4858                                assert( type );
    4959                                if ( type->get_base() ) {
    50                                         return conversionCost( src, type->get_base(), indexer, env ) + Cost( 0, 0, 1 );
     60                                        return conversionCost( src, type->get_base(), indexer, env ) + Cost::safe;
    5161                                } // if
    5262                        } // if
    53 ///     std::cout << " not found" << std::endl;
    54                 } // if
    55 ///   std::cout << "src is ";
    56 ///   src->print( std::cout );
    57 ///   std::cout << std::endl << "dest is ";
    58 ///   dest->print( std::cout );
    59 ///   std::cout << std::endl << "env is" << std::endl;
    60 ///   env.print( std::cout, 8 );
     63                        PRINT( std::cerr << " not found" << std::endl; )
     64                } // if
     65                PRINT(
     66                        std::cerr << "src is ";
     67                        src->print( std::cerr );
     68                        std::cerr << std::endl << "dest is ";
     69                        dest->print( std::cerr );
     70                        std::cerr << std::endl << "env is" << std::endl;
     71                        env.print( std::cerr, 8 );
     72                )
    6173                if ( typesCompatibleIgnoreQualifiers( src, dest, indexer, env ) ) {
    62 ///     std::cout << "compatible!" << std::endl;
    63                         return Cost( 0, 0, 0 );
     74                        PRINT( std::cerr << "compatible!" << std::endl; )
     75                        return Cost::zero;
    6476                } else if ( dynamic_cast< VoidType* >( dest ) ) {
    65                         return Cost( 0, 0, 1 );
     77                        return Cost::safe;
     78                } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
     79                        PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
     80                        return convertToReferenceCost( src, refType, indexer, env );
    6681                } else {
    6782                        ConversionCost converter( dest, indexer, env );
     
    7085                                return Cost::infinity;
    7186                        } else {
    72                                 return converter.get_cost() + Cost( 0, 0, 0 );
    73                         } // if
    74                 } // if
     87                                return converter.get_cost() + Cost::zero;
     88                        } // if
     89                } // if
     90        }
     91
     92        Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     93                PRINT( std::cerr << "convert to reference cost..." << std::endl; )
     94                if ( diff > 0 ) {
     95                        // TODO: document this
     96                        Cost cost = convertToReferenceCost( safe_dynamic_cast< ReferenceType * >( src )->get_base(), dest, diff-1, indexer, env );
     97                        cost.incReference();
     98                        return cost;
     99                } else if ( diff < -1 ) {
     100                        // TODO: document this
     101                        Cost cost = convertToReferenceCost( src, safe_dynamic_cast< ReferenceType * >( dest )->get_base(), diff+1, indexer, env );
     102                        cost.incReference();
     103                        return cost;
     104                } else if ( diff == 0 ) {
     105                        ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
     106                        ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
     107                        if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
     108                                PRINT( std::cerr << "converting between references" << std::endl; )
     109                                if ( srcAsRef->get_base()->get_qualifiers() <= destAsRef->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( srcAsRef->get_base(), destAsRef->get_base(), indexer, env ) ) {
     110                                        return Cost::safe;
     111                                } else {  // xxx - this discards reference qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
     112                                        int assignResult = ptrsAssignable( srcAsRef->get_base(), destAsRef->get_base(), env );
     113                                        PRINT( std::cerr << "comparing references: " << assignResult << " " << srcAsRef << " " << destAsRef << std::endl; )
     114                                        if ( assignResult < 0 ) {
     115                                                return Cost::safe;
     116                                        } else if ( assignResult > 0 ) {
     117                                                return Cost::unsafe;
     118                                        } // if
     119                                } // if
     120                        } else {
     121                                PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
     122                                ConversionCost converter( dest, indexer, env );
     123                                src->accept( converter );
     124                                return converter.get_cost();
     125                        } // if
     126                } else {
     127                        ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
     128                        assert( diff == -1 && destAsRef );
     129                        if ( typesCompatibleIgnoreQualifiers( src, destAsRef->get_base(), indexer, env ) ) {
     130                                PRINT( std::cerr << "converting compatible base type" << std::endl; )
     131                                if ( src->get_lvalue() ) {
     132                                        PRINT(
     133                                                std::cerr << "lvalue to reference conversion" << std::endl;
     134                                                std::cerr << src << " => " << destAsRef << std::endl;
     135                                        )
     136                                        // lvalue-to-reference conversion:  cv lvalue T => cv T &
     137                                        if ( src->get_qualifiers() == destAsRef->get_base()->get_qualifiers() ) {
     138                                                return Cost::reference; // cost needs to be non-zero to add cast
     139                                        } if ( src->get_qualifiers() < destAsRef->get_base()->get_qualifiers() ) {
     140                                                return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
     141                                        } else {
     142                                                return Cost::unsafe;
     143                                        } // if
     144                                } else if ( destAsRef->get_base()->get_const() ) {
     145                                        PRINT( std::cerr << "rvalue to const ref conversion" << std::endl; )
     146                                        // rvalue-to-const-reference conversion: T => const T &
     147                                        return Cost::safe;
     148                                } else {
     149                                        PRINT( std::cerr << "rvalue to non-const reference conversion" << std::endl; )
     150                                        // rvalue-to-reference conversion: T => T &
     151                                        return Cost::unsafe;
     152                                } // if
     153                        } // if
     154                        PRINT( std::cerr << "attempting to convert from incompatible base type -- fail" << std::endl; )
     155                }
     156                return Cost::infinity;
     157        }
     158
     159        Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     160                int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
     161                return convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env );
    75162        }
    76163
     
    164251                        int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
    165252                        if ( tableResult == -1 ) {
    166                                 cost = Cost( 1, 0, 0 );
    167                         } else {
    168                                 cost = Cost( 0, 0, tableResult );
     253                                cost = Cost::unsafe;
     254                        } else {
     255                                cost = Cost::zero;
     256                                cost.incSafe( tableResult );
    169257                        } // if
    170258                } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
    171259                        // xxx - not positive this is correct, but appears to allow casting int => enum
    172                         cost = Cost( 1, 0, 0 );
     260                        cost = Cost::unsafe;
    173261                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    174                         cost = Cost( 1, 0, 0 );
     262                        cost = Cost::unsafe;
    175263                } // if
    176264        }
     
    178266        void ConversionCost::visit(PointerType *pointerType) {
    179267                if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    180                         if ( pointerType->get_base()->get_qualifiers() <= destAsPtr->get_base()->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
    181                                 cost = Cost( 0, 0, 1 );
    182                         } else {
     268                        PRINT( std::cerr << pointerType << " ===> " << destAsPtr; )
     269                        Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers();
     270                        Type::Qualifiers tq2 = destAsPtr->get_base()->get_qualifiers();
     271                        if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->get_base(), destAsPtr->get_base(), indexer, env ) ) {
     272                                if ( tq1 == tq2 ) {
     273                                        // types are the same
     274                                        cost = Cost::zero;
     275                                } else {
     276                                        // types are the same, except otherPointer has more qualifiers
     277                                        PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
     278                                        cost = Cost::safe;
     279                                }
     280                        } else {  // xxx - this discards qualifiers from consideration -- reducing qualifiers is a safe conversion; is this right?
    183281                                int assignResult = ptrsAssignable( pointerType->get_base(), destAsPtr->get_base(), env );
    184                                 if ( assignResult < 0 ) {
    185                                         cost = Cost( 0, 0, 1 );
     282                                PRINT( std::cerr << " :: " << assignResult << std::endl; )
     283                                if ( assignResult < 0 && pointerType->get_base()->get_qualifiers() <= destAsPtr->get_qualifiers() ) {
     284                                        cost = Cost::safe;
    186285                                } else if ( assignResult > 0 ) {
    187                                         cost = Cost( 1, 0, 0 );
     286                                        cost = Cost::unsafe;
    188287                                } // if
     288                                // assignResult == 0 means Cost::Infinity
    189289                        } // if
    190290                } else if ( dynamic_cast< ZeroType* >( dest ) != nullptr || dynamic_cast< OneType* >( dest ) != nullptr ) {
    191                         cost = Cost( 1, 0, 0 );
     291                        cost = Cost::unsafe;
    192292                } // if
    193293        }
    194294
    195295        void ConversionCost::visit(__attribute((unused)) ArrayType *arrayType) {}
     296
     297        void ConversionCost::visit(ReferenceType *refType) {
     298                // Note: dest can never be a reference, since it would have been caught in an earlier check
     299                assert( ! dynamic_cast< ReferenceType * >( dest ) );
     300                // convert reference to rvalue: cv T1 & => T2
     301                // recursively compute conversion cost from T1 to T2.
     302                // cv can be safely dropped because of 'implicit dereference' behavior.
     303                refType->get_base()->accept( *this );
     304                if ( refType->get_base()->get_qualifiers() == dest->get_qualifiers() ) {
     305                        cost.incReference();  // prefer exact qualifiers
     306                } else if ( refType->get_base()->get_qualifiers() < dest->get_qualifiers() ) {
     307                        cost.incSafe(); // then gaining qualifiers
     308                } else {
     309                        cost.incUnsafe(); // lose qualifiers as last resort
     310                }
     311                PRINT( std::cerr << refType << " ==> " << dest << " " << cost << std::endl; )
     312        }
     313
    196314        void ConversionCost::visit(__attribute((unused)) FunctionType *functionType) {}
    197315
     
    215333                static Type::Qualifiers q;
    216334                static BasicType integer( q, BasicType::SignedInt );
    217                 integer.accept( *this );
    218                 if ( cost < Cost( 1, 0, 0 ) ) {
     335                integer.accept( *this );  // safe if dest >= int
     336                if ( cost < Cost::unsafe ) {
    219337                        cost.incSafe();
    220338                } // if
     
    238356                        assert( type );
    239357                        if ( type->get_base() ) {
    240                                 cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost( 0, 0, 1 );
     358                                cost = conversionCost( type->get_base(), dest, indexer, env ) + Cost::safe;
    241359                        } // if
    242360                } // if
     
    244362
    245363        void ConversionCost::visit( __attribute((unused)) TupleType *tupleType) {
    246                 Cost c;
     364                Cost c = Cost::zero;
    247365                if ( TupleType *destAsTuple = dynamic_cast< TupleType* >( dest ) ) {
    248366                        std::list< Type* >::const_iterator srcIt = tupleType->get_types().begin();
     
    276394                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    277395                        if ( tableResult == -1 ) {
    278                                 cost = Cost( 1, 0, 0 );
    279                         } else {
    280                                 cost = Cost( 0, 0, tableResult + 1 );
     396                                cost = Cost::unsafe;
     397                        } else {
     398                                cost = Cost::zero;
     399                                cost.incSafe( tableResult + 1 );
    281400                        }
    282401                } else if ( dynamic_cast< PointerType* >( dest ) ) {
    283                         cost = Cost( 0, 0, 1 );
     402                        cost = Cost::safe;
    284403                }
    285404        }
     
    292411                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
    293412                        if ( tableResult == -1 ) {
    294                                 cost = Cost( 1, 0, 0 );
    295                         } else {
    296                                 cost = Cost( 0, 0, tableResult + 1 );
     413                                cost = Cost::unsafe;
     414                        } else {
     415                                cost = Cost::zero;
     416                                cost.incSafe( tableResult + 1 );
    297417                        }
    298418                }
Note: See TracChangeset for help on using the changeset viewer.