Changeset f831177 for src/Tuples
- Timestamp:
- Jan 9, 2017, 3:37:36 PM (8 years ago)
- 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
- Location:
- src/Tuples
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/Explode.h
r6c3a988f rf831177 33 33 /// helper function used by explode 34 34 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 } 36 50 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 ) ) { 46 52 if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( expr ) ) { 47 53 // can open tuple expr and dump its exploded components 48 54 for ( Expression * expr : tupleExpr->get_exprs() ) { 49 explodeUnique( expr, alt, indexer, out );55 explodeUnique( expr, alt, indexer, out, isTupleAssign ); 50 56 } 51 57 } else { … … 58 64 for ( unsigned int i = 0; i < tupleType->size(); i++ ) { 59 65 TupleIndexExpr * idx = new TupleIndexExpr( arg->clone(), i ); 60 explodeUnique( idx, alt, indexer, out );66 explodeUnique( idx, alt, indexer, out, isTupleAssign ); 61 67 delete idx; 62 68 } … … 71 77 /// expands a tuple-valued alternative into multiple alternatives, each with a non-tuple-type 72 78 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 ); 75 81 } 76 82 77 83 // explode list of alternatives 78 84 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 ) { 80 86 for ( ; altBegin != altEnd; ++altBegin ) { 81 explode( *altBegin, indexer, out );87 explode( *altBegin, indexer, out, isTupleAssign ); 82 88 } 83 89 } 84 90 85 91 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 ); 88 94 } 89 95 } // namespace Tuples -
src/Tuples/TupleAssignment.cc
r6c3a988f rf831177 42 42 private: 43 43 void match(); 44 void handleEmptyTuple( const ResolvExpr::AltList & alts );45 44 46 45 struct Matcher { … … 74 73 }; 75 74 76 /// true if expr is an expression of tuple type , i.e. a tuple expression, tuple variable, or MRV (multiple-return-value) function75 /// true if expr is an expression of tuple type 77 76 bool isTuple( Expression *expr ) { 78 77 if ( ! expr ) return false; 79 78 assert( expr->has_result() ); 80 return dynamic_cast< TupleExpr *>(expr) || expr->get_result()->size() > 1;79 return dynamic_cast< TupleType * >( expr->get_result() ); 81 80 } 82 81 … … 131 130 } 132 131 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 the136 // 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 exploded137 // 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 left140 // 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 );142 132 } 143 133 } … … 152 142 matcher->match( new_assigns ); 153 143 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 } 155 149 ResolvExpr::AltList current; 156 150 // now resolve new assignments … … 196 190 197 191 // 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 ); 199 193 200 194 // and finally, re-add the cast to each lhs expr, so that qualified tuple fields can be constructed … … 221 215 TupleAssignSpotter::MultipleAssignMatcher::MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList & alts ) : Matcher( spotter, alts ) { 222 216 // 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 ); 224 218 } 225 219 … … 258 252 static UniqueName lhsNamer( "__massassign_L" ); 259 253 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()) ); 261 256 262 257 ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr; 263 258 for ( ResolvExpr::Alternative & lhsAlt : lhs ) { 259 // create a temporary object for each value in the lhs and create a call involving the rhs 264 260 ObjectDecl * ltmp = newObject( lhsNamer, lhsAlt.expr ); 265 261 out.push_back( createFunc( spotter.fname, ltmp, rtmp ) ); … … 273 269 static UniqueName rhsNamer( "__multassign_R" ); 274 270 275 // xxx - need more complicated matching?276 271 if ( lhs.size() == rhs.size() ) { 272 // produce a new temporary object for each value in the lhs and rhs and pairwise create the calls 277 273 std::list< ObjectDecl * > ltmp; 278 274 std::list< ObjectDecl * > rtmp; … … 288 284 } 289 285 } 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 allowed302 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 }310 286 } // namespace Tuples 311 287
Note: See TracChangeset
for help on using the changeset viewer.