Changeset b067d9b for src/Tuples/TupleAssignment.cc
- 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
- 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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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
Note:
See TracChangeset
for help on using the changeset viewer.