[turbofan] maintain source positions in loop peeling and polymorphic inlining
I also used the opportunity to clean up the loop peeler a bit by making the class stateful, to avoid passing long argument lists around. Bug: v8:5864 Change-Id: I2e034c6eabd381b01e15cf3e6aa3ce7b14e7b3d8 Reviewed-on: https://chromium-review.googlesource.com/822933 Commit-Queue: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#50067}
This commit is contained in:
parent
1edca59ffa
commit
60247ea2ce
@ -6,6 +6,7 @@
|
||||
|
||||
#include "src/compilation-info.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/compiler-source-position-table.h"
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
#include "src/objects-inl.h"
|
||||
@ -556,6 +557,8 @@ void JSInliningHeuristic::CreateOrReuseDispatch(Node* node, Node* callee,
|
||||
Node** if_successes,
|
||||
Node** calls, Node** inputs,
|
||||
int input_count) {
|
||||
SourcePositionTable::Scope position(
|
||||
source_positions_, source_positions_->GetSourcePosition(node));
|
||||
if (TryReuseDispatch(node, callee, candidate, if_successes, calls, inputs,
|
||||
input_count)) {
|
||||
return;
|
||||
|
@ -22,6 +22,7 @@ class JSInliningHeuristic final : public AdvancedReducer {
|
||||
inliner_(editor, local_zone, info, jsgraph, source_positions),
|
||||
candidates_(local_zone),
|
||||
seen_(local_zone),
|
||||
source_positions_(source_positions),
|
||||
jsgraph_(jsgraph) {}
|
||||
|
||||
const char* reducer_name() const override { return "JSInliningHeuristic"; }
|
||||
@ -85,6 +86,7 @@ class JSInliningHeuristic final : public AdvancedReducer {
|
||||
JSInliner inliner_;
|
||||
Candidates candidates_;
|
||||
ZoneSet<NodeId> seen_;
|
||||
SourcePositionTable* source_positions_;
|
||||
JSGraph* const jsgraph_;
|
||||
int cumulative_count_ = 0;
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/compiler/loop-peeling.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/compiler-source-position-table.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/node-marker.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
@ -107,7 +108,7 @@ struct Peeling {
|
||||
// The vector which contains the mapped nodes.
|
||||
NodeVector* pairs;
|
||||
|
||||
Peeling(Graph* graph, Zone* tmp_zone, size_t max, NodeVector* p)
|
||||
Peeling(Graph* graph, size_t max, NodeVector* p)
|
||||
: node_map(graph, static_cast<uint32_t>(max)), pairs(p) {}
|
||||
|
||||
Node* map(Node* node) {
|
||||
@ -121,10 +122,13 @@ struct Peeling {
|
||||
pairs->push_back(copy);
|
||||
}
|
||||
|
||||
void CopyNodes(Graph* graph, Zone* tmp_zone, Node* dead, NodeRange nodes) {
|
||||
NodeVector inputs(tmp_zone);
|
||||
void CopyNodes(Graph* graph, Zone* tmp_zone_, Node* dead, NodeRange nodes,
|
||||
SourcePositionTable* source_positions) {
|
||||
NodeVector inputs(tmp_zone_);
|
||||
// Copy all the nodes first.
|
||||
for (Node* node : nodes) {
|
||||
SourcePositionTable::Scope position(
|
||||
source_positions, source_positions->GetSourcePosition(node));
|
||||
inputs.clear();
|
||||
for (Node* input : node->inputs()) {
|
||||
inputs.push_back(map(input));
|
||||
@ -166,13 +170,13 @@ Node* PeeledIteration::map(Node* node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
bool LoopPeeler::CanPeel(LoopTree* loop_tree, LoopTree::Loop* loop) {
|
||||
bool LoopPeeler::CanPeel(LoopTree::Loop* loop) {
|
||||
// Look for returns and if projections that are outside the loop but whose
|
||||
// control input is inside the loop.
|
||||
Node* loop_node = loop_tree->GetLoopControl(loop);
|
||||
for (Node* node : loop_tree->LoopNodes(loop)) {
|
||||
Node* loop_node = loop_tree_->GetLoopControl(loop);
|
||||
for (Node* node : loop_tree_->LoopNodes(loop)) {
|
||||
for (Node* use : node->uses()) {
|
||||
if (!loop_tree->Contains(loop, use)) {
|
||||
if (!loop_tree_->Contains(loop, use)) {
|
||||
bool unmarked_exit;
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kLoopExit:
|
||||
@ -187,7 +191,7 @@ bool LoopPeeler::CanPeel(LoopTree* loop_tree, LoopTree::Loop* loop) {
|
||||
}
|
||||
if (unmarked_exit) {
|
||||
if (FLAG_trace_turbo_loop) {
|
||||
Node* loop_node = loop_tree->GetLoopControl(loop);
|
||||
Node* loop_node = loop_tree_->GetLoopControl(loop);
|
||||
PrintF(
|
||||
"Cannot peel loop %i. Loop exit without explicit mark: Node %i "
|
||||
"(%s) is inside "
|
||||
@ -203,47 +207,45 @@ bool LoopPeeler::CanPeel(LoopTree* loop_tree, LoopTree::Loop* loop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
|
||||
LoopTree* loop_tree, LoopTree::Loop* loop,
|
||||
Zone* tmp_zone) {
|
||||
if (!CanPeel(loop_tree, loop)) return nullptr;
|
||||
PeeledIteration* LoopPeeler::Peel(LoopTree::Loop* loop) {
|
||||
if (!CanPeel(loop)) return nullptr;
|
||||
|
||||
//============================================================================
|
||||
// Construct the peeled iteration.
|
||||
//============================================================================
|
||||
PeeledIterationImpl* iter = new (tmp_zone) PeeledIterationImpl(tmp_zone);
|
||||
PeeledIterationImpl* iter = new (tmp_zone_) PeeledIterationImpl(tmp_zone_);
|
||||
size_t estimated_peeled_size = 5 + (loop->TotalSize()) * 2;
|
||||
Peeling peeling(graph, tmp_zone, estimated_peeled_size, &iter->node_pairs_);
|
||||
Peeling peeling(graph_, estimated_peeled_size, &iter->node_pairs_);
|
||||
|
||||
Node* dead = graph->NewNode(common->Dead());
|
||||
Node* dead = graph_->NewNode(common_->Dead());
|
||||
|
||||
// Map the loop header nodes to their entry values.
|
||||
for (Node* node : loop_tree->HeaderNodes(loop)) {
|
||||
for (Node* node : loop_tree_->HeaderNodes(loop)) {
|
||||
peeling.Insert(node, node->InputAt(kAssumedLoopEntryIndex));
|
||||
}
|
||||
|
||||
// Copy all the nodes of loop body for the peeled iteration.
|
||||
peeling.CopyNodes(graph, tmp_zone, dead, loop_tree->BodyNodes(loop));
|
||||
peeling.CopyNodes(graph_, tmp_zone_, dead, loop_tree_->BodyNodes(loop),
|
||||
source_positions_);
|
||||
|
||||
//============================================================================
|
||||
// Replace the entry to the loop with the output of the peeled iteration.
|
||||
//============================================================================
|
||||
Node* loop_node = loop_tree->GetLoopControl(loop);
|
||||
Node* loop_node = loop_tree_->GetLoopControl(loop);
|
||||
Node* new_entry;
|
||||
int backedges = loop_node->InputCount() - 1;
|
||||
if (backedges > 1) {
|
||||
// Multiple backedges from original loop, therefore multiple output edges
|
||||
// from the peeled iteration.
|
||||
NodeVector inputs(tmp_zone);
|
||||
NodeVector inputs(tmp_zone_);
|
||||
for (int i = 1; i < loop_node->InputCount(); i++) {
|
||||
inputs.push_back(peeling.map(loop_node->InputAt(i)));
|
||||
}
|
||||
Node* merge =
|
||||
graph->NewNode(common->Merge(backedges), backedges, &inputs[0]);
|
||||
graph_->NewNode(common_->Merge(backedges), backedges, &inputs[0]);
|
||||
|
||||
// Merge values from the multiple output edges of the peeled iteration.
|
||||
for (Node* node : loop_tree->HeaderNodes(loop)) {
|
||||
for (Node* node : loop_tree_->HeaderNodes(loop)) {
|
||||
if (node->opcode() == IrOpcode::kLoop) continue; // already done.
|
||||
inputs.clear();
|
||||
for (int i = 0; i < backedges; i++) {
|
||||
@ -252,8 +254,8 @@ PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
|
||||
for (Node* input : inputs) {
|
||||
if (input != inputs[0]) { // Non-redundant phi.
|
||||
inputs.push_back(merge);
|
||||
const Operator* op = common->ResizeMergeOrPhi(node->op(), backedges);
|
||||
Node* phi = graph->NewNode(op, backedges + 1, &inputs[0]);
|
||||
const Operator* op = common_->ResizeMergeOrPhi(node->op(), backedges);
|
||||
Node* phi = graph_->NewNode(op, backedges + 1, &inputs[0]);
|
||||
node->ReplaceInput(0, phi);
|
||||
break;
|
||||
}
|
||||
@ -263,7 +265,7 @@ PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
|
||||
} else {
|
||||
// Only one backedge, simply replace the input to loop with output of
|
||||
// peeling.
|
||||
for (Node* node : loop_tree->HeaderNodes(loop)) {
|
||||
for (Node* node : loop_tree_->HeaderNodes(loop)) {
|
||||
node->ReplaceInput(0, peeling.map(node->InputAt(1)));
|
||||
}
|
||||
new_entry = peeling.map(loop_node->InputAt(1));
|
||||
@ -273,23 +275,23 @@ PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
|
||||
//============================================================================
|
||||
// Change the exit and exit markers to merge/phi/effect-phi.
|
||||
//============================================================================
|
||||
for (Node* exit : loop_tree->ExitNodes(loop)) {
|
||||
for (Node* exit : loop_tree_->ExitNodes(loop)) {
|
||||
switch (exit->opcode()) {
|
||||
case IrOpcode::kLoopExit:
|
||||
// Change the loop exit node to a merge node.
|
||||
exit->ReplaceInput(1, peeling.map(exit->InputAt(0)));
|
||||
NodeProperties::ChangeOp(exit, common->Merge(2));
|
||||
NodeProperties::ChangeOp(exit, common_->Merge(2));
|
||||
break;
|
||||
case IrOpcode::kLoopExitValue:
|
||||
// Change exit marker to phi.
|
||||
exit->InsertInput(graph->zone(), 1, peeling.map(exit->InputAt(0)));
|
||||
exit->InsertInput(graph_->zone(), 1, peeling.map(exit->InputAt(0)));
|
||||
NodeProperties::ChangeOp(
|
||||
exit, common->Phi(MachineRepresentation::kTagged, 2));
|
||||
exit, common_->Phi(MachineRepresentation::kTagged, 2));
|
||||
break;
|
||||
case IrOpcode::kLoopExitEffect:
|
||||
// Change effect exit marker to effect phi.
|
||||
exit->InsertInput(graph->zone(), 1, peeling.map(exit->InputAt(0)));
|
||||
NodeProperties::ChangeOp(exit, common->EffectPhi(2));
|
||||
exit->InsertInput(graph_->zone(), 1, peeling.map(exit->InputAt(0)));
|
||||
NodeProperties::ChangeOp(exit, common_->EffectPhi(2));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -298,15 +300,11 @@ PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
|
||||
return iter;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void PeelInnerLoops(Graph* graph, CommonOperatorBuilder* common,
|
||||
LoopTree* loop_tree, LoopTree::Loop* loop,
|
||||
Zone* temp_zone) {
|
||||
void LoopPeeler::PeelInnerLoops(LoopTree::Loop* loop) {
|
||||
// If the loop has nested loops, peel inside those.
|
||||
if (!loop->children().empty()) {
|
||||
for (LoopTree::Loop* inner_loop : loop->children()) {
|
||||
PeelInnerLoops(graph, common, loop_tree, inner_loop, temp_zone);
|
||||
PeelInnerLoops(inner_loop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -314,15 +312,17 @@ void PeelInnerLoops(Graph* graph, CommonOperatorBuilder* common,
|
||||
if (loop->TotalSize() > LoopPeeler::kMaxPeeledNodes) return;
|
||||
if (FLAG_trace_turbo_loop) {
|
||||
PrintF("Peeling loop with header: ");
|
||||
for (Node* node : loop_tree->HeaderNodes(loop)) {
|
||||
for (Node* node : loop_tree_->HeaderNodes(loop)) {
|
||||
PrintF("%i ", node->id());
|
||||
}
|
||||
PrintF("\n");
|
||||
}
|
||||
|
||||
LoopPeeler::Peel(graph, common, loop_tree, loop, temp_zone);
|
||||
Peel(loop);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void EliminateLoopExit(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kLoopExit, node->opcode());
|
||||
// The exit markers take the loop exit as input. We iterate over uses
|
||||
@ -347,21 +347,18 @@ void EliminateLoopExit(Node* node) {
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void LoopPeeler::PeelInnerLoopsOfTree(Graph* graph,
|
||||
CommonOperatorBuilder* common,
|
||||
LoopTree* loop_tree, Zone* temp_zone) {
|
||||
for (LoopTree::Loop* loop : loop_tree->outer_loops()) {
|
||||
PeelInnerLoops(graph, common, loop_tree, loop, temp_zone);
|
||||
void LoopPeeler::PeelInnerLoopsOfTree() {
|
||||
for (LoopTree::Loop* loop : loop_tree_->outer_loops()) {
|
||||
PeelInnerLoops(loop);
|
||||
}
|
||||
|
||||
EliminateLoopExits(graph, temp_zone);
|
||||
EliminateLoopExits(graph_, tmp_zone_);
|
||||
}
|
||||
|
||||
// static
|
||||
void LoopPeeler::EliminateLoopExits(Graph* graph, Zone* temp_zone) {
|
||||
ZoneQueue<Node*> queue(temp_zone);
|
||||
ZoneVector<bool> visited(graph->NodeCount(), false, temp_zone);
|
||||
void LoopPeeler::EliminateLoopExits(Graph* graph, Zone* tmp_zone) {
|
||||
ZoneQueue<Node*> queue(tmp_zone);
|
||||
ZoneVector<bool> visited(graph->NodeCount(), false, tmp_zone);
|
||||
queue.push(graph->end());
|
||||
while (!queue.empty()) {
|
||||
Node* node = queue.front();
|
||||
|
@ -13,6 +13,8 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class SourcePositionTable;
|
||||
|
||||
// Represents the output of peeling a loop, which is basically the mapping
|
||||
// from the body of the loop to the corresponding nodes in the peeled
|
||||
// iteration.
|
||||
@ -31,15 +33,28 @@ class CommonOperatorBuilder;
|
||||
// Implements loop peeling.
|
||||
class V8_EXPORT_PRIVATE LoopPeeler {
|
||||
public:
|
||||
static bool CanPeel(LoopTree* loop_tree, LoopTree::Loop* loop);
|
||||
static PeeledIteration* Peel(Graph* graph, CommonOperatorBuilder* common,
|
||||
LoopTree* loop_tree, LoopTree::Loop* loop,
|
||||
Zone* tmp_zone);
|
||||
static void PeelInnerLoopsOfTree(Graph* graph, CommonOperatorBuilder* common,
|
||||
LoopTree* loop_tree, Zone* tmp_zone);
|
||||
LoopPeeler(Graph* graph, CommonOperatorBuilder* common, LoopTree* loop_tree,
|
||||
Zone* tmp_zone, SourcePositionTable* source_positions)
|
||||
: graph_(graph),
|
||||
common_(common),
|
||||
loop_tree_(loop_tree),
|
||||
tmp_zone_(tmp_zone),
|
||||
source_positions_(source_positions) {}
|
||||
bool CanPeel(LoopTree::Loop* loop);
|
||||
PeeledIteration* Peel(LoopTree::Loop* loop);
|
||||
void PeelInnerLoopsOfTree();
|
||||
|
||||
static void EliminateLoopExits(Graph* graph, Zone* temp_zone);
|
||||
static void EliminateLoopExits(Graph* graph, Zone* tmp_zone);
|
||||
static const size_t kMaxPeeledNodes = 1000;
|
||||
|
||||
private:
|
||||
Graph* const graph_;
|
||||
CommonOperatorBuilder* const common_;
|
||||
LoopTree* const loop_tree_;
|
||||
Zone* const tmp_zone_;
|
||||
SourcePositionTable* const source_positions_;
|
||||
|
||||
void PeelInnerLoops(LoopTree::Loop* loop);
|
||||
};
|
||||
|
||||
|
||||
|
@ -1268,8 +1268,9 @@ struct LoopPeelingPhase {
|
||||
|
||||
LoopTree* loop_tree =
|
||||
LoopFinder::BuildLoopTree(data->jsgraph()->graph(), temp_zone);
|
||||
LoopPeeler::PeelInnerLoopsOfTree(data->graph(), data->common(), loop_tree,
|
||||
temp_zone);
|
||||
LoopPeeler(data->graph(), data->common(), loop_tree, temp_zone,
|
||||
data->source_positions())
|
||||
.PeelInnerLoopsOfTree();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,8 @@ GraphTest::GraphTest(int num_parameters)
|
||||
: TestWithNativeContext(),
|
||||
TestWithIsolateAndZone(),
|
||||
common_(zone()),
|
||||
graph_(zone()) {
|
||||
graph_(zone()),
|
||||
source_positions_(&graph_) {
|
||||
graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
|
||||
graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start()));
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_UNITTESTS_COMPILER_GRAPH_UNITTEST_H_
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/compiler-source-position-table.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/typer.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
@ -58,10 +59,12 @@ class GraphTest : public virtual TestWithNativeContext,
|
||||
|
||||
CommonOperatorBuilder* common() { return &common_; }
|
||||
Graph* graph() { return &graph_; }
|
||||
SourcePositionTable* source_positions() { return &source_positions_; }
|
||||
|
||||
private:
|
||||
CommonOperatorBuilder common_;
|
||||
Graph graph_;
|
||||
SourcePositionTable source_positions_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -74,14 +74,14 @@ class LoopPeelingTest : public GraphTest {
|
||||
PeeledIteration* PeelOne() {
|
||||
LoopTree* loop_tree = GetLoopTree();
|
||||
LoopTree::Loop* loop = loop_tree->outer_loops()[0];
|
||||
EXPECT_TRUE(LoopPeeler::CanPeel(loop_tree, loop));
|
||||
return Peel(loop_tree, loop);
|
||||
LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions());
|
||||
EXPECT_TRUE(peeler.CanPeel(loop));
|
||||
return Peel(peeler, loop);
|
||||
}
|
||||
|
||||
PeeledIteration* Peel(LoopTree* loop_tree, LoopTree::Loop* loop) {
|
||||
EXPECT_TRUE(LoopPeeler::CanPeel(loop_tree, loop));
|
||||
PeeledIteration* peeled =
|
||||
LoopPeeler::Peel(graph(), common(), loop_tree, loop, zone());
|
||||
PeeledIteration* Peel(LoopPeeler peeler, LoopTree::Loop* loop) {
|
||||
EXPECT_TRUE(peeler.CanPeel(loop));
|
||||
PeeledIteration* peeled = peeler.Peel(loop);
|
||||
if (FLAG_trace_turbo_graph) {
|
||||
OFStream os(stdout);
|
||||
os << AsRPO(*graph());
|
||||
@ -250,7 +250,8 @@ TEST_F(LoopPeelingTest, SimpleNestedLoopWithCounter_peel_inner) {
|
||||
EXPECT_NE(nullptr, loop);
|
||||
EXPECT_EQ(1u, loop->depth());
|
||||
|
||||
PeeledIteration* peeled = Peel(loop_tree, loop);
|
||||
LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions());
|
||||
PeeledIteration* peeled = Peel(peeler, loop);
|
||||
|
||||
ExpectNotPeeled(outer.loop, peeled);
|
||||
ExpectNotPeeled(outer.branch, peeled);
|
||||
@ -289,7 +290,8 @@ TEST_F(LoopPeelingTest, SimpleInnerCounter_peel_inner) {
|
||||
EXPECT_NE(nullptr, loop);
|
||||
EXPECT_EQ(1u, loop->depth());
|
||||
|
||||
PeeledIteration* peeled = Peel(loop_tree, loop);
|
||||
LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions());
|
||||
PeeledIteration* peeled = Peel(peeler, loop);
|
||||
|
||||
ExpectNotPeeled(outer.loop, peeled);
|
||||
ExpectNotPeeled(outer.branch, peeled);
|
||||
@ -517,7 +519,8 @@ TEST_F(LoopPeelingTest, SimpleLoopWithUnmarkedExit) {
|
||||
{
|
||||
LoopTree* loop_tree = GetLoopTree();
|
||||
LoopTree::Loop* loop = loop_tree->outer_loops()[0];
|
||||
EXPECT_FALSE(LoopPeeler::CanPeel(loop_tree, loop));
|
||||
LoopPeeler peeler(graph(), common(), loop_tree, zone(), source_positions());
|
||||
EXPECT_FALSE(peeler.CanPeel(loop));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user