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