Changeset 5b643ea


Ignore:
Timestamp:
Aug 16, 2024, 12:06:25 PM (5 weeks ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
afb15cf
Parents:
cef5bfc (diff), 8da3cc4d (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

Files:
6 added
3 edited

Legend:

Unmodified
Added
Removed
  • src/GenPoly/GenPoly.cpp

    rcef5bfc r5b643ea  
    2727#include "AST/Type.hpp"
    2828#include "AST/TypeSubstitution.hpp"
     29#include "Common/Eval.hpp"                // for eval
    2930#include "GenPoly/ErasableScopedMap.hpp"  // for ErasableScopedMap<>::const_...
    3031#include "ResolvExpr/Typeops.hpp"         // for flatten
     
    243244} // namespace
    244245
     246// This function, and its helpers following, have logic duplicated from
     247// unification.  The difference in context is that unification applies where
     248// the types "must" match, while this variation applies to arbitrary type
     249// pairs, when an optimization could apply if they happen to match.  This
     250// variation does not bind type variables.  The helper functions support
     251// the case for matching ArrayType.
     252bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
     253
     254static bool exprsPolyCompatibleByStaticValue(
     255                const ast::Expr * e1, const ast::Expr * e2 ) {
     256        Evaluation r1 = eval(e1);
     257        Evaluation r2 = eval(e2);
     258
     259        if ( !r1.hasKnownValue ) return false;
     260        if ( !r2.hasKnownValue ) return false;
     261
     262        if ( r1.knownValue != r2.knownValue ) return false;
     263
     264        return true;
     265}
     266
     267static bool exprsPolyCompatible( ast::Expr const * lhs,
     268                ast::Expr const * rhs ) {
     269        type_index const lid = typeid(*lhs);
     270        type_index const rid = typeid(*rhs);
     271        if ( lid != rid ) return false;
     272
     273        if ( exprsPolyCompatibleByStaticValue( lhs, rhs ) ) return true;
     274
     275        if ( type_index(typeid(ast::CastExpr)) == lid ) {
     276                ast::CastExpr const * l = as<ast::CastExpr>(lhs);
     277                ast::CastExpr const * r = as<ast::CastExpr>(rhs);
     278
     279                // inspect casts' target types
     280                if ( !typesPolyCompatible(
     281                        l->result, r->result ) ) return false;
     282
     283                // inspect casts' inner expressions
     284                return exprsPolyCompatible( l->arg, r->arg );
     285
     286        } else if ( type_index(typeid(ast::VariableExpr)) == lid ) {
     287                ast::VariableExpr const * l = as<ast::VariableExpr>(lhs);
     288                ast::VariableExpr const * r = as<ast::VariableExpr>(rhs);
     289
     290                assert(l->var);
     291                assert(r->var);
     292
     293                // conservative: variable exprs match if their declarations are
     294                // represented by the same C++ AST object
     295                return (l->var == r->var);
     296
     297        } else if ( type_index(typeid(ast::SizeofExpr)) == lid ) {
     298                ast::SizeofExpr const * l = as<ast::SizeofExpr>(lhs);
     299                ast::SizeofExpr const * r = as<ast::SizeofExpr>(rhs);
     300
     301                assert((l->type != nullptr) ^ (l->expr != nullptr));
     302                assert((r->type != nullptr) ^ (r->expr != nullptr));
     303                if ( !(l->type && r->type) ) return false;
     304
     305                // mutual recursion with type poly compatibility
     306                return typesPolyCompatible( l->type, r->type );
     307
     308        } else {
     309                // All other forms compare on static value only, done earlier
     310                return false;
     311        }
     312}
     313
    245314bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ) {
    246315        type_index const lid = typeid(*lhs);
     
    256325
    257326        // So remaining types can be examined case by case.
    258         // Recurse through type structure (conditions borrowed from Unify.cpp).
     327        // Recurse through type structure (conditions duplicated from Unify.cpp).
    259328
    260329        if ( type_index(typeid(ast::BasicType)) == lid ) {
     
    280349                ast::ArrayType const * r = as<ast::ArrayType>(rhs);
    281350
    282                 if ( l->isVarLen ) {
    283                         if ( !r->isVarLen ) return false;
    284                 } else {
    285                         if ( r->isVarLen ) return false;
    286 
    287                         auto lc = l->dimension.as<ast::ConstantExpr>();
    288                         auto rc = r->dimension.as<ast::ConstantExpr>();
    289                         if ( lc && rc && lc->intValue() != rc->intValue() ) {
     351                if ( l->isVarLen != r->isVarLen ) return false;
     352                if ( (l->dimension != nullptr) != (r->dimension != nullptr) )
     353                        return false;
     354
     355                if ( l->dimension ) {
     356                        assert( r->dimension );
     357                        // mutual recursion with expression poly compatibility
     358                        if ( !exprsPolyCompatible(l->dimension, r->dimension) )
    290359                                return false;
    291                         }
    292360                }
    293361
  • src/ResolvExpr/CandidateFinder.cpp

    rcef5bfc r5b643ea  
    12411241                Cost minCastCost = Cost::infinity;
    12421242                for ( CandidateRef & cand : finder.candidates ) {
     1243                        ast::ptr< ast::Type > fromType = cand->expr->result;
     1244                        assert( fromType );
     1245                        fromType = resolveTypeof( fromType, context );
     1246                        fromType = adjustExprType( fromType, tenv, symtab );
     1247
    12431248                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    12441249                        ast::OpenVarSet open( cand->open );
     
    12501255                        // subexpression results that are cast directly. The candidate is invalid if it
    12511256                        // has fewer results than there are types to cast to.
    1252                         int discardedValues = cand->expr->result->size() - toType->size();
     1257                        int discardedValues = fromType->size() - toType->size();
    12531258                        if ( discardedValues < 0 ) continue;
    12541259
    12551260                        // unification run for side-effects
    1256                         unify( toType, cand->expr->result, cand->env, need, have, open );
     1261                        unify( toType, fromType, cand->env, need, have, open );
    12571262                        Cost thisCost =
    12581263                                (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1259                                         ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1260                                         : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1264                                        ? conversionCost( fromType, toType, cand->expr->get_lvalue(), symtab, cand->env )
     1265                                        : castCost( fromType, toType, cand->expr->get_lvalue(), symtab, cand->env );
    12611266                       
    12621267                        // Redefine enum cast
    1263                         auto argAsEnum = cand->expr->result.as<ast::EnumInstType>();
     1268                        auto argAsEnum = fromType.as<ast::EnumInstType>();
    12641269                        auto toAsEnum = toType.as<ast::EnumInstType>();
    12651270                        if ( argAsEnum && toAsEnum && argAsEnum->name != toAsEnum->name ) {
     
    12721277                        PRINT(
    12731278                                std::cerr << "working on cast with result: " << toType << std::endl;
    1274                                 std::cerr << "and expr type: " << cand->expr->result << std::endl;
     1279                                std::cerr << "and expr type: " << fromType << std::endl;
    12751280                                std::cerr << "env: " << cand->env << std::endl;
    12761281                        )
     
    12811286                                // count one safe conversion for each value that is thrown away
    12821287                                thisCost.incSafe( discardedValues );
     1288
     1289                                // See Aaron Moss, page 47; this reasoning does not hold since implicit conversions
     1290                                // can create the same resolution issue. The C intrinsic interpretations are pruned
     1291                                // immediately for the lowest cost option regardless of result type. Related code in
     1292                                // postvisit (UntypedExpr).
     1293                                // Cast expression costs are updated now to use the general rules.
     1294                                /*
    12831295                                // select first on argument cost, then conversion cost
    12841296                                if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) {
     
    12891301                                // ambigious case, still output candidates to print in error message
    12901302                                if ( cand->cost == minExprCost && thisCost == minCastCost ) {
     1303                                */
     1304                                cand->cost += thisCost;
     1305                                if (cand->cost < minExprCost) {
     1306                                        minExprCost = cand->cost;
     1307                                        matches.clear();
     1308                                }
     1309                                if (cand->cost == minExprCost) {
    12911310                                        CandidateRef newCand = std::make_shared<Candidate>(
    12921311                                                restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1293                                                 copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);
     1312                                                copy( cand->env ), std::move( open ), std::move( need ), cand->cost);
    12941313                                        // currently assertions are always resolved immediately so this should have no effect.
    12951314                                        // if this somehow changes in the future (e.g. delayed by indeterminate return type)
  • tests/array-collections/dimexpr-match.hfa

    rcef5bfc r5b643ea  
    1515//
    1616//      compiler=gcc -x c           # pick one
    17 //      compiler=$fa
     17//      compiler=$cfa
    1818//
    1919//      test=dimexpr-match-c.cfa    # pick one
Note: See TracChangeset for help on using the changeset viewer.