Repository: WebKit/WebKit
Pull request #42949: [JSC] DFGLoopUnrollingPhase: Support partial loop unrolling for non-constant bounds
Author: login: hyjorc1
Labels: name: New Bugs
description: Unclassified bugs are placed in this component until the correct component can be determined.
Created: 2025-03-24T20:19:40Z | Merged: 2025-03-26T06:11:50Z

#### b16849008e438b42d44b16e43da8b99c0796cf87
<pre>
[JSC] DFGLoopUnrollingPhase: Support partial loop unrolling for non-constant bounds
<a href="https://bugs.webkit.org/show_bug.cgi?id=290335">https://bugs.webkit.org/show_bug.cgi?id=290335</a>
<a href="https://rdar.apple.com/147775029">rdar://147775029</a>

Reviewed by Yusuke Suzuki.

This patch enhances the DFG loop unrolling phase to support partial unrolling
for loops with non-constant bounds. Previously, loop unrolling was limited to
loops with statically known iteration counts. Now, loops with dynamic operands
can be unrolled partially based on new thresholds. And this version offers:

                                             without                     with

loop-unrolling-variable-medium            7.3285+-0.0263     !      7.4737+-0.0300        ! definitely 1.0198x slower
loop-unrolling-variable                   0.3481+-0.0077            0.3477+-0.0082
loop-unrolling-variable-medium-dep       28.6089+-0.5330     ^     10.9441+-0.0331        ^ definitely 2.6141x faster
loop-unrolling-variable-large            66.6766+-0.0446     !     66.8410+-0.0559        ! definitely 1.0025x slower
loop-unrolling-variable-small             0.6056+-0.0088            0.6029+-0.0092

Currently, partial loop unrolling is disabled and it would be reenabled once
the heuristics tuning is done.

* JSTests/stress/loop-unrolling-partial.js: Added.
(func1):
(test):
* Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp:
(JSC::DFG::LoopUnrollingPhase::LoopData::isOperandConstant const):
(JSC::DFG::LoopUnrollingPhase::run):
(JSC::DFG::LoopUnrollingPhase::tryUnroll):
(JSC::DFG::LoopUnrollingPhase::identifyInductionVariable):
(JSC::DFG::LoopUnrollingPhase::shouldUnrollLoop):
(JSC::DFG::LoopUnrollingPhase::unrollLoop):
(JSC::DFG::LoopUnrollingPhase::LoopData::dump const):
* Source/JavaScriptCore/runtime/OptionsList.h:

