5 #include "src/compiler/common-operator-reducer.h" 9 #include "src/compiler/common-operator.h" 10 #include "src/compiler/graph.h" 11 #include "src/compiler/machine-operator.h" 12 #include "src/compiler/node.h" 13 #include "src/compiler/node-matchers.h" 14 #include "src/compiler/node-properties.h" 22 Decision DecideCondition(JSHeapBroker* broker, Node*
const cond) {
23 switch (cond->opcode()) {
24 case IrOpcode::kInt32Constant: {
25 Int32Matcher mcond(cond);
26 return mcond.Value() ? Decision::kTrue : Decision::kFalse;
28 case IrOpcode::kHeapConstant: {
29 HeapObjectMatcher mcond(cond);
30 return mcond.Ref(broker).BooleanValue() ? Decision::kTrue
34 return Decision::kUnknown;
40 CommonOperatorReducer::CommonOperatorReducer(Editor* editor, Graph* graph,
42 CommonOperatorBuilder* common,
43 MachineOperatorBuilder* machine,
45 : AdvancedReducer(editor),
50 dead_(graph->NewNode(common->Dead())),
52 NodeProperties::SetType(dead_, Type::None());
55 Reduction CommonOperatorReducer::Reduce(Node* node) {
56 DisallowHeapAccess no_heap_access;
57 switch (node->opcode()) {
58 case IrOpcode::kBranch:
59 return ReduceBranch(node);
60 case IrOpcode::kDeoptimizeIf:
61 case IrOpcode::kDeoptimizeUnless:
62 return ReduceDeoptimizeConditional(node);
63 case IrOpcode::kMerge:
64 return ReduceMerge(node);
65 case IrOpcode::kEffectPhi:
66 return ReduceEffectPhi(node);
68 return ReducePhi(node);
69 case IrOpcode::kReturn:
70 return ReduceReturn(node);
71 case IrOpcode::kSelect:
72 return ReduceSelect(node);
73 case IrOpcode::kSwitch:
74 return ReduceSwitch(node);
82 Reduction CommonOperatorReducer::ReduceBranch(Node* node) {
83 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
84 Node*
const cond = node->InputAt(0);
90 if (cond->opcode() == IrOpcode::kBooleanNot ||
91 (cond->opcode() == IrOpcode::kSelect &&
92 DecideCondition(broker(), cond->InputAt(1)) == Decision::kFalse &&
93 DecideCondition(broker(), cond->InputAt(2)) == Decision::kTrue)) {
94 for (Node*
const use : node->uses()) {
95 switch (use->opcode()) {
96 case IrOpcode::kIfTrue:
97 NodeProperties::ChangeOp(use, common()->IfFalse());
99 case IrOpcode::kIfFalse:
100 NodeProperties::ChangeOp(use, common()->IfTrue());
109 node->ReplaceInput(0, cond->InputAt(0));
111 NodeProperties::ChangeOp(
112 node, common()->Branch(NegateBranchHint(BranchHintOf(node->op()))));
113 return Changed(node);
115 Decision
const decision = DecideCondition(broker(), cond);
116 if (decision == Decision::kUnknown)
return NoChange();
117 Node*
const control = node->InputAt(1);
118 for (Node*
const use : node->uses()) {
119 switch (use->opcode()) {
120 case IrOpcode::kIfTrue:
121 Replace(use, (decision == Decision::kTrue) ? control : dead());
123 case IrOpcode::kIfFalse:
124 Replace(use, (decision == Decision::kFalse) ? control : dead());
130 return Replace(dead());
133 Reduction CommonOperatorReducer::ReduceDeoptimizeConditional(Node* node) {
134 DCHECK(node->opcode() == IrOpcode::kDeoptimizeIf ||
135 node->opcode() == IrOpcode::kDeoptimizeUnless);
136 bool condition_is_true = node->opcode() == IrOpcode::kDeoptimizeUnless;
137 DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
138 Node* condition = NodeProperties::GetValueInput(node, 0);
139 Node* frame_state = NodeProperties::GetValueInput(node, 1);
140 Node* effect = NodeProperties::GetEffectInput(node);
141 Node* control = NodeProperties::GetControlInput(node);
146 if (condition->opcode() == IrOpcode::kBooleanNot) {
147 NodeProperties::ReplaceValueInput(node, condition->InputAt(0), 0);
148 NodeProperties::ChangeOp(
151 ? common()->DeoptimizeIf(p.kind(), p.reason(), p.feedback())
152 : common()->DeoptimizeUnless(p.kind(), p.reason(), p.feedback()));
153 return Changed(node);
155 Decision
const decision = DecideCondition(broker(), condition);
156 if (decision == Decision::kUnknown)
return NoChange();
157 if (condition_is_true == (decision == Decision::kTrue)) {
158 ReplaceWithValue(node, dead(), effect, control);
160 control = graph()->NewNode(
161 common()->Deoptimize(p.kind(), p.reason(), p.feedback()), frame_state,
164 NodeProperties::MergeControlToEnd(graph(), common(), control);
165 Revisit(graph()->end());
167 return Replace(dead());
170 Reduction CommonOperatorReducer::ReduceMerge(Node* node) {
171 DCHECK_EQ(IrOpcode::kMerge, node->opcode());
181 if (node->InputCount() == 2) {
182 for (Node*
const use : node->uses()) {
183 if (IrOpcode::IsPhiOpcode(use->opcode()))
return NoChange();
185 Node* if_true = node->InputAt(0);
186 Node* if_false = node->InputAt(1);
187 if (if_true->opcode() != IrOpcode::kIfTrue) std::swap(if_true, if_false);
188 if (if_true->opcode() == IrOpcode::kIfTrue &&
189 if_false->opcode() == IrOpcode::kIfFalse &&
190 if_true->InputAt(0) == if_false->InputAt(0) && if_true->OwnedBy(node) &&
191 if_false->OwnedBy(node)) {
192 Node*
const branch = if_true->InputAt(0);
193 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
194 DCHECK(branch->OwnedBy(if_true, if_false));
195 Node*
const control = branch->InputAt(1);
197 branch->TrimInputCount(0);
198 NodeProperties::ChangeOp(branch, common()->Dead());
199 return Replace(control);
206 Reduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
207 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
208 Node::Inputs inputs = node->inputs();
209 int const effect_input_count = inputs.count() - 1;
210 DCHECK_LE(1, effect_input_count);
211 Node*
const merge = inputs[effect_input_count];
212 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
213 DCHECK_EQ(effect_input_count, merge->InputCount());
214 Node*
const effect = inputs[0];
215 DCHECK_NE(node, effect);
216 for (
int i = 1;
i < effect_input_count; ++
i) {
217 Node*
const input = inputs[
i];
220 DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
223 if (input != effect)
return NoChange();
227 return Replace(effect);
231 Reduction CommonOperatorReducer::ReducePhi(Node* node) {
232 DCHECK_EQ(IrOpcode::kPhi, node->opcode());
233 Node::Inputs inputs = node->inputs();
234 int const value_input_count = inputs.count() - 1;
235 DCHECK_LE(1, value_input_count);
236 Node*
const merge = inputs[value_input_count];
237 DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
238 DCHECK_EQ(value_input_count, merge->InputCount());
239 if (value_input_count == 2) {
240 Node* vtrue = inputs[0];
241 Node* vfalse = inputs[1];
242 Node::Inputs merge_inputs = merge->inputs();
243 Node* if_true = merge_inputs[0];
244 Node* if_false = merge_inputs[1];
245 if (if_true->opcode() != IrOpcode::kIfTrue) {
246 std::swap(if_true, if_false);
247 std::swap(vtrue, vfalse);
249 if (if_true->opcode() == IrOpcode::kIfTrue &&
250 if_false->opcode() == IrOpcode::kIfFalse &&
251 if_true->InputAt(0) == if_false->InputAt(0)) {
252 Node*
const branch = if_true->InputAt(0);
254 if (branch->opcode() != IrOpcode::kBranch)
return NoChange();
255 Node*
const cond = branch->InputAt(0);
256 if (cond->opcode() == IrOpcode::kFloat32LessThan) {
257 Float32BinopMatcher mcond(cond);
258 if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
259 vfalse->opcode() == IrOpcode::kFloat32Sub) {
260 Float32BinopMatcher mvfalse(vfalse);
261 if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
264 return Change(node, machine()->Float32Abs(), vtrue);
267 }
else if (cond->opcode() == IrOpcode::kFloat64LessThan) {
268 Float64BinopMatcher mcond(cond);
269 if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
270 vfalse->opcode() == IrOpcode::kFloat64Sub) {
271 Float64BinopMatcher mvfalse(vfalse);
272 if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
275 return Change(node, machine()->Float64Abs(), vtrue);
281 Node*
const value = inputs[0];
282 DCHECK_NE(node, value);
283 for (
int i = 1;
i < value_input_count; ++
i) {
284 Node*
const input = inputs[
i];
287 DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
290 if (input != value)
return NoChange();
294 return Replace(value);
297 Reduction CommonOperatorReducer::ReduceReturn(Node* node) {
298 DCHECK_EQ(IrOpcode::kReturn, node->opcode());
299 Node* effect = NodeProperties::GetEffectInput(node);
300 if (effect->opcode() == IrOpcode::kCheckpoint) {
303 effect = NodeProperties::GetEffectInput(effect);
304 NodeProperties::ReplaceEffectInput(node, effect);
305 Reduction
const reduction = ReduceReturn(node);
306 return reduction.Changed() ? reduction : Changed(node);
309 if (ValueInputCountOfReturn(node->op()) != 1) {
312 Node* pop_count = NodeProperties::GetValueInput(node, 0);
313 Node* value = NodeProperties::GetValueInput(node, 1);
314 Node* control = NodeProperties::GetControlInput(node);
315 if (value->opcode() == IrOpcode::kPhi &&
316 NodeProperties::GetControlInput(value) == control &&
317 control->opcode() == IrOpcode::kMerge) {
342 Node::Inputs control_inputs = control->inputs();
343 Node::Inputs value_inputs = value->inputs();
344 DCHECK_NE(0, control_inputs.count());
345 DCHECK_EQ(control_inputs.count(), value_inputs.count() - 1);
346 DCHECK_EQ(IrOpcode::kEnd, graph()->end()->opcode());
347 DCHECK_NE(0, graph()->end()->InputCount());
348 if (control->OwnedBy(node, value)) {
349 for (
int i = 0;
i < control_inputs.count(); ++
i) {
354 Node* ret = graph()->NewNode(node->op(), pop_count, value_inputs[
i],
355 effect, control_inputs[
i]);
356 NodeProperties::MergeControlToEnd(graph(), common(), ret);
359 Replace(control, dead());
360 return Replace(dead());
361 }
else if (effect->opcode() == IrOpcode::kEffectPhi &&
362 NodeProperties::GetControlInput(effect) == control) {
363 Node::Inputs effect_inputs = effect->inputs();
364 DCHECK_EQ(control_inputs.count(), effect_inputs.count() - 1);
365 for (
int i = 0;
i < control_inputs.count(); ++
i) {
370 Node* ret = graph()->NewNode(node->op(), pop_count, value_inputs[
i],
371 effect_inputs[
i], control_inputs[
i]);
372 NodeProperties::MergeControlToEnd(graph(), common(), ret);
375 Replace(control, dead());
376 return Replace(dead());
382 Reduction CommonOperatorReducer::ReduceSelect(Node* node) {
383 DCHECK_EQ(IrOpcode::kSelect, node->opcode());
384 Node*
const cond = node->InputAt(0);
385 Node*
const vtrue = node->InputAt(1);
386 Node*
const vfalse = node->InputAt(2);
387 if (vtrue == vfalse)
return Replace(vtrue);
388 switch (DecideCondition(broker(), cond)) {
389 case Decision::kTrue:
390 return Replace(vtrue);
391 case Decision::kFalse:
392 return Replace(vfalse);
393 case Decision::kUnknown:
396 switch (cond->opcode()) {
397 case IrOpcode::kFloat32LessThan: {
398 Float32BinopMatcher mcond(cond);
399 if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
400 vfalse->opcode() == IrOpcode::kFloat32Sub) {
401 Float32BinopMatcher mvfalse(vfalse);
402 if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
403 return Change(node, machine()->Float32Abs(), vtrue);
408 case IrOpcode::kFloat64LessThan: {
409 Float64BinopMatcher mcond(cond);
410 if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
411 vfalse->opcode() == IrOpcode::kFloat64Sub) {
412 Float64BinopMatcher mvfalse(vfalse);
413 if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
414 return Change(node, machine()->Float64Abs(), vtrue);
425 Reduction CommonOperatorReducer::ReduceSwitch(Node* node) {
426 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
427 Node*
const switched_value = node->InputAt(0);
428 Node*
const control = node->InputAt(1);
434 Int32Matcher mswitched(switched_value);
435 if (mswitched.HasValue()) {
436 bool matched =
false;
438 size_t const projection_count = node->op()->ControlOutputCount();
439 Node** projections = zone_->NewArray<Node*>(projection_count);
440 NodeProperties::CollectControlProjections(node, projections,
442 for (
size_t i = 0;
i < projection_count - 1;
i++) {
443 Node* if_value = projections[
i];
444 DCHECK_EQ(IrOpcode::kIfValue, if_value->opcode());
445 const IfValueParameters& p = IfValueParametersOf(if_value->op());
446 if (p.value() == mswitched.Value()) {
448 Replace(if_value, control);
453 Node* if_default = projections[projection_count - 1];
454 DCHECK_EQ(IrOpcode::kIfDefault, if_default->opcode());
455 Replace(if_default, control);
457 return Replace(dead());
462 Reduction CommonOperatorReducer::Change(Node* node, Operator
const* op,
464 node->ReplaceInput(0, a);
465 node->TrimInputCount(1);
466 NodeProperties::ChangeOp(node, op);
467 return Changed(node);
471 Reduction CommonOperatorReducer::Change(Node* node, Operator
const* op, Node* a,
473 node->ReplaceInput(0, a);
474 node->ReplaceInput(1, b);
475 node->TrimInputCount(2);
476 NodeProperties::ChangeOp(node, op);
477 return Changed(node);