Ignore:
Timestamp:
Jun 20, 2019, 2:32:55 PM (5 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
b8524ca, f5edcb4
Parents:
c0f9efe
Message:

Port TupleAssignment? to new AST

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/TupleAssignment.cc

    rc0f9efe r234b1cb  
    2222#include <vector>
    2323
     24#include "AST/Decl.hpp"
     25#include "AST/Init.hpp"
     26#include "AST/Pass.hpp"
     27#include "AST/Stmt.hpp"
     28#include "AST/TypeEnvironment.hpp"
    2429#include "CodeGen/OperatorTable.h"
    2530#include "Common/PassVisitor.h"
    2631#include "Common/UniqueName.h"             // for UniqueName
    27 #include "Common/utility.h"                // for zipWith
     32#include "Common/utility.h"                // for splice, zipWith
    2833#include "Explode.h"                       // for explode
    2934#include "InitTweak/GenInit.h"             // for genCtorInit
     
    5156
    5257namespace Tuples {
    53         class TupleAssignSpotter {
     58        class TupleAssignSpotter_old {
    5459          public:
    5560                // dispatcher for Tuple (multiple and mass) assignment operations
    56                 TupleAssignSpotter( ResolvExpr::AlternativeFinder & );
     61                TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & );
    5762                void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args );
    5863
     
    6267                struct Matcher {
    6368                  public:
    64                         Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     69                        Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    6570                                const ResolvExpr::AltList& rhs );
    6671                        virtual ~Matcher() {}
     
    8085                       
    8186                        ResolvExpr::AltList lhs, rhs;
    82                         TupleAssignSpotter &spotter;
     87                        TupleAssignSpotter_old &spotter;
    8388                        ResolvExpr::Cost baseCost;
    8489                        std::list< ObjectDecl * > tmpDecls;
     
    9095                struct MassAssignMatcher : public Matcher {
    9196                  public:
    92                         MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     97                        MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    9398                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    9499                        virtual void match( std::list< Expression * > &out );
     
    97102                struct MultipleAssignMatcher : public Matcher {
    98103                  public:
    99                         MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     104                        MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    100105                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    101106                        virtual void match( std::list< Expression * > &out );
     
    136141        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    137142                                std::vector<ResolvExpr::AlternativeFinder> &args ) {
    138                 TupleAssignSpotter spotter( currentFinder );
     143                TupleAssignSpotter_old spotter( currentFinder );
    139144                spotter.spot( expr, args );
    140145        }
    141146
    142         TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )
     147        TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    143148                : currentFinder(f) {}
    144149
    145         void TupleAssignSpotter::spot( UntypedExpr * expr,
     150        void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    146151                        std::vector<ResolvExpr::AlternativeFinder> &args ) {
    147152                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     
    224229        }
    225230
    226         void TupleAssignSpotter::match() {
     231        void TupleAssignSpotter_old::match() {
    227232                assert ( matcher != 0 );
    228233
     
    275280        }
    276281
    277         TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter,
     282        TupleAssignSpotter_old::Matcher::Matcher( TupleAssignSpotter_old &spotter,
    278283                const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    279284        : lhs(lhs), rhs(rhs), spotter(spotter),
     
    313318        };
    314319
    315         ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
     320        ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    316321                assert( expr->result && ! expr->get_result()->isVoid() );
    317322                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
     
    329334        }
    330335
    331         void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
     336        void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    332337                static UniqueName lhsNamer( "__massassign_L" );
    333338                static UniqueName rhsNamer( "__massassign_R" );
     
    347352        }
    348353
    349         void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
     354        void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    350355                static UniqueName lhsNamer( "__multassign_L" );
    351356                static UniqueName rhsNamer( "__multassign_R" );
     
    378383        }
    379384
    380         void handleTupleAssignment(
    381                 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
    382                 std::vector< ResolvExpr::CandidateFinder > & args
    383         ) {
    384                 #warning unimplmented
    385                 (void)finder; (void)assign; (void)args;
    386                 assert(false);
    387         }
     385namespace {
     386        /// true if `expr` is of tuple type
     387        bool isTuple( const ast::Expr * expr ) {
     388                if ( ! expr ) return false;
     389                assert( expr->result );
     390                return dynamic_cast< const ast::TupleType * >( expr->result->stripReferences() );
     391        }
     392       
     393        /// true if `expr` is of tuple type or a reference to one
     394        bool refToTuple( const ast::Expr * expr ) {
     395                assert( expr->result );
     396                // check for function returning tuple of reference types
     397                if ( auto castExpr = dynamic_cast< const ast::CastExpr * >( expr ) ) {
     398                        return refToTuple( castExpr->arg );
     399                } else {
     400                        return isTuple( expr );
     401                }
     402        }
     403
     404        /// Dispatcher for tuple (multiple and mass) assignment operations
     405        class TupleAssignSpotter_new final {
     406                /// Actually finds tuple assignment operations, by subclass
     407                struct Matcher {
     408                        ResolvExpr::CandidateList lhs, rhs;
     409                        TupleAssignSpotter_new & spotter;
     410                        CodeLocation location;
     411                        ResolvExpr::Cost baseCost;
     412                        std::vector< ast::ptr< ast::ObjectDecl > > tmpDecls;
     413                        ast::TypeEnvironment env;
     414                        ast::OpenVarSet open;
     415                        ast::AssertionSet need;
     416
     417                        void combineState( const ResolvExpr::Candidate & cand ) {
     418                                env.simpleCombine( cand.env );
     419                                ast::mergeOpenVars( open, cand.open );
     420                                need.insert( cand.need.begin(), cand.need.end() );
     421                        }
     422
     423                        Matcher(
     424                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     425                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     426                        : lhs( l ), rhs( r ), spotter( s ), location( loc ),
     427                          baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ), tmpDecls(),
     428                          env(), open(), need() {
     429                                for ( auto & cand : lhs ) combineState( *cand );
     430                                for ( auto & cand : rhs ) combineState( *cand );
     431                        }
     432
     433                        virtual std::vector< ast::ptr< ast::Expr > > match() = 0;
     434
     435                        /// removes environments from subexpressions within statement expressions, which could
     436                        /// throw off later passes like those in Box which rely on PolyMutator, and adds the
     437                        /// bindings to the env
     438                        struct EnvRemover {
     439                                /// environment to hoist ExprStmt environments to
     440                                ast::TypeEnvironment & tenv;
     441
     442                                EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {}
     443
     444                                const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) {
     445                                        if ( stmt->expr->env ) {
     446                                                tenv.add( *stmt->expr->env );
     447                                                ast::ExprStmt * mut = mutate( stmt );
     448                                                mut->expr.get_and_mutate()->env = nullptr;
     449                                                return mut;
     450                                        }
     451                                        return stmt;
     452                                }
     453                        };
     454
     455                        ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) {
     456                                assert( expr->result && ! expr->result->isVoid() );
     457                               
     458                                ast::ObjectDecl * ret = new ast::ObjectDecl{
     459                                        location, namer.newName(), expr->result, new ast::SingleInit{ location, expr },
     460                                        ast::Storage::Classes{}, ast::Linkage::Cforall };
     461                               
     462                                // if expression type is a reference, just need an initializer, otherwise construct
     463                                if ( ! expr->result.as< ast::ReferenceType >() ) {
     464                                        // resolve ctor/dtor for the new object
     465                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
     466                                                        InitTweak::genCtorInit( ret ), spotter.crntFinder.symtab );
     467                                        // remove environments from subexpressions of stmtExpr
     468                                        ast::Pass< EnvRemover > rm{ env };
     469                                        ret->init = ctorInit->accept( rm );
     470                                }
     471
     472                                PRINT( std::cerr << "new object: " << ret << std::endl; )
     473                                return ret;
     474                        }
     475
     476                        ast::UntypedExpr * createFunc(
     477                                const std::string & fname, const ast::ObjectDecl * left,
     478                                const ast::ObjectDecl * right
     479                        ) {
     480                                assert( left );
     481                                std::vector< ast::ptr< ast::Expr > > args;
     482                                args.emplace_back( new ast::VariableExpr{ location, left } );
     483                                if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); }
     484
     485                                if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
     486                                        args.front() = new ast::AddressExpr{ location, args.front() };
     487                                        if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; }
     488                                        return new ast::UntypedExpr{
     489                                                location, new ast::NameExpr{ location, "?=?" }, std::move(args) };
     490                                } else {
     491                                        return new ast::UntypedExpr{
     492                                                location, new ast::NameExpr{ location, fname }, std::move(args) };
     493                                }
     494                        }
     495                };
     496
     497                /// Finds mass-assignment operations
     498                struct MassAssignMatcher final : public Matcher {
     499                        MassAssignMatcher(
     500                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     501                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     502                        : Matcher( s, loc, l, r ) {}
     503
     504                        std::vector< ast::ptr< ast::Expr > > match() override {
     505                                static UniqueName lhsNamer( "__massassign_L" );
     506                                static UniqueName rhsNamer( "__massassign_R" );
     507                                // empty tuple case falls into this matcher
     508                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     509
     510                                ast::ptr< ast::ObjectDecl > rtmp =
     511                                        rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr;
     512
     513                                std::vector< ast::ptr< ast::Expr > > out;
     514                                for ( ResolvExpr::CandidateRef & lhsCand : lhs ) {
     515                                        // create a temporary object for each value in the LHS and create a call
     516                                        // involving the RHS
     517                                        ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr );
     518                                        out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) );
     519                                        tmpDecls.emplace_back( std::move( ltmp ) );
     520                                }
     521                                if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) );
     522
     523                                return out;
     524                        }
     525                };
     526
     527                /// Finds multiple-assignment operations
     528                struct MultipleAssignMatcher final : public Matcher {
     529                        MultipleAssignMatcher(
     530                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     531                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     532                        : Matcher( s, loc, l, r ) {}
     533
     534                        std::vector< ast::ptr< ast::Expr > > match() override {
     535                                static UniqueName lhsNamer( "__multassign_L" );
     536                                static UniqueName rhsNamer( "__multassign_R" );
     537
     538                                if ( lhs.size() != rhs.size() ) return {};
     539
     540                                // produce a new temporary object for each value in the LHS and RHS and pairwise
     541                                // create the calls
     542                                std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp;
     543
     544                                std::vector< ast::ptr< ast::Expr > > out;
     545                                for ( unsigned i = 0; i < lhs.size(); ++i ) {
     546                                        ResolvExpr::CandidateRef & lhsCand = lhs[i];
     547                                        ResolvExpr::CandidateRef & rhsCand = rhs[i];
     548
     549                                        // convert RHS to LHS type minus one reference -- important for case where LHS
     550                                        // is && and RHS is lvalue
     551                                        auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >();
     552                                        rhsCand->expr = new ast::CastExpr{
     553                                                rhsCand->expr->location, rhsCand->expr, lhsType->base };
     554                                        ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr );
     555                                        ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr );
     556                                        out.emplace_back( createFunc( spotter.fname, lobj, robj ) );
     557                                        ltmp.emplace_back( std::move( lobj ) );
     558                                        rtmp.emplace_back( std::move( robj ) );
     559
     560                                        // resolve the cast expression so that rhsCand return type is bound by the cast
     561                                        // type as needed, and transfer the resulting environment
     562                                        ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
     563                                        finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
     564                                        assert( finder.candidates.size() == 1 );
     565                                        env = std::move( finder.candidates.front()->env );
     566                                }
     567                               
     568                                splice( tmpDecls, ltmp );
     569                                splice( tmpDecls, rtmp );
     570                               
     571                                return out;
     572                        }
     573                };
     574
     575                ResolvExpr::CandidateFinder & crntFinder;
     576                std::string fname;
     577                std::unique_ptr< Matcher > matcher;
     578       
     579        public:
     580                TupleAssignSpotter_new( ResolvExpr::CandidateFinder & f )
     581                : crntFinder( f ), fname(), matcher() {}
     582
     583                // find left- and right-hand-sides for mass or multiple assignment
     584                void spot(
     585                        const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args
     586                ) {
     587                        if ( auto op = expr->func.as< ast::NameExpr >() ) {
     588                                // skip non-assignment functions
     589                                if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return;
     590                                fname = op->name;
     591
     592                                // handled by CandidateFinder if applicable (both odd cases)
     593                                if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) {
     594                                        return;
     595                                }
     596
     597                                // look over all possible left-hand-side
     598                                for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) {
     599                                        // skip non-tuple LHS
     600                                        if ( ! refToTuple( lhsCand->expr ) ) continue;
     601
     602                                        // explode is aware of casts - ensure every LHS is sent into explode with a
     603                                        // reference cast
     604                                        if ( ! lhsCand->expr.as< ast::CastExpr >() ) {
     605                                                lhsCand->expr = new ast::CastExpr{
     606                                                        lhsCand->expr->location, lhsCand->expr,
     607                                                        new ast::ReferenceType{ lhsCand->expr->result } };
     608                                        }
     609
     610                                        // explode the LHS so that each field of a tuple-valued expr is assigned
     611                                        ResolvExpr::CandidateList lhs;
     612                                        explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
     613                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
     614                                                // each LHS value must be a reference - some come in with a cast, if not
     615                                                // just cast to reference here
     616                                                if ( ! cand->expr->result.as< ast::ReferenceType >() ) {
     617                                                        cand->expr = new ast::CastExpr{
     618                                                                cand->expr->location, cand->expr,
     619                                                                new ast::ReferenceType{ cand->expr->result } };
     620                                                }
     621                                        }
     622
     623                                        if ( args.size() == 1 ) {
     624                                                // mass default-initialization/destruction
     625                                                ResolvExpr::CandidateList rhs{};
     626                                                matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
     627                                                match();
     628                                        } else if ( args.size() == 2 ) {
     629                                                for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
     630                                                        ResolvExpr::CandidateList rhs;
     631                                                        if ( isTuple( rhsCand->expr ) ) {
     632                                                                // multiple assignment
     633                                                                explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     634                                                                matcher.reset(
     635                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     636                                                        } else {
     637                                                                // mass assignment
     638                                                                rhs.emplace_back( rhsCand );
     639                                                                matcher.reset(
     640                                                                        new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
     641                                                        }
     642                                                        match();
     643                                                }
     644                                        } else {
     645                                                // expand all possible RHS possibilities
     646                                                std::vector< ResolvExpr::CandidateList > rhsCands;
     647                                                combos(
     648                                                        std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
     649                                                for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
     650                                                        // multiple assignment
     651                                                        ResolvExpr::CandidateList rhs;
     652                                                        explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     653                                                        matcher.reset(
     654                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     655                                                        match();
     656                                                }
     657                                        }
     658                                }
     659                        }
     660                }
     661
     662                void match() {
     663                        assert( matcher );
     664
     665                        std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();
     666
     667                        if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) {
     668                                // if both LHS and RHS are empty than this is the empty tuple case, wherein it's
     669                                // okay for newAssigns to be empty. Otherwise, return early so that no new
     670                                // candidates are generated
     671                                if ( newAssigns.empty() ) return;
     672                        }
     673
     674                        ResolvExpr::CandidateList crnt;
     675                        // now resolve new assignments
     676                        for ( const ast::Expr * expr : newAssigns ) {
     677                                PRINT(
     678                                        std::cerr << "== resolving tuple assign ==" << std::endl;
     679                                        std::cerr << expr << std::endl;
     680                                )
     681
     682                                ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
     683
     684                                try {
     685                                        finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() );
     686                                } catch (...) {
     687                                        // no match is not failure, just that this tuple assignment is invalid
     688                                        return;
     689                                }
     690
     691                                ResolvExpr::CandidateList & cands = finder.candidates;
     692                                assert( cands.size() == 1 );
     693                                assert( cands.front()->expr );
     694                                crnt.emplace_back( std::move( cands.front() ) );
     695                        }
     696
     697                        // extract expressions from the assignment candidates to produce a list of assignments
     698                        // that together form a sigle candidate
     699                        std::vector< ast::ptr< ast::Expr > > solved;
     700                        for ( ResolvExpr::CandidateRef & cand : crnt ) {
     701                                solved.emplace_back( cand->expr );
     702                                matcher->combineState( *cand );
     703                        }
     704
     705                        crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
     706                                new ast::TupleAssignExpr{
     707                                        matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) },
     708                                std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),
     709                                ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );
     710                }
     711        };
     712} // anonymous namespace
     713
     714void handleTupleAssignment(
     715        ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     716        std::vector< ResolvExpr::CandidateFinder > & args
     717) {
     718        TupleAssignSpotter_new spotter{ finder };
     719        spotter.spot( assign, args );
     720}
     721
    388722} // namespace Tuples
    389723
Note: See TracChangeset for help on using the changeset viewer.