Canonical link: <a href="https://commits.webkit.org/292691@main">https://commits.webkit.org/292691@main</a>
</pre>
<!--EWS-Status-Bubble-Start-->
https://github.com/WebKit/WebKit/commit/3b3c8afbfbd08bede506973e5d2e5f060fc3dcbe

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96771 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/16385 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/6542 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101844 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/47291 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16681 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24825 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73742 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30956 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99774 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12561 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/87523 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/54077 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/12324 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/5335 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46619 "Built successfully") | 
| [✅ 🛠 🧪 jsc](https://ews-build.webkit.org/#/builders/20/builds/89444 "Built successfully and passed tests") | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/82418 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/5419 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103867 "Built successfully") | 
| [✅ 🛠 🧪 jsc-arm64](https://ews-build.webkit.org/#/builders/12/builds/95392 "Built successfully and passed tests") | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23839 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/17382 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/82790 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/24090 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/83591 "Passed tests") | [❌ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/82178 "Found 3 new API test failures: /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/print-errors, /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/print, /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/close-after-print (failure)") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/20648 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26837 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/4374 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/17317 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23801 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/28956 "Built successfully") | [✅ 🛠 jsc-armv7](https://ews-build.webkit.org/#/builders/35/builds/119019 "Built successfully") | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/23460 "Built successfully") | | [  ~~🧪 jsc-armv7-tests~~](https://ews-build.webkit.org/#/builders/25/builds/33471 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26940 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/25201 "Built successfully") | | | 
<!--EWS-Status-Bubble-End-->


Diff:
diff --git a/JSTests/stress/loop-unrolling-variable.js b/JSTests/stress/loop-unrolling-variable.js
new file mode 100644
index 000000000000..77018a7d8f5f
--- /dev/null
+++ b/JSTests/stress/loop-unrolling-variable.js
@@ -0,0 +1,22 @@
+function func1(x) {
+    let sum = 0;
+    for (let i = 0; i < x; i++) {
+        sum += i;
+    }
+    return sum;
+}
+noInline(func1);
+
+function test(func) {
+    let expected;
+    for (let i = 0; i < testLoopCount; i++) {
+        let res = func(4);
+        if (i == 0)
+            expected = res;
+        if (expected != res) {
+            throw new Error("bad! expected=", expected, " res=", res);
+        }
+    }
+}
+
+test(func1);
diff --git a/Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp b/Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp
index f260d81e83d9..885285cb5b68 100644
--- a/Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp
@@ -53,6 +53,7 @@ class LoopUnrollingPhase : public Phase {
         uint32_t loopSize() { return loop->size(); }
         BasicBlock* loopBody(uint32_t i) { return loop->at(i).node(); }
         BasicBlock* header() const { return loop->header().node(); }
+        bool isOperandConstant() const { return std::holds_alternative<CheckedInt32>(operand); }
 
         Node* condition() const
         {
@@ -72,7 +73,7 @@ class LoopUnrollingPhase : public Phase {
         // for (i = initialValue; condition(i, operand); i = update(i, updateValue)) { ... }
         Node* inductionVariable { nullptr };
         CheckedInt32 initialValue { INT_MIN };
-        CheckedInt32 operand { INT_MIN };
+        std::variant<Node*, CheckedInt32> operand { INT_MIN };
         Node* update { nullptr };
         CheckedInt32 updateValue { INT_MIN };
         CheckedUint32 iterationCount { 0 };
@@ -100,6 +101,11 @@ class LoopUnrollingPhase : public Phase {
             for (auto [loop, depth] : loops) {
                 if (!loop)
                     break;
+                BasicBlock* header = loop->header().node();
+                if (m_unrolledLoopHeaders.contains(header)) {
+                    dataLogLnIf(Options::verboseLoopUnrolling(), "Skipping the loop with header ", header, " since it's already unrolled. Looking for anther candidate.");
+                    continue;
+                }
                 if (tryUnroll(loop)) {
                     unrolled = true;
                     ++unrolledCount;
@@ -190,6 +196,8 @@ class LoopUnrollingPhase : public Phase {
 
         dataLogIf(Options::verboseLoopUnrolling(), "\tGraph after Loop Unrolling for loop\n", m_graph);
         dataLogLnIf(Options::printEachUnrolledLoop(), "\tIn function ", m_graph.m_codeBlock->inferredName(), ", successfully unrolled the loop header=", *header);
+
+        m_unrolledLoopHeaders.add(header);
         return true;
     }
 
@@ -322,10 +330,12 @@ class LoopUnrollingPhase : public Phase {
 
             // Condition right
             Edge operand = condition->child2();
-            if (!operand->isInt32Constant() || operand.useKind() != Int32Use)
+            if (operand->isInt32Constant() && operand.useKind() == Int32Use)
+                data.operand = operand->asInt32();
+            else if (Options::usePartialLoopUnrolling())
+                data.operand = operand.node();
+            else
                 return false;
-
-            data.operand = condition->child2()->asInt32();
             data.update = condition->child1().node();
             data.updateValue = update->child2()->asInt32();
             data.inductionVariable = condition->child1()->child1().node();
@@ -376,12 +386,13 @@ class LoopUnrollingPhase : public Phase {
             return false;
         }
 
-        // Compute the number of iterations in the loop.
-        {
+        // Compute the number of iterations in the loop, if it has a constant iteration count.
+        if (data.isOperandConstant()) {
             CheckedUint32 iterationCount = 0;
             auto compare = comparisonFunction(condition, data.inverseCondition.value());
             auto update = updateFunction(data.update);
-            for (CheckedInt32 i = data.initialValue; compare(i, data.operand);) {
+            for (CheckedInt32 i = data.initialValue; compare(i, std::get<CheckedInt32>(data.operand));) {
+                // FIXME: We should compute code generated codes instead here. See LowerDFGToB3::compileBlock for details.
                 if (iterationCount > Options::maxLoopUnrollingIterationCount()) {
                     dataLogLnIf(Options::verboseLoopUnrolling(), "Skipping loop with header ", *data.header(), " since maxLoopUnrollingIterationCount =", Options::maxLoopUnrollingIterationCount());
                     return false;
@@ -409,6 +420,7 @@ class LoopUnrollingPhase : public Phase {
     bool shouldUnrollLoop(LoopData& data)
     {
         uint32_t totalNodeCount = 0;
+        uint32_t maxLoopUnrollingBodyNodeSize = data.isOperandConstant() ? Options::maxLoopUnrollingBodyNodeSize() : Options::maxPartialLoopUnrollingBodyNodeSize();
         for (uint32_t i = 0; i < data.loopSize(); ++i) {
             BasicBlock* body = data.loopBody(i);
             if (!body->isReachable) {
@@ -421,7 +433,7 @@ class LoopUnrollingPhase : public Phase {
             // ignore the loop, avoiding unnecessary cloneability checks for nodes in invalid blocks.
 
             totalNodeCount += body->size();
-            if (totalNodeCount > Options::maxLoopUnrollingBodyNodeSize()) {
+            if (totalNodeCount > maxLoopUnrollingBodyNodeSize) {
                 dataLogLnIf(Options::verboseLoopUnrolling(), "Skipping loop with header ", *data.header(), " and loop node count=", totalNodeCount, " since maxLoopUnrollingBodyNodeSize =", Options::maxLoopUnrollingBodyNodeSize());
                 return false;
             }
@@ -454,8 +466,11 @@ class LoopUnrollingPhase : public Phase {
 
     void unrollLoop(LoopData& data)
     {
+        dataLogLnIf(Options::verboseLoopUnrolling(), " unroll ", data.isOperandConstant() ?  " with constant iterations" : " partially");
+
         BasicBlock* const header = data.header();
         BasicBlock* const tail = data.tail;
+        BasicBlock* const next = data.next;
 
         dataLogLnIf(Options::verboseLoopUnrolling(), "tailTerminalOriginSemantic ", tail->terminal()->origin.semantic);
 
@@ -473,30 +488,51 @@ class LoopUnrollingPhase : public Phase {
             }
         };
 
-        auto convertTailBranchToNextJump = [&](BasicBlock* tail, BasicBlock* next) {
-            // Why don't we use Jump instead of Branch? The reason is tail's original terminal was Branch.
-            // If we change this from Branch to Jump, we need to preserve how variables are used (via GetLocal, MovHint, SetLocal)
-            // not to confuse these variables liveness, it involves what blocks are used for successors of this tail block.
-            // Here, we can simplify the problem by using Branch and using the original "header" successors as never-taken branch.
-            // FTL's subsequent pass will optimize this and convert this Branch to Jump and/or eliminate this Branch and merge
-            // multiple blocks easily since its condition is constant boolean True. But we do not need to do the complicated analysis
-            // here. So let's just use Branch.
-            ASSERT(tail->terminal()->isBranch());
-            auto* constant = m_graph.addNode(SpecBoolean, JSConstant, tail->terminal()->origin, OpInfo(m_graph.freezeStrong(jsBoolean(true))));
-            tail->insertBeforeTerminal(constant);
+        //  ### Constant ###         ### Partial ###
+        //
+        //  PreHeader                 PreHeader
+        //   |                          |
+        //  BodyGraph_0 <----       -> BodyGraph_0 --
+        //   |    |      |  |       |   |           |
+        //   |T   --------  |F      |T  |T          |F
+        //   |       F      |       |   |           |
+        //  BodyGraph_1 -----       -- BodyGraph_1  |
+        //   |T                         |F          |
+        //  Next                       Next <--------
+        auto convertTailBranchToNextJump = [&](BasicBlock* tail, BasicBlock* taken) {
+            BasicBlock* notTaken = next;
             auto* terminal = tail->terminal();
-            terminal->child1() = Edge(constant, KnownBooleanUse);
-            terminal->branchData()->taken = BranchTarget(next);
-            terminal->branchData()->notTaken = BranchTarget(header);
+            if (data.isOperandConstant()) {
+                // Why don't we use Jump instead of Branch? The reason is tail's original terminal was Branch.
+                // If we change this from Branch to Jump, we need to preserve how variables are used (via GetLocal, MovHint, SetLocal)
+                // not to confuse these variables liveness, it involves what blocks are used for successors of this tail block.
+                // Here, we can simplify the problem by using Branch and using the original "header" successors as never-taken branch.
+                // FTL's subsequent pass will optimize this and convert this Branch to Jump and/or eliminate this Branch and merge
+                // multiple blocks easily since its condition is constant boolean True. But we do not need to do the complicated analysis
+                // here. So let's just use Branch.
+                ASSERT(tail->terminal()->isBranch());
+                auto* constant = m_graph.addNode(SpecBoolean, JSConstant, tail->terminal()->origin, OpInfo(m_graph.freezeStrong(jsBoolean(true))));
+                tail->insertBeforeTerminal(constant);
+                terminal->child1() = Edge(constant, KnownBooleanUse);
+                notTaken = header;
+            }
+
+            terminal->branchData()->taken = BranchTarget(taken);
+            terminal->branchData()->notTaken = BranchTarget(notTaken);
         };
 
 #if ASSERT_ENABLED
         m_graph.initializeNodeOwners(); // This is only used for the debug assertion in cloneNodeImpl.
 #endif
 
-        BasicBlock* next = data.next;
-        ASSERT(!data.iterationCount.hasOverflowed() && data.iterationCount);
-        for (uint32_t cloneCount = data.iterationCount - 1; cloneCount--;) {
+        BasicBlock* taken = next;
+        uint32_t cloneCount = 0;
+        if (data.isOperandConstant()) {
+            ASSERT(!data.iterationCount.hasOverflowed() && data.iterationCount);
+            cloneCount = data.iterationCount - 1;
+        } else
+            cloneCount = Options::maxPartialLoopUnrollingIterationCount() - 1;
+        while (cloneCount--) {
             blockClones.clear();
             nodeClones.clear();
 
@@ -532,7 +568,8 @@ class LoopUnrollingPhase : public Phase {
                 // 5. Clone successors. (predecessors will be fixed in resetReachability below)
                 if (body == tail) {
                     ASSERT(tail->terminal()->isBranch());
-                    convertTailBranchToNextJump(clone, next);
+                    bool isTakenNextInPartialMode = taken == next && !data.isOperandConstant();
+                    convertTailBranchToNextJump(clone, isTakenNextInPartialMode ? header : taken);
                 } else {
                     for (uint32_t i = 0; i < body->numSuccessors(); ++i) {
                         auto& successor = clone->successor(i);
@@ -543,11 +580,11 @@ class LoopUnrollingPhase : public Phase {
                 }
             }
 
-            next = blockClones.get(header);
+            taken = blockClones.get(header);
         }
 
         // 6. Replace the original loop tail branch with a jump to the last header clone.
-        convertTailBranchToNextJump(tail, next);
+        convertTailBranchToNextJump(tail, taken);
 
         // Done clone.
         if (!m_blockInsertionSet.execute()) {
@@ -565,6 +602,7 @@ class LoopUnrollingPhase : public Phase {
 
 private:
     BlockInsertionSet m_blockInsertionSet;
+    UncheckedKeyHashSet<BasicBlock*> m_unrolledLoopHeaders;
 };
 
 bool performLoopUnrolling(Graph& graph)
@@ -610,7 +648,10 @@ void LoopUnrollingPhase::LoopData::dump(PrintStream& out) const
     out.print(", ");
 
     out.print("initValue=", initialValue, ", ");
-    out.print("operand=", operand, ", ");
+    if (isOperandConstant())
+        out.print("operand=", std::get<CheckedInt32>(operand), ", ");
+    else
+        out.print("operand=", std::get<Node*>(operand), ", ");
 
     out.print("update=");
     if (update)
@@ -632,6 +673,7 @@ bool LoopUnrollingPhase::isNodeCloneable(HashSet<Node*>& cloneableCache, Node* n
         return true;
 
     bool result = true;
+    // FIXME: We should support all DFG nodes.
     switch (node->op()) {
     case Phi:
         break;
diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h
index 5f2180f7aa00..764a0bd3f94a 100644
--- a/Source/JavaScriptCore/runtime/OptionsList.h
+++ b/Source/JavaScriptCore/runtime/OptionsList.h
@@ -579,10 +579,13 @@ bool hasCapacityToUseLargeGigacage();
     v(Bool, dumpBaselineJITSizeStatistics, false, Normal, nullptr) \
     v(Bool, dumpDFGJITSizeStatistics, false, Normal, nullptr) \
     v(Bool, useLoopUnrolling, true, Normal, nullptr) \
+    v(Bool, usePartialLoopUnrolling, false, Normal, nullptr) \
     v(Bool, verboseLoopUnrolling, false, Normal, nullptr) \
     v(Unsigned, maxLoopUnrollingCount, 2, Normal, nullptr) \
     v(Unsigned, maxLoopUnrollingBodyNodeSize, 200, Normal, nullptr) \
     v(Unsigned, maxLoopUnrollingIterationCount, 4, Normal, nullptr) \
+    v(Unsigned, maxPartialLoopUnrollingBodyNodeSize, 200, Normal, nullptr) \
+    v(Unsigned, maxPartialLoopUnrollingIterationCount, 4, Normal, nullptr) \
     v(Bool, printEachUnrolledLoop, false, Normal, nullptr) \
     v(Bool, verboseExecutablePoolAllocation, false, Normal, nullptr) \
     v(Bool, useHandlerIC, canUseHandlerIC(), Normal, nullptr) \


Reviews:
user: login: hyjorc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T21:02:25Z
user: login: hyjorc1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T21:02:49Z
user: login: justinmichaud
body: Nice. I wonder if we could detect some of these loops quickly before reaching FTL to emit a trip counter.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T01:56:57Z
user: login: Constellation
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T22:02:23Z

Review comments:
diff_hunk: @@ -473,30 +485,47 @@ class LoopUnrollingPhase : public Phase {
             }
         };
 
-        auto convertTailBranchToNextJump = [&](BasicBlock* tail, BasicBlock* next) {
-            // Why don't we use Jump instead of Branch? The reason is tail's original terminal was Branch.
-            // If we change this from Branch to Jump, we need to preserve how variables are used (via GetLocal, MovHint, SetLocal)
-            // not to confuse these variables liveness, it involves what blocks are used for successors of this tail block.
-            // Here, we can simplify the problem by using Branch and using the original "header" successors as never-taken branch.
-            // FTL's subsequent pass will optimize this and convert this Branch to Jump and/or eliminate this Branch and merge
-            // multiple blocks easily since its condition is constant boolean True. But we do not need to do the complicated analysis
-            // here. So let's just use Branch.
-            ASSERT(tail->terminal()->isBranch());
-            auto* constant = m_graph.addNode(SpecBoolean, JSConstant, tail->terminal()->origin, OpInfo(m_graph.freezeStrong(jsBoolean(true))));
-            tail->insertBeforeTerminal(constant);
+        //  ### Constant ###         ### Partial ###
+        //
+        //  PreHeader                 PreHeader
+        //   |                          |
+        //  Header <-------        -> Header --------
path: Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp
user: login: hyjorc1
body: Oops, this `Header` should be `HeaderBodyTailGraph_0`.
created_at: 2025-03-24T21:02:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -473,30 +485,47 @@ class LoopUnrollingPhase : public Phase {
             }
         };
 
-        auto convertTailBranchToNextJump = [&](BasicBlock* tail, BasicBlock* next) {
-            // Why don't we use Jump instead of Branch? The reason is tail's original terminal was Branch.
-            // If we change this from Branch to Jump, we need to preserve how variables are used (via GetLocal, MovHint, SetLocal)
-            // not to confuse these variables liveness, it involves what blocks are used for successors of this tail block.
-            // Here, we can simplify the problem by using Branch and using the original "header" successors as never-taken branch.
-            // FTL's subsequent pass will optimize this and convert this Branch to Jump and/or eliminate this Branch and merge
-            // multiple blocks easily since its condition is constant boolean True. But we do not need to do the complicated analysis
-            // here. So let's just use Branch.
-            ASSERT(tail->terminal()->isBranch());
-            auto* constant = m_graph.addNode(SpecBoolean, JSConstant, tail->terminal()->origin, OpInfo(m_graph.freezeStrong(jsBoolean(true))));
-            tail->insertBeforeTerminal(constant);
+        //  ### Constant ###         ### Partial ###
+        //
+        //  PreHeader                 PreHeader
+        //   |                          |
+        //  Header <-------        -> Header --------
+        //   |   |   | F  |        |    |           |
+        //   | T -----    | F      | T  | T         | F
+        //   |            |        |    |           |
+        //  BodyTailGraph -        -- BodyTailGraph |
path: Source/JavaScriptCore/dfg/DFGLoopUnrollingPhase.cpp
user: login: hyjorc1
body: And this `BodyTailGraph` should be `HeaderBodyTailGraph_1`.
created_at: 2025-03-24T21:02:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -579,10 +579,13 @@ bool hasCapacityToUseLargeGigacage();
     v(Bool, dumpBaselineJITSizeStatistics, false, Normal, nullptr) \
     v(Bool, dumpDFGJITSizeStatistics, false, Normal, nullptr) \
     v(Bool, useLoopUnrolling, true, Normal, nullptr) \
+    v(Bool, enablePartialLoopUnrolling, false, Normal, nullptr) \
path: Source/JavaScriptCore/runtime/OptionsList.h
user: login: Constellation
body: Let's rename it to `usePartialLoopUnrolling` 
created_at: 2025-03-25T22:01:34Z
author_association: MEMBER

PR comments:
user: login: webkit-early-warning-system
created_at: 2025-03-24T20:19:47Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/d05e9aa3ee28d3b163fe4cf85126eefff6de2a50)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96572 "Passed style check") | [  ~~🛠 ios~~](https://ews-build.webkit.org/#/builders/131/builds/16186 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 mac~~](https://ews-build.webkit.org/#/builders/138/builds/6287 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 wpe~~](https://ews-build.webkit.org/#/builders/5/builds/101644 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 win~~](https://ews-build.webkit.org/#/builders/59/builds/47092 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") 
| | [  ~~🛠 ios-sim~~](https://ews-build.webkit.org/#/builders/130/builds/16482 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24620 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/5/builds/101644 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 win-tests~~](https://ews-build.webkit.org/#/builders/59/builds/47092 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99575 "Passed tests") | [  ~~🧪 ios-wk2~~](https://ews-build.webkit.org/#/builders/130/builds/16482 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 api-mac~~](https://ews-build.webkit.org/#/builders/138/builds/6287 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 api-wpe~~](https://ews-build.webkit.org/#/builders/5/builds/101644 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [  ~~🧪 ios-wk2-wpt~~](https://ews-build.webkit.org/#/builders/130/builds/16482 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk1~~](https://ews-build.webkit.org/#/builders/138/builds/6287 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 wpe-cairo~~](https://ews-build.webkit.org/#/builders/65/builds/46420 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| [  ~~🛠 🧪 jsc~~](https://ews-build.webkit.org/#/builders/20/builds/89245 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/130/builds/16482 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk2~~](https://ews-build.webkit.org/#/builders/138/builds/6287 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 gtk~~](https://ews-build.webkit.org/#/builders/2/builds/103668 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| [  ~~🛠 🧪 jsc-arm64~~](https://ews-build.webkit.org/#/builders/12/builds/95193 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 vision~~](https://ews-build.webkit.org/#/builders/128/builds/23639 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [⏳ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/macOS-Sequoia-Debug-WK2-Tests-EWS "Waiting to run tests") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/2/builds/103668 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [  ~~🛠 vision-sim~~](https://ews-build.webkit.org/#/builders/121/builds/23890 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk2-stress~~](https://ews-build.webkit.org/#/builders/138/builds/6287 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 api-gtk~~](https://ews-build.webkit.org/#/builders/2/builds/103668 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [⏳ 🧪 vision-wk2 ](https://ews-build.webkit.org/#/builders/visionOS-2-Simulator-WK2-Tests-EWS "Waiting in queue, processing has not started yet") | [  ~~🧪 mac-intel-wk2~~](https://ews-build.webkit.org/#/builders/138/builds/6287 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/17113 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [  ~~🛠 tv~~](https://ews-build.webkit.org/#/builders/127/builds/23602 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/28757 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 jsc-armv7](https://ews-build.webkit.org/#/builders/35/builds/118819 "Built successfully") | 
| | [  ~~🛠 tv-sim~~](https://ews-build.webkit.org/#/builders/125/builds/23261 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | [⏳ 🧪 jsc-armv7-tests](https://ews-build.webkit.org/#/builders/JSC-ARMv7-32bits-Tests-EWS "Waiting to run tests") | 
| | [  ~~🛠 watch~~](https://ews-build.webkit.org/#/builders/129/builds/26741 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | | 
| | [  ~~🛠 watch-sim~~](https://ews-build.webkit.org/#/builders/124/builds/25002 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-03-24T20:25:40Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/897a0bdd196a866cababd44b4c90f2d1a821b792)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96573 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/16187 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/6288 "Built successfully") | [  ~~🛠 wpe~~](https://ews-build.webkit.org/#/builders/5/builds/101645 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 win~~](https://ews-build.webkit.org/#/builders/59/builds/47093 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16483 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24621 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/5/builds/101645 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 win-tests~~](https://ews-build.webkit.org/#/builders/59/builds/47093 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99576 "Passed tests") | [  ~~🧪 ios-wk2~~](https://ews-build.webkit.org/#/builders/132/builds/12405 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [⏳ 🧪 api-mac](https://ews-build.webkit.org/#/builders/API-Tests-macOS-EWS "Waiting to run tests") | [  ~~🧪 api-wpe~~](https://ews-build.webkit.org/#/builders/5/builds/101645 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [  ~~🧪 ios-wk2-wpt~~](https://ews-build.webkit.org/#/builders/133/builds/12162 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk1~~](https://ews-build.webkit.org/#/builders/135/builds/5126 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🛠 wpe-cairo~~](https://ews-build.webkit.org/#/builders/65/builds/46421 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| [✅ 🛠 🧪 jsc](https://ews-build.webkit.org/#/builders/20/builds/89246 "Built successfully and passed tests") | [⏳ 🧪 api-ios](https://ews-build.webkit.org/#/builders/API-Tests-iOS-Simulator-EWS "Waiting to run tests") | [  ~~🧪 mac-wk2~~](https://ews-build.webkit.org/#/builders/136/builds/5219 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103669 "Built successfully") | 
| [✅ 🛠 🧪 jsc-arm64](https://ews-build.webkit.org/#/builders/12/builds/95194 "Built successfully and passed tests") | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23640 "Built successfully") | [⏳ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/macOS-Sequoia-Debug-WK2-Tests-EWS "Waiting to run tests") | [⏳ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/GTK-WK2-Tests-EWS "Waiting to run tests") | 
| | [  ~~🛠 vision-sim~~](https://ews-build.webkit.org/#/builders/121/builds/23891 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 mac-wk2-stress~~](https://ews-build.webkit.org/#/builders/8/builds/83381 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [⏳ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/API-Tests-GTK-EWS "Waiting to run tests") | 
| | [⏳ 🧪 vision-wk2 ](https://ews-build.webkit.org/#/builders/visionOS-2-Simulator-WK2-Tests-EWS "Waiting in queue, processing has not started yet") | [⏳ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/macOS-Sonoma-Release-WK2-Intel-Tests-EWS "Waiting to run tests") | [  ~~🛠 playstation~~](https://ews-build.webkit.org/#/builders/134/builds/17114 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23603 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/28758 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 jsc-armv7](https://ews-build.webkit.org/#/builders/35/builds/118820 "Built successfully") | 
| | [  ~~🛠 tv-sim~~](https://ews-build.webkit.org/#/builders/125/builds/23262 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | [⏳ 🧪 jsc-armv7-tests](https://ews-build.webkit.org/#/builders/JSC-ARMv7-32bits-Tests-EWS "Waiting to run tests") | 
| | [  ~~🛠 watch~~](https://ews-build.webkit.org/#/builders/129/builds/26742 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/25003 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-03-24T21:08:42Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/ad6844aa42f8506c5d51444c1618ddc8c056abb5)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96581 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/16195 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/6297 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101653 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/47101 "Built successfully") 
| | [![loading](https://user-images.githubusercontent.com/3098702/171232313-daa606f1-8fd6-4b0f-a20b-2cb93c43d19b.png) 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16491 "Build is in progress. Recent messages:OS: Sequoia (15.2), Xcode: 16.2; Skipping applying patch since patch_id isn't provided; Checked out pull request; Compiled WebKit (warnings)") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24629 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73628 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30843 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99584 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12414 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/87343 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/53964 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/12172 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/5134 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46429 "Built successfully") | 
| [✅ 🛠 🧪 jsc](https://ews-build.webkit.org/#/builders/20/builds/89254 "Built successfully and passed tests") | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/82276 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/5227 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103677 "Built successfully") | 
| [✅ 🛠 🧪 jsc-arm64](https://ews-build.webkit.org/#/builders/12/builds/95202 "Built successfully and passed tests") | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23648 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/17244 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/82668 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/23899 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/83389 "Passed tests") | [❌ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/82043 "Found 3 new API test failures: /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/print-errors, /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/print, /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/close-after-print (failure)") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26694 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/4214 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/17122 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23611 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/28766 "Built successfully") | [✅ 🛠 jsc-armv7](https://ews-build.webkit.org/#/builders/35/builds/118828 "Built successfully") | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/23270 "Built successfully") | | [⏳ 🧪 jsc-armv7-tests](https://ews-build.webkit.org/#/builders/JSC-ARMv7-32bits-Tests-EWS "Waiting to run tests") | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26750 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/25011 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-03-25T20:05:27Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/79acb6f70bce6298bc0685640b508884fd9adea0)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96739 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/16353 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/6504 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101812 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/47259 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16649 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24793 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73730 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30945 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99742 "Passed tests") | [❌ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12538 "Found 1 new test failure: fast/forms/ios/focus-input-via-button.html (failure)") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/87500 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/54065 "Passed tests") | 
| | [  ~~🧪 ios-wk2-wpt~~](https://ews-build.webkit.org/#/builders/133/builds/12297 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/5308 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46587 "Built successfully") | 
| [✅ 🛠 🧪 jsc](https://ews-build.webkit.org/#/builders/20/builds/89412 "Built successfully and passed tests") | [  ~~🧪 api-ios~~](https://ews-build.webkit.org/#/builders/13/builds/82395 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/5394 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103835 "Built successfully") | 
| [✅ 🛠 🧪 jsc-arm64](https://ews-build.webkit.org/#/builders/12/builds/95360 "Built successfully and passed tests") | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23807 "Built successfully") | [  ~~🧪 mac-AS-debug-wk2~~](https://ews-build.webkit.org/#/builders/122/builds/17366 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/1/builds/82783 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/24058 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/83564 "Passed tests") | [  ~~🧪 api-gtk~~](https://ews-build.webkit.org/#/builders/21/builds/82170 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26819 "Passed tests") | [  ~~🧪 mac-intel-wk2~~](https://ews-build.webkit.org/#/builders/137/builds/4353 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/17285 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23769 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/28924 "Built successfully") | [✅ 🛠 jsc-armv7](https://ews-build.webkit.org/#/builders/35/builds/118987 "Built successfully") | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/23428 "Built successfully") | | [⏳ 🧪 jsc-armv7-tests](https://ews-build.webkit.org/#/builders/JSC-ARMv7-32bits-Tests-EWS "Waiting to run tests") | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26908 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/25169 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-03-25T22:15:46Z
body: EWS run on current version of this PR (hash https://github.com/WebKit/WebKit/commit/3b3c8afbfbd08bede506973e5d2e5f060fc3dcbe)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96771 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/16385 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/6542 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101844 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/47291 "Built successfully") 
| | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16681 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24825 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73742 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30956 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99774 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12561 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/87523 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/54077 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/12324 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/5335 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46619 "Built successfully") | 
| [✅ 🛠 🧪 jsc](https://ews-build.webkit.org/#/builders/20/builds/89444 "Built successfully and passed tests") | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/82418 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/5419 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103867 "Built successfully") | 
| [✅ 🛠 🧪 jsc-arm64](https://ews-build.webkit.org/#/builders/12/builds/95392 "Built successfully and passed tests") | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23839 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/17382 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/82790 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/24090 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/83591 "Passed tests") | [❌ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/82178 "Found 3 new API test failures: /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/print-errors, /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/print, /WebKitGTK/TestPrinting:/webkit/WebKitPrintOperation/close-after-print (failure)") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/20648 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26837 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/4374 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/17317 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23801 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/28956 "Built successfully") | [✅ 🛠 jsc-armv7](https://ews-build.webkit.org/#/builders/35/builds/119019 "Built successfully") | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/23460 "Built successfully") | | [  ~~🧪 jsc-armv7-tests~~](https://ews-build.webkit.org/#/builders/25/builds/33471 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26940 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/25201 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: hyjorc1
created_at: 2025-03-25T22:24:52Z
body: > Nice. I wonder if we could detect some of these loops quickly before reaching FTL to emit a trip counter.

Yeah, I think that might be a good idea to metadata the loop count in DFG and then do partial unrolling in FTL based on that.
author_association: CONTRIBUTOR
user: login: webkit-ews-buildbot
created_at: 2025-03-26T04:08:07Z
body: Failed api-gtk checks. Please resolve failures and re-apply `safe-merge-queue` label.

Rejecting #42949 from merge queue.
author_association: COLLABORATOR
user: login: webkit-ews-buildbot
created_at: 2025-03-26T04:08:15Z
body: 

Safe-Merge-Queue: Build [#52559](https://ews-build.webkit.org/#/builders/40/builds/52559).
author_association: COLLABORATOR
user: login: webkit-commit-queue
created_at: 2025-03-26T06:11:51Z
body: Committed 292691@main (b16849008e43): <https://commits.webkit.org/292691@main>

Reviewed commits have been landed. Closing PR #42949 and removing active labels.
author_association: COLLABORATOR