Changeset 286053 in webkit
- Timestamp:
- Nov 19, 2021, 1:38:27 AM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 edited
-
ChangeLog (modified) (1 diff)
-
b3/air/AirFixObviousSpills.cpp (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r286045 r286053 1 2021-11-19 Robin Morisset <rmorisset@apple.com> 2 3 AirFixObviousSpills should be optimized 4 https://bugs.webkit.org/show_bug.cgi?id=228052 5 6 Reviewed by Yusuke Suzuki. 7 8 There were two problems with AirFixObviousSpills: 9 - merge() had a quadratic blow-up, as for each element in a vector, it was searching it in a different vector. 10 - it would visit blocks even when their state at head had not changed. 11 12 I fixed the first problem by making sure that the vectors are sorted before calling merge, and making use of that invariant in the search of the vectors 13 (see filterVectorAgainst) 14 This reduced the total time spent in that phase from 390ms to 230ms, and the worst case time spent in that phase for one function from 100ms to 30ms (all of the results in this Changelog are for JetStream2 on a M1 MBP). 15 16 I fixed the second problem even more easily by adding a m_shouldVisit BitVector. I also moved the m_wasVisited boolean that was in State to a m_notBottom BitVector for simplicity and symmetry. 17 That change further reduced the total/max time from 230ms/30ms to 140ms/16ms. 18 19 * b3/air/AirFixObviousSpills.cpp: 20 1 21 2021-11-18 Robin Morisset <rmorisset@apple.com> 2 22 -
trunk/Source/JavaScriptCore/b3/air/AirFixObviousSpills.cpp
r278253 r286053 49 49 : m_code(code) 50 50 , m_atHead(code.size()) 51 , m_notBottom(code.size()) 52 , m_shouldVisit(code.size()) 51 53 { 52 54 } … … 64 66 void computeAliases() 65 67 { 66 m_atHead[m_code[0]].wasVisited = true; 68 m_notBottom.quickSet(0); 69 m_shouldVisit.quickSet(0); 67 70 68 71 bool changed = true; … … 70 73 changed = false; 71 74 72 for (BasicBlock* block : m_code) { 75 for (unsigned blockIndex : m_shouldVisit) { 76 m_shouldVisit.quickClear(blockIndex); 77 BasicBlock* block = m_code[blockIndex]; 78 ASSERT(m_notBottom.quickGet(blockIndex)); 73 79 m_block = block; 74 80 m_state = m_atHead[block]; 75 if (!m_state.wasVisited)76 continue;77 81 78 82 if (AirFixObviousSpillsInternal::verbose) … … 82 86 executeInst(); 83 87 88 // Before we call merge we must make sure that the two states are sorted. 89 m_state.sort(); 90 84 91 for (BasicBlock* successor : block->successorBlocks()) { 92 unsigned successorIndex = successor->index(); 85 93 State& toState = m_atHead[successor]; 86 if (toState.wasVisited) 87 changed |= toState.merge(m_state); 88 else { 94 if (m_notBottom.quickGet(successorIndex)) { 95 bool changedAtSuccessorHead = toState.merge(m_state); 96 if (changedAtSuccessorHead) { 97 changed = true; 98 m_shouldVisit.quickSet(successorIndex); 99 } 100 } else { // The state at head of successor is bottom 89 101 toState = m_state; 90 102 changed = true; 103 m_notBottom.quickSet(successorIndex); 104 m_shouldVisit.quickSet(successorIndex); 91 105 } 92 106 } … … 100 114 m_block = block; 101 115 m_state = m_atHead[block]; 102 RELEASE_ASSERT(m_ state.wasVisited);116 RELEASE_ASSERT(m_notBottom.quickGet(block->index())); 103 117 104 118 for (m_instIndex = 0; m_instIndex < block->size(); ++m_instIndex) { … … 342 356 } 343 357 358 bool operator<(const RegConst& other) const 359 { 360 return reg < other.reg || (reg == other.reg && constant < other.constant); 361 } 362 344 363 void dump(PrintStream& out) const 345 364 { … … 379 398 && reg == other.reg 380 399 && mode == other.mode; 400 } 401 402 bool operator<(const RegSlot& other) const 403 { 404 // We ignore `mode` on purpose, see merge() for how we deal with it. 405 return slot < other.slot || (slot == other.slot && reg < other.reg); 381 406 } 382 407 … … 424 449 } 425 450 451 bool operator<(const SlotConst& other) const 452 { 453 return slot < other.slot || (slot == other.slot && constant < other.constant); 454 } 455 426 456 void dump(PrintStream& out) const 427 457 { … … 436 466 void addAlias(const RegConst& newAlias) 437 467 { 438 return regConst.append(newAlias); 468 regConst.append(newAlias); 469 #if ASSERT_ENABLED 470 m_isSorted = false; 471 #endif 439 472 } 440 473 void addAlias(const RegSlot& newAlias) 441 474 { 442 return regSlot.append(newAlias); 475 regSlot.append(newAlias); 476 #if ASSERT_ENABLED 477 m_isSorted = false; 478 #endif 443 479 } 444 480 void addAlias(const SlotConst& newAlias) 445 481 { 446 return slotConst.append(newAlias); 482 slotConst.append(newAlias); 483 #if ASSERT_ENABLED 484 m_isSorted = false; 485 #endif 447 486 } 448 487 … … 545 584 } 546 585 586 void sort() 587 { 588 std::sort(regConst.begin(), regConst.end(), [] (const RegConst& a, const RegConst& b) { 589 return a < b; 590 }); 591 std::sort(slotConst.begin(), slotConst.end(), [] (const SlotConst& a, const SlotConst& b) { 592 return a < b; 593 }); 594 std::sort(regSlot.begin(), regSlot.end(), [] (const RegSlot& a, const RegSlot& b) { 595 return a < b; 596 }); 597 #if ASSERT_ENABLED 598 m_isSorted = true; 599 #endif 600 } 601 602 // Takes two sorted vectors, for each element in the first, it looks for the first element in the second which is not smaller. 603 // If such an element exist, call f on both the element from the first vector and this element. 604 // Remove the element from the first vector unless f returned true (so f says whether to keep the element) 605 // Returns true if any element has been removed. 606 template<typename T, typename Func> 607 static bool filterVectorAgainst(Vector<T>& own, const Vector<T>& other, Func f) 608 { 609 const T* it = other.begin(); 610 const T* end = other.end(); 611 return !!own.removeAllMatching( 612 [&] (T& alias) { 613 it = std::find_if_not(it, end, [&] (const T& otherAlias) { 614 return otherAlias < alias; 615 }); 616 if (it == end) 617 return true; 618 return !f(alias, *it); 619 }); 620 } 621 547 622 bool merge(const State& other) 548 623 { 624 ASSERT(m_isSorted); 625 ASSERT(other.m_isSorted); 549 626 bool changed = false; 550 551 changed |= !!regConst.removeAllMatching( 552 [&] (RegConst& alias) -> bool { 553 const RegConst* otherAlias = other.getRegConst(alias.reg); 554 if (!otherAlias) 555 return true; 556 if (alias.constant != otherAlias->constant) 557 return true; 627 628 changed |= filterVectorAgainst(regConst, other.regConst, [](RegConst& a, const RegConst& b) { return a == b; }); 629 changed |= filterVectorAgainst(slotConst, other.slotConst, [](SlotConst& a, const SlotConst& b) { return a == b; }); 630 changed |= filterVectorAgainst(regSlot, other.regSlot, [&](RegSlot& alias, const RegSlot& otherAlias) { 631 if (alias.reg != otherAlias.reg || alias.slot != otherAlias.slot) 558 632 return false; 559 }); 560 561 changed |= !!slotConst.removeAllMatching( 562 [&] (SlotConst& alias) -> bool { 563 const SlotConst* otherAlias = other.getSlotConst(alias.slot); 564 if (!otherAlias) 565 return true; 566 if (alias.constant != otherAlias->constant) 567 return true; 568 return false; 569 }); 570 571 changed |= !!regSlot.removeAllMatching( 572 [&] (RegSlot& alias) -> bool { 573 const RegSlot* otherAlias = other.getRegSlot(alias.reg, alias.slot); 574 if (!otherAlias) 575 return true; 576 if (alias.mode != RegSlot::Match32 && alias.mode != otherAlias->mode) { 577 alias.mode = RegSlot::Match32; 578 changed = true; 579 } 580 return false; 581 }); 633 if (alias.mode != RegSlot::Match32 && alias.mode != otherAlias.mode) { 634 alias.mode = RegSlot::Match32; 635 changed = true; 636 } 637 return true; 638 }); 582 639 583 640 return changed; … … 588 645 out.print( 589 646 "{regConst = [", listDump(regConst), "], slotConst = [", listDump(slotConst), 590 "], regSlot = [", listDump(regSlot), "] , wasVisited = ", wasVisited, "}");647 "], regSlot = [", listDump(regSlot), "]}"); 591 648 } 592 649 … … 594 651 Vector<SlotConst> slotConst; 595 652 Vector<RegSlot> regSlot; 596 bool wasVisited { false }; 653 #if ASSERT_ENABLED 654 bool m_isSorted { true }; 655 #endif 597 656 }; 598 657 … … 600 659 IndexMap<BasicBlock*, State> m_atHead; 601 660 State m_state; 661 BitVector m_notBottom; 662 BitVector m_shouldVisit; 602 663 BasicBlock* m_block { nullptr }; 603 664 unsigned m_instIndex { 0 };
Note:
See TracChangeset
for help on using the changeset viewer.