Commit 3f1de995 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[turbofan] Do not unroll loops with function calls

Spending time on unrolling loops that contain function calls will often
not be worth it, as these loops will run for potentially a long time,
mitigating the performance benefit of loop unrolling.

Bug: v8:11298, v8:12047
Change-Id: Idd59cea499e495e90c48f82133a809b22f899d74
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3081614
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#76203}
parent fc6b999e
...@@ -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;
} }
#if V8_ENABLE_WEBASSEMBLY
// static // static
ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader( ZoneUnorderedSet<Node*>* LoopFinder::FindSmallUnnestedLoopFromHeader(
Node* loop_header, Zone* zone, size_t max_size) { 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;
...@@ -580,6 +581,12 @@ ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader( ...@@ -580,6 +581,12 @@ ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader(
loop_header); loop_header);
// All uses are outside the loop, do nothing. // All uses are outside the loop, do nothing.
break; break;
case IrOpcode::kCall:
case IrOpcode::kTailCall:
case IrOpcode::kJSWasmCall:
case IrOpcode::kJSCall:
// Call nodes are considered to have unbounded size, i.e. >max_size.
return nullptr;
default: default:
for (Node* use : node->uses()) { for (Node* use : node->uses()) {
if (visited->count(use) == 0) queue.push_back(use); if (visited->count(use) == 0) queue.push_back(use);
...@@ -614,6 +621,7 @@ ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader( ...@@ -614,6 +621,7 @@ ZoneUnorderedSet<Node*>* LoopFinder::FindUnnestedLoopFromHeader(
return visited; return visited;
} }
#endif // V8_ENABLE_WEBASSEMBLY
bool LoopFinder::HasMarkedExits(LoopTree* loop_tree, bool LoopFinder::HasMarkedExits(LoopTree* loop_tree,
const LoopTree::Loop* loop) { const LoopTree::Loop* loop) {
......
...@@ -179,16 +179,19 @@ class V8_EXPORT_PRIVATE LoopFinder { ...@@ -179,16 +179,19 @@ 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. Will exit early once the #if V8_ENABLE_WEBASSEMBLY
// current loop size exceed {max_size}. This is a very restricted version of // Find all nodes of a loop given headed by {loop_header}. Returns {nullptr}
// BuildLoopTree. // if the loop size in Nodes exceeds {max_size}. In that context, function
// Assumptions: // calls are considered to have unbounded size, so if the loop contains a
// function call, {nullptr} is always returned.
// This is a very restricted version of BuildLoopTree and makes the following
// 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*>* FindSmallUnnestedLoopFromHeader(
Zone* zone, Node* loop_header, Zone* zone, size_t max_size);
size_t max_size); #endif
}; };
// Copies a range of nodes any number of times. // Copies a range of nodes any number of times.
......
...@@ -1672,11 +1672,12 @@ struct WasmLoopUnrollingPhase { ...@@ -1672,11 +1672,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 = LoopFinder::FindUnnestedLoopFromHeader( ZoneUnorderedSet<Node*>* loop =
loop_info.header, temp_zone, LoopFinder::FindSmallUnnestedLoopFromHeader(
// Only discover the loop until its size is the maximum unrolled loop_info.header, temp_zone,
// size for its depth. // Only discover the loop until its size is the maximum unrolled
maximum_unrollable_size(loop_info.nesting_depth)); // size for its depth.
maximum_unrollable_size(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