11cb0ef41Sopenharmony_ci// Copyright 2014 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/common-operator-reducer.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <algorithm>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h"
101cb0ef41Sopenharmony_ci#include "src/compiler/graph.h"
111cb0ef41Sopenharmony_ci#include "src/compiler/js-heap-broker.h"
121cb0ef41Sopenharmony_ci#include "src/compiler/machine-operator.h"
131cb0ef41Sopenharmony_ci#include "src/compiler/node-matchers.h"
141cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h"
151cb0ef41Sopenharmony_ci#include "src/compiler/node.h"
161cb0ef41Sopenharmony_ci#include "src/compiler/opcodes.h"
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cinamespace v8 {
191cb0ef41Sopenharmony_cinamespace internal {
201cb0ef41Sopenharmony_cinamespace compiler {
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ciCommonOperatorReducer::CommonOperatorReducer(Editor* editor, Graph* graph,
231cb0ef41Sopenharmony_ci                                             JSHeapBroker* broker,
241cb0ef41Sopenharmony_ci                                             CommonOperatorBuilder* common,
251cb0ef41Sopenharmony_ci                                             MachineOperatorBuilder* machine,
261cb0ef41Sopenharmony_ci                                             Zone* temp_zone,
271cb0ef41Sopenharmony_ci                                             BranchSemantics branch_semantics)
281cb0ef41Sopenharmony_ci    : AdvancedReducer(editor),
291cb0ef41Sopenharmony_ci      graph_(graph),
301cb0ef41Sopenharmony_ci      broker_(broker),
311cb0ef41Sopenharmony_ci      common_(common),
321cb0ef41Sopenharmony_ci      machine_(machine),
331cb0ef41Sopenharmony_ci      dead_(graph->NewNode(common->Dead())),
341cb0ef41Sopenharmony_ci      zone_(temp_zone),
351cb0ef41Sopenharmony_ci      branch_semantics_(branch_semantics) {
361cb0ef41Sopenharmony_ci  NodeProperties::SetType(dead_, Type::None());
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::Reduce(Node* node) {
401cb0ef41Sopenharmony_ci  DisallowHeapAccessIf no_heap_access(broker() == nullptr);
411cb0ef41Sopenharmony_ci  switch (node->opcode()) {
421cb0ef41Sopenharmony_ci    case IrOpcode::kBranch:
431cb0ef41Sopenharmony_ci      return ReduceBranch(node);
441cb0ef41Sopenharmony_ci    case IrOpcode::kDeoptimizeIf:
451cb0ef41Sopenharmony_ci    case IrOpcode::kDeoptimizeUnless:
461cb0ef41Sopenharmony_ci      return ReduceDeoptimizeConditional(node);
471cb0ef41Sopenharmony_ci    case IrOpcode::kMerge:
481cb0ef41Sopenharmony_ci      return ReduceMerge(node);
491cb0ef41Sopenharmony_ci    case IrOpcode::kEffectPhi:
501cb0ef41Sopenharmony_ci      return ReduceEffectPhi(node);
511cb0ef41Sopenharmony_ci    case IrOpcode::kPhi:
521cb0ef41Sopenharmony_ci      return ReducePhi(node);
531cb0ef41Sopenharmony_ci    case IrOpcode::kReturn:
541cb0ef41Sopenharmony_ci      return ReduceReturn(node);
551cb0ef41Sopenharmony_ci    case IrOpcode::kSelect:
561cb0ef41Sopenharmony_ci      return ReduceSelect(node);
571cb0ef41Sopenharmony_ci    case IrOpcode::kSwitch:
581cb0ef41Sopenharmony_ci      return ReduceSwitch(node);
591cb0ef41Sopenharmony_ci    case IrOpcode::kStaticAssert:
601cb0ef41Sopenharmony_ci      return ReduceStaticAssert(node);
611cb0ef41Sopenharmony_ci    case IrOpcode::kTrapIf:
621cb0ef41Sopenharmony_ci    case IrOpcode::kTrapUnless:
631cb0ef41Sopenharmony_ci      return ReduceTrapConditional(node);
641cb0ef41Sopenharmony_ci    default:
651cb0ef41Sopenharmony_ci      break;
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci  return NoChange();
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ciDecision CommonOperatorReducer::DecideCondition(Node* const cond) {
711cb0ef41Sopenharmony_ci  Node* unwrapped = SkipValueIdentities(cond);
721cb0ef41Sopenharmony_ci  switch (unwrapped->opcode()) {
731cb0ef41Sopenharmony_ci    case IrOpcode::kInt32Constant: {
741cb0ef41Sopenharmony_ci      DCHECK_EQ(branch_semantics_, BranchSemantics::kMachine);
751cb0ef41Sopenharmony_ci      Int32Matcher m(unwrapped);
761cb0ef41Sopenharmony_ci      return m.ResolvedValue() ? Decision::kTrue : Decision::kFalse;
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci    case IrOpcode::kHeapConstant: {
791cb0ef41Sopenharmony_ci      if (branch_semantics_ == BranchSemantics::kMachine) {
801cb0ef41Sopenharmony_ci        return Decision::kTrue;
811cb0ef41Sopenharmony_ci      }
821cb0ef41Sopenharmony_ci      HeapObjectMatcher m(unwrapped);
831cb0ef41Sopenharmony_ci      base::Optional<bool> maybe_result = m.Ref(broker_).TryGetBooleanValue();
841cb0ef41Sopenharmony_ci      if (!maybe_result.has_value()) return Decision::kUnknown;
851cb0ef41Sopenharmony_ci      return *maybe_result ? Decision::kTrue : Decision::kFalse;
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci    default:
881cb0ef41Sopenharmony_ci      return Decision::kUnknown;
891cb0ef41Sopenharmony_ci  }
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceBranch(Node* node) {
931cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kBranch, node->opcode());
941cb0ef41Sopenharmony_ci  Node* const cond = node->InputAt(0);
951cb0ef41Sopenharmony_ci  // Swap IfTrue/IfFalse on {branch} if {cond} is a BooleanNot and use the input
961cb0ef41Sopenharmony_ci  // to BooleanNot as new condition for {branch}. Note we assume that {cond} was
971cb0ef41Sopenharmony_ci  // already properly optimized before we get here (as guaranteed by the graph
981cb0ef41Sopenharmony_ci  // reduction logic). The same applies if {cond} is a Select acting as boolean
991cb0ef41Sopenharmony_ci  // not (i.e. true being returned in the false case and vice versa).
1001cb0ef41Sopenharmony_ci  if (cond->opcode() == IrOpcode::kBooleanNot ||
1011cb0ef41Sopenharmony_ci      (cond->opcode() == IrOpcode::kSelect &&
1021cb0ef41Sopenharmony_ci       DecideCondition(cond->InputAt(1)) == Decision::kFalse &&
1031cb0ef41Sopenharmony_ci       DecideCondition(cond->InputAt(2)) == Decision::kTrue)) {
1041cb0ef41Sopenharmony_ci    for (Node* const use : node->uses()) {
1051cb0ef41Sopenharmony_ci      switch (use->opcode()) {
1061cb0ef41Sopenharmony_ci        case IrOpcode::kIfTrue:
1071cb0ef41Sopenharmony_ci          NodeProperties::ChangeOp(use, common()->IfFalse());
1081cb0ef41Sopenharmony_ci          break;
1091cb0ef41Sopenharmony_ci        case IrOpcode::kIfFalse:
1101cb0ef41Sopenharmony_ci          NodeProperties::ChangeOp(use, common()->IfTrue());
1111cb0ef41Sopenharmony_ci          break;
1121cb0ef41Sopenharmony_ci        default:
1131cb0ef41Sopenharmony_ci          UNREACHABLE();
1141cb0ef41Sopenharmony_ci      }
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci    // Update the condition of {branch}. No need to mark the uses for revisit,
1171cb0ef41Sopenharmony_ci    // since we tell the graph reducer that the {branch} was changed and the
1181cb0ef41Sopenharmony_ci    // graph reduction logic will ensure that the uses are revisited properly.
1191cb0ef41Sopenharmony_ci    node->ReplaceInput(0, cond->InputAt(0));
1201cb0ef41Sopenharmony_ci    // Negate the hint for {branch}.
1211cb0ef41Sopenharmony_ci    NodeProperties::ChangeOp(
1221cb0ef41Sopenharmony_ci        node, common()->Branch(NegateBranchHint(BranchHintOf(node->op()))));
1231cb0ef41Sopenharmony_ci    return Changed(node);
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci  Decision const decision = DecideCondition(cond);
1261cb0ef41Sopenharmony_ci  if (decision == Decision::kUnknown) return NoChange();
1271cb0ef41Sopenharmony_ci  Node* const control = node->InputAt(1);
1281cb0ef41Sopenharmony_ci  for (Node* const use : node->uses()) {
1291cb0ef41Sopenharmony_ci    switch (use->opcode()) {
1301cb0ef41Sopenharmony_ci      case IrOpcode::kIfTrue:
1311cb0ef41Sopenharmony_ci        Replace(use, (decision == Decision::kTrue) ? control : dead());
1321cb0ef41Sopenharmony_ci        break;
1331cb0ef41Sopenharmony_ci      case IrOpcode::kIfFalse:
1341cb0ef41Sopenharmony_ci        Replace(use, (decision == Decision::kFalse) ? control : dead());
1351cb0ef41Sopenharmony_ci        break;
1361cb0ef41Sopenharmony_ci      default:
1371cb0ef41Sopenharmony_ci        UNREACHABLE();
1381cb0ef41Sopenharmony_ci    }
1391cb0ef41Sopenharmony_ci  }
1401cb0ef41Sopenharmony_ci  return Replace(dead());
1411cb0ef41Sopenharmony_ci}
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceDeoptimizeConditional(Node* node) {
1441cb0ef41Sopenharmony_ci  DCHECK(node->opcode() == IrOpcode::kDeoptimizeIf ||
1451cb0ef41Sopenharmony_ci         node->opcode() == IrOpcode::kDeoptimizeUnless);
1461cb0ef41Sopenharmony_ci  bool condition_is_true = node->opcode() == IrOpcode::kDeoptimizeUnless;
1471cb0ef41Sopenharmony_ci  DeoptimizeParameters p = DeoptimizeParametersOf(node->op());
1481cb0ef41Sopenharmony_ci  Node* condition = NodeProperties::GetValueInput(node, 0);
1491cb0ef41Sopenharmony_ci  Node* frame_state = NodeProperties::GetValueInput(node, 1);
1501cb0ef41Sopenharmony_ci  Node* effect = NodeProperties::GetEffectInput(node);
1511cb0ef41Sopenharmony_ci  Node* control = NodeProperties::GetControlInput(node);
1521cb0ef41Sopenharmony_ci  // Swap DeoptimizeIf/DeoptimizeUnless on {node} if {cond} is a BooleaNot
1531cb0ef41Sopenharmony_ci  // and use the input to BooleanNot as new condition for {node}.  Note we
1541cb0ef41Sopenharmony_ci  // assume that {cond} was already properly optimized before we get here
1551cb0ef41Sopenharmony_ci  // (as guaranteed by the graph reduction logic).
1561cb0ef41Sopenharmony_ci  if (condition->opcode() == IrOpcode::kBooleanNot) {
1571cb0ef41Sopenharmony_ci    NodeProperties::ReplaceValueInput(node, condition->InputAt(0), 0);
1581cb0ef41Sopenharmony_ci    NodeProperties::ChangeOp(
1591cb0ef41Sopenharmony_ci        node, condition_is_true
1601cb0ef41Sopenharmony_ci                  ? common()->DeoptimizeIf(p.reason(), p.feedback())
1611cb0ef41Sopenharmony_ci                  : common()->DeoptimizeUnless(p.reason(), p.feedback()));
1621cb0ef41Sopenharmony_ci    return Changed(node);
1631cb0ef41Sopenharmony_ci  }
1641cb0ef41Sopenharmony_ci  Decision const decision = DecideCondition(condition);
1651cb0ef41Sopenharmony_ci  if (decision == Decision::kUnknown) return NoChange();
1661cb0ef41Sopenharmony_ci  if (condition_is_true == (decision == Decision::kTrue)) {
1671cb0ef41Sopenharmony_ci    ReplaceWithValue(node, dead(), effect, control);
1681cb0ef41Sopenharmony_ci  } else {
1691cb0ef41Sopenharmony_ci    control = graph()->NewNode(common()->Deoptimize(p.reason(), p.feedback()),
1701cb0ef41Sopenharmony_ci                               frame_state, effect, control);
1711cb0ef41Sopenharmony_ci    // TODO(bmeurer): This should be on the AdvancedReducer somehow.
1721cb0ef41Sopenharmony_ci    NodeProperties::MergeControlToEnd(graph(), common(), control);
1731cb0ef41Sopenharmony_ci    Revisit(graph()->end());
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci  return Replace(dead());
1761cb0ef41Sopenharmony_ci}
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceMerge(Node* node) {
1791cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kMerge, node->opcode());
1801cb0ef41Sopenharmony_ci  //
1811cb0ef41Sopenharmony_ci  // Check if this is a merge that belongs to an unused diamond, which means
1821cb0ef41Sopenharmony_ci  // that:
1831cb0ef41Sopenharmony_ci  //
1841cb0ef41Sopenharmony_ci  //  a) the {Merge} has no {Phi} or {EffectPhi} uses, and
1851cb0ef41Sopenharmony_ci  //  b) the {Merge} has two inputs, one {IfTrue} and one {IfFalse}, which are
1861cb0ef41Sopenharmony_ci  //     both owned by the Merge, and
1871cb0ef41Sopenharmony_ci  //  c) and the {IfTrue} and {IfFalse} nodes point to the same {Branch}.
1881cb0ef41Sopenharmony_ci  //
1891cb0ef41Sopenharmony_ci  if (node->InputCount() == 2) {
1901cb0ef41Sopenharmony_ci    for (Node* const use : node->uses()) {
1911cb0ef41Sopenharmony_ci      if (IrOpcode::IsPhiOpcode(use->opcode())) return NoChange();
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci    Node* if_true = node->InputAt(0);
1941cb0ef41Sopenharmony_ci    Node* if_false = node->InputAt(1);
1951cb0ef41Sopenharmony_ci    if (if_true->opcode() != IrOpcode::kIfTrue) std::swap(if_true, if_false);
1961cb0ef41Sopenharmony_ci    if (if_true->opcode() == IrOpcode::kIfTrue &&
1971cb0ef41Sopenharmony_ci        if_false->opcode() == IrOpcode::kIfFalse &&
1981cb0ef41Sopenharmony_ci        if_true->InputAt(0) == if_false->InputAt(0) && if_true->OwnedBy(node) &&
1991cb0ef41Sopenharmony_ci        if_false->OwnedBy(node)) {
2001cb0ef41Sopenharmony_ci      Node* const branch = if_true->InputAt(0);
2011cb0ef41Sopenharmony_ci      DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
2021cb0ef41Sopenharmony_ci      DCHECK(branch->OwnedBy(if_true, if_false));
2031cb0ef41Sopenharmony_ci      Node* const control = branch->InputAt(1);
2041cb0ef41Sopenharmony_ci      // Mark the {branch} as {Dead}.
2051cb0ef41Sopenharmony_ci      branch->TrimInputCount(0);
2061cb0ef41Sopenharmony_ci      NodeProperties::ChangeOp(branch, common()->Dead());
2071cb0ef41Sopenharmony_ci      return Replace(control);
2081cb0ef41Sopenharmony_ci    }
2091cb0ef41Sopenharmony_ci  }
2101cb0ef41Sopenharmony_ci  return NoChange();
2111cb0ef41Sopenharmony_ci}
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceEffectPhi(Node* node) {
2151cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
2161cb0ef41Sopenharmony_ci  Node::Inputs inputs = node->inputs();
2171cb0ef41Sopenharmony_ci  int const effect_input_count = inputs.count() - 1;
2181cb0ef41Sopenharmony_ci  DCHECK_LE(1, effect_input_count);
2191cb0ef41Sopenharmony_ci  Node* const merge = inputs[effect_input_count];
2201cb0ef41Sopenharmony_ci  DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
2211cb0ef41Sopenharmony_ci  DCHECK_EQ(effect_input_count, merge->InputCount());
2221cb0ef41Sopenharmony_ci  Node* const effect = inputs[0];
2231cb0ef41Sopenharmony_ci  DCHECK_NE(node, effect);
2241cb0ef41Sopenharmony_ci  for (int i = 1; i < effect_input_count; ++i) {
2251cb0ef41Sopenharmony_ci    Node* const input = inputs[i];
2261cb0ef41Sopenharmony_ci    if (input == node) {
2271cb0ef41Sopenharmony_ci      // Ignore redundant inputs.
2281cb0ef41Sopenharmony_ci      DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
2291cb0ef41Sopenharmony_ci      continue;
2301cb0ef41Sopenharmony_ci    }
2311cb0ef41Sopenharmony_ci    if (input != effect) return NoChange();
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci  // We might now be able to further reduce the {merge} node.
2341cb0ef41Sopenharmony_ci  Revisit(merge);
2351cb0ef41Sopenharmony_ci  return Replace(effect);
2361cb0ef41Sopenharmony_ci}
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReducePhi(Node* node) {
2401cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kPhi, node->opcode());
2411cb0ef41Sopenharmony_ci  Node::Inputs inputs = node->inputs();
2421cb0ef41Sopenharmony_ci  int const value_input_count = inputs.count() - 1;
2431cb0ef41Sopenharmony_ci  DCHECK_LE(1, value_input_count);
2441cb0ef41Sopenharmony_ci  Node* const merge = inputs[value_input_count];
2451cb0ef41Sopenharmony_ci  DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
2461cb0ef41Sopenharmony_ci  DCHECK_EQ(value_input_count, merge->InputCount());
2471cb0ef41Sopenharmony_ci  if (value_input_count == 2) {
2481cb0ef41Sopenharmony_ci    Node* vtrue = inputs[0];
2491cb0ef41Sopenharmony_ci    Node* vfalse = inputs[1];
2501cb0ef41Sopenharmony_ci    Node::Inputs merge_inputs = merge->inputs();
2511cb0ef41Sopenharmony_ci    Node* if_true = merge_inputs[0];
2521cb0ef41Sopenharmony_ci    Node* if_false = merge_inputs[1];
2531cb0ef41Sopenharmony_ci    if (if_true->opcode() != IrOpcode::kIfTrue) {
2541cb0ef41Sopenharmony_ci      std::swap(if_true, if_false);
2551cb0ef41Sopenharmony_ci      std::swap(vtrue, vfalse);
2561cb0ef41Sopenharmony_ci    }
2571cb0ef41Sopenharmony_ci    if (if_true->opcode() == IrOpcode::kIfTrue &&
2581cb0ef41Sopenharmony_ci        if_false->opcode() == IrOpcode::kIfFalse &&
2591cb0ef41Sopenharmony_ci        if_true->InputAt(0) == if_false->InputAt(0)) {
2601cb0ef41Sopenharmony_ci      Node* const branch = if_true->InputAt(0);
2611cb0ef41Sopenharmony_ci      // Check that the branch is not dead already.
2621cb0ef41Sopenharmony_ci      if (branch->opcode() != IrOpcode::kBranch) return NoChange();
2631cb0ef41Sopenharmony_ci      Node* const cond = branch->InputAt(0);
2641cb0ef41Sopenharmony_ci      if (cond->opcode() == IrOpcode::kFloat32LessThan) {
2651cb0ef41Sopenharmony_ci        Float32BinopMatcher mcond(cond);
2661cb0ef41Sopenharmony_ci        if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
2671cb0ef41Sopenharmony_ci            vfalse->opcode() == IrOpcode::kFloat32Sub) {
2681cb0ef41Sopenharmony_ci          Float32BinopMatcher mvfalse(vfalse);
2691cb0ef41Sopenharmony_ci          if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
2701cb0ef41Sopenharmony_ci            // We might now be able to further reduce the {merge} node.
2711cb0ef41Sopenharmony_ci            Revisit(merge);
2721cb0ef41Sopenharmony_ci            return Change(node, machine()->Float32Abs(), vtrue);
2731cb0ef41Sopenharmony_ci          }
2741cb0ef41Sopenharmony_ci        }
2751cb0ef41Sopenharmony_ci      } else if (cond->opcode() == IrOpcode::kFloat64LessThan) {
2761cb0ef41Sopenharmony_ci        Float64BinopMatcher mcond(cond);
2771cb0ef41Sopenharmony_ci        if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
2781cb0ef41Sopenharmony_ci            vfalse->opcode() == IrOpcode::kFloat64Sub) {
2791cb0ef41Sopenharmony_ci          Float64BinopMatcher mvfalse(vfalse);
2801cb0ef41Sopenharmony_ci          if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
2811cb0ef41Sopenharmony_ci            // We might now be able to further reduce the {merge} node.
2821cb0ef41Sopenharmony_ci            Revisit(merge);
2831cb0ef41Sopenharmony_ci            return Change(node, machine()->Float64Abs(), vtrue);
2841cb0ef41Sopenharmony_ci          }
2851cb0ef41Sopenharmony_ci        }
2861cb0ef41Sopenharmony_ci      }
2871cb0ef41Sopenharmony_ci    }
2881cb0ef41Sopenharmony_ci  }
2891cb0ef41Sopenharmony_ci  Node* const value = inputs[0];
2901cb0ef41Sopenharmony_ci  DCHECK_NE(node, value);
2911cb0ef41Sopenharmony_ci  for (int i = 1; i < value_input_count; ++i) {
2921cb0ef41Sopenharmony_ci    Node* const input = inputs[i];
2931cb0ef41Sopenharmony_ci    if (input == node) {
2941cb0ef41Sopenharmony_ci      // Ignore redundant inputs.
2951cb0ef41Sopenharmony_ci      DCHECK_EQ(IrOpcode::kLoop, merge->opcode());
2961cb0ef41Sopenharmony_ci      continue;
2971cb0ef41Sopenharmony_ci    }
2981cb0ef41Sopenharmony_ci    if (input != value) return NoChange();
2991cb0ef41Sopenharmony_ci  }
3001cb0ef41Sopenharmony_ci  // We might now be able to further reduce the {merge} node.
3011cb0ef41Sopenharmony_ci  Revisit(merge);
3021cb0ef41Sopenharmony_ci  return Replace(value);
3031cb0ef41Sopenharmony_ci}
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceReturn(Node* node) {
3061cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kReturn, node->opcode());
3071cb0ef41Sopenharmony_ci  Node* effect = NodeProperties::GetEffectInput(node);
3081cb0ef41Sopenharmony_ci  if (effect->opcode() == IrOpcode::kCheckpoint) {
3091cb0ef41Sopenharmony_ci    // Any {Return} node can never be used to insert a deoptimization point,
3101cb0ef41Sopenharmony_ci    // hence checkpoints can be cut out of the effect chain flowing into it.
3111cb0ef41Sopenharmony_ci    effect = NodeProperties::GetEffectInput(effect);
3121cb0ef41Sopenharmony_ci    NodeProperties::ReplaceEffectInput(node, effect);
3131cb0ef41Sopenharmony_ci    return Changed(node).FollowedBy(ReduceReturn(node));
3141cb0ef41Sopenharmony_ci  }
3151cb0ef41Sopenharmony_ci  // TODO(ahaas): Extend the reduction below to multiple return values.
3161cb0ef41Sopenharmony_ci  if (ValueInputCountOfReturn(node->op()) != 1) {
3171cb0ef41Sopenharmony_ci    return NoChange();
3181cb0ef41Sopenharmony_ci  }
3191cb0ef41Sopenharmony_ci  Node* pop_count = NodeProperties::GetValueInput(node, 0);
3201cb0ef41Sopenharmony_ci  Node* value = NodeProperties::GetValueInput(node, 1);
3211cb0ef41Sopenharmony_ci  Node* control = NodeProperties::GetControlInput(node);
3221cb0ef41Sopenharmony_ci  if (value->opcode() == IrOpcode::kPhi &&
3231cb0ef41Sopenharmony_ci      NodeProperties::GetControlInput(value) == control &&
3241cb0ef41Sopenharmony_ci      control->opcode() == IrOpcode::kMerge) {
3251cb0ef41Sopenharmony_ci    // This optimization pushes {Return} nodes through merges. It checks that
3261cb0ef41Sopenharmony_ci    // the return value is actually a {Phi} and the return control dependency
3271cb0ef41Sopenharmony_ci    // is the {Merge} to which the {Phi} belongs.
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci    // Value1 ... ValueN Control1 ... ControlN
3301cb0ef41Sopenharmony_ci    //   ^          ^       ^            ^
3311cb0ef41Sopenharmony_ci    //   |          |       |            |
3321cb0ef41Sopenharmony_ci    //   +----+-----+       +------+-----+
3331cb0ef41Sopenharmony_ci    //        |                    |
3341cb0ef41Sopenharmony_ci    //       Phi --------------> Merge
3351cb0ef41Sopenharmony_ci    //        ^                    ^
3361cb0ef41Sopenharmony_ci    //        |                    |
3371cb0ef41Sopenharmony_ci    //        |  +-----------------+
3381cb0ef41Sopenharmony_ci    //        |  |
3391cb0ef41Sopenharmony_ci    //       Return -----> Effect
3401cb0ef41Sopenharmony_ci    //         ^
3411cb0ef41Sopenharmony_ci    //         |
3421cb0ef41Sopenharmony_ci    //        End
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci    // Now the effect input to the {Return} node can be either an {EffectPhi}
3451cb0ef41Sopenharmony_ci    // hanging off the same {Merge}, or the effect chain doesn't depend on the
3461cb0ef41Sopenharmony_ci    // {Phi} or the {Merge}, in which case we know that the effect input must
3471cb0ef41Sopenharmony_ci    // somehow dominate all merged branches.
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci    Node::Inputs control_inputs = control->inputs();
3501cb0ef41Sopenharmony_ci    Node::Inputs value_inputs = value->inputs();
3511cb0ef41Sopenharmony_ci    DCHECK_NE(0, control_inputs.count());
3521cb0ef41Sopenharmony_ci    DCHECK_EQ(control_inputs.count(), value_inputs.count() - 1);
3531cb0ef41Sopenharmony_ci    DCHECK_EQ(IrOpcode::kEnd, graph()->end()->opcode());
3541cb0ef41Sopenharmony_ci    DCHECK_NE(0, graph()->end()->InputCount());
3551cb0ef41Sopenharmony_ci    if (control->OwnedBy(node, value) && value->OwnedBy(node)) {
3561cb0ef41Sopenharmony_ci      for (int i = 0; i < control_inputs.count(); ++i) {
3571cb0ef41Sopenharmony_ci        // Create a new {Return} and connect it to {end}. We don't need to mark
3581cb0ef41Sopenharmony_ci        // {end} as revisit, because we mark {node} as {Dead} below, which was
3591cb0ef41Sopenharmony_ci        // previously connected to {end}, so we know for sure that at some point
3601cb0ef41Sopenharmony_ci        // the reducer logic will visit {end} again.
3611cb0ef41Sopenharmony_ci        Node* ret = graph()->NewNode(node->op(), pop_count, value_inputs[i],
3621cb0ef41Sopenharmony_ci                                     effect, control_inputs[i]);
3631cb0ef41Sopenharmony_ci        NodeProperties::MergeControlToEnd(graph(), common(), ret);
3641cb0ef41Sopenharmony_ci      }
3651cb0ef41Sopenharmony_ci      // Mark the Merge {control} and Return {node} as {dead}.
3661cb0ef41Sopenharmony_ci      Replace(control, dead());
3671cb0ef41Sopenharmony_ci      return Replace(dead());
3681cb0ef41Sopenharmony_ci    } else if (effect->opcode() == IrOpcode::kEffectPhi &&
3691cb0ef41Sopenharmony_ci               NodeProperties::GetControlInput(effect) == control) {
3701cb0ef41Sopenharmony_ci      Node::Inputs effect_inputs = effect->inputs();
3711cb0ef41Sopenharmony_ci      DCHECK_EQ(control_inputs.count(), effect_inputs.count() - 1);
3721cb0ef41Sopenharmony_ci      for (int i = 0; i < control_inputs.count(); ++i) {
3731cb0ef41Sopenharmony_ci        // Create a new {Return} and connect it to {end}. We don't need to mark
3741cb0ef41Sopenharmony_ci        // {end} as revisit, because we mark {node} as {Dead} below, which was
3751cb0ef41Sopenharmony_ci        // previously connected to {end}, so we know for sure that at some point
3761cb0ef41Sopenharmony_ci        // the reducer logic will visit {end} again.
3771cb0ef41Sopenharmony_ci        Node* ret = graph()->NewNode(node->op(), pop_count, value_inputs[i],
3781cb0ef41Sopenharmony_ci                                     effect_inputs[i], control_inputs[i]);
3791cb0ef41Sopenharmony_ci        NodeProperties::MergeControlToEnd(graph(), common(), ret);
3801cb0ef41Sopenharmony_ci      }
3811cb0ef41Sopenharmony_ci      // Mark the Merge {control} and Return {node} as {dead}.
3821cb0ef41Sopenharmony_ci      Replace(control, dead());
3831cb0ef41Sopenharmony_ci      return Replace(dead());
3841cb0ef41Sopenharmony_ci    }
3851cb0ef41Sopenharmony_ci  }
3861cb0ef41Sopenharmony_ci  return NoChange();
3871cb0ef41Sopenharmony_ci}
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceSelect(Node* node) {
3901cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kSelect, node->opcode());
3911cb0ef41Sopenharmony_ci  Node* const cond = node->InputAt(0);
3921cb0ef41Sopenharmony_ci  Node* const vtrue = node->InputAt(1);
3931cb0ef41Sopenharmony_ci  Node* const vfalse = node->InputAt(2);
3941cb0ef41Sopenharmony_ci  if (vtrue == vfalse) return Replace(vtrue);
3951cb0ef41Sopenharmony_ci  switch (DecideCondition(cond)) {
3961cb0ef41Sopenharmony_ci    case Decision::kTrue:
3971cb0ef41Sopenharmony_ci      return Replace(vtrue);
3981cb0ef41Sopenharmony_ci    case Decision::kFalse:
3991cb0ef41Sopenharmony_ci      return Replace(vfalse);
4001cb0ef41Sopenharmony_ci    case Decision::kUnknown:
4011cb0ef41Sopenharmony_ci      break;
4021cb0ef41Sopenharmony_ci  }
4031cb0ef41Sopenharmony_ci  switch (cond->opcode()) {
4041cb0ef41Sopenharmony_ci    case IrOpcode::kFloat32LessThan: {
4051cb0ef41Sopenharmony_ci      Float32BinopMatcher mcond(cond);
4061cb0ef41Sopenharmony_ci      if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
4071cb0ef41Sopenharmony_ci          vfalse->opcode() == IrOpcode::kFloat32Sub) {
4081cb0ef41Sopenharmony_ci        Float32BinopMatcher mvfalse(vfalse);
4091cb0ef41Sopenharmony_ci        if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
4101cb0ef41Sopenharmony_ci          return Change(node, machine()->Float32Abs(), vtrue);
4111cb0ef41Sopenharmony_ci        }
4121cb0ef41Sopenharmony_ci      }
4131cb0ef41Sopenharmony_ci      break;
4141cb0ef41Sopenharmony_ci    }
4151cb0ef41Sopenharmony_ci    case IrOpcode::kFloat64LessThan: {
4161cb0ef41Sopenharmony_ci      Float64BinopMatcher mcond(cond);
4171cb0ef41Sopenharmony_ci      if (mcond.left().Is(0.0) && mcond.right().Equals(vtrue) &&
4181cb0ef41Sopenharmony_ci          vfalse->opcode() == IrOpcode::kFloat64Sub) {
4191cb0ef41Sopenharmony_ci        Float64BinopMatcher mvfalse(vfalse);
4201cb0ef41Sopenharmony_ci        if (mvfalse.left().IsZero() && mvfalse.right().Equals(vtrue)) {
4211cb0ef41Sopenharmony_ci          return Change(node, machine()->Float64Abs(), vtrue);
4221cb0ef41Sopenharmony_ci        }
4231cb0ef41Sopenharmony_ci      }
4241cb0ef41Sopenharmony_ci      break;
4251cb0ef41Sopenharmony_ci    }
4261cb0ef41Sopenharmony_ci    default:
4271cb0ef41Sopenharmony_ci      break;
4281cb0ef41Sopenharmony_ci  }
4291cb0ef41Sopenharmony_ci  return NoChange();
4301cb0ef41Sopenharmony_ci}
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceSwitch(Node* node) {
4331cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
4341cb0ef41Sopenharmony_ci  Node* const switched_value = node->InputAt(0);
4351cb0ef41Sopenharmony_ci  Node* const control = node->InputAt(1);
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci  // Attempt to constant match the switched value against the IfValue cases. If
4381cb0ef41Sopenharmony_ci  // no case matches, then use the IfDefault. We don't bother marking
4391cb0ef41Sopenharmony_ci  // non-matching cases as dead code (same for an unused IfDefault), because the
4401cb0ef41Sopenharmony_ci  // Switch itself will be marked as dead code.
4411cb0ef41Sopenharmony_ci  Int32Matcher mswitched(switched_value);
4421cb0ef41Sopenharmony_ci  if (mswitched.HasResolvedValue()) {
4431cb0ef41Sopenharmony_ci    bool matched = false;
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci    size_t const projection_count = node->op()->ControlOutputCount();
4461cb0ef41Sopenharmony_ci    Node** projections = zone_->NewArray<Node*>(projection_count);
4471cb0ef41Sopenharmony_ci    NodeProperties::CollectControlProjections(node, projections,
4481cb0ef41Sopenharmony_ci                                              projection_count);
4491cb0ef41Sopenharmony_ci    for (size_t i = 0; i < projection_count - 1; i++) {
4501cb0ef41Sopenharmony_ci      Node* if_value = projections[i];
4511cb0ef41Sopenharmony_ci      DCHECK_EQ(IrOpcode::kIfValue, if_value->opcode());
4521cb0ef41Sopenharmony_ci      const IfValueParameters& p = IfValueParametersOf(if_value->op());
4531cb0ef41Sopenharmony_ci      if (p.value() == mswitched.ResolvedValue()) {
4541cb0ef41Sopenharmony_ci        matched = true;
4551cb0ef41Sopenharmony_ci        Replace(if_value, control);
4561cb0ef41Sopenharmony_ci        break;
4571cb0ef41Sopenharmony_ci      }
4581cb0ef41Sopenharmony_ci    }
4591cb0ef41Sopenharmony_ci    if (!matched) {
4601cb0ef41Sopenharmony_ci      Node* if_default = projections[projection_count - 1];
4611cb0ef41Sopenharmony_ci      DCHECK_EQ(IrOpcode::kIfDefault, if_default->opcode());
4621cb0ef41Sopenharmony_ci      Replace(if_default, control);
4631cb0ef41Sopenharmony_ci    }
4641cb0ef41Sopenharmony_ci    return Replace(dead());
4651cb0ef41Sopenharmony_ci  }
4661cb0ef41Sopenharmony_ci  return NoChange();
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceStaticAssert(Node* node) {
4701cb0ef41Sopenharmony_ci  DCHECK_EQ(IrOpcode::kStaticAssert, node->opcode());
4711cb0ef41Sopenharmony_ci  Node* const cond = node->InputAt(0);
4721cb0ef41Sopenharmony_ci  Decision decision = DecideCondition(cond);
4731cb0ef41Sopenharmony_ci  if (decision == Decision::kTrue) {
4741cb0ef41Sopenharmony_ci    RelaxEffectsAndControls(node);
4751cb0ef41Sopenharmony_ci    return Changed(node);
4761cb0ef41Sopenharmony_ci  } else {
4771cb0ef41Sopenharmony_ci    return NoChange();
4781cb0ef41Sopenharmony_ci  }
4791cb0ef41Sopenharmony_ci}
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::ReduceTrapConditional(Node* trap) {
4821cb0ef41Sopenharmony_ci  DCHECK(trap->opcode() == IrOpcode::kTrapIf ||
4831cb0ef41Sopenharmony_ci         trap->opcode() == IrOpcode::kTrapUnless);
4841cb0ef41Sopenharmony_ci  bool trapping_condition = trap->opcode() == IrOpcode::kTrapIf;
4851cb0ef41Sopenharmony_ci  Node* const cond = trap->InputAt(0);
4861cb0ef41Sopenharmony_ci  Decision decision = DecideCondition(cond);
4871cb0ef41Sopenharmony_ci
4881cb0ef41Sopenharmony_ci  if (decision == Decision::kUnknown) {
4891cb0ef41Sopenharmony_ci    return NoChange();
4901cb0ef41Sopenharmony_ci  } else if ((decision == Decision::kTrue) == trapping_condition) {
4911cb0ef41Sopenharmony_ci    // This will always trap. Mark its outputs as dead and connect it to
4921cb0ef41Sopenharmony_ci    // graph()->end().
4931cb0ef41Sopenharmony_ci    ReplaceWithValue(trap, dead(), dead(), dead());
4941cb0ef41Sopenharmony_ci    Node* effect = NodeProperties::GetEffectInput(trap);
4951cb0ef41Sopenharmony_ci    Node* control = graph()->NewNode(common()->Throw(), effect, trap);
4961cb0ef41Sopenharmony_ci    NodeProperties::MergeControlToEnd(graph(), common(), control);
4971cb0ef41Sopenharmony_ci    Revisit(graph()->end());
4981cb0ef41Sopenharmony_ci    return Changed(trap);
4991cb0ef41Sopenharmony_ci  } else {
5001cb0ef41Sopenharmony_ci    // This will not trap, remove it.
5011cb0ef41Sopenharmony_ci    return Replace(NodeProperties::GetControlInput(trap));
5021cb0ef41Sopenharmony_ci  }
5031cb0ef41Sopenharmony_ci}
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::Change(Node* node, Operator const* op,
5061cb0ef41Sopenharmony_ci                                        Node* a) {
5071cb0ef41Sopenharmony_ci  node->ReplaceInput(0, a);
5081cb0ef41Sopenharmony_ci  node->TrimInputCount(1);
5091cb0ef41Sopenharmony_ci  NodeProperties::ChangeOp(node, op);
5101cb0ef41Sopenharmony_ci  return Changed(node);
5111cb0ef41Sopenharmony_ci}
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci
5141cb0ef41Sopenharmony_ciReduction CommonOperatorReducer::Change(Node* node, Operator const* op, Node* a,
5151cb0ef41Sopenharmony_ci                                        Node* b) {
5161cb0ef41Sopenharmony_ci  node->ReplaceInput(0, a);
5171cb0ef41Sopenharmony_ci  node->ReplaceInput(1, b);
5181cb0ef41Sopenharmony_ci  node->TrimInputCount(2);
5191cb0ef41Sopenharmony_ci  NodeProperties::ChangeOp(node, op);
5201cb0ef41Sopenharmony_ci  return Changed(node);
5211cb0ef41Sopenharmony_ci}
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci}  // namespace compiler
5241cb0ef41Sopenharmony_ci}  // namespace internal
5251cb0ef41Sopenharmony_ci}  // namespace v8
526