blob: 9649dbda08ca2f2904fc35c0828f5d622ce49397 [file] [log] [blame]
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/constant-folding-reducer.h"
#include "src/compiler/js-graph.h"
#include "src/objects/objects-inl.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
Node* TryGetConstant(JSGraph* jsgraph, Node* node) {
Type type = NodeProperties::GetType(node);
Node* result;
if (type.IsNone()) {
result = nullptr;
} else if (type.Is(Type::Null())) {
result = jsgraph->NullConstant();
} else if (type.Is(Type::Undefined())) {
result = jsgraph->UndefinedConstant();
} else if (type.Is(Type::MinusZero())) {
result = jsgraph->MinusZeroConstant();
} else if (type.Is(Type::NaN())) {
result = jsgraph->NaNConstant();
} else if (type.Is(Type::Hole())) {
result = jsgraph->TheHoleConstant();
} else if (type.IsHeapConstant()) {
result = jsgraph->Constant(type.AsHeapConstant()->Ref());
} else if (type.Is(Type::PlainNumber()) && type.Min() == type.Max()) {
result = jsgraph->Constant(type.Min());
} else {
result = nullptr;
}
DCHECK_EQ(result != nullptr, type.IsSingleton());
DCHECK_IMPLIES(result != nullptr,
type.Equals(NodeProperties::GetType(result)));
return result;
}
bool IsAlreadyBeingFolded(Node* node) {
DCHECK(FLAG_assert_types);
if (node->opcode() == IrOpcode::kFoldConstant) return true;
for (Edge edge : node->use_edges()) {
if (NodeProperties::IsValueEdge(edge) &&
edge.from()->opcode() == IrOpcode::kFoldConstant) {
// Note: {node} may have gained new value uses since the time it was
// "constant-folded", and theses uses should ideally be rewritten as well.
// For simplicity, we ignore them here.
return true;
}
}
return false;
}
} // namespace
ConstantFoldingReducer::ConstantFoldingReducer(Editor* editor, JSGraph* jsgraph,
JSHeapBroker* broker)
: AdvancedReducer(editor), jsgraph_(jsgraph), broker_(broker) {}
ConstantFoldingReducer::~ConstantFoldingReducer() = default;
Reduction ConstantFoldingReducer::Reduce(Node* node) {
DisallowHeapAccess no_heap_access;
if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) &&
node->op()->HasProperty(Operator::kEliminatable) &&
node->opcode() != IrOpcode::kFinishRegion) {
Node* constant = TryGetConstant(jsgraph(), node);
if (constant != nullptr) {
DCHECK(NodeProperties::IsTyped(constant));
if (!FLAG_assert_types) {
DCHECK_EQ(node->op()->ControlOutputCount(), 0);
ReplaceWithValue(node, constant);
return Replace(constant);
} else if (!IsAlreadyBeingFolded(node)) {
// Delay the constant folding (by inserting a FoldConstant operation
// instead) in order to keep type assertions meaningful.
Node* fold_constant = jsgraph()->graph()->NewNode(
jsgraph()->common()->FoldConstant(), node, constant);
DCHECK(NodeProperties::IsTyped(fold_constant));
ReplaceWithValue(node, fold_constant, node, node);
fold_constant->ReplaceInput(0, node);
DCHECK(IsAlreadyBeingFolded(node));
DCHECK(IsAlreadyBeingFolded(fold_constant));
return Changed(node);
}
}
}
return NoChange();
}
} // namespace compiler
} // namespace internal
} // namespace v8