1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/constant-folding-reducer.h"
6
7#include "src/compiler/js-graph.h"
8#include "src/compiler/js-heap-broker.h"
9#include "src/objects/objects-inl.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
15namespace {
16Node* TryGetConstant(JSGraph* jsgraph, Node* node) {
17  Type type = NodeProperties::GetType(node);
18  Node* result;
19  if (type.IsNone()) {
20    result = nullptr;
21  } else if (type.Is(Type::Null())) {
22    result = jsgraph->NullConstant();
23  } else if (type.Is(Type::Undefined())) {
24    result = jsgraph->UndefinedConstant();
25  } else if (type.Is(Type::MinusZero())) {
26    result = jsgraph->MinusZeroConstant();
27  } else if (type.Is(Type::NaN())) {
28    result = jsgraph->NaNConstant();
29  } else if (type.Is(Type::Hole())) {
30    result = jsgraph->TheHoleConstant();
31  } else if (type.IsHeapConstant()) {
32    result = jsgraph->Constant(type.AsHeapConstant()->Ref());
33  } else if (type.Is(Type::PlainNumber()) && type.Min() == type.Max()) {
34    result = jsgraph->Constant(type.Min());
35  } else {
36    result = nullptr;
37  }
38  DCHECK_EQ(result != nullptr, type.IsSingleton());
39  DCHECK_IMPLIES(result != nullptr,
40                 type.Equals(NodeProperties::GetType(result)));
41  return result;
42}
43
44bool IsAlreadyBeingFolded(Node* node) {
45  DCHECK(FLAG_assert_types);
46  if (node->opcode() == IrOpcode::kFoldConstant) return true;
47  for (Edge edge : node->use_edges()) {
48    if (NodeProperties::IsValueEdge(edge) &&
49        edge.from()->opcode() == IrOpcode::kFoldConstant) {
50      // Note: {node} may have gained new value uses since the time it was
51      // "constant-folded", and theses uses should ideally be rewritten as well.
52      // For simplicity, we ignore them here.
53      return true;
54    }
55  }
56  return false;
57}
58}  // namespace
59
60ConstantFoldingReducer::ConstantFoldingReducer(Editor* editor, JSGraph* jsgraph,
61                                               JSHeapBroker* broker)
62    : AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
63
64ConstantFoldingReducer::~ConstantFoldingReducer() = default;
65
66Reduction ConstantFoldingReducer::Reduce(Node* node) {
67  if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
68      node->op()->HasProperty(Operator::kEliminatable) &&
69      node->opcode() != IrOpcode::kFinishRegion) {
70    Node* constant = TryGetConstant(jsgraph(), node);
71    if (constant != nullptr) {
72      DCHECK(NodeProperties::IsTyped(constant));
73      if (!FLAG_assert_types) {
74        DCHECK_EQ(node->op()->ControlOutputCount(), 0);
75        ReplaceWithValue(node, constant);
76        return Replace(constant);
77      } else if (!IsAlreadyBeingFolded(node)) {
78        // Delay the constant folding (by inserting a FoldConstant operation
79        // instead) in order to keep type assertions meaningful.
80        Node* fold_constant = jsgraph()->graph()->NewNode(
81            jsgraph()->common()->FoldConstant(), node, constant);
82        DCHECK(NodeProperties::IsTyped(fold_constant));
83        ReplaceWithValue(node, fold_constant, node, node);
84        fold_constant->ReplaceInput(0, node);
85        DCHECK(IsAlreadyBeingFolded(node));
86        DCHECK(IsAlreadyBeingFolded(fold_constant));
87        return Changed(node);
88      }
89    }
90  }
91  return NoChange();
92}
93
94}  // namespace compiler
95}  // namespace internal
96}  // namespace v8
97