From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Olivier=20Fl=C3=BCckiger?= <olivf@chromium.org>
Date: Wed, 8 Jan 2025 16:06:43 +0100
Subject: Merged: [maglev] regalloc: handle non-loop resumable_loops
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Resumable loops which are not loops can be either:

1. An unreachable loop with only a back-edge
2. A fall-through to a resumable loop with a dead back-edge

Only (1) starts with an empty register state.

Fixed: 386143468
(cherry picked from commit b44bd24761f1a2eae131bd90be15b5a68cc70f83)

Change-Id: I9ebb028fe17c6f1de00825837acec6f8169dbf67
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6172463
Auto-Submit: Olivier Flückiger <olivf@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/branch-heads/13.2@{#60}
Cr-Branched-From: 24068c59cedad9ee976ddc05431f5f497b1ebd71-refs/heads/13.2.152@{#1}
Cr-Branched-From: 6054ba94db0969220be4f94dc1677fc4696bdc4f-refs/heads/main@{#97085}

diff --git a/src/maglev/maglev-interpreter-frame-state.cc b/src/maglev/maglev-interpreter-frame-state.cc
index 562f88cabaf9a32b0197c7762bb1336541b95a29..21561ea57364d9fbcecb118596141ac3af081798 100644
--- a/src/maglev/maglev-interpreter-frame-state.cc
+++ b/src/maglev/maglev-interpreter-frame-state.cc
@@ -1338,6 +1338,23 @@ void MergePointInterpreterFrameState::ReducePhiPredecessorCount(unsigned num) {
   }
 }
 
+bool MergePointInterpreterFrameState::IsUnreachable() const {
+  DCHECK_EQ(predecessors_so_far_, predecessor_count_);
+  if (predecessor_count_ > 1) {
+    return false;
+  }
+  // This should actually only support predecessor_count == 1, but we
+  // currently don't eliminate resumable loop headers (and subsequent code
+  // until the next resume) that end up being unreachable from JumpLoop.
+  if (predecessor_count_ == 0) {
+    DCHECK(is_resumable_loop());
+    return true;
+  }
+  DCHECK_EQ(predecessor_count_, 1);
+  DCHECK_IMPLIES(is_loop(), predecessor_at(0)->control_node()->Is<JumpLoop>());
+  return is_loop();
+}
+
 }  // namespace maglev
 }  // namespace internal
 }  // namespace v8
diff --git a/src/maglev/maglev-interpreter-frame-state.h b/src/maglev/maglev-interpreter-frame-state.h
index 0f84499a4f605013d4a9328497ef9fa1825a53af..f3802780bc49aa10869e1dd725aa769474c7697a 100644
--- a/src/maglev/maglev-interpreter-frame-state.h
+++ b/src/maglev/maglev-interpreter-frame-state.h
@@ -935,6 +935,8 @@ class MergePointInterpreterFrameState {
            predecessors_so_far_ == 0;
   }
 
+  bool IsUnreachable() const;
+
   BasicBlockType basic_block_type() const {
     return kBasicBlockTypeBits::decode(bitfield_);
   }
diff --git a/src/maglev/maglev-regalloc.cc b/src/maglev/maglev-regalloc.cc
index d21bc5128b9b8d70b86bf121a75846f57e0f113b..b11a8684e457f6a1abb6a7b1b24eab7296ae488c 100644
--- a/src/maglev/maglev-regalloc.cc
+++ b/src/maglev/maglev-regalloc.cc
@@ -155,7 +155,7 @@ bool IsLiveAtTarget(ValueNode* node, ControlNode* source, BasicBlock* target) {
   }
 
   // Drop all values on resumable loop headers.
-  if (target->has_state() && target->state()->is_resumable_loop()) return false;
+  if (target->is_loop() && target->state()->is_resumable_loop()) return false;
 
   // TODO(verwaest): This should be true but isn't because we don't yet
   // eliminate dead code.
@@ -407,13 +407,9 @@ void StraightForwardRegisterAllocator::AllocateRegisters() {
       if (block->state()->is_exception_handler()) {
         // Exceptions start from a blank state of register values.
         ClearRegisterValues();
-      } else if (block->state()->is_resumable_loop() &&
-                 block->state()->predecessor_count() <= 1) {
+      } else if (block->state()->IsUnreachable()) {
         // Loops that are only reachable through JumpLoop start from a blank
         // state of register values.
-        // This should actually only support predecessor_count == 1, but we
-        // currently don't eliminate resumable loop headers (and subsequent code
-        // until the next resume) that end up being unreachable from JumpLoop.
         ClearRegisterValues();
       } else {
         InitializeRegisterValues(block->state()->register_state());
