11cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/compiler/loop-peeling.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h" 81cb0ef41Sopenharmony_ci#include "src/compiler/compiler-source-position-table.h" 91cb0ef41Sopenharmony_ci#include "src/compiler/graph.h" 101cb0ef41Sopenharmony_ci#include "src/compiler/loop-analysis.h" 111cb0ef41Sopenharmony_ci#include "src/compiler/node-marker.h" 121cb0ef41Sopenharmony_ci#include "src/compiler/node-origin-table.h" 131cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h" 141cb0ef41Sopenharmony_ci#include "src/compiler/node.h" 151cb0ef41Sopenharmony_ci#include "src/zone/zone.h" 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci// Loop peeling is an optimization that copies the body of a loop, creating 181cb0ef41Sopenharmony_ci// a new copy of the body called the "peeled iteration" that represents the 191cb0ef41Sopenharmony_ci// first iteration. Beginning with a loop as follows: 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci// E 221cb0ef41Sopenharmony_ci// | A 231cb0ef41Sopenharmony_ci// | | (backedges) 241cb0ef41Sopenharmony_ci// | +---------------|---------------------------------+ 251cb0ef41Sopenharmony_ci// | | +-------------|-------------------------------+ | 261cb0ef41Sopenharmony_ci// | | | | +--------+ | | 271cb0ef41Sopenharmony_ci// | | | | | +----+ | | | 281cb0ef41Sopenharmony_ci// | | | | | | | | | | 291cb0ef41Sopenharmony_ci// ( Loop )<-------- ( phiA ) | | | | 301cb0ef41Sopenharmony_ci// | | | | | | 311cb0ef41Sopenharmony_ci// ((======P=================U=======|=|=====)) | | 321cb0ef41Sopenharmony_ci// (( | | )) | | 331cb0ef41Sopenharmony_ci// (( X <---------------------+ | )) | | 341cb0ef41Sopenharmony_ci// (( | )) | | 351cb0ef41Sopenharmony_ci// (( body | )) | | 361cb0ef41Sopenharmony_ci// (( | )) | | 371cb0ef41Sopenharmony_ci// (( Y <-----------------------+ )) | | 381cb0ef41Sopenharmony_ci// (( )) | | 391cb0ef41Sopenharmony_ci// ((===K====L====M==========================)) | | 401cb0ef41Sopenharmony_ci// | | | | | 411cb0ef41Sopenharmony_ci// | | +-----------------------------------------+ | 421cb0ef41Sopenharmony_ci// | +------------------------------------------------+ 431cb0ef41Sopenharmony_ci// | 441cb0ef41Sopenharmony_ci// exit 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci// The body of the loop is duplicated so that all nodes considered "inside" 471cb0ef41Sopenharmony_ci// the loop (e.g. {P, U, X, Y, K, L, M}) have a corresponding copies in the 481cb0ef41Sopenharmony_ci// peeled iteration (e.g. {P', U', X', Y', K', L', M'}). What were considered 491cb0ef41Sopenharmony_ci// backedges of the loop correspond to edges from the peeled iteration to 501cb0ef41Sopenharmony_ci// the main loop body, with multiple backedges requiring a merge. 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci// Similarly, any exits from the loop body need to be merged with "exits" 531cb0ef41Sopenharmony_ci// from the peeled iteration, resulting in the graph as follows: 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci// E 561cb0ef41Sopenharmony_ci// | A 571cb0ef41Sopenharmony_ci// | | 581cb0ef41Sopenharmony_ci// ((=====P'================U'===============)) 591cb0ef41Sopenharmony_ci// (( )) 601cb0ef41Sopenharmony_ci// (( X'<-------------+ )) 611cb0ef41Sopenharmony_ci// (( | )) 621cb0ef41Sopenharmony_ci// (( peeled iteration | )) 631cb0ef41Sopenharmony_ci// (( | )) 641cb0ef41Sopenharmony_ci// (( Y'<-----------+ | )) 651cb0ef41Sopenharmony_ci// (( | | )) 661cb0ef41Sopenharmony_ci// ((===K'===L'====M'======|=|===============)) 671cb0ef41Sopenharmony_ci// | | | | | 681cb0ef41Sopenharmony_ci// +--------+ +-+ +-+ | | 691cb0ef41Sopenharmony_ci// | | | | | 701cb0ef41Sopenharmony_ci// | Merge <------phi 711cb0ef41Sopenharmony_ci// | | | 721cb0ef41Sopenharmony_ci// | +-----+ | 731cb0ef41Sopenharmony_ci// | | | (backedges) 741cb0ef41Sopenharmony_ci// | | +---------------|---------------------------------+ 751cb0ef41Sopenharmony_ci// | | | +-------------|-------------------------------+ | 761cb0ef41Sopenharmony_ci// | | | | | +--------+ | | 771cb0ef41Sopenharmony_ci// | | | | | | +----+ | | | 781cb0ef41Sopenharmony_ci// | | | | | | | | | | | 791cb0ef41Sopenharmony_ci// | ( Loop )<-------- ( phiA ) | | | | 801cb0ef41Sopenharmony_ci// | | | | | | | 811cb0ef41Sopenharmony_ci// | ((======P=================U=======|=|=====)) | | 821cb0ef41Sopenharmony_ci// | (( | | )) | | 831cb0ef41Sopenharmony_ci// | (( X <---------------------+ | )) | | 841cb0ef41Sopenharmony_ci// | (( | )) | | 851cb0ef41Sopenharmony_ci// | (( body | )) | | 861cb0ef41Sopenharmony_ci// | (( | )) | | 871cb0ef41Sopenharmony_ci// | (( Y <-----------------------+ )) | | 881cb0ef41Sopenharmony_ci// | (( )) | | 891cb0ef41Sopenharmony_ci// | ((===K====L====M==========================)) | | 901cb0ef41Sopenharmony_ci// | | | | | | 911cb0ef41Sopenharmony_ci// | | | +-----------------------------------------+ | 921cb0ef41Sopenharmony_ci// | | +------------------------------------------------+ 931cb0ef41Sopenharmony_ci// | | 941cb0ef41Sopenharmony_ci// | | 951cb0ef41Sopenharmony_ci// +----+ +-+ 961cb0ef41Sopenharmony_ci// | | 971cb0ef41Sopenharmony_ci// Merge 981cb0ef41Sopenharmony_ci// | 991cb0ef41Sopenharmony_ci// exit 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci// Note that the boxes ((===)) above are not explicitly represented in the 1021cb0ef41Sopenharmony_ci// graph, but are instead computed by the {LoopFinder}. 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_cinamespace v8 { 1051cb0ef41Sopenharmony_cinamespace internal { 1061cb0ef41Sopenharmony_cinamespace compiler { 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ciclass PeeledIterationImpl : public PeeledIteration { 1091cb0ef41Sopenharmony_ci public: 1101cb0ef41Sopenharmony_ci NodeVector node_pairs_; 1111cb0ef41Sopenharmony_ci explicit PeeledIterationImpl(Zone* zone) : node_pairs_(zone) {} 1121cb0ef41Sopenharmony_ci}; 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ciNode* PeeledIteration::map(Node* node) { 1161cb0ef41Sopenharmony_ci // TODO(turbofan): we use a simple linear search, since the peeled iteration 1171cb0ef41Sopenharmony_ci // is really only used in testing. 1181cb0ef41Sopenharmony_ci PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this); 1191cb0ef41Sopenharmony_ci for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) { 1201cb0ef41Sopenharmony_ci if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1]; 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci return node; 1231cb0ef41Sopenharmony_ci} 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ciPeeledIteration* LoopPeeler::Peel(LoopTree::Loop* loop) { 1261cb0ef41Sopenharmony_ci if (!CanPeel(loop)) return nullptr; 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci //============================================================================ 1291cb0ef41Sopenharmony_ci // Construct the peeled iteration. 1301cb0ef41Sopenharmony_ci //============================================================================ 1311cb0ef41Sopenharmony_ci PeeledIterationImpl* iter = tmp_zone_->New<PeeledIterationImpl>(tmp_zone_); 1321cb0ef41Sopenharmony_ci uint32_t estimated_peeled_size = 5 + loop->TotalSize() * 2; 1331cb0ef41Sopenharmony_ci NodeCopier copier(graph_, estimated_peeled_size, &iter->node_pairs_, 1); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci Node* dead = graph_->NewNode(common_->Dead()); 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci // Map the loop header nodes to their entry values. 1381cb0ef41Sopenharmony_ci for (Node* node : loop_tree_->HeaderNodes(loop)) { 1391cb0ef41Sopenharmony_ci copier.Insert(node, node->InputAt(kAssumedLoopEntryIndex)); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci // Copy all the nodes of loop body for the peeled iteration. 1431cb0ef41Sopenharmony_ci copier.CopyNodes(graph_, tmp_zone_, dead, loop_tree_->BodyNodes(loop), 1441cb0ef41Sopenharmony_ci source_positions_, node_origins_); 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci //============================================================================ 1471cb0ef41Sopenharmony_ci // Replace the entry to the loop with the output of the peeled iteration. 1481cb0ef41Sopenharmony_ci //============================================================================ 1491cb0ef41Sopenharmony_ci Node* loop_node = loop_tree_->GetLoopControl(loop); 1501cb0ef41Sopenharmony_ci Node* new_entry; 1511cb0ef41Sopenharmony_ci int backedges = loop_node->InputCount() - 1; 1521cb0ef41Sopenharmony_ci if (backedges > 1) { 1531cb0ef41Sopenharmony_ci // Multiple backedges from original loop, therefore multiple output edges 1541cb0ef41Sopenharmony_ci // from the peeled iteration. 1551cb0ef41Sopenharmony_ci NodeVector inputs(tmp_zone_); 1561cb0ef41Sopenharmony_ci for (int i = 1; i < loop_node->InputCount(); i++) { 1571cb0ef41Sopenharmony_ci inputs.push_back(copier.map(loop_node->InputAt(i))); 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci Node* merge = 1601cb0ef41Sopenharmony_ci graph_->NewNode(common_->Merge(backedges), backedges, &inputs[0]); 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci // Merge values from the multiple output edges of the peeled iteration. 1631cb0ef41Sopenharmony_ci for (Node* node : loop_tree_->HeaderNodes(loop)) { 1641cb0ef41Sopenharmony_ci if (node->opcode() == IrOpcode::kLoop) continue; // already done. 1651cb0ef41Sopenharmony_ci inputs.clear(); 1661cb0ef41Sopenharmony_ci for (int i = 0; i < backedges; i++) { 1671cb0ef41Sopenharmony_ci inputs.push_back(copier.map(node->InputAt(1 + i))); 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci for (Node* input : inputs) { 1701cb0ef41Sopenharmony_ci if (input != inputs[0]) { // Non-redundant phi. 1711cb0ef41Sopenharmony_ci inputs.push_back(merge); 1721cb0ef41Sopenharmony_ci const Operator* op = common_->ResizeMergeOrPhi(node->op(), backedges); 1731cb0ef41Sopenharmony_ci Node* phi = graph_->NewNode(op, backedges + 1, &inputs[0]); 1741cb0ef41Sopenharmony_ci node->ReplaceInput(0, phi); 1751cb0ef41Sopenharmony_ci break; 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci new_entry = merge; 1801cb0ef41Sopenharmony_ci } else { 1811cb0ef41Sopenharmony_ci // Only one backedge, simply replace the input to loop with output of 1821cb0ef41Sopenharmony_ci // peeling. 1831cb0ef41Sopenharmony_ci for (Node* node : loop_tree_->HeaderNodes(loop)) { 1841cb0ef41Sopenharmony_ci node->ReplaceInput(0, copier.map(node->InputAt(1))); 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci new_entry = copier.map(loop_node->InputAt(1)); 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci loop_node->ReplaceInput(0, new_entry); 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci //============================================================================ 1911cb0ef41Sopenharmony_ci // Change the exit and exit markers to merge/phi/effect-phi. 1921cb0ef41Sopenharmony_ci //============================================================================ 1931cb0ef41Sopenharmony_ci for (Node* exit : loop_tree_->ExitNodes(loop)) { 1941cb0ef41Sopenharmony_ci switch (exit->opcode()) { 1951cb0ef41Sopenharmony_ci case IrOpcode::kLoopExit: 1961cb0ef41Sopenharmony_ci // Change the loop exit node to a merge node. 1971cb0ef41Sopenharmony_ci exit->ReplaceInput(1, copier.map(exit->InputAt(0))); 1981cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(exit, common_->Merge(2)); 1991cb0ef41Sopenharmony_ci break; 2001cb0ef41Sopenharmony_ci case IrOpcode::kLoopExitValue: 2011cb0ef41Sopenharmony_ci // Change exit marker to phi. 2021cb0ef41Sopenharmony_ci exit->InsertInput(graph_->zone(), 1, copier.map(exit->InputAt(0))); 2031cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 2041cb0ef41Sopenharmony_ci exit, common_->Phi(LoopExitValueRepresentationOf(exit->op()), 2)); 2051cb0ef41Sopenharmony_ci break; 2061cb0ef41Sopenharmony_ci case IrOpcode::kLoopExitEffect: 2071cb0ef41Sopenharmony_ci // Change effect exit marker to effect phi. 2081cb0ef41Sopenharmony_ci exit->InsertInput(graph_->zone(), 1, copier.map(exit->InputAt(0))); 2091cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(exit, common_->EffectPhi(2)); 2101cb0ef41Sopenharmony_ci break; 2111cb0ef41Sopenharmony_ci default: 2121cb0ef41Sopenharmony_ci break; 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci } 2151cb0ef41Sopenharmony_ci return iter; 2161cb0ef41Sopenharmony_ci} 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_civoid LoopPeeler::PeelInnerLoops(LoopTree::Loop* loop) { 2191cb0ef41Sopenharmony_ci // If the loop has nested loops, peel inside those. 2201cb0ef41Sopenharmony_ci if (!loop->children().empty()) { 2211cb0ef41Sopenharmony_ci for (LoopTree::Loop* inner_loop : loop->children()) { 2221cb0ef41Sopenharmony_ci PeelInnerLoops(inner_loop); 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci return; 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci // Only peel small-enough loops. 2271cb0ef41Sopenharmony_ci if (loop->TotalSize() > LoopPeeler::kMaxPeeledNodes) return; 2281cb0ef41Sopenharmony_ci if (FLAG_trace_turbo_loop) { 2291cb0ef41Sopenharmony_ci PrintF("Peeling loop with header: "); 2301cb0ef41Sopenharmony_ci for (Node* node : loop_tree_->HeaderNodes(loop)) { 2311cb0ef41Sopenharmony_ci PrintF("%i ", node->id()); 2321cb0ef41Sopenharmony_ci } 2331cb0ef41Sopenharmony_ci PrintF("\n"); 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci Peel(loop); 2371cb0ef41Sopenharmony_ci} 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_civoid LoopPeeler::EliminateLoopExit(Node* node) { 2401cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kLoopExit, node->opcode()); 2411cb0ef41Sopenharmony_ci // The exit markers take the loop exit as input. We iterate over uses 2421cb0ef41Sopenharmony_ci // and remove all the markers from the graph. 2431cb0ef41Sopenharmony_ci for (Edge edge : node->use_edges()) { 2441cb0ef41Sopenharmony_ci if (NodeProperties::IsControlEdge(edge)) { 2451cb0ef41Sopenharmony_ci Node* marker = edge.from(); 2461cb0ef41Sopenharmony_ci if (marker->opcode() == IrOpcode::kLoopExitValue) { 2471cb0ef41Sopenharmony_ci NodeProperties::ReplaceUses(marker, marker->InputAt(0)); 2481cb0ef41Sopenharmony_ci marker->Kill(); 2491cb0ef41Sopenharmony_ci } else if (marker->opcode() == IrOpcode::kLoopExitEffect) { 2501cb0ef41Sopenharmony_ci NodeProperties::ReplaceUses(marker, nullptr, 2511cb0ef41Sopenharmony_ci NodeProperties::GetEffectInput(marker)); 2521cb0ef41Sopenharmony_ci marker->Kill(); 2531cb0ef41Sopenharmony_ci } 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci NodeProperties::ReplaceUses(node, nullptr, nullptr, 2571cb0ef41Sopenharmony_ci NodeProperties::GetControlInput(node, 0)); 2581cb0ef41Sopenharmony_ci node->Kill(); 2591cb0ef41Sopenharmony_ci} 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_civoid LoopPeeler::PeelInnerLoopsOfTree() { 2621cb0ef41Sopenharmony_ci for (LoopTree::Loop* loop : loop_tree_->outer_loops()) { 2631cb0ef41Sopenharmony_ci PeelInnerLoops(loop); 2641cb0ef41Sopenharmony_ci } 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci EliminateLoopExits(graph_, tmp_zone_); 2671cb0ef41Sopenharmony_ci} 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci// static 2701cb0ef41Sopenharmony_civoid LoopPeeler::EliminateLoopExits(Graph* graph, Zone* tmp_zone) { 2711cb0ef41Sopenharmony_ci ZoneQueue<Node*> queue(tmp_zone); 2721cb0ef41Sopenharmony_ci ZoneVector<bool> visited(graph->NodeCount(), false, tmp_zone); 2731cb0ef41Sopenharmony_ci queue.push(graph->end()); 2741cb0ef41Sopenharmony_ci while (!queue.empty()) { 2751cb0ef41Sopenharmony_ci Node* node = queue.front(); 2761cb0ef41Sopenharmony_ci queue.pop(); 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci if (node->opcode() == IrOpcode::kLoopExit) { 2791cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 2801cb0ef41Sopenharmony_ci EliminateLoopExit(node); 2811cb0ef41Sopenharmony_ci if (!visited[control->id()]) { 2821cb0ef41Sopenharmony_ci visited[control->id()] = true; 2831cb0ef41Sopenharmony_ci queue.push(control); 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci } else { 2861cb0ef41Sopenharmony_ci for (int i = 0; i < node->op()->ControlInputCount(); i++) { 2871cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node, i); 2881cb0ef41Sopenharmony_ci if (!visited[control->id()]) { 2891cb0ef41Sopenharmony_ci visited[control->id()] = true; 2901cb0ef41Sopenharmony_ci queue.push(control); 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci } 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci} 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci} // namespace compiler 2981cb0ef41Sopenharmony_ci} // namespace internal 2991cb0ef41Sopenharmony_ci} // namespace v8 300