Changeset b067d9b for src/Tuples


Ignore:
Timestamp:
Oct 29, 2019, 4:01:24 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
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, stuck-waitfor-destruct
Children:
773db65, 9421f3d8
Parents:
7951100 (diff), 8364209 (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

Location:
src/Tuples
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/Explode.cc

    r7951100 rb067d9b  
    99// Author           : Rob Schluntz
    1010// Created On       : Wed Nov 9 13:12:24 2016
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Wed Nov 9 13:20:24 2016
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jun 12 16:40:00 2016
     13// Update Count     : 3
    1414//
    1515
     
    106106                return expr;
    107107        }
     108
     109namespace {
     110
     111// Remove one level of reference from a reference type.
     112const ast::Type * getReferenceBase( const ast::Type * t ) {
     113        if ( const ast::ReferenceType * ref = dynamic_cast< const ast::ReferenceType * >( t ) ) {
     114                return ref->base;
     115        } else {
     116                assertf( false, "getReferenceBase for non-ref: %s", toString( t ).c_str() );
     117                return nullptr;
     118        }
     119}
     120
     121struct CastExploderCore {
     122        bool castAdded = false;
     123        bool foundUniqueExpr = false;
     124        const ast::Expr * applyCast( const ast::Expr * expr, bool first = true ) {
     125                // On tuple push the cast down.
     126                if ( const ast::TupleExpr * tupleExpr = dynamic_cast< const ast::TupleExpr * >( expr ) ) {
     127                        foundUniqueExpr = true;
     128                        std::vector< ast::ptr< ast::Expr > > exprs;
     129                        for ( const ast::Expr * expr : tupleExpr->exprs ) {
     130                                exprs.emplace_back( applyCast( expr, false ) );
     131                                //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
     132                        }
     133                        if ( first ) {
     134                                castAdded = true;
     135                                const ast::Expr * tuple = new ast::TupleExpr{
     136                                        tupleExpr->location, std::move( exprs ) };
     137                                return new ast::CastExpr{ tuple, new ast::ReferenceType{ tuple->result } };
     138                        } else {
     139                                return new ast::TupleExpr( tupleExpr->location, std::move( exprs ) );
     140                        }
     141                }
     142                if ( dynamic_cast< const ast::ReferenceType * >( expr->result.get() ) ) {
     143                        return expr;
     144                } else {
     145                        castAdded = true;
     146                        return new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
     147                }
     148        }
     149
     150        const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
     151                // move cast into unique expr so that the unique expr has type T& rather than
     152                // type T. In particular, this transformation helps with generating the
     153                // correct code for reference-cast member tuple expressions, since the result
     154                // should now be a tuple of references rather than a reference to a tuple.
     155                // Still, this code is a bit awkward, and could use some improvement.
     156                const ast::UniqueExpr * newNode = new ast::UniqueExpr( node->location,
     157                                applyCast( node->expr ), node->id );
     158                if ( castAdded ) {
     159                        // if a cast was added by applyCast, then unique expr now has one more layer of reference
     160                        // than it had coming into this function. To ensure types still match correctly, need to cast
     161                        //  to reference base so that outer expressions are still correct.
     162                        castAdded = false;
     163                        const ast::Type * newType = getReferenceBase( newNode->result );
     164                        return new ast::CastExpr{ newNode->location, node, newType };
     165                }
     166                return newNode;
     167        }
     168
     169        const ast::Expr * postmutate( const ast::TupleIndexExpr * tupleExpr ) {
     170                // tuple index expr needs to be rebuilt to ensure that the type of the
     171                // field is consistent with the type of the tuple expr, since the field
     172                // may have changed from type T to T&.
     173                return new ast::TupleIndexExpr( tupleExpr->location, tupleExpr->tuple, tupleExpr->index );
     174        }
     175};
     176
     177} // namespace
     178
     179const ast::Expr * distributeReference( const ast::Expr * expr ) {
     180        ast::Pass<CastExploderCore> exploder;
     181        expr = expr->accept( exploder );
     182        if ( ! exploder.pass.foundUniqueExpr ) {
     183                expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
     184        }
     185        return expr;
     186}
     187
    108188} // namespace Tuples
    109189
  • src/Tuples/Explode.h

    r7951100 rb067d9b  
    99// Author           : Rob Schluntz
    1010// Created On       : Wed Nov 9 13:12:24 2016
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:55:16 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Jun 17 14:36:00 2019
     13// Update Count     : 4
    1414//
    1515
     
    1919#include <utility>                      // for forward
    2020
     21#include "AST/Expr.hpp"
    2122#include "ResolvExpr/Alternative.h"     // for Alternative, AltList
     23#include "ResolvExpr/Candidate.hpp"     // for Candidate, CandidateList
    2224#include "ResolvExpr/ExplodedActual.h"  // for ExplodedActual
     25#include "ResolvExpr/ExplodedArg.hpp"   // for ExplodedArg
    2326#include "SynTree/Expression.h"         // for Expression, UniqueExpr, AddressExpr
    2427#include "SynTree/Type.h"               // for TupleType, Type
    2528#include "Tuples.h"                     // for maybeImpure
     29
     30namespace ast {
     31        class SymbolTable;
     32}
    2633
    2734namespace SymTab {
     
    4451        template<typename OutputIterator>
    4552        void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env,
     53                        const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need,
    4654                        const ResolvExpr::Cost& cost, const ResolvExpr::Cost& cvtCost ) {
    47                 *out++ = ResolvExpr::Alternative{ expr, env, cost, cvtCost };
     55                *out++ = ResolvExpr::Alternative{ expr, env, openVars, need, cost, cvtCost };
    4856        }
    4957
    5058        /// Append alternative to an ExplodedActual
    5159        static inline void append( ResolvExpr::ExplodedActual& ea, Expression* expr,
    52                         const ResolvExpr::TypeEnvironment&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
     60                        const ResolvExpr::TypeEnvironment&, const ResolvExpr::OpenVarSet&,
     61                        const ResolvExpr::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
    5362                ea.exprs.emplace_back( expr );
    54                 /// xxx -- merge environment, cost?
     63                /// xxx -- merge environment, openVars, need, cost?
    5564        }
    5665
     
    6877                                        // distribute reference cast over all components
    6978                                        append( std::forward<Output>(out), distributeReference( alt.release_expr() ),
    70                                                 alt.env, alt.cost, alt.cvtCost );
     79                                                alt.env, alt.openVars, alt.need, alt.cost, alt.cvtCost );
    7180                                }
    7281                                // in tuple assignment, still need to handle the other cases, but only if not already handled here (don't want to output too many alternatives)
     
    102111                } else {
    103112                        // atomic (non-tuple) type - output a clone of the expression in a new alternative
    104                         append( std::forward<Output>(out), expr->clone(), alt.env, alt.cost, alt.cvtCost );
     113                        append( std::forward<Output>(out), expr->clone(), alt.env, alt.openVars, alt.need,
     114                                alt.cost, alt.cvtCost );
    105115                }
    106116        }
     
    127137                explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign );
    128138        }
     139
     140const ast::Expr * distributeReference( const ast::Expr * );
     141
     142/// Append candidate to an OutputIterator of Candidates.
     143template<typename OutputIterator>
     144void append( OutputIterator out, const ast::Expr * expr, const ast::TypeEnvironment & env,
     145                const ast::OpenVarSet & open, const ast::AssertionList & need,
     146                const ResolvExpr::Cost & cost, const ResolvExpr::Cost & cvtCost ) {
     147        ast::TypeEnvironment copyEnv = env;
     148        ast::OpenVarSet copyOpen = open;
     149        ast::AssertionSet set;
     150        mergeAssertionSet( set, need );
     151        *out++ = std::make_shared<ResolvExpr::Candidate>( expr, std::move( copyEnv ),
     152                std::move( copyOpen ), std::move( set ), cost, cvtCost );
     153}
     154
     155/// Append candidate to an ExplodedArg.
     156static inline void append( ResolvExpr::ExplodedArg& ea, const ast::Expr * expr,
     157                const ast::TypeEnvironment&, const ast::OpenVarSet&,
     158                const ast::AssertionList&, const ResolvExpr::Cost&, const ResolvExpr::Cost& ) {
     159        // I'm not sure why most of the arguments are unused. But they were in the old version.
     160        ea.exprs.emplace_back( expr );
     161}
     162
     163/// Check if the expression is a cast to a reference type, return it if it is.
     164static inline const ast::CastExpr * isReferenceCast( const ast::Expr * expr ) {
     165        if ( const ast::CastExpr * cast = dynamic_cast< const ast::CastExpr * >( expr ) ) {
     166                if ( dynamic_cast< const ast::ReferenceType * >( cast->result.get() ) ) {
     167                        return cast;
     168                }
     169        }
     170        return nullptr;
     171}
     172
     173/// helper function (indirectely) used by explode
     174template< typename Output >
     175void explodeRecursive(
     176        const ast::CastExpr *, const ResolvExpr::Candidate &,
     177        const ast::SymbolTable &, Output &&
     178) {
     179}
     180
     181/// helper function used by explode
     182template< typename Output >
     183void explodeUnique(
     184        const ast::ptr< ast::Expr > & expr, const ResolvExpr::Candidate & arg,
     185        const ast::SymbolTable & symtab, Output && out, bool isTupleAssign
     186) {
     187        // Tuple assignment can use a faster method if it is cast. Uses recursive exploding.
     188        if ( isTupleAssign ) if ( const ast::CastExpr * castExpr = isReferenceCast( expr ) ) {
     189                ResolvExpr::CandidateList candidates;
     190                explodeUnique( castExpr->arg, arg, symtab, back_inserter( candidates ), true );
     191                for ( ResolvExpr::CandidateRef & cand : candidates ) {
     192                        // Distribute the reference cast over all components of the candidate.
     193                        append( std::forward<Output>(out), distributeReference( cand->expr ), cand->env,
     194                                cand->open, cand->need, cand->cost, cand->cvtCost );
     195                }
     196                return;
     197        }
     198        const ast::Type * res = expr->result->stripReferences();
     199        if ( const ast::TupleType * tupleType = dynamic_cast< const ast::TupleType * >( res ) ) {
     200                if ( const ast::ptr< ast::TupleExpr > & tupleExpr = expr.as< ast::TupleExpr >() ) {
     201                        // Open the tuple expr and continue on its components.
     202                        for ( const ast::Expr * expr : tupleExpr->exprs ) {
     203                                explodeUnique( expr, arg, symtab, std::forward<Output>(out), isTupleAssign );
     204                        }
     205                } else {
     206                        ast::ptr< ast::Expr > local = expr;
     207                        // Expressions which may have side effects require a single unique instance.
     208                        if ( Tuples::maybeImpureIgnoreUnique( local ) ) {
     209                                local = new ast::UniqueExpr( local->location, local );
     210                        }
     211                        // Cast a reference away to a value-type to allow further explosion.
     212                        if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
     213                                local = new ast::CastExpr{ local, tupleType };
     214                        }
     215                        // Now we have to go across the tuple via indexing.
     216                        for ( unsigned int i = 0 ; i < tupleType->size() ; ++i ) {
     217                                ast::TupleIndexExpr * idx = new ast::TupleIndexExpr( local->location, local, i );
     218                                explodeUnique( idx, arg, symtab, std::forward<Output>(out), isTupleAssign );
     219                                // TODO: We need more input to figure out the exact lifetimes of these types.
     220                                // delete idx;
     221                        }
     222                        // delete local;
     223                }
     224        } else {
     225                // For atomic/non-tuple types, no explosion is used.
     226                append( std::forward<Output>(out), expr, arg.env, arg.open, arg.need, arg.cost,
     227                        arg.cvtCost );
     228        }
     229}
     230
     231/// expands a tuple-valued candidate into multiple candidates, each with a non-tuple type
     232template< typename Output >
     233void explode(
     234        const ResolvExpr::Candidate & arg, const ast::SymbolTable & symtab, Output && out,
     235        bool isTupleAssign = false
     236) {
     237        explodeUnique( arg.expr, arg, symtab, std::forward< Output >( out ), isTupleAssign );
     238}
     239
     240/// explode list of candidates into flattened list of candidates
     241template< typename Output >
     242void explode(
     243        const ResolvExpr::CandidateList & cands, const ast::SymbolTable & symtab, Output && out,
     244        bool isTupleAssign = false
     245) {
     246        for ( const ResolvExpr::CandidateRef & cand : cands ) {
     247                explode( *cand, symtab, std::forward< Output >( out ), isTupleAssign );
     248        }
     249}
     250
    129251} // namespace Tuples
    130252
  • src/Tuples/TupleAssignment.cc

    r7951100 rb067d9b  
    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, const
    65                                 ResolvExpr::AltList& rhs );
     69                        Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
     70                                const ResolvExpr::AltList& rhs );
    6671                        virtual ~Matcher() {}
     72
    6773                        virtual void match( std::list< Expression * > &out ) = 0;
    6874                        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
    6986                        ResolvExpr::AltList lhs, rhs;
    70                         TupleAssignSpotter &spotter;
     87                        TupleAssignSpotter_old &spotter;
    7188                        ResolvExpr::Cost baseCost;
    7289                        std::list< ObjectDecl * > tmpDecls;
    7390                        ResolvExpr::TypeEnvironment compositeEnv;
     91                        ResolvExpr::OpenVarSet openVars;
     92                        ResolvExpr::AssertionSet need;
    7493                };
    7594
    7695                struct MassAssignMatcher : public Matcher {
    7796                  public:
    78                         MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     97                        MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    7998                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    8099                        virtual void match( std::list< Expression * > &out );
     
    83102                struct MultipleAssignMatcher : public Matcher {
    84103                  public:
    85                         MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,
     104                        MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs,
    86105                                const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {}
    87106                        virtual void match( std::list< Expression * > &out );
     
    122141        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr,
    123142                                std::vector<ResolvExpr::AlternativeFinder> &args ) {
    124                 TupleAssignSpotter spotter( currentFinder );
     143                TupleAssignSpotter_old spotter( currentFinder );
    125144                spotter.spot( expr, args );
    126145        }
    127146
    128         TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )
     147        TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )
    129148                : currentFinder(f) {}
    130149
    131         void TupleAssignSpotter::spot( UntypedExpr * expr,
     150        void TupleAssignSpotter_old::spot( UntypedExpr * expr,
    132151                        std::vector<ResolvExpr::AlternativeFinder> &args ) {
    133152                if (  NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) {
     
    210229        }
    211230
    212         void TupleAssignSpotter::match() {
     231        void TupleAssignSpotter_old::match() {
    213232                assert ( matcher != 0 );
    214233
     
    245264                }
    246265
    247                 // extract expressions from the assignment alternatives to produce a list of assignments that
    248                 // together form a single alternative
     266                // extract expressions from the assignment alternatives to produce a list of assignments
     267                // that together form a single alternative
    249268                std::list< Expression *> solved_assigns;
    250269                for ( ResolvExpr::Alternative & alt : current ) {
    251270                        solved_assigns.push_back( alt.expr->clone() );
    252                 }
    253                 // combine assignment environments into combined expression environment
    254                 simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv );
     271                        matcher->combineState( alt );
     272                }
     273
    255274                // xxx -- was push_front
    256                 currentFinder.get_alternatives().push_back( ResolvExpr::Alternative(
    257                         new TupleAssignExpr(solved_assigns, matcher->tmpDecls), matcher->compositeEnv,
    258                         ResolvExpr::sumCost( current ) + matcher->baseCost ) );
    259         }
    260 
    261         TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter,
     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,
    262283                const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs )
    263284        : lhs(lhs), rhs(rhs), spotter(spotter),
    264285          baseCost( ResolvExpr::sumCost( lhs ) + ResolvExpr::sumCost( rhs ) ) {
    265                 simpleCombineEnvironments( lhs.begin(), lhs.end(), compositeEnv );
    266                 simpleCombineEnvironments( rhs.begin(), rhs.end(), compositeEnv );
     286                combineState( lhs );
     287                combineState( rhs );
    267288        }
    268289
     
    297318        };
    298319
    299         ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) {
     320        ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) {
    300321                assert( expr->result && ! expr->get_result()->isVoid() );
    301322                ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) );
     
    313334        }
    314335
    315         void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) {
     336        void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) {
    316337                static UniqueName lhsNamer( "__massassign_L" );
    317338                static UniqueName rhsNamer( "__massassign_R" );
     
    331352        }
    332353
    333         void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
     354        void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {
    334355                static UniqueName lhsNamer( "__multassign_L" );
    335356                static UniqueName rhsNamer( "__multassign_R" );
     
    361382                }
    362383        }
     384
     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                        virtual ~Matcher() = default;
     433
     434                        virtual std::vector< ast::ptr< ast::Expr > > match() = 0;
     435
     436                        /// removes environments from subexpressions within statement expressions, which could
     437                        /// throw off later passes like those in Box which rely on PolyMutator, and adds the
     438                        /// bindings to the env
     439                        struct EnvRemover {
     440                                /// environment to hoist ExprStmt environments to
     441                                ast::TypeEnvironment & tenv;
     442
     443                                EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {}
     444
     445                                const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) {
     446                                        if ( stmt->expr->env ) {
     447                                                tenv.add( *stmt->expr->env );
     448                                                ast::ExprStmt * mut = mutate( stmt );
     449                                                mut->expr.get_and_mutate()->env = nullptr;
     450                                                return mut;
     451                                        }
     452                                        return stmt;
     453                                }
     454                        };
     455
     456                        ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) {
     457                                assert( expr->result && ! expr->result->isVoid() );
     458
     459                                ast::ObjectDecl * ret = new ast::ObjectDecl{
     460                                        location, namer.newName(), expr->result, new ast::SingleInit{ location, expr },
     461                                        ast::Storage::Classes{}, ast::Linkage::Cforall };
     462
     463                                // if expression type is a reference, just need an initializer, otherwise construct
     464                                if ( ! expr->result.as< ast::ReferenceType >() ) {
     465                                        // resolve ctor/dtor for the new object
     466                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
     467                                                        InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
     468                                        // remove environments from subexpressions of stmtExpr
     469                                        ast::Pass< EnvRemover > rm{ env };
     470                                        ret->init = ctorInit->accept( rm );
     471                                }
     472
     473                                PRINT( std::cerr << "new object: " << ret << std::endl; )
     474                                return ret;
     475                        }
     476
     477                        ast::UntypedExpr * createFunc(
     478                                const std::string & fname, const ast::ObjectDecl * left,
     479                                const ast::ObjectDecl * right
     480                        ) {
     481                                assert( left );
     482                                std::vector< ast::ptr< ast::Expr > > args;
     483                                args.emplace_back( new ast::VariableExpr{ location, left } );
     484                                if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); }
     485
     486                                if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) {
     487                                        args.front() = new ast::AddressExpr{ location, args.front() };
     488                                        if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; }
     489                                        return new ast::UntypedExpr{
     490                                                location, new ast::NameExpr{ location, "?=?" }, std::move(args) };
     491                                } else {
     492                                        return new ast::UntypedExpr{
     493                                                location, new ast::NameExpr{ location, fname }, std::move(args) };
     494                                }
     495                        }
     496                };
     497
     498                /// Finds mass-assignment operations
     499                struct MassAssignMatcher final : public Matcher {
     500                        MassAssignMatcher(
     501                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     502                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     503                        : Matcher( s, loc, l, r ) {}
     504
     505                        std::vector< ast::ptr< ast::Expr > > match() override {
     506                                static UniqueName lhsNamer( "__massassign_L" );
     507                                static UniqueName rhsNamer( "__massassign_R" );
     508                                // empty tuple case falls into this matcher
     509                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     510
     511                                ast::ptr< ast::ObjectDecl > rtmp =
     512                                        rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr;
     513
     514                                std::vector< ast::ptr< ast::Expr > > out;
     515                                for ( ResolvExpr::CandidateRef & lhsCand : lhs ) {
     516                                        // create a temporary object for each value in the LHS and create a call
     517                                        // involving the RHS
     518                                        ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr );
     519                                        out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) );
     520                                        tmpDecls.emplace_back( std::move( ltmp ) );
     521                                }
     522                                if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) );
     523
     524                                return out;
     525                        }
     526                };
     527
     528                /// Finds multiple-assignment operations
     529                struct MultipleAssignMatcher final : public Matcher {
     530                        MultipleAssignMatcher(
     531                                TupleAssignSpotter_new & s, const CodeLocation & loc,
     532                                const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r )
     533                        : Matcher( s, loc, l, r ) {}
     534
     535                        std::vector< ast::ptr< ast::Expr > > match() override {
     536                                static UniqueName lhsNamer( "__multassign_L" );
     537                                static UniqueName rhsNamer( "__multassign_R" );
     538
     539                                if ( lhs.size() != rhs.size() ) return {};
     540
     541                                // produce a new temporary object for each value in the LHS and RHS and pairwise
     542                                // create the calls
     543                                std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp;
     544
     545                                std::vector< ast::ptr< ast::Expr > > out;
     546                                for ( unsigned i = 0; i < lhs.size(); ++i ) {
     547                                        ResolvExpr::CandidateRef & lhsCand = lhs[i];
     548                                        ResolvExpr::CandidateRef & rhsCand = rhs[i];
     549
     550                                        // convert RHS to LHS type minus one reference -- important for case where LHS
     551                                        // is && and RHS is lvalue
     552                                        auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >();
     553                                        rhsCand->expr = new ast::CastExpr{ 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, new ast::ReferenceType{ lhsCand->expr->result } };
     607                                        }
     608
     609                                        // explode the LHS so that each field of a tuple-valued expr is assigned
     610                                        ResolvExpr::CandidateList lhs;
     611                                        explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
     612                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
     613                                                // each LHS value must be a reference - some come in with a cast, if not
     614                                                // just cast to reference here
     615                                                if ( ! cand->expr->result.as< ast::ReferenceType >() ) {
     616                                                        cand->expr = new ast::CastExpr{
     617                                                                cand->expr, new ast::ReferenceType{ cand->expr->result } };
     618                                                }
     619                                        }
     620
     621                                        if ( args.size() == 1 ) {
     622                                                // mass default-initialization/destruction
     623                                                ResolvExpr::CandidateList rhs{};
     624                                                matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
     625                                                match();
     626                                        } else if ( args.size() == 2 ) {
     627                                                for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) {
     628                                                        ResolvExpr::CandidateList rhs;
     629                                                        if ( isTuple( rhsCand->expr ) ) {
     630                                                                // multiple assignment
     631                                                                explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     632                                                                matcher.reset(
     633                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     634                                                        } else {
     635                                                                // mass assignment
     636                                                                rhs.emplace_back( rhsCand );
     637                                                                matcher.reset(
     638                                                                        new MassAssignMatcher{ *this, expr->location, lhs, rhs } );
     639                                                        }
     640                                                        match();
     641                                                }
     642                                        } else {
     643                                                // expand all possible RHS possibilities
     644                                                std::vector< ResolvExpr::CandidateList > rhsCands;
     645                                                combos(
     646                                                        std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) );
     647                                                for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) {
     648                                                        // multiple assignment
     649                                                        ResolvExpr::CandidateList rhs;
     650                                                        explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     651                                                        matcher.reset(
     652                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     653                                                        match();
     654                                                }
     655                                        }
     656                                }
     657                        }
     658                }
     659
     660                void match() {
     661                        assert( matcher );
     662
     663                        std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match();
     664
     665                        if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) {
     666                                // if both LHS and RHS are empty than this is the empty tuple case, wherein it's
     667                                // okay for newAssigns to be empty. Otherwise, return early so that no new
     668                                // candidates are generated
     669                                if ( newAssigns.empty() ) return;
     670                        }
     671
     672                        ResolvExpr::CandidateList crnt;
     673                        // now resolve new assignments
     674                        for ( const ast::Expr * expr : newAssigns ) {
     675                                PRINT(
     676                                        std::cerr << "== resolving tuple assign ==" << std::endl;
     677                                        std::cerr << expr << std::endl;
     678                                )
     679
     680                                ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
     681
     682                                try {
     683                                        finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() );
     684                                } catch (...) {
     685                                        // no match is not failure, just that this tuple assignment is invalid
     686                                        return;
     687                                }
     688
     689                                ResolvExpr::CandidateList & cands = finder.candidates;
     690                                assert( cands.size() == 1 );
     691                                assert( cands.front()->expr );
     692                                crnt.emplace_back( std::move( cands.front() ) );
     693                        }
     694
     695                        // extract expressions from the assignment candidates to produce a list of assignments
     696                        // that together form a sigle candidate
     697                        std::vector< ast::ptr< ast::Expr > > solved;
     698                        for ( ResolvExpr::CandidateRef & cand : crnt ) {
     699                                solved.emplace_back( cand->expr );
     700                                matcher->combineState( *cand );
     701                        }
     702
     703                        crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >(
     704                                new ast::TupleAssignExpr{
     705                                        matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) },
     706                                std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ),
     707                                ResolvExpr::sumCost( crnt ) + matcher->baseCost ) );
     708                }
     709        };
     710} // anonymous namespace
     711
     712void handleTupleAssignment(
     713        ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     714        std::vector< ResolvExpr::CandidateFinder > & args
     715) {
     716        TupleAssignSpotter_new spotter{ finder };
     717        spotter.spot( assign, args );
     718}
     719
    363720} // namespace Tuples
    364721
  • src/Tuples/TupleExpansion.cc

    r7951100 rb067d9b  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 21 17:35:04 2017
    13 // Update Count     : 19
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jul 19 14:39:00 2019
     13// Update Count     : 22
    1414//
    1515
     
    1717#include <cassert>                // for assert
    1818#include <list>                   // for list
    19 
     19#include <vector>
     20
     21#include "AST/CVQualifiers.hpp"
     22#include "AST/Expr.hpp"
     23#include "AST/Node.hpp"
     24#include "AST/Type.hpp"
    2025#include "Common/PassVisitor.h"   // for PassVisitor, WithDeclsToAdd, WithGu...
    2126#include "Common/ScopedMap.h"     // for ScopedMap
     
    5863                };
    5964
    60                 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithTypeSubstitution {
     65                struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution {
    6166                        Type * postmutate( TupleType * tupleType );
    6267
     
    299304                // produce the TupleType which aggregates the types of the exprs
    300305                std::list< Type * > types;
    301                 Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Lvalue | Type::Atomic | Type::Mutex );
     306                Type::Qualifiers qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic | Type::Mutex );
    302307                for ( Expression * expr : exprs ) {
    303308                        assert( expr->get_result() );
     
    314319                return new TupleType( qualifiers, types );
    315320        }
     321        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ) {
     322                // produce the TupleType which aggregates the types of the exprs
     323                std::vector<ast::ptr<ast::Type>> types;
     324                ast::CV::Qualifiers quals{
     325                        ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
     326                        ast::CV::Atomic | ast::CV::Mutex };
     327
     328                for ( const ast::Expr * expr : exprs ) {
     329                        assert( expr->result );
     330                        // if the type of any expr is void, the type of the entire tuple is void
     331                        if ( expr->result->isVoid() ) return new ast::VoidType{};
     332
     333                        // qualifiers on the tuple type are the qualifiers that exist on all components
     334                        quals &= expr->result->qualifiers;
     335
     336                        types.emplace_back( expr->result );
     337                }
     338
     339                if ( exprs.empty() ) { quals = ast::CV::Qualifiers{}; }
     340                return new ast::TupleType{ std::move(types), quals };
     341        }
    316342
    317343        TypeInstType * isTtype( Type * type ) {
     
    324350        }
    325351
     352        const TypeInstType * isTtype( const Type * type ) {
     353                if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type ) ) {
     354                        if ( inst->baseType && inst->baseType->kind == TypeDecl::Ttype ) {
     355                                return inst;
     356                        }
     357                }
     358                return nullptr;
     359        }
     360
     361        const ast::TypeInstType * isTtype( const ast::Type * type ) {
     362                if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
     363                        if ( inst->base && inst->base->kind == ast::TypeVar::Ttype ) {
     364                                return inst;
     365                        }
     366                }
     367                return nullptr;
     368        }
     369
    326370        namespace {
    327371                /// determines if impurity (read: side-effects) may exist in a piece of code. Currently gives a very crude approximation, wherein any function call expression means the code may be impure
     
    329373                        ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {}
    330374
    331                         void previsit( ApplicationExpr * appExpr ) {
     375                        void previsit( const ApplicationExpr * appExpr ) {
    332376                                visit_children = false;
    333                                 if ( DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
    334                                         if ( function->get_linkage() == LinkageSpec::Intrinsic ) {
    335                                                 if ( function->get_name() == "*?" || function->get_name() == "?[?]" ) {
     377                                if ( const DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
     378                                        if ( function->linkage == LinkageSpec::Intrinsic ) {
     379                                                if ( function->name == "*?" || function->name == "?[?]" ) {
    336380                                                        // intrinsic dereference, subscript are pure, but need to recursively look for impurity
    337381                                                        visit_children = true;
     
    342386                                maybeImpure = true;
    343387                        }
    344                         void previsit( UntypedExpr * ) { maybeImpure = true; visit_children = false; }
    345                         void previsit( UniqueExpr * ) {
     388                        void previsit( const UntypedExpr * ) { maybeImpure = true; visit_children = false; }
     389                        void previsit( const UniqueExpr * ) {
    346390                                if ( ignoreUnique ) {
    347391                                        // bottom out at unique expression.
     
    358402        } // namespace
    359403
    360         bool maybeImpure( Expression * expr ) {
     404        bool maybeImpure( const Expression * expr ) {
    361405                PassVisitor<ImpurityDetector> detector( false );
    362406                expr->accept( detector );
     
    364408        }
    365409
    366         bool maybeImpureIgnoreUnique( Expression * expr ) {
     410        bool maybeImpureIgnoreUnique( const Expression * expr ) {
    367411                PassVisitor<ImpurityDetector> detector( true );
    368412                expr->accept( detector );
  • src/Tuples/Tuples.h

    r7951100 rb067d9b  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:55:00 2017
    13 // Update Count     : 16
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Jun 18 09:36:00 2019
     13// Update Count     : 18
    1414//
    1515
     
    1919#include <vector>
    2020
     21#include "AST/Fwd.hpp"
     22#include "AST/Node.hpp"
    2123#include "SynTree/Expression.h"
    2224#include "SynTree/Declaration.h"
     
    2426
    2527#include "ResolvExpr/AlternativeFinder.h"
     28#include "ResolvExpr/CandidateFinder.hpp"
    2629
    2730namespace Tuples {
    2831        // TupleAssignment.cc
    29         void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 
     32        void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
    3033                std::vector< ResolvExpr::AlternativeFinder >& args );
    31        
     34        void handleTupleAssignment(
     35                ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
     36                std::vector< ResolvExpr::CandidateFinder > & args );
     37
    3238        // TupleExpansion.cc
    3339        /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate
     
    4248        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
    4349        Type * makeTupleType( const std::list< Expression * > & exprs );
     50        const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs );
    4451
    4552        /// returns a TypeInstType if `type` is a ttype, nullptr otherwise
    4653        TypeInstType * isTtype( Type * type );
     54        const TypeInstType * isTtype( const Type * type );
     55        const ast::TypeInstType * isTtype( const ast::Type * type );
    4756
    4857        /// returns true if the expression may contain side-effects.
    49         bool maybeImpure( Expression * expr );
     58        bool maybeImpure( const Expression * expr );
     59        bool maybeImpure( const ast::Expr * expr );
    5060
    51         /// returns true if the expression may contain side-effect, ignoring the presence of unique expressions.
    52         bool maybeImpureIgnoreUnique( Expression * expr );
     61        /// Returns true if the expression may contain side-effect,
     62        /// ignoring the presence of unique expressions.
     63        bool maybeImpureIgnoreUnique( const Expression * expr );
     64        bool maybeImpureIgnoreUnique( const ast::Expr * expr );
    5365} // namespace Tuples
    5466
  • src/Tuples/module.mk

    r7951100 rb067d9b  
    1515###############################################################################
    1616
    17 SRC +=  Tuples/TupleAssignment.cc \
    18         Tuples/TupleExpansion.cc \
    19         Tuples/Explode.cc
     17SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
     18        Tuples/Tuples.cc
     19SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \
     20        Tuples/Tuples.cc
Note: See TracChangeset for help on using the changeset viewer.