Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/TupleAssignment.cc

    r0bd3faf r46da46b  
    2828#include "AST/TypeEnvironment.hpp"
    2929#include "CodeGen/OperatorTable.h"
     30#include "Common/PassVisitor.h"
    3031#include "Common/UniqueName.h"             // for UniqueName
    3132#include "Common/utility.h"                // for splice, zipWith
     
    3334#include "InitTweak/GenInit.h"             // for genCtorInit
    3435#include "InitTweak/InitTweak.h"           // for getPointerBase, isAssignment
     36#include "ResolvExpr/Alternative.h"        // for AltList, Alternative
     37#include "ResolvExpr/AlternativeFinder.h"  // for AlternativeFinder, simpleC...
    3538#include "ResolvExpr/Cost.h"               // for Cost
    3639#include "ResolvExpr/Resolver.h"           // for resolveCtorInit
     40#include "ResolvExpr/TypeEnvironment.h"    // for TypeEnvironment
    3741#include "ResolvExpr/typeops.h"            // for combos
     42#include "SynTree/LinkageSpec.h"           // for Cforall
     43#include "SynTree/Declaration.h"           // for ObjectDecl
     44#include "SynTree/Expression.h"            // for Expression, CastExpr, Name...
     45#include "SynTree/Initializer.h"           // for ConstructorInit, SingleInit
     46#include "SynTree/Statement.h"             // for ExprStmt
     47#include "SynTree/Type.h"                  // for Type, Type::Qualifiers
     48#include "SynTree/TypeSubstitution.h"      // for TypeSubstitution
     49#include "SynTree/Visitor.h"               // for Visitor
    3850
    3951#if 0
     
    4456
    4557namespace Tuples {
     58        class TupleAssignSpotter_old {
     59          public:
     60                // dispatcher for Tuple (multiple and mass) assignment operations
     61                TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
     62                void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
     63
     64          private:
     65                void match();
     66
     67                struct Matcher {
     68                  public:
     69                        Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
     70                                const ResolvExpr::AltList& rhs );
     71                        virtual ~Matcher() {}
     72
     73                        virtual void match( std::list< Expression * > &out ) = 0;
     74                        ObjectDecl * newObject( UniqueName & namer, Expression * expr );
     75
     76                        void combineState( const ResolvExpr::Alternative& alt ) {
     77                                compositeEnv.simpleCombine( alt.env );
     78                                ResolvExpr::mergeOpenVars( openVars, alt.openVars );
     79                                cloneAll( alt.need, need );
     80                        }
     81
     82                        void combineState( const ResolvExpr::AltList& alts ) {
     83                                for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); }
     84                        }
     85
     86                        ResolvExpr::AltList lhs, rhs;
     87                        TupleAssignSpotter_old &spotter;
     88                        ResolvExpr::Cost baseCost;
     89                        std::list< ObjectDecl * > tmpDecls;
     90                        ResolvExpr::TypeEnvironment compositeEnv;
     91                        ResolvExpr::OpenVarSet openVars;
     92                        ResolvExpr::AssertionSet need;
     93                };
     94
     95                struct MassAssignMatcher : public Matcher {
     96                  public:
     97                        MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
     98                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
     99                        virtual void match( std::list< Expression * > &out );
     100                };
     101
     102                struct MultipleAssignMatcher : public Matcher {
     103                  public:
     104                        MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
     105                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
     106                        virtual void match( std::list< Expression * > &out );
     107                };
     108
     109                ResolvExpr::AlternativeFinder &currentFinder;
     110                std::string fname;
     111                std::unique_ptr< Matcher > matcher;
     112        };
     113
     114        /// true if expr is an expression of tuple type
     115        bool isTuple( Expression *expr ) {
     116                if ( ! expr ) return false;
     117                assert( expr->result );
     118                return dynamic_cast< TupleType * >( expr->get_result()->stripReferences() );
     119        }
     120
     121        template< typename AltIter >
     122        bool isMultAssign( AltIter begin, AltIter end ) {
     123                // multiple assignment if more than one alternative in the range or if
     124                // the alternative is a tuple
     125                if ( begin == end ) return false;
     126                if ( isTuple( begin->expr ) ) return true;
     127                return ++begin != end;
     128        }
     129
     130        bool refToTuple( Expression *expr ) {
     131                assert( expr->get_result() );
     132                // also check for function returning tuple of reference types
     133                if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
     134                        return refToTuple( castExpr->get_arg() );
     135                } else {
     136                        return isTuple( expr );
     137                }
     138                return false;
     139        }
     140
     141        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
     142                                std::vector<ResolvExpr::AlternativeFinder> &args ) {
     143                TupleAssignSpotter_old spotter( currentFinder );
     144                spotter.spot( expr, args );
     145        }
     146
     147        TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
     148                : currentFinder(f) {}
     149
     150        void TupleAssignSpotter_old::spot( UntypedExpr * expr,
     151                        std::vector<ResolvExpr::AlternativeFinder> &args ) {
     152                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     153                        if ( CodeGen::isCtorDtorAssign( op->get_name() ) ) {
     154                                fname = op->get_name();
     155
     156                                // AlternativeFinder will naturally handle this case case, if it's legal
     157                                if ( args.size() == 0 ) return;
     158
     159                                // if an assignment only takes 1 argument, that's odd, but maybe someone wrote
     160                                // the function, in which case AlternativeFinder will handle it normally
     161                                if ( args.size() == 1 && CodeGen::isAssignment( fname ) ) return;
     162
     163                                // look over all possible left-hand-sides
     164                                for ( ResolvExpr::Alternative& lhsAlt : args[0] ) {
     165                                        // skip non-tuple LHS
     166                                        if ( ! refToTuple(lhsAlt.expr) ) continue;
     167
     168                                        // explode is aware of casts - ensure every LHS expression is sent into explode
     169                                        // with a reference cast
     170                                        // xxx - this seems to change the alternatives before the normal
     171                                        //  AlternativeFinder flow; maybe this is desired?
     172                                        if ( ! dynamic_cast<CastExpr*>( lhsAlt.expr ) ) {
     173                                                lhsAlt.expr = new CastExpr( lhsAlt.expr,
     174                                                                new ReferenceType( Type::Qualifiers(),
     175                                                                        lhsAlt.expr->result->clone() ) );
     176                                        }
     177
     178                                        // explode the LHS so that each field of a tuple-valued-expr is assigned
     179                                        ResolvExpr::AltList lhs;
     180                                        explode( lhsAlt, currentFinder.get_indexer(), back_inserter(lhs), true );
     181                                        for ( ResolvExpr::Alternative& alt : lhs ) {
     182                                                // each LHS value must be a reference - some come in with a cast expression,
     183                                                // if not just cast to reference here
     184                                                if ( ! dynamic_cast<ReferenceType*>( alt.expr->get_result() ) ) {
     185                                                        alt.expr = new CastExpr( alt.expr,
     186                                                                new ReferenceType( Type::Qualifiers(),
     187                                                                        alt.expr->get_result()->clone() ) );
     188                                                }
     189                                        }
     190
     191                                        if ( args.size() == 1 ) {
     192                                                // mass default-initialization/destruction
     193                                                ResolvExpr::AltList rhs{};
     194                                                matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
     195                                                match();
     196                                        } else if ( args.size() > 2 ) {
     197                                                // expand all possible RHS possibilities
     198                                                // TODO build iterative version of this instead of using combos
     199                                                std::vector< ResolvExpr::AltList > rhsAlts;
     200                                                combos( std::next(args.begin(), 1), args.end(),
     201                                                        std::back_inserter( rhsAlts ) );
     202                                                for ( const ResolvExpr::AltList& rhsAlt : rhsAlts ) {
     203                                                        // multiple assignment
     204                                                        ResolvExpr::AltList rhs;
     205                                                        explode( rhsAlt, currentFinder.get_indexer(),
     206                                                                std::back_inserter(rhs), true );
     207                                                        matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
     208                                                        match();
     209                                                }
     210                                        } else {
     211                                                for ( const ResolvExpr::Alternative& rhsAlt : args[1] ) {
     212                                                        ResolvExpr::AltList rhs;
     213                                                        if ( isTuple(rhsAlt.expr) ) {
     214                                                                // multiple assignment
     215                                                                explode( rhsAlt, currentFinder.get_indexer(),
     216                                                                        std::back_inserter(rhs), true );
     217                                                                matcher.reset( new MultipleAssignMatcher( *this, lhs, rhs ) );
     218                                                        } else {
     219                                                                // mass assignment
     220                                                                rhs.push_back( rhsAlt );
     221                                                                matcher.reset( new MassAssignMatcher( *this, lhs, rhs ) );
     222                                                        }
     223                                                        match();
     224                                                }
     225                                        }
     226                                }
     227                        }
     228                }
     229        }
     230
     231        void TupleAssignSpotter_old::match() {
     232                assert ( matcher != 0 );
     233
     234                std::list< Expression * > new_assigns;
     235                matcher->match( new_assigns );
     236
     237                if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
     238                        // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
     239                        // if not the empty tuple case, return early so that no new alternatives are generated.
     240                        if ( new_assigns.empty() ) return;
     241                }
     242                ResolvExpr::AltList current;
     243                // now resolve new assignments
     244                for ( std::list< Expression * >::iterator i = new_assigns.begin();
     245                                i != new_assigns.end(); ++i ) {
     246                        PRINT(
     247                                std::cerr << "== resolving tuple assign ==" << std::endl;
     248                                std::cerr << *i << std::endl;
     249                        )
     250
     251                        ResolvExpr::AlternativeFinder finder{ currentFinder.get_indexer(),
     252                                matcher->compositeEnv };
     253
     254                        try {
     255                                finder.findWithAdjustment(*i);
     256                        } catch (...) {
     257                                return; // no match should not mean failure, it just means this particular tuple assignment isn't valid
     258                        }
     259                        // prune expressions that don't coincide with
     260                        ResolvExpr::AltList alts = finder.get_alternatives();
     261                        assert( alts.size() == 1 );
     262                        assert( alts.front().expr != 0 );
     263                        current.push_back( alts.front() );
     264                }
     265
     266                // extract expressions from the assignment alternatives to produce a list of assignments
     267                // that together form a single alternative
     268                std::list< Expression *> solved_assigns;
     269                for ( ResolvExpr::Alternative & alt : current ) {
     270                        solved_assigns.push_back( alt.expr->clone() );
     271                        matcher->combineState( alt );
     272                }
     273
     274                // xxx -- was push_front
     275                currentFinder.get_alternatives().push_back( ResolvExpr::Alternative{
     276                        new TupleAssignExpr{ solved_assigns, matcher->tmpDecls }, matcher->compositeEnv,
     277                        matcher->openVars,
     278                        ResolvExpr::AssertionList( matcher->need.begin(), matcher->need.end() ),
     279                        ResolvExpr::sumCost( current ) + matcher->baseCost } );
     280        }
     281
     282        TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
     283                const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
     284        : lhs(lhs), rhs(rhs), spotter(spotter),
     285          baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
     286                combineState( lhs );
     287                combineState( rhs );
     288        }
     289
     290        UntypedExpr * createFunc( const std::string &fname, ObjectDecl *left, ObjectDecl *right ) {
     291                assert( left );
     292                std::list< Expression * > args;
     293                args.push_back( new VariableExpr( left ) );
     294                // args.push_back( new AddressExpr( new VariableExpr( left ) ) );
     295                if ( right ) args.push_back( new VariableExpr( right ) );
     296                if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
     297                        args.front() = new AddressExpr( args.front() );
     298                        if ( right ) args.back() = new AddressExpr( args.back() );
     299                        return new UntypedExpr( new NameExpr( "?=?" ), args );
     300                } else {
     301                        return new UntypedExpr( new NameExpr( fname ), args );
     302                }
     303        }
     304
     305        // removes environments from subexpressions within statement exprs, which could throw off later passes like those in Box which rely on PolyMutator, and adds the bindings to the compositeEnv
     306        // xxx - maybe this should happen in alternative finder for every StmtExpr?
     307        struct EnvRemover {
     308                void previsit( ExprStmt * stmt ) {
     309                        assert( compositeEnv );
     310                        if ( stmt->expr->env ) {
     311                                compositeEnv->add( *stmt->expr->env );
     312                                delete stmt->expr->env;
     313                                stmt->expr->env = nullptr;
     314                        }
     315                }
     316
     317                ResolvExpr::TypeEnvironment * compositeEnv = nullptr;
     318        };
     319
     320        ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
     321                assert( expr->result && ! expr->get_result()->isVoid() );
     322                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
     323                // if expression type is a reference, don't need to construct anything, a simple initializer is sufficient.
     324                if ( ! dynamic_cast< ReferenceType * >( expr->result ) ) {
     325                        ConstructorInit * ctorInit = InitTweak::genCtorInit( ret );
     326                        ret->init = ctorInit;
     327                        ResolvExpr::resolveCtorInit( ctorInit, spotter.currentFinder.get_indexer() ); // resolve ctor/dtors for the new object
     328                        PassVisitor<EnvRemover> rm; // remove environments from subexpressions of StmtExprs
     329                        rm.pass.compositeEnv = &compositeEnv;
     330                        ctorInit->accept( rm );
     331                }
     332                PRINT( std::cerr << "new object: " << ret << std::endl; )
     333                return ret;
     334        }
     335
     336        void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
     337                static UniqueName lhsNamer( "__massassign_L" );
     338                static UniqueName rhsNamer( "__massassign_R" );
     339                // empty tuple case falls into this matcher, hence the second part of the assert
     340                assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
     341
     342                // xxx - may need to split this up into multiple declarations, because potential conversion to references
     343                //  probably should not reference local variable - see MultipleAssignMatcher::match
     344                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
     345                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
     346                        // create a temporary object for each value in the lhs and create a call involving the rhs
     347                        ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
     348                        out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
     349                        tmpDecls.push_back( ltmp );
     350                }
     351                if ( rtmp ) tmpDecls.push_back( rtmp );
     352        }
     353
     354        void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
     355                static UniqueName lhsNamer( "__multassign_L" );
     356                static UniqueName rhsNamer( "__multassign_R" );
     357
     358                if ( lhs.size() == rhs.size() ) {
     359                        // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
     360                        std::list< ObjectDecl * > ltmp;
     361                        std::list< ObjectDecl * > rtmp;
     362                        for ( auto p : group_iterate( lhs, rhs ) ) {
     363                                ResolvExpr::Alternative & lhsAlt = std::get<0>(p);
     364                                ResolvExpr::Alternative & rhsAlt = std::get<1>(p);
     365                                // convert RHS to LHS type minus one reference -- important for the case where LHS is && and RHS is lvalue, etc.
     366                                ReferenceType * lhsType = strict_dynamic_cast<ReferenceType *>( lhsAlt.expr->result );
     367                                rhsAlt.expr = new CastExpr( rhsAlt.expr, lhsType->base->clone() );
     368                                ObjectDecl * lobj = newObject( lhsNamer, lhsAlt.expr );
     369                                ObjectDecl * robj = newObject( rhsNamer, rhsAlt.expr );
     370                                out.push_back( createFunc(spotter.fname, lobj, robj) );
     371                                ltmp.push_back( lobj );
     372                                rtmp.push_back( robj );
     373
     374                                // resolve the cast expression so that rhsAlt return type is bound by the cast type as needed, and transfer the resulting environment
     375                                ResolvExpr::AlternativeFinder finder{ spotter.currentFinder.get_indexer(), compositeEnv };
     376                                finder.findWithAdjustment( rhsAlt.expr );
     377                                assert( finder.get_alternatives().size() == 1 );
     378                                compositeEnv = std::move( finder.get_alternatives().front().env );
     379                        }
     380                        tmpDecls.splice( tmpDecls.end(), ltmp );
     381                        tmpDecls.splice( tmpDecls.end(), rtmp );
     382                }
     383        }
    46384
    47385namespace {
     
    65403
    66404        /// Dispatcher for tuple (multiple and mass) assignment operations
    67         class TupleAssignSpotter final {
     405        class TupleAssignSpotter_new final {
    68406                /// Actually finds tuple assignment operations, by subclass
    69407                struct Matcher {
    70408                        ResolvExpr::CandidateList lhs, rhs;
    71                         TupleAssignSpotter & spotter;
     409                        TupleAssignSpotter_new & spotter;
    72410                        CodeLocation location;
    73411                        ResolvExpr::Cost baseCost;
     
    84422
    85423                        Matcher(
    86                                 TupleAssignSpotter & s, const CodeLocation & loc,
     424                                TupleAssignSpotter_new & s, const CodeLocation & loc,
    87425                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    88426                        : lhs( l ), rhs( r ), spotter( s ), location( loc ),
     
    161499                struct MassAssignMatcher final : public Matcher {
    162500                        MassAssignMatcher(
    163                                 TupleAssignSpotter & s, const CodeLocation & loc,
     501                                TupleAssignSpotter_new & s, const CodeLocation & loc,
    164502                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    165503                        : Matcher( s, loc, l, r ) {}
     
    191529                struct MultipleAssignMatcher final : public Matcher {
    192530                        MultipleAssignMatcher(
    193                                 TupleAssignSpotter & s, const CodeLocation & loc,
     531                                TupleAssignSpotter_new & s, const CodeLocation & loc,
    194532                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
    195533                        : Matcher( s, loc, l, r ) {}
     
    240578
    241579        public:
    242                 TupleAssignSpotter( ResolvExpr::CandidateFinder & f )
     580                TupleAssignSpotter_new( ResolvExpr::CandidateFinder & f )
    243581                : crntFinder( f ), fname(), matcher() {}
    244582
     
    377715        std::vector< ResolvExpr::CandidateFinder > & args
    378716) {
    379         TupleAssignSpotter spotter{ finder };
     717        TupleAssignSpotter_new spotter{ finder };
    380718        spotter.spot( assign, args );
    381719}
Note: See TracChangeset for help on using the changeset viewer.