11cb0ef41Sopenharmony_ci// Copyright 2018 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/constant-folding-reducer.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/compiler/js-graph.h"
81cb0ef41Sopenharmony_ci#include "src/compiler/js-heap-broker.h"
91cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cinamespace v8 {
121cb0ef41Sopenharmony_cinamespace internal {
131cb0ef41Sopenharmony_cinamespace compiler {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cinamespace {
161cb0ef41Sopenharmony_ciNode* TryGetConstant(JSGraph* jsgraph, Node* node) {
171cb0ef41Sopenharmony_ci  Type type = NodeProperties::GetType(node);
181cb0ef41Sopenharmony_ci  Node* result;
191cb0ef41Sopenharmony_ci  if (type.IsNone()) {
201cb0ef41Sopenharmony_ci    result = nullptr;
211cb0ef41Sopenharmony_ci  } else if (type.Is(Type::Null())) {
221cb0ef41Sopenharmony_ci    result = jsgraph->NullConstant();
231cb0ef41Sopenharmony_ci  } else if (type.Is(Type::Undefined())) {
241cb0ef41Sopenharmony_ci    result = jsgraph->UndefinedConstant();
251cb0ef41Sopenharmony_ci  } else if (type.Is(Type::MinusZero())) {
261cb0ef41Sopenharmony_ci    result = jsgraph->MinusZeroConstant();
271cb0ef41Sopenharmony_ci  } else if (type.Is(Type::NaN())) {
281cb0ef41Sopenharmony_ci    result = jsgraph->NaNConstant();
291cb0ef41Sopenharmony_ci  } else if (type.Is(Type::Hole())) {
301cb0ef41Sopenharmony_ci    result = jsgraph->TheHoleConstant();
311cb0ef41Sopenharmony_ci  } else if (type.IsHeapConstant()) {
321cb0ef41Sopenharmony_ci    result = jsgraph->Constant(type.AsHeapConstant()->Ref());
331cb0ef41Sopenharmony_ci  } else if (type.Is(Type::PlainNumber()) && type.Min() == type.Max()) {
341cb0ef41Sopenharmony_ci    result = jsgraph->Constant(type.Min());
351cb0ef41Sopenharmony_ci  } else {
361cb0ef41Sopenharmony_ci    result = nullptr;
371cb0ef41Sopenharmony_ci  }
381cb0ef41Sopenharmony_ci  DCHECK_EQ(result != nullptr, type.IsSingleton());
391cb0ef41Sopenharmony_ci  DCHECK_IMPLIES(result != nullptr,
401cb0ef41Sopenharmony_ci                 type.Equals(NodeProperties::GetType(result)));
411cb0ef41Sopenharmony_ci  return result;
421cb0ef41Sopenharmony_ci}
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cibool IsAlreadyBeingFolded(Node* node) {
451cb0ef41Sopenharmony_ci  DCHECK(FLAG_assert_types);
461cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kFoldConstant) return true;
471cb0ef41Sopenharmony_ci  for (Edge edge : node->use_edges()) {
481cb0ef41Sopenharmony_ci    if (NodeProperties::IsValueEdge(edge) &&
491cb0ef41Sopenharmony_ci        edge.from()->opcode() == IrOpcode::kFoldConstant) {
501cb0ef41Sopenharmony_ci      // Note: {node} may have gained new value uses since the time it was
511cb0ef41Sopenharmony_ci      // "constant-folded", and theses uses should ideally be rewritten as well.
521cb0ef41Sopenharmony_ci      // For simplicity, we ignore them here.
531cb0ef41Sopenharmony_ci      return true;
541cb0ef41Sopenharmony_ci    }
551cb0ef41Sopenharmony_ci  }
561cb0ef41Sopenharmony_ci  return false;
571cb0ef41Sopenharmony_ci}
581cb0ef41Sopenharmony_ci}  // namespace
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ciConstantFoldingReducer::ConstantFoldingReducer(Editor* editor, JSGraph* jsgraph,
611cb0ef41Sopenharmony_ci                                               JSHeapBroker* broker)
621cb0ef41Sopenharmony_ci    : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ciConstantFoldingReducer::~ConstantFoldingReducer() = default;
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciReduction ConstantFoldingReducer::Reduce(Node* node) {
671cb0ef41Sopenharmony_ci  if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
681cb0ef41Sopenharmony_ci      node->op()->HasProperty(Operator::kEliminatable) &&
691cb0ef41Sopenharmony_ci      node->opcode() != IrOpcode::kFinishRegion) {
701cb0ef41Sopenharmony_ci    Node* constant = TryGetConstant(jsgraph(), node);
711cb0ef41Sopenharmony_ci    if (constant != nullptr) {
721cb0ef41Sopenharmony_ci      DCHECK(NodeProperties::IsTyped(constant));
731cb0ef41Sopenharmony_ci      if (!FLAG_assert_types) {
741cb0ef41Sopenharmony_ci        DCHECK_EQ(node->op()->ControlOutputCount(), 0);
751cb0ef41Sopenharmony_ci        ReplaceWithValue(node, constant);
761cb0ef41Sopenharmony_ci        return Replace(constant);
771cb0ef41Sopenharmony_ci      } else if (!IsAlreadyBeingFolded(node)) {
781cb0ef41Sopenharmony_ci        // Delay the constant folding (by inserting a FoldConstant operation
791cb0ef41Sopenharmony_ci        // instead) in order to keep type assertions meaningful.
801cb0ef41Sopenharmony_ci        Node* fold_constant = jsgraph()->graph()->NewNode(
811cb0ef41Sopenharmony_ci            jsgraph()->common()->FoldConstant(), node, constant);
821cb0ef41Sopenharmony_ci        DCHECK(NodeProperties::IsTyped(fold_constant));
831cb0ef41Sopenharmony_ci        ReplaceWithValue(node, fold_constant, node, node);
841cb0ef41Sopenharmony_ci        fold_constant->ReplaceInput(0, node);
851cb0ef41Sopenharmony_ci        DCHECK(IsAlreadyBeingFolded(node));
861cb0ef41Sopenharmony_ci        DCHECK(IsAlreadyBeingFolded(fold_constant));
871cb0ef41Sopenharmony_ci        return Changed(node);
881cb0ef41Sopenharmony_ci      }
891cb0ef41Sopenharmony_ci    }
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci  return NoChange();
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci}  // namespace compiler
951cb0ef41Sopenharmony_ci}  // namespace internal
961cb0ef41Sopenharmony_ci}  // namespace v8
97