Changeset f831177 for src/Tuples


Ignore:
Timestamp:
Jan 9, 2017, 3:37:36 PM (8 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
627f585
Parents:
6c3a988f
Message:

address exprs are now only exploded for tuple assignments

Location:
src/Tuples
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/Tuples/Explode.h

    r6c3a988f rf831177  
    3333        /// helper function used by explode
    3434        template< typename OutputIterator >
    35         void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, const SymTab::Indexer & indexer, OutputIterator out ) {
     35        void explodeUnique( Expression * expr, const ResolvExpr::Alternative & alt, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign ) {
     36                if ( isTupleAssign ) {
     37                        // tuple assignment needs AddressExprs to be recursively exploded to easily get at all of the components
     38                        if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
     39                                ResolvExpr::AltList alts;
     40                                explodeUnique( addrExpr->get_arg(), alt, indexer, back_inserter( alts ), isTupleAssign );
     41                                for ( ResolvExpr::Alternative & alt : alts ) {
     42                                        // distribute '&' over all components
     43                                        alt.expr = distributeAddr( alt.expr );
     44                                        *out++ = alt;
     45                                }
     46                                // 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)
     47                                return;
     48                        }
     49                }
    3650                Type * res = expr->get_result();
    37                 if ( AddressExpr * addrExpr = dynamic_cast< AddressExpr * >( expr ) ) {
    38                         ResolvExpr::AltList alts;
    39                         explodeUnique( addrExpr->get_arg(), alt, indexer, back_inserter( alts ) );
    40                         for ( ResolvExpr::Alternative & alt : alts ) {
    41                                 // distribute '&' over all components
    42                                 alt.expr = distributeAddr( alt.expr );
    43                                 *out++ = alt;
    44                         }
    45                 } else if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
     51                if ( TupleType * tupleType = dynamic_cast< TupleType * > ( res ) ) {
    4652                        if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) {
    4753                                // can open tuple expr and dump its exploded components
    4854                                for ( Expression * expr : tupleExpr->get_exprs() ) {
    49                                         explodeUnique( expr, alt, indexer, out );
     55                                        explodeUnique( expr, alt, indexer, out, isTupleAssign );
    5056                                }
    5157                        } else {
     
    5864                                for ( unsigned int i = 0; i < tupleType->size(); i++ ) {
    5965                                        TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i );
    60                                         explodeUnique( idx, alt, indexer, out );
     66                                        explodeUnique( idx, alt, indexer, out, isTupleAssign );
    6167                                        delete idx;
    6268                                }
     
    7177        /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type
    7278        template< typename OutputIterator >
    73         void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer, OutputIterator out ) {
    74                 explodeUnique( alt.expr, alt, indexer, out );
     79        void explode( const ResolvExpr::Alternative &alt, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign = false ) {
     80                explodeUnique( alt.expr, alt, indexer, out, isTupleAssign );
    7581        }
    7682
    7783        // explode list of alternatives
    7884        template< typename AltIterator, typename OutputIterator >
    79         void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer, OutputIterator out ) {
     85        void explode( AltIterator altBegin, AltIterator altEnd, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign = false ) {
    8086                for ( ; altBegin != altEnd; ++altBegin ) {
    81                         explode( *altBegin, indexer, out );
     87                        explode( *altBegin, indexer, out, isTupleAssign );
    8288                }
    8389        }
    8490
    8591        template< typename OutputIterator >
    86         void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, OutputIterator out ) {
    87                 explode( alts.begin(), alts.end(), indexer, out );
     92        void explode( const ResolvExpr::AltList & alts, const SymTab::Indexer & indexer, OutputIterator out, bool isTupleAssign = false ) {
     93                explode( alts.begin(), alts.end(), indexer, out, isTupleAssign );
    8894        }
    8995} // namespace Tuples
  • src/Tuples/TupleAssignment.cc

    r6c3a988f rf831177  
    4242          private:
    4343                void match();
    44                 void handleEmptyTuple( const ResolvExpr::AltList & alts );
    4544
    4645                struct Matcher {
     
    7473        };
    7574
    76         /// true if expr is an expression of tuple type, i.e. a tuple expression, tuple variable, or MRV (multiple-return-value) function
     75        /// true if expr is an expression of tuple type
    7776        bool isTuple( Expression *expr ) {
    7877                if ( ! expr ) return false;
    7978                assert( expr->has_result() );
    80                 return dynamic_cast<TupleExpr *>(expr) || expr->get_result()->size() > 1;
     79                return dynamic_cast< TupleType * >( expr->get_result() );
    8180        }
    8281
     
    131130                                                }
    132131                                                match();
    133                                         } else {
    134                                                 // handle empty case specially. It is easy to cause conflicts for tuple assignment when we consider any expression with Tuple type to be a tuple.
    135                                                 // Instead, only tuple expressions and expressions with at least 2 results are considered tuples for tuple assignment. This most obviously leaves out the
    136                                                 // nullary and unary cases. The unary case is handled nicely by the alternative finder as is. For example, an expression of type [int] will be exploded
    137                                                 // into a list of one element (combined with the RHS elements), which will easily allow for intrinsic construction. This seems like a best case scenario anyway,
    138                                                 // since intrinsic construction is much simpler from a code-gen perspective than tuple construction is.
    139                                                 // This leaves the empty case, which is not easily handled by existing alternative finder logic. Instead, it seems simple enough to hanlde here that if the left
    140                                                 // side is an empty tuple, then the right side is allowed to be either an empty tuple or an empty list. Fortunately, these cases are identical when exploded.
    141                                                 handleEmptyTuple( *ali );
    142132                                        }
    143133                                }
     
    152142                matcher->match( new_assigns );
    153143
    154                 if ( new_assigns.empty() ) return;
     144                if ( ! matcher->lhs.empty() || ! matcher->rhs.empty() ) {
     145                        // if both lhs and rhs are empty then this is the empty tuple case, wherein it's okay for new_assigns to be empty.
     146                        // if not the empty tuple case, return early so that no new alternatives are generated.
     147                        if ( new_assigns.empty() ) return;
     148                }
    155149                ResolvExpr::AltList current;
    156150                // now resolve new assignments
     
    196190
    197191                // explode the lhs so that each field of the tuple-valued-expr is assigned.
    198                 explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs) );
     192                explode( lhsAlt, spotter.currentFinder.get_indexer(), back_inserter(lhs), true );
    199193
    200194                // and finally, re-add the cast to each lhs expr, so that qualified tuple fields can be constructed
     
    221215        TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) {
    222216                // explode the rhs so that each field of the tuple-valued-expr is assigned.
    223                 explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs) );
     217                explode( std::next(alts.begin(), 1), alts.end(), spotter.currentFinder.get_indexer(), back_inserter(rhs), true );
    224218        }
    225219
     
    258252                static UniqueName lhsNamer( "__massassign_L" );
    259253                static UniqueName rhsNamer( "__massassign_R" );
    260                 assert( ! lhs.empty() && rhs.size() <= 1 );
     254                // empty tuple case falls into this matcher, hence the second part of the assert
     255                assert( (! lhs.empty() && rhs.size() <= 1) || (lhs.empty() && rhs.empty()) );
    261256
    262257                ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
    263258                for ( ResolvExpr::Alternative & lhsAlt : lhs ) {
     259                        // create a temporary object for each value in the lhs and create a call involving the rhs
    264260                        ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr );
    265261                        out.push_back( createFunc( spotter.fname, ltmp, rtmp ) );
     
    273269                static UniqueName rhsNamer( "__multassign_R" );
    274270
    275                 // xxx - need more complicated matching?
    276271                if ( lhs.size() == rhs.size() ) {
     272                        // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls
    277273                        std::list< ObjectDecl * > ltmp;
    278274                        std::list< ObjectDecl * > rtmp;
     
    288284                }
    289285        }
    290 
    291         // empty case is okay when right side is also "empty" (empty explosion handles no argument case as well as empty tuple case)
    292         void TupleAssignSpotter::handleEmptyTuple( const ResolvExpr::AltList & alts ) {
    293                 assert( ! alts.empty() );
    294                 Expression * lhs = alts.front().expr;
    295                 if ( PointerType * ptrType = dynamic_cast< PointerType * >( lhs->get_result() ) ) {
    296                         if ( TupleType * tupleType = dynamic_cast< TupleType * >( ptrType->get_base() ) ) {
    297                                 if ( tupleType->size() == 0 ) {
    298                                         ResolvExpr::AltList rhs;
    299                                         explode( std::next(alts.begin(), 1), alts.end(), currentFinder.get_indexer(), back_inserter(rhs) );
    300                                         if ( rhs.empty() ) {
    301                                                 // okay, no other case is allowed
    302                                                 ResolvExpr::TypeEnvironment compositeEnv;
    303                                                 simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
    304                                                 currentFinder.get_alternatives().push_front( ResolvExpr::Alternative( new TupleAssignExpr( std::list< Expression * >(), std::list< ObjectDecl * >() ), compositeEnv, ResolvExpr::sumCost( alts ) ) );
    305                                         }
    306                                 }
    307                         }
    308                 }
    309         }
    310286} // namespace Tuples
    311287
Note: See TracChangeset for help on using the changeset viewer.