Skip to content

[JSC] GreedyRegAlloc: Add loop-aware live range splitting (disabled by default)#64182

Merged
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
dhecht:eng/JSC-GreedyRegAlloc-Add-loop-aware-live-range-splitting-disabled-by-default
May 6, 2026
Merged

[JSC] GreedyRegAlloc: Add loop-aware live range splitting (disabled by default)#64182
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
dhecht:eng/JSC-GreedyRegAlloc-Add-loop-aware-live-range-splitting-disabled-by-default

Conversation

@dhecht
Copy link
Copy Markdown
Contributor

@dhecht dhecht commented May 4, 2026

899099b

[JSC] GreedyRegAlloc: Add loop-aware live range splitting (disabled by default)
https://bugs.webkit.org/show_bug.cgi?id=312905
rdar://175260380

Reviewed by Keith Miller.

Add loop-aware live range splitting to the greedy register allocator.
When a tmp's live range crosses a loop boundary, split it into a loop
portion and a non-loop portion. This allows the two portions to be
allocated independently, reducing interference between the loop body
and the surrounding code. For example, a tmp live across a loop but
unused inside it can be split so that the loop portion is spilled,
freeing a register for the loop body. Similarly, a tmp that conflicts
with others outside the loop may get a register inside it after
splitting.

A new CFG normalization pass (ensureDedicatedLoopEntryExitBlocks)
ensures non-critical entry edges and dedicated exit blocks so that
fixup code can be safely inserted at loop boundaries. Entry/exit
fixups use Shuffle instructions to handle potential register cycles
when multiple tmps are split around the same loop.

The feature is off by default (airGreedyRegAllocSplitAroundLoops).
The mechanism is working and passes tests, but improvements to the
splitting policy and integration with the allocator's priority-driven
allocation order are needed to realize the potential.

Test: Source/JavaScriptCore/b3/air/testair.cpp
      JSTests/stress/regalloc-loop-splitting.js

* JSTests/stress/regalloc-loop-splitting.js: Added.
(clobber):
(test):
* Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj:
* Source/JavaScriptCore/Sources.txt:
* Source/JavaScriptCore/b3/air/AirAllocateRegistersByGreedy.cpp:
(JSC::B3::Air::Greedy::Cost::subtractSaturating):
(JSC::B3::Air::Greedy::LiveRange::contains const):
(JSC::B3::Air::Greedy::LiveRange::overlaps const):
(JSC::B3::Air::Greedy::AroundLoopSplitMetadata::AroundLoopSplitMetadata):
(JSC::B3::Air::Greedy::AroundLoopSplitMetadata::dump const):
(JSC::B3::Air::Greedy::GreedyAllocator::dump const):
(JSC::B3::Air::Greedy::GreedyAllocator::forEachBlockInLiveRange):
(JSC::B3::Air::Greedy::GreedyAllocator::findBlockIndexContainingPoint):
(JSC::B3::Air::Greedy::GreedyAllocator::findBlockContainingPoint):
(JSC::B3::Air::Greedy::GreedyAllocator::rewriteCoalescedTmps):
(JSC::B3::Air::Greedy::GreedyAllocator::addSplitTmp):
(JSC::B3::Air::Greedy::GreedyAllocator::trySplit):
(JSC::B3::Air::Greedy::GreedyAllocator::analyzeLoop):
(JSC::B3::Air::Greedy::GreedyAllocator::ensureLoopAnalysis):
(JSC::B3::Air::Greedy::GreedyAllocator::chooseLoopForSplit):
(JSC::B3::Air::Greedy::GreedyAllocator::trySplitAroundLoop):
(JSC::B3::Air::Greedy::GreedyAllocator::trySplitAroundClobbers):
(JSC::B3::Air::Greedy::GreedyAllocator::insertFixupCode):
(JSC::B3::Air::Greedy::GreedyAllocator::insertSplitAroundLoopFixupCode):
(JSC::B3::Air::allocateRegistersByGreedy):
(JSC::B3::Air::Greedy::LiveRange::overlaps): Deleted.
* Source/JavaScriptCore/b3/air/AirCode.cpp:
* Source/JavaScriptCore/b3/air/AirCode.h:
* Source/JavaScriptCore/b3/air/AirEnsureDedicatedLoopEntryExitBlocks.cpp: Added.
(JSC::B3::Air::ensureDedicatedLoopEntryExitBlocks):
* Source/JavaScriptCore/b3/air/AirEnsureDedicatedLoopEntryExitBlocks.h: Added.
* Source/JavaScriptCore/b3/air/AirRegisterAllocatorStats.h:
* Source/JavaScriptCore/b3/air/testair.cpp:
* Source/JavaScriptCore/runtime/OptionsList.h:

Canonical link: https://commits.webkit.org/312693@main

d5fd1d5

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
❌ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win loading 🛠 ios-apple
✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ❌ 🧪 win-tests loading 🛠 mac-apple
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe loading 🛠 vision-apple
✅ 🧪 ios-wk2-wpt ✅ 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
✅ 🛠 🧪 jsc ✅ 🧪 api-ios ✅ 🧪 mac-wk1 ✅ 🛠 gtk
✅ 🛠 🧪 jsc-debug-arm64 ✅ 🛠 ios-safer-cpp ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🛠 🧪 unsafe-merge ✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2 ✅ 🛠 jsc-armv7
✅ 🛠 tv ✅ 🛠 mac-safer-cpp ✅ 🧪 jsc-armv7-tests
✅ 🛠 tv-sim
✅ 🛠 watch
loading 🛠 watch-sim

@dhecht dhecht self-assigned this May 4, 2026
@dhecht dhecht added the JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. label May 4, 2026
@dhecht dhecht marked this pull request as ready for review May 4, 2026 17:47
@dhecht dhecht requested a review from a team as a code owner May 4, 2026 17:47
Copy link
Copy Markdown
Contributor

@kmiller68 kmiller68 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me on second patch too.

@dhecht dhecht force-pushed the eng/JSC-GreedyRegAlloc-Add-loop-aware-live-range-splitting-disabled-by-default branch from 1bce483 to d5fd1d5 Compare May 5, 2026 16:57
@dhecht dhecht added the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label May 6, 2026
…y default)

https://bugs.webkit.org/show_bug.cgi?id=312905
rdar://175260380

Reviewed by Keith Miller.

Add loop-aware live range splitting to the greedy register allocator.
When a tmp's live range crosses a loop boundary, split it into a loop
portion and a non-loop portion. This allows the two portions to be
allocated independently, reducing interference between the loop body
and the surrounding code. For example, a tmp live across a loop but
unused inside it can be split so that the loop portion is spilled,
freeing a register for the loop body. Similarly, a tmp that conflicts
with others outside the loop may get a register inside it after
splitting.

A new CFG normalization pass (ensureDedicatedLoopEntryExitBlocks)
ensures non-critical entry edges and dedicated exit blocks so that
fixup code can be safely inserted at loop boundaries. Entry/exit
fixups use Shuffle instructions to handle potential register cycles
when multiple tmps are split around the same loop.

The feature is off by default (airGreedyRegAllocSplitAroundLoops).
The mechanism is working and passes tests, but improvements to the
splitting policy and integration with the allocator's priority-driven
allocation order are needed to realize the potential.

Test: Source/JavaScriptCore/b3/air/testair.cpp
      JSTests/stress/regalloc-loop-splitting.js

* JSTests/stress/regalloc-loop-splitting.js: Added.
(clobber):
(test):
* Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj:
* Source/JavaScriptCore/Sources.txt:
* Source/JavaScriptCore/b3/air/AirAllocateRegistersByGreedy.cpp:
(JSC::B3::Air::Greedy::Cost::subtractSaturating):
(JSC::B3::Air::Greedy::LiveRange::contains const):
(JSC::B3::Air::Greedy::LiveRange::overlaps const):
(JSC::B3::Air::Greedy::AroundLoopSplitMetadata::AroundLoopSplitMetadata):
(JSC::B3::Air::Greedy::AroundLoopSplitMetadata::dump const):
(JSC::B3::Air::Greedy::GreedyAllocator::dump const):
(JSC::B3::Air::Greedy::GreedyAllocator::forEachBlockInLiveRange):
(JSC::B3::Air::Greedy::GreedyAllocator::findBlockIndexContainingPoint):
(JSC::B3::Air::Greedy::GreedyAllocator::findBlockContainingPoint):
(JSC::B3::Air::Greedy::GreedyAllocator::rewriteCoalescedTmps):
(JSC::B3::Air::Greedy::GreedyAllocator::addSplitTmp):
(JSC::B3::Air::Greedy::GreedyAllocator::trySplit):
(JSC::B3::Air::Greedy::GreedyAllocator::analyzeLoop):
(JSC::B3::Air::Greedy::GreedyAllocator::ensureLoopAnalysis):
(JSC::B3::Air::Greedy::GreedyAllocator::chooseLoopForSplit):
(JSC::B3::Air::Greedy::GreedyAllocator::trySplitAroundLoop):
(JSC::B3::Air::Greedy::GreedyAllocator::trySplitAroundClobbers):
(JSC::B3::Air::Greedy::GreedyAllocator::insertFixupCode):
(JSC::B3::Air::Greedy::GreedyAllocator::insertSplitAroundLoopFixupCode):
(JSC::B3::Air::allocateRegistersByGreedy):
(JSC::B3::Air::Greedy::LiveRange::overlaps): Deleted.
* Source/JavaScriptCore/b3/air/AirCode.cpp:
* Source/JavaScriptCore/b3/air/AirCode.h:
* Source/JavaScriptCore/b3/air/AirEnsureDedicatedLoopEntryExitBlocks.cpp: Added.
(JSC::B3::Air::ensureDedicatedLoopEntryExitBlocks):
* Source/JavaScriptCore/b3/air/AirEnsureDedicatedLoopEntryExitBlocks.h: Added.
* Source/JavaScriptCore/b3/air/AirRegisterAllocatorStats.h:
* Source/JavaScriptCore/b3/air/testair.cpp:
* Source/JavaScriptCore/runtime/OptionsList.h:

Canonical link: https://commits.webkit.org/312693@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/JSC-GreedyRegAlloc-Add-loop-aware-live-range-splitting-disabled-by-default branch from d5fd1d5 to 899099b Compare May 6, 2026 14:50
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 312693@main (899099b): https://commits.webkit.org/312693@main

Reviewed commits have been landed. Closing PR #64182 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit 899099b into WebKit:main May 6, 2026
@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants