1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/branch-condition-duplicator.h"
#include "src/compiler/graph.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/opcodes.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
bool IsBranch(Node* node) { return node->opcode() == IrOpcode::kBranch; }
bool CanDuplicate(Node* node) {
// We only allow duplication of comparisons and "cheap" binary operations
// (cheap = not multiplication or division). The idea is that those
// instructions set the ZF flag, and thus do not require a "== 0" to be added
// before the branch. Duplicating other nodes, on the other hand, makes little
// sense, because a "== 0" would need to be inserted in branches anyways.
switch (node->opcode()) {
#define BRANCH_CASE(op) \
case IrOpcode::k##op: \
break;
MACHINE_COMPARE_BINOP_LIST(BRANCH_CASE)
case IrOpcode::kInt32Add:
case IrOpcode::kInt32Sub:
case IrOpcode::kWord32And:
case IrOpcode::kWord32Or:
case IrOpcode::kInt64Add:
case IrOpcode::kInt64Sub:
case IrOpcode::kWord64And:
case IrOpcode::kWord64Or:
case IrOpcode::kWord32Shl:
case IrOpcode::kWord32Shr:
case IrOpcode::kWord64Shl:
case IrOpcode::kWord64Shr:
break;
default:
return false;
}
// We do not duplicate nodes if all their inputs are used a single time,
// because this would keep those inputs alive, thus increasing register
// pressure.
int all_inputs_have_only_a_single_use = true;
for (Node* input : node->inputs()) {
if (input->UseCount() > 1) {
all_inputs_have_only_a_single_use = false;
}
}
if (all_inputs_have_only_a_single_use) {
return false;
}
return true;
}
} // namespace
Node* BranchConditionDuplicator::DuplicateNode(Node* node) {
return graph_->CloneNode(node);
}
void BranchConditionDuplicator::DuplicateConditionIfNeeded(Node* node) {
if (!IsBranch(node)) return;
Node* condNode = node->InputAt(0);
if (condNode->BranchUseCount() > 1 && CanDuplicate(condNode)) {
node->ReplaceInput(0, DuplicateNode(condNode));
}
}
void BranchConditionDuplicator::Enqueue(Node* node) {
if (seen_.Get(node)) return;
seen_.Set(node, true);
to_visit_.push(node);
}
void BranchConditionDuplicator::VisitNode(Node* node) {
DuplicateConditionIfNeeded(node);
for (int i = 0; i < node->op()->ControlInputCount(); i++) {
Enqueue(NodeProperties::GetControlInput(node, i));
}
}
void BranchConditionDuplicator::ProcessGraph() {
Enqueue(graph_->end());
while (!to_visit_.empty()) {
Node* node = to_visit_.front();
to_visit_.pop();
VisitNode(node);
}
}
BranchConditionDuplicator::BranchConditionDuplicator(Zone* zone, Graph* graph)
: graph_(graph), to_visit_(zone), seen_(graph, 2) {}
void BranchConditionDuplicator::Reduce() { ProcessGraph(); }
} // namespace compiler
} // namespace internal
} // namespace v8
|