Commit bf43d206 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm][turbofan] Exit loop exploration early if loop is too large

During loop exploration implemented for wasm loop unrolling, we can exit
early if we already know that the loop is too large to unroll.

Bug: v8:11298
Change-Id: I213edef995b58500d07d428f1f1a725132dd44e5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2726501Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73095}
parent 0ebbcb16
...@@ -543,8 +543,9 @@ LoopTree* LoopFinder::BuildLoopTree(Graph* graph, TickCounter* tick_counter, ...@@ -543,8 +543,9 @@ LoopTree* LoopFinder::BuildLoopTree(Graph* graph, TickCounter* tick_counter,
return loop_tree; return loop_tree;
} }
// static
ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader( ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader(
Node* loop_header, Zone* zone) { Node* loop_header, Zone* zone, size_t max_size) {
auto* visited = zone->New<ZoneUnorderedSet<Node*>>(zone); auto* visited = zone->New<ZoneUnorderedSet<Node*>>(zone);
std::vector<Node*> queue; std::vector<Node*> queue;
...@@ -562,6 +563,7 @@ ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader( ...@@ -562,6 +563,7 @@ ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader(
continue; continue;
} }
visited->insert(node); visited->insert(node);
if (visited->size() > max_size) return nullptr;
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kLoopExit: case IrOpcode::kLoopExit:
DCHECK_EQ(node->InputAt(1), loop_header); DCHECK_EQ(node->InputAt(1), loop_header);
......
...@@ -179,14 +179,16 @@ class V8_EXPORT_PRIVATE LoopFinder { ...@@ -179,14 +179,16 @@ class V8_EXPORT_PRIVATE LoopFinder {
static bool HasMarkedExits(LoopTree* loop_tree_, const LoopTree::Loop* loop); static bool HasMarkedExits(LoopTree* loop_tree_, const LoopTree::Loop* loop);
// Find all nodes of a loop given its header node. This is much more // Find all nodes of a loop given its header node. Will exit early once the
// restricted than BuildLoopTree. // current loop size exceed {max_size}. This is a very restricted version of
// BuildLoopTree.
// Assumptions: // Assumptions:
// 1) All loop exits of the loop are marked with LoopExit, LoopExitEffect, // 1) All loop exits of the loop are marked with LoopExit, LoopExitEffect,
// and LoopExitValue nodes. // and LoopExitValue nodes.
// 2) There are no nested loops within this loop. // 2) There are no nested loops within this loop.
static ZoneUnorderedSet<Node*>* FindUnnestedLoopFromHeader(Node* loop_header, static ZoneUnorderedSet<Node*>* FindUnnestedLoopFromHeader(Node* loop_header,
Zone* zone); Zone* zone,
size_t max_size);
}; };
// Copies a range of nodes any number of times. // Copies a range of nodes any number of times.
......
...@@ -14,22 +14,13 @@ namespace v8 { ...@@ -14,22 +14,13 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
// A simple heuristic to decide how many times to unroll a loop. Favors small
// and deeply nested loops.
// TODO(manoskouk): Investigate how this can be improved.
V8_INLINE uint32_t unrolling_count_heuristic(uint32_t size, uint32_t depth) {
static constexpr uint32_t kMaximumUnnestedSize = 50;
static constexpr uint32_t kMaximumUnrollingCount = 7;
return std::min((depth + 1) * kMaximumUnnestedSize / size,
kMaximumUnrollingCount);
}
void UnrollLoop(Node* loop_node, ZoneUnorderedSet<Node*>* loop, uint32_t depth, void UnrollLoop(Node* loop_node, ZoneUnorderedSet<Node*>* loop, uint32_t depth,
Graph* graph, CommonOperatorBuilder* common, Zone* tmp_zone, Graph* graph, CommonOperatorBuilder* common, Zone* tmp_zone,
SourcePositionTable* source_positions, SourcePositionTable* source_positions,
NodeOriginTable* node_origins) { NodeOriginTable* node_origins) {
DCHECK_EQ(loop_node->opcode(), IrOpcode::kLoop); DCHECK_EQ(loop_node->opcode(), IrOpcode::kLoop);
if (loop == nullptr) return;
// No back-jump to the loop header means this is not really a loop. // No back-jump to the loop header means this is not really a loop.
if (loop_node->InputCount() < 2) return; if (loop_node->InputCount() < 2) return;
......
...@@ -17,6 +17,17 @@ namespace v8 { ...@@ -17,6 +17,17 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
static constexpr uint32_t kMaximumUnnestedSize = 50;
static constexpr uint32_t kMaximumUnrollingCount = 7;
// A simple heuristic to decide how many times to unroll a loop. Favors small
// and deeply nested loops.
// TODO(manoskouk): Investigate how this can be improved.
V8_INLINE uint32_t unrolling_count_heuristic(uint32_t size, uint32_t depth) {
return std::min((depth + 1) * kMaximumUnnestedSize / size,
kMaximumUnrollingCount);
}
void UnrollLoop(Node* loop_node, ZoneUnorderedSet<Node*>* loop, uint32_t depth, void UnrollLoop(Node* loop_node, ZoneUnorderedSet<Node*>* loop, uint32_t depth,
Graph* graph, CommonOperatorBuilder* common, Zone* tmp_zone, Graph* graph, CommonOperatorBuilder* common, Zone* tmp_zone,
SourcePositionTable* source_positions, SourcePositionTable* source_positions,
......
...@@ -1784,8 +1784,12 @@ struct WasmLoopUnrollingPhase { ...@@ -1784,8 +1784,12 @@ struct WasmLoopUnrollingPhase {
std::vector<compiler::WasmLoopInfo>* loop_infos) { std::vector<compiler::WasmLoopInfo>* loop_infos) {
for (WasmLoopInfo& loop_info : *loop_infos) { for (WasmLoopInfo& loop_info : *loop_infos) {
if (loop_info.is_innermost) { if (loop_info.is_innermost) {
ZoneUnorderedSet<Node*>* loop = ZoneUnorderedSet<Node*>* loop = LoopFinder::FindUnnestedLoopFromHeader(
LoopFinder::FindUnnestedLoopFromHeader(loop_info.header, temp_zone); loop_info.header, temp_zone,
// Only discover the loop until its size is the maximum unrolled
// size for its depth.
unrolling_count_heuristic(kMaximumUnnestedSize,
loop_info.nesting_depth));
UnrollLoop(loop_info.header, loop, loop_info.nesting_depth, UnrollLoop(loop_info.header, loop, loop_info.nesting_depth,
data->graph(), data->common(), temp_zone, data->graph(), data->common(), temp_zone,
data->source_positions(), data->node_origins()); data->source_positions(), data->node_origins());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment