Changes in src/Tuples/TupleAssignment.cc [b8524ca:432ce7a]
- File:
-
- 1 edited
-
src/Tuples/TupleAssignment.cc (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/Tuples/TupleAssignment.cc
rb8524ca r432ce7a 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"29 24 #include "CodeGen/OperatorTable.h" 30 25 #include "Common/PassVisitor.h" 31 26 #include "Common/UniqueName.h" // for UniqueName 32 #include "Common/utility.h" // for splice,zipWith27 #include "Common/utility.h" // for zipWith 33 28 #include "Explode.h" // for explode 34 29 #include "InitTweak/GenInit.h" // for genCtorInit … … 56 51 57 52 namespace Tuples { 58 class TupleAssignSpotter _old{53 class TupleAssignSpotter { 59 54 public: 60 55 // dispatcher for Tuple (multiple and mass) assignment operations 61 TupleAssignSpotter _old( ResolvExpr::AlternativeFinder & );56 TupleAssignSpotter( ResolvExpr::AlternativeFinder & ); 62 57 void spot( UntypedExpr * expr, std::vector<ResolvExpr::AlternativeFinder> &args ); 63 58 … … 67 62 struct Matcher { 68 63 public: 69 Matcher( TupleAssignSpotter _old&spotter, const ResolvExpr::AltList& lhs,64 Matcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, 70 65 const ResolvExpr::AltList& rhs ); 71 66 virtual ~Matcher() {} … … 85 80 86 81 ResolvExpr::AltList lhs, rhs; 87 TupleAssignSpotter _old&spotter;82 TupleAssignSpotter &spotter; 88 83 ResolvExpr::Cost baseCost; 89 84 std::list< ObjectDecl * > tmpDecls; … … 95 90 struct MassAssignMatcher : public Matcher { 96 91 public: 97 MassAssignMatcher( TupleAssignSpotter _old&spotter, const ResolvExpr::AltList& lhs,92 MassAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, 98 93 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 99 94 virtual void match( std::list< Expression * > &out ); … … 102 97 struct MultipleAssignMatcher : public Matcher { 103 98 public: 104 MultipleAssignMatcher( TupleAssignSpotter _old&spotter, const ResolvExpr::AltList& lhs,99 MultipleAssignMatcher( TupleAssignSpotter &spotter, const ResolvExpr::AltList& lhs, 105 100 const ResolvExpr::AltList& rhs ) : Matcher(spotter, lhs, rhs) {} 106 101 virtual void match( std::list< Expression * > &out ); … … 141 136 void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * expr, 142 137 std::vector<ResolvExpr::AlternativeFinder> &args ) { 143 TupleAssignSpotter _oldspotter( currentFinder );138 TupleAssignSpotter spotter( currentFinder ); 144 139 spotter.spot( expr, args ); 145 140 } 146 141 147 TupleAssignSpotter _old::TupleAssignSpotter_old( ResolvExpr::AlternativeFinder &f )142 TupleAssignSpotter::TupleAssignSpotter( ResolvExpr::AlternativeFinder &f ) 148 143 : currentFinder(f) {} 149 144 150 void TupleAssignSpotter _old::spot( UntypedExpr * expr,145 void TupleAssignSpotter::spot( UntypedExpr * expr, 151 146 std::vector<ResolvExpr::AlternativeFinder> &args ) { 152 147 if ( NameExpr *op = dynamic_cast< NameExpr * >(expr->get_function()) ) { … … 229 224 } 230 225 231 void TupleAssignSpotter _old::match() {226 void TupleAssignSpotter::match() { 232 227 assert ( matcher != 0 ); 233 228 … … 280 275 } 281 276 282 TupleAssignSpotter _old::Matcher::Matcher( TupleAssignSpotter_old&spotter,277 TupleAssignSpotter::Matcher::Matcher( TupleAssignSpotter &spotter, 283 278 const ResolvExpr::AltList &lhs, const ResolvExpr::AltList &rhs ) 284 279 : lhs(lhs), rhs(rhs), spotter(spotter), … … 318 313 }; 319 314 320 ObjectDecl * TupleAssignSpotter _old::Matcher::newObject( UniqueName & namer, Expression * expr ) {315 ObjectDecl * TupleAssignSpotter::Matcher::newObject( UniqueName & namer, Expression * expr ) { 321 316 assert( expr->result && ! expr->get_result()->isVoid() ); 322 317 ObjectDecl * ret = new ObjectDecl( namer.newName(), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, expr->result->clone(), new SingleInit( expr->clone() ) ); … … 334 329 } 335 330 336 void TupleAssignSpotter _old::MassAssignMatcher::match( std::list< Expression * > &out ) {331 void TupleAssignSpotter::MassAssignMatcher::match( std::list< Expression * > &out ) { 337 332 static UniqueName lhsNamer( "__massassign_L" ); 338 333 static UniqueName rhsNamer( "__massassign_R" ); … … 352 347 } 353 348 354 void TupleAssignSpotter _old::MultipleAssignMatcher::match( std::list< Expression * > &out ) {349 void TupleAssignSpotter::MultipleAssignMatcher::match( std::list< Expression * > &out ) { 355 350 static UniqueName lhsNamer( "__multassign_L" ); 356 351 static UniqueName rhsNamer( "__multassign_R" ); … … 383 378 } 384 379 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 433 virtual std::vector< ast::ptr< ast::Expr > > match() = 0; 434 435 /// removes environments from subexpressions within statement expressions, which could 436 /// throw off later passes like those in Box which rely on PolyMutator, and adds the 437 /// bindings to the env 438 struct EnvRemover { 439 /// environment to hoist ExprStmt environments to 440 ast::TypeEnvironment & tenv; 441 442 EnvRemover( ast::TypeEnvironment & e ) : tenv( e ) {} 443 444 const ast::ExprStmt * previsit( const ast::ExprStmt * stmt ) { 445 if ( stmt->expr->env ) { 446 tenv.add( *stmt->expr->env ); 447 ast::ExprStmt * mut = mutate( stmt ); 448 mut->expr.get_and_mutate()->env = nullptr; 449 return mut; 450 } 451 return stmt; 452 } 453 }; 454 455 ast::ObjectDecl * newObject( UniqueName & namer, const ast::Expr * expr ) { 456 assert( expr->result && ! expr->result->isVoid() ); 457 458 ast::ObjectDecl * ret = new ast::ObjectDecl{ 459 location, namer.newName(), expr->result, new ast::SingleInit{ location, expr }, 460 ast::Storage::Classes{}, ast::Linkage::Cforall }; 461 462 // if expression type is a reference, just need an initializer, otherwise construct 463 if ( ! expr->result.as< ast::ReferenceType >() ) { 464 // resolve ctor/dtor for the new object 465 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 466 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab ); 467 // remove environments from subexpressions of stmtExpr 468 ast::Pass< EnvRemover > rm{ env }; 469 ret->init = ctorInit->accept( rm ); 470 } 471 472 PRINT( std::cerr << "new object: " << ret << std::endl; ) 473 return ret; 474 } 475 476 ast::UntypedExpr * createFunc( 477 const std::string & fname, const ast::ObjectDecl * left, 478 const ast::ObjectDecl * right 479 ) { 480 assert( left ); 481 std::vector< ast::ptr< ast::Expr > > args; 482 args.emplace_back( new ast::VariableExpr{ location, left } ); 483 if ( right ) { args.emplace_back( new ast::VariableExpr{ location, right } ); } 484 485 if ( left->type->referenceDepth() > 1 && CodeGen::isConstructor( fname ) ) { 486 args.front() = new ast::AddressExpr{ location, args.front() }; 487 if ( right ) { args.back() = new ast::AddressExpr{ location, args.back() }; } 488 return new ast::UntypedExpr{ 489 location, new ast::NameExpr{ location, "?=?" }, std::move(args) }; 490 } else { 491 return new ast::UntypedExpr{ 492 location, new ast::NameExpr{ location, fname }, std::move(args) }; 493 } 494 } 495 }; 496 497 /// Finds mass-assignment operations 498 struct MassAssignMatcher final : public Matcher { 499 MassAssignMatcher( 500 TupleAssignSpotter_new & s, const CodeLocation & loc, 501 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 502 : Matcher( s, loc, l, r ) {} 503 504 std::vector< ast::ptr< ast::Expr > > match() override { 505 static UniqueName lhsNamer( "__massassign_L" ); 506 static UniqueName rhsNamer( "__massassign_R" ); 507 // empty tuple case falls into this matcher 508 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 ); 509 510 ast::ptr< ast::ObjectDecl > rtmp = 511 rhs.size() == 1 ? newObject( rhsNamer, rhs.front()->expr ) : nullptr; 512 513 std::vector< ast::ptr< ast::Expr > > out; 514 for ( ResolvExpr::CandidateRef & lhsCand : lhs ) { 515 // create a temporary object for each value in the LHS and create a call 516 // involving the RHS 517 ast::ptr< ast::ObjectDecl > ltmp = newObject( lhsNamer, lhsCand->expr ); 518 out.emplace_back( createFunc( spotter.fname, ltmp, rtmp ) ); 519 tmpDecls.emplace_back( std::move( ltmp ) ); 520 } 521 if ( rtmp ) tmpDecls.emplace_back( std::move( rtmp ) ); 522 523 return out; 524 } 525 }; 526 527 /// Finds multiple-assignment operations 528 struct MultipleAssignMatcher final : public Matcher { 529 MultipleAssignMatcher( 530 TupleAssignSpotter_new & s, const CodeLocation & loc, 531 const ResolvExpr::CandidateList & l, const ResolvExpr::CandidateList & r ) 532 : Matcher( s, loc, l, r ) {} 533 534 std::vector< ast::ptr< ast::Expr > > match() override { 535 static UniqueName lhsNamer( "__multassign_L" ); 536 static UniqueName rhsNamer( "__multassign_R" ); 537 538 if ( lhs.size() != rhs.size() ) return {}; 539 540 // produce a new temporary object for each value in the LHS and RHS and pairwise 541 // create the calls 542 std::vector< ast::ptr< ast::ObjectDecl > > ltmp, rtmp; 543 544 std::vector< ast::ptr< ast::Expr > > out; 545 for ( unsigned i = 0; i < lhs.size(); ++i ) { 546 ResolvExpr::CandidateRef & lhsCand = lhs[i]; 547 ResolvExpr::CandidateRef & rhsCand = rhs[i]; 548 549 // convert RHS to LHS type minus one reference -- important for case where LHS 550 // is && and RHS is lvalue 551 auto lhsType = lhsCand->expr->result.strict_as< ast::ReferenceType >(); 552 rhsCand->expr = new ast::CastExpr{ rhsCand->expr, lhsType->base }; 553 ast::ptr< ast::ObjectDecl > lobj = newObject( lhsNamer, lhsCand->expr ); 554 ast::ptr< ast::ObjectDecl > robj = newObject( rhsNamer, rhsCand->expr ); 555 out.emplace_back( createFunc( spotter.fname, lobj, robj ) ); 556 ltmp.emplace_back( std::move( lobj ) ); 557 rtmp.emplace_back( std::move( robj ) ); 558 559 // resolve the cast expression so that rhsCand return type is bound by the cast 560 // type as needed, and transfer the resulting environment 561 ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env }; 562 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 563 assert( finder.candidates.size() == 1 ); 564 env = std::move( finder.candidates.front()->env ); 565 } 566 567 splice( tmpDecls, ltmp ); 568 splice( tmpDecls, rtmp ); 569 570 return out; 571 } 572 }; 573 574 ResolvExpr::CandidateFinder & crntFinder; 575 std::string fname; 576 std::unique_ptr< Matcher > matcher; 577 578 public: 579 TupleAssignSpotter_new( ResolvExpr::CandidateFinder & f ) 580 : crntFinder( f ), fname(), matcher() {} 581 582 // find left- and right-hand-sides for mass or multiple assignment 583 void spot( 584 const ast::UntypedExpr * expr, std::vector< ResolvExpr::CandidateFinder > & args 585 ) { 586 if ( auto op = expr->func.as< ast::NameExpr >() ) { 587 // skip non-assignment functions 588 if ( ! CodeGen::isCtorDtorAssign( op->name ) ) return; 589 fname = op->name; 590 591 // handled by CandidateFinder if applicable (both odd cases) 592 if ( args.empty() || ( args.size() == 1 && CodeGen::isAssignment( fname ) ) ) { 593 return; 594 } 595 596 // look over all possible left-hand-side 597 for ( ResolvExpr::CandidateRef & lhsCand : args[0] ) { 598 // skip non-tuple LHS 599 if ( ! refToTuple( lhsCand->expr ) ) continue; 600 601 // explode is aware of casts - ensure every LHS is sent into explode with a 602 // reference cast 603 if ( ! lhsCand->expr.as< ast::CastExpr >() ) { 604 lhsCand->expr = new ast::CastExpr{ 605 lhsCand->expr, new ast::ReferenceType{ lhsCand->expr->result } }; 606 } 607 608 // explode the LHS so that each field of a tuple-valued expr is assigned 609 ResolvExpr::CandidateList lhs; 610 explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true ); 611 for ( ResolvExpr::CandidateRef & cand : lhs ) { 612 // each LHS value must be a reference - some come in with a cast, if not 613 // just cast to reference here 614 if ( ! cand->expr->result.as< ast::ReferenceType >() ) { 615 cand->expr = new ast::CastExpr{ 616 cand->expr, new ast::ReferenceType{ cand->expr->result } }; 617 } 618 } 619 620 if ( args.size() == 1 ) { 621 // mass default-initialization/destruction 622 ResolvExpr::CandidateList rhs{}; 623 matcher.reset( new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 624 match(); 625 } else if ( args.size() == 2 ) { 626 for ( const ResolvExpr::CandidateRef & rhsCand : args[1] ) { 627 ResolvExpr::CandidateList rhs; 628 if ( isTuple( rhsCand->expr ) ) { 629 // multiple assignment 630 explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true ); 631 matcher.reset( 632 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 633 } else { 634 // mass assignment 635 rhs.emplace_back( rhsCand ); 636 matcher.reset( 637 new MassAssignMatcher{ *this, expr->location, lhs, rhs } ); 638 } 639 match(); 640 } 641 } else { 642 // expand all possible RHS possibilities 643 std::vector< ResolvExpr::CandidateList > rhsCands; 644 combos( 645 std::next( args.begin(), 1 ), args.end(), back_inserter( rhsCands ) ); 646 for ( const ResolvExpr::CandidateList & rhsCand : rhsCands ) { 647 // multiple assignment 648 ResolvExpr::CandidateList rhs; 649 explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true ); 650 matcher.reset( 651 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); 652 match(); 653 } 654 } 655 } 656 } 657 } 658 659 void match() { 660 assert( matcher ); 661 662 std::vector< ast::ptr< ast::Expr > > newAssigns = matcher->match(); 663 664 if ( ! ( matcher->lhs.empty() && matcher->rhs.empty() ) ) { 665 // if both LHS and RHS are empty than this is the empty tuple case, wherein it's 666 // okay for newAssigns to be empty. Otherwise, return early so that no new 667 // candidates are generated 668 if ( newAssigns.empty() ) return; 669 } 670 671 ResolvExpr::CandidateList crnt; 672 // now resolve new assignments 673 for ( const ast::Expr * expr : newAssigns ) { 674 PRINT( 675 std::cerr << "== resolving tuple assign ==" << std::endl; 676 std::cerr << expr << std::endl; 677 ) 678 679 ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env }; 680 681 try { 682 finder.find( expr, ResolvExpr::ResolvMode::withAdjustment() ); 683 } catch (...) { 684 // no match is not failure, just that this tuple assignment is invalid 685 return; 686 } 687 688 ResolvExpr::CandidateList & cands = finder.candidates; 689 assert( cands.size() == 1 ); 690 assert( cands.front()->expr ); 691 crnt.emplace_back( std::move( cands.front() ) ); 692 } 693 694 // extract expressions from the assignment candidates to produce a list of assignments 695 // that together form a sigle candidate 696 std::vector< ast::ptr< ast::Expr > > solved; 697 for ( ResolvExpr::CandidateRef & cand : crnt ) { 698 solved.emplace_back( cand->expr ); 699 matcher->combineState( *cand ); 700 } 701 702 crntFinder.candidates.emplace_back( std::make_shared< ResolvExpr::Candidate >( 703 new ast::TupleAssignExpr{ 704 matcher->location, std::move( solved ), std::move( matcher->tmpDecls ) }, 705 std::move( matcher->env ), std::move( matcher->open ), std::move( matcher->need ), 706 ResolvExpr::sumCost( crnt ) + matcher->baseCost ) ); 707 } 708 }; 709 } // anonymous namespace 710 711 void handleTupleAssignment( 712 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 713 std::vector< ResolvExpr::CandidateFinder > & args 714 ) { 715 TupleAssignSpotter_new spotter{ finder }; 716 spotter.spot( assign, args ); 717 } 718 380 void handleTupleAssignment( 381 ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 382 std::vector< ResolvExpr::CandidateFinder > & args 383 ) { 384 #warning unimplmented 385 (void)finder; (void)assign; (void)args; 386 assert(false); 387 } 719 388 } // namespace Tuples 720 389
Note:
See TracChangeset
for help on using the changeset viewer.