Changeset b067d9b for src/Tuples
- Timestamp:
- Oct 29, 2019, 4:01:24 PM (6 years ago)
- 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. - Location:
- src/Tuples
- Files:
-
- 1 added
- 6 edited
-
Explode.cc (modified) (2 diffs)
-
Explode.h (modified) (6 diffs)
-
TupleAssignment.cc (modified) (11 diffs)
-
TupleExpansion.cc (modified) (10 diffs)
-
Tuples.cc (added)
-
Tuples.h (modified) (4 diffs)
-
module.mk (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/Explode.cc
r7951100 rb067d9b 9 9 // Author : Rob Schluntz 10 10 // Created On : Wed Nov 9 13:12:24 2016 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Wed Nov 9 13:20:24201613 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 12 16:40:00 2016 13 // Update Count : 3 14 14 // 15 15 … … 106 106 return expr; 107 107 } 108 109 namespace { 110 111 // Remove one level of reference from a reference type. 112 const 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 121 struct 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 179 const 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 108 188 } // namespace Tuples 109 189 -
src/Tuples/Explode.h
r7951100 rb067d9b 9 9 // Author : Rob Schluntz 10 10 // Created On : Wed Nov 9 13:12:24 2016 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:55:16 201713 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 17 14:36:00 2019 13 // Update Count : 4 14 14 // 15 15 … … 19 19 #include <utility> // for forward 20 20 21 #include "AST/Expr.hpp" 21 22 #include "ResolvExpr/Alternative.h" // for Alternative, AltList 23 #include "ResolvExpr/Candidate.hpp" // for Candidate, CandidateList 22 24 #include "ResolvExpr/ExplodedActual.h" // for ExplodedActual 25 #include "ResolvExpr/ExplodedArg.hpp" // for ExplodedArg 23 26 #include "SynTree/Expression.h" // for Expression, UniqueExpr, AddressExpr 24 27 #include "SynTree/Type.h" // for TupleType, Type 25 28 #include "Tuples.h" // for maybeImpure 29 30 namespace ast { 31 class SymbolTable; 32 } 26 33 27 34 namespace SymTab { … … 44 51 template<typename OutputIterator> 45 52 void append( OutputIterator out, Expression* expr, const ResolvExpr::TypeEnvironment& env, 53 const ResolvExpr::OpenVarSet& openVars, const ResolvExpr::AssertionList& need, 46 54 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 }; 48 56 } 49 57 50 58 /// Append alternative to an ExplodedActual 51 59 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& ) { 53 62 ea.exprs.emplace_back( expr ); 54 /// xxx -- merge environment, cost?63 /// xxx -- merge environment, openVars, need, cost? 55 64 } 56 65 … … 68 77 // distribute reference cast over all components 69 78 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 ); 71 80 } 72 81 // 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) … … 102 111 } else { 103 112 // 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 ); 105 115 } 106 116 } … … 127 137 explode( alts.begin(), alts.end(), indexer, std::forward<Output>(out), isTupleAssign ); 128 138 } 139 140 const ast::Expr * distributeReference( const ast::Expr * ); 141 142 /// Append candidate to an OutputIterator of Candidates. 143 template<typename OutputIterator> 144 void 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. 156 static 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. 164 static 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 174 template< typename Output > 175 void explodeRecursive( 176 const ast::CastExpr *, const ResolvExpr::Candidate &, 177 const ast::SymbolTable &, Output && 178 ) { 179 } 180 181 /// helper function used by explode 182 template< typename Output > 183 void 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 232 template< typename Output > 233 void 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 241 template< typename Output > 242 void 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 129 251 } // namespace Tuples 130 252 -
src/Tuples/TupleAssignment.cc
r7951100 rb067d9b 22 22 #include <vector> 23 23 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" 24 29 #include "CodeGen/OperatorTable.h" 25 30 #include "Common/PassVisitor.h" 26 31 #include "Common/UniqueName.h" // for UniqueName 27 #include "Common/utility.h" // for zipWith32 #include "Common/utility.h" // for splice, zipWith 28 33 #include "Explode.h" // for explode 29 34 #include "InitTweak/GenInit.h" // for genCtorInit … … 51 56 52 57 namespace Tuples { 53 class TupleAssignSpotter {58 class TupleAssignSpotter_old { 54 59 public: 55 60 // dispatcher for Tuple (multiple and mass) assignment operations 56 TupleAssignSpotter ( ResolvExpr::AlternativeFinder & );61 TupleAssignSpotter_old( ResolvExpr::AlternativeFinder & ); 57 62 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args ); 58 63 … … 62 67 struct Matcher { 63 68 public: 64 Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, const65 ResolvExpr::AltList& rhs );69 Matcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 70 const ResolvExpr::AltList& rhs ); 66 71 virtual ~Matcher() {} 72 67 73 virtual void match( std::list< Expression * > &out ) = 0; 68 74 ObjectDecl * newObject( UniqueName & namer, Expression * expr ); 75 76 void combineState( const ResolvExpr::Alternative& alt ) { 77 compositeEnv.simpleCombine( alt.env ); 78 ResolvExpr::mergeOpenVars( openVars, alt.openVars ); 79 cloneAll( alt.need, need ); 80 } 81 82 void combineState( const ResolvExpr::AltList& alts ) { 83 for ( const ResolvExpr::Alternative& alt : alts ) { combineState( alt ); } 84 } 85 69 86 ResolvExpr::AltList lhs, rhs; 70 TupleAssignSpotter &spotter;87 TupleAssignSpotter_old &spotter; 71 88 ResolvExpr::Cost baseCost; 72 89 std::list< ObjectDecl * > tmpDecls; 73 90 ResolvExpr::TypeEnvironment compositeEnv; 91 ResolvExpr::OpenVarSet openVars; 92 ResolvExpr::AssertionSet need; 74 93 }; 75 94 76 95 struct MassAssignMatcher : public Matcher { 77 96 public: 78 MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,97 MassAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 79 98 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 80 99 virtual void match( std::list< Expression * > &out ); … … 83 102 struct MultipleAssignMatcher : public Matcher { 84 103 public: 85 MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs,104 MultipleAssignMatcher( TupleAssignSpotter_old &spotter, const ResolvExpr::AltList& lhs, 86 105 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 87 106 virtual void match( std::list< Expression * > &out ); … … 122 141 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, 123 142 std::vector<ResolvExpr::AlternativeFinder> &args ) { 124 TupleAssignSpotter spotter( currentFinder );143 TupleAssignSpotter_old spotter( currentFinder ); 125 144 spotter.spot( expr, args ); 126 145 } 127 146 128 TupleAssignSpotter ::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f )147 TupleAssignSpotter_old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f ) 129 148 : currentFinder(f) {} 130 149 131 void TupleAssignSpotter ::spot( UntypedExpr * expr,150 void TupleAssignSpotter_old::spot( UntypedExpr * expr, 132 151 std::vector<ResolvExpr::AlternativeFinder> &args ) { 133 152 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) { … … 210 229 } 211 230 212 void TupleAssignSpotter ::match() {231 void TupleAssignSpotter_old::match() { 213 232 assert ( matcher != 0 ); 214 233 … … 245 264 } 246 265 247 // extract expressions from the assignment alternatives to produce a list of assignments that248 // t ogether form a single alternative266 // extract expressions from the assignment alternatives to produce a list of assignments 267 // that together form a single alternative 249 268 std::list< Expression *> solved_assigns; 250 269 for ( ResolvExpr::Alternative & alt : current ) { 251 270 solved_assigns.push_back( alt.expr->clone() ); 252 }253 // combine assignment environments into combined expression environment254 simpleCombineEnvironments( current.begin(), current.end(), matcher->compositeEnv ); 271 matcher->combineState( alt ); 272 } 273 255 274 // 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, 262 283 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs ) 263 284 : lhs(lhs), rhs(rhs), spotter(spotter), 264 285 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 ); 267 288 } 268 289 … … 297 318 }; 298 319 299 ObjectDecl * TupleAssignSpotter ::Matcher::newObject( UniqueName & namer, Expression * expr ) {320 ObjectDecl * TupleAssignSpotter_old::Matcher::newObject( UniqueName & namer, Expression * expr ) { 300 321 assert( expr->result && ! expr->get_result()->isVoid() ); 301 322 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) ); … … 313 334 } 314 335 315 void TupleAssignSpotter ::MassAssignMatcher::match( std::list< Expression * > &out ) {336 void TupleAssignSpotter_old::MassAssignMatcher::match( std::list< Expression * > &out ) { 316 337 static UniqueName lhsNamer( "__massassign_L" ); 317 338 static UniqueName rhsNamer( "__massassign_R" ); … … 331 352 } 332 353 333 void TupleAssignSpotter ::MultipleAssignMatcher::match( std::list< Expression * > &out ) {354 void TupleAssignSpotter_old::MultipleAssignMatcher::match( std::list< Expression * > &out ) { 334 355 static UniqueName lhsNamer( "__multassign_L" ); 335 356 static UniqueName rhsNamer( "__multassign_R" ); … … 361 382 } 362 383 } 384 385 namespace { 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 712 void 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 363 720 } // namespace Tuples 364 721 -
src/Tuples/TupleExpansion.cc
r7951100 rb067d9b 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Jun 21 17:35:04 201713 // Update Count : 1911 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jul 19 14:39:00 2019 13 // Update Count : 22 14 14 // 15 15 … … 17 17 #include <cassert> // for assert 18 18 #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" 20 25 #include "Common/PassVisitor.h" // for PassVisitor, WithDeclsToAdd, WithGu... 21 26 #include "Common/ScopedMap.h" // for ScopedMap … … 58 63 }; 59 64 60 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public With TypeSubstitution {65 struct TupleTypeReplacer : public WithDeclsToAdd, public WithGuards, public WithConstTypeSubstitution { 61 66 Type * postmutate( TupleType * tupleType ); 62 67 … … 299 304 // produce the TupleType which aggregates the types of the exprs 300 305 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 ); 302 307 for ( Expression * expr : exprs ) { 303 308 assert( expr->get_result() ); … … 314 319 return new TupleType( qualifiers, types ); 315 320 } 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 } 316 342 317 343 TypeInstType * isTtype( Type * type ) { … … 324 350 } 325 351 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 326 370 namespace { 327 371 /// 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 … … 329 373 ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {} 330 374 331 void previsit( ApplicationExpr * appExpr ) {375 void previsit( const ApplicationExpr * appExpr ) { 332 376 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 == "?[?]" ) { 336 380 // intrinsic dereference, subscript are pure, but need to recursively look for impurity 337 381 visit_children = true; … … 342 386 maybeImpure = true; 343 387 } 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 * ) { 346 390 if ( ignoreUnique ) { 347 391 // bottom out at unique expression. … … 358 402 } // namespace 359 403 360 bool maybeImpure( Expression * expr ) {404 bool maybeImpure( const Expression * expr ) { 361 405 PassVisitor<ImpurityDetector> detector( false ); 362 406 expr->accept( detector ); … … 364 408 } 365 409 366 bool maybeImpureIgnoreUnique( Expression * expr ) {410 bool maybeImpureIgnoreUnique( const Expression * expr ) { 367 411 PassVisitor<ImpurityDetector> detector( true ); 368 412 expr->accept( detector ); -
src/Tuples/Tuples.h
r7951100 rb067d9b 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:55:00 201713 // Update Count : 1 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Jun 18 09:36:00 2019 13 // Update Count : 18 14 14 // 15 15 … … 19 19 #include <vector> 20 20 21 #include "AST/Fwd.hpp" 22 #include "AST/Node.hpp" 21 23 #include "SynTree/Expression.h" 22 24 #include "SynTree/Declaration.h" … … 24 26 25 27 #include "ResolvExpr/AlternativeFinder.h" 28 #include "ResolvExpr/CandidateFinder.hpp" 26 29 27 30 namespace Tuples { 28 31 // TupleAssignment.cc 29 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 32 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign, 30 33 std::vector< ResolvExpr::AlternativeFinder >& args ); 31 34 void handleTupleAssignment( 35 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 36 std::vector< ResolvExpr::CandidateFinder > & args ); 37 32 38 // TupleExpansion.cc 33 39 /// expands z.[a, b.[x, y], c] into [z.a, z.b.x, z.b.y, z.c], inserting UniqueExprs as appropriate … … 42 48 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types 43 49 Type * makeTupleType( const std::list< Expression * > & exprs ); 50 const ast::Type * makeTupleType( const std::vector<ast::ptr<ast::Expr>> & exprs ); 44 51 45 52 /// returns a TypeInstType if `type` is a ttype, nullptr otherwise 46 53 TypeInstType * isTtype( Type * type ); 54 const TypeInstType * isTtype( const Type * type ); 55 const ast::TypeInstType * isTtype( const ast::Type * type ); 47 56 48 57 /// 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 ); 50 60 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 ); 53 65 } // namespace Tuples 54 66 -
src/Tuples/module.mk
r7951100 rb067d9b 15 15 ############################################################################### 16 16 17 SRC += Tuples/TupleAssignment.cc \ 18 Tuples/TupleExpansion.cc \ 19 Tuples/Explode.cc 17 SRC += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \ 18 Tuples/Tuples.cc 19 SRCDEMANGLE += Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc Tuples/Explode.cc \ 20 Tuples/Tuples.cc
Note:
See TracChangeset
for help on using the changeset viewer.