5 #include "src/compiler/branch-elimination.h" 7 #include "src/compiler/js-graph.h" 8 #include "src/compiler/node-properties.h" 9 #include "src/compiler/simplified-operator.h" 15 BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
17 : AdvancedReducer(editor),
19 node_conditions_(js_graph->graph()->NodeCount(), zone),
20 reduced_(js_graph->graph()->NodeCount(), zone),
22 dead_(js_graph->Dead()) {}
24 BranchElimination::~BranchElimination() =
default;
27 Reduction BranchElimination::Reduce(Node* node) {
28 switch (node->opcode()) {
31 case IrOpcode::kDeoptimizeIf:
32 case IrOpcode::kDeoptimizeUnless:
33 return ReduceDeoptimizeConditional(node);
34 case IrOpcode::kMerge:
35 return ReduceMerge(node);
37 return ReduceLoop(node);
38 case IrOpcode::kBranch:
39 return ReduceBranch(node);
40 case IrOpcode::kIfFalse:
41 return ReduceIf(node,
false);
42 case IrOpcode::kIfTrue:
43 return ReduceIf(node,
true);
44 case IrOpcode::kStart:
45 return ReduceStart(node);
47 if (node->op()->ControlOutputCount() > 0) {
48 return ReduceOtherControl(node);
56 Reduction BranchElimination::ReduceBranch(Node* node) {
57 Node* condition = node->InputAt(0);
58 Node* control_input = NodeProperties::GetControlInput(node, 0);
59 ControlPathConditions from_input = node_conditions_.Get(control_input);
63 if (from_input.LookupCondition(condition, &branch, &condition_value)) {
66 if (!branch->IsDead()) {
67 IsSafetyCheck branch_safety = IsSafetyCheckOf(branch->op());
68 IsSafetyCheck combined_safety =
69 CombineSafetyChecks(branch_safety, IsSafetyCheckOf(node->op()));
70 if (branch_safety != combined_safety) {
71 NodeProperties::ChangeOp(
72 branch, common()->MarkAsSafetyCheck(branch->op(), combined_safety));
76 for (Node*
const use : node->uses()) {
77 switch (use->opcode()) {
78 case IrOpcode::kIfTrue:
79 Replace(use, condition_value ? control_input : dead());
81 case IrOpcode::kIfFalse:
82 Replace(use, condition_value ? dead() : control_input);
88 return Replace(dead());
90 return TakeConditionsFromFirstControl(node);
93 Reduction BranchElimination::ReduceDeoptimizeConditional(Node* node) {
94 DCHECK(node->opcode() == IrOpcode::kDeoptimizeIf ||
95 node->opcode() == IrOpcode::kDeoptimizeUnless);
96 bool condition_is_true = node->opcode() == IrOpcode::kDeoptimizeUnless;
97 DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
98 Node* condition = NodeProperties::GetValueInput(node, 0);
99 Node* frame_state = NodeProperties::GetValueInput(node, 1);
100 Node* effect = NodeProperties::GetEffectInput(node);
101 Node* control = NodeProperties::GetControlInput(node);
105 if (!reduced_.Get(control)) {
109 ControlPathConditions conditions = node_conditions_.Get(control);
110 bool condition_value;
112 if (conditions.LookupCondition(condition, &branch, &condition_value)) {
114 IsSafetyCheck branch_safety = IsSafetyCheckOf(branch->op());
115 IsSafetyCheck combined_safety =
116 CombineSafetyChecks(branch_safety, p.is_safety_check());
117 if (branch_safety != combined_safety) {
118 NodeProperties::ChangeOp(
119 branch, common()->MarkAsSafetyCheck(branch->op(), combined_safety));
123 if (condition_is_true == condition_value) {
126 ReplaceWithValue(node, dead(), effect, control);
128 control = graph()->NewNode(
129 common()->Deoptimize(p.kind(), p.reason(), p.feedback()), frame_state,
132 NodeProperties::MergeControlToEnd(graph(), common(), control);
133 Revisit(graph()->end());
135 return Replace(dead());
137 return UpdateConditions(node, conditions, condition, node, condition_is_true);
140 Reduction BranchElimination::ReduceIf(Node* node,
bool is_true_branch) {
142 Node* branch = NodeProperties::GetControlInput(node, 0);
143 ControlPathConditions from_branch = node_conditions_.Get(branch);
147 if (!reduced_.Get(branch)) {
150 Node* condition = branch->InputAt(0);
151 return UpdateConditions(node, from_branch, condition, branch, is_true_branch);
155 Reduction BranchElimination::ReduceLoop(Node* node) {
159 return TakeConditionsFromFirstControl(node);
163 Reduction BranchElimination::ReduceMerge(Node* node) {
166 Node::Inputs inputs = node->inputs();
167 for (Node* input : inputs) {
168 if (!reduced_.Get(input)) {
173 auto input_it = inputs.begin();
175 DCHECK_GT(inputs.count(), 0);
177 ControlPathConditions conditions = node_conditions_.Get(*input_it);
181 auto input_end = inputs.end();
182 for (; input_it != input_end; ++input_it) {
186 conditions.ResetToCommonAncestor(node_conditions_.Get(*input_it));
188 return UpdateConditions(node, conditions);
192 Reduction BranchElimination::ReduceStart(Node* node) {
193 return UpdateConditions(node, {});
197 Reduction BranchElimination::ReduceOtherControl(Node* node) {
198 DCHECK_EQ(1, node->op()->ControlInputCount());
199 return TakeConditionsFromFirstControl(node);
203 Reduction BranchElimination::TakeConditionsFromFirstControl(Node* node) {
206 Node* input = NodeProperties::GetControlInput(node, 0);
207 if (!reduced_.Get(input))
return NoChange();
208 return UpdateConditions(node, node_conditions_.Get(input));
211 Reduction BranchElimination::UpdateConditions(
212 Node* node, ControlPathConditions conditions) {
215 if (reduced_.Set(node,
true) | node_conditions_.Set(node, conditions)) {
216 return Changed(node);
221 Reduction BranchElimination::UpdateConditions(
222 Node* node, ControlPathConditions prev_conditions, Node* current_condition,
223 Node* current_branch,
bool is_true_branch) {
224 ControlPathConditions original = node_conditions_.Get(node);
228 prev_conditions.AddCondition(zone_, current_condition, current_branch,
229 is_true_branch, original);
230 return UpdateConditions(node, prev_conditions);
233 void BranchElimination::ControlPathConditions::AddCondition(
234 Zone* zone, Node* condition, Node* branch,
bool is_true,
235 ControlPathConditions hint) {
236 DCHECK_EQ(
false, LookupCondition(condition,
nullptr,
nullptr));
237 PushFront({condition, branch, is_true}, zone, hint);
240 bool BranchElimination::ControlPathConditions::LookupCondition(
241 Node* condition, Node** branch,
bool* is_true)
const {
242 for (BranchCondition element : *
this) {
243 if (element.condition == condition) {
244 *is_true = element.is_true;
245 *branch = element.branch;
252 Graph* BranchElimination::graph()
const {
return jsgraph()->graph(); }
254 Isolate* BranchElimination::isolate()
const {
return jsgraph()->isolate(); }
256 CommonOperatorBuilder* BranchElimination::common()
const {
257 return jsgraph()->common();