blob: 50f29d968bfdf6f5ea6040e81d0540228a94b42d [file] [log] [blame]
// Copyright 2015 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/graph-assembler.h"
#include "src/codegen/code-factory.h"
#include "src/compiler/linkage.h"
namespace v8 {
namespace internal {
namespace compiler {
GraphAssembler::GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control,
Zone* zone)
: temp_zone_(zone),
jsgraph_(jsgraph),
current_effect_(effect),
current_control_(control) {}
Node* GraphAssembler::IntPtrConstant(intptr_t value) {
return jsgraph()->IntPtrConstant(value);
}
Node* GraphAssembler::Int32Constant(int32_t value) {
return jsgraph()->Int32Constant(value);
}
Node* GraphAssembler::Int64Constant(int64_t value) {
return jsgraph()->Int64Constant(value);
}
Node* GraphAssembler::UniqueIntPtrConstant(intptr_t value) {
return graph()->NewNode(
machine()->Is64() ? common()->Int64Constant(value)
: common()->Int32Constant(static_cast<int32_t>(value)));
}
Node* GraphAssembler::SmiConstant(int32_t value) {
return jsgraph()->SmiConstant(value);
}
Node* GraphAssembler::Uint32Constant(int32_t value) {
return jsgraph()->Uint32Constant(value);
}
Node* GraphAssembler::Float64Constant(double value) {
return jsgraph()->Float64Constant(value);
}
Node* GraphAssembler::HeapConstant(Handle<HeapObject> object) {
return jsgraph()->HeapConstant(object);
}
Node* GraphAssembler::NumberConstant(double value) {
return jsgraph()->Constant(value);
}
Node* GraphAssembler::ExternalConstant(ExternalReference ref) {
return jsgraph()->ExternalConstant(ref);
}
Node* GraphAssembler::CEntryStubConstant(int result_size) {
return jsgraph()->CEntryStubConstant(result_size);
}
Node* GraphAssembler::LoadFramePointer() {
return graph()->NewNode(machine()->LoadFramePointer());
}
#define SINGLETON_CONST_DEF(Name) \
Node* GraphAssembler::Name() { return jsgraph()->Name(); }
JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DEF)
#undef SINGLETON_CONST_DEF
#define PURE_UNOP_DEF(Name) \
Node* GraphAssembler::Name(Node* input) { \
return graph()->NewNode(machine()->Name(), input); \
}
PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DEF)
#undef PURE_UNOP_DEF
#define PURE_BINOP_DEF(Name) \
Node* GraphAssembler::Name(Node* left, Node* right) { \
return graph()->NewNode(machine()->Name(), left, right); \
}
PURE_ASSEMBLER_MACH_BINOP_LIST(PURE_BINOP_DEF)
#undef PURE_BINOP_DEF
#define CHECKED_BINOP_DEF(Name) \
Node* GraphAssembler::Name(Node* left, Node* right) { \
return graph()->NewNode(machine()->Name(), left, right, current_control_); \
}
CHECKED_ASSEMBLER_MACH_BINOP_LIST(CHECKED_BINOP_DEF)
#undef CHECKED_BINOP_DEF
Node* GraphAssembler::Float64RoundDown(Node* value) {
CHECK(machine()->Float64RoundDown().IsSupported());
return graph()->NewNode(machine()->Float64RoundDown().op(), value);
}
Node* GraphAssembler::Float64RoundTruncate(Node* value) {
CHECK(machine()->Float64RoundTruncate().IsSupported());
return graph()->NewNode(machine()->Float64RoundTruncate().op(), value);
}
Node* GraphAssembler::Projection(int index, Node* value) {
return graph()->NewNode(common()->Projection(index), value, current_control_);
}
Node* GraphAssembler::Allocate(AllocationType allocation, Node* size) {
return current_control_ = current_effect_ = graph()->NewNode(
simplified()->AllocateRaw(Type::Any(), allocation), size,
current_effect_, current_control_);
}
Node* GraphAssembler::LoadField(FieldAccess const& access, Node* object) {
Node* value = current_effect_ =
graph()->NewNode(simplified()->LoadField(access), object, current_effect_,
current_control_);
return InsertDecompressionIfNeeded(access.machine_type.representation(),
value);
}
Node* GraphAssembler::LoadElement(ElementAccess const& access, Node* object,
Node* index) {
Node* value = current_effect_ =
graph()->NewNode(simplified()->LoadElement(access), object, index,
current_effect_, current_control_);
return InsertDecompressionIfNeeded(access.machine_type.representation(),
value);
}
Node* GraphAssembler::StoreField(FieldAccess const& access, Node* object,
Node* value) {
value =
InsertCompressionIfNeeded(access.machine_type.representation(), value);
return current_effect_ =
graph()->NewNode(simplified()->StoreField(access), object, value,
current_effect_, current_control_);
}
Node* GraphAssembler::StoreElement(ElementAccess const& access, Node* object,
Node* index, Node* value) {
value =
InsertCompressionIfNeeded(access.machine_type.representation(), value);
return current_effect_ =
graph()->NewNode(simplified()->StoreElement(access), object, index,
value, current_effect_, current_control_);
}
Node* GraphAssembler::DebugBreak() {
return current_effect_ = graph()->NewNode(machine()->DebugBreak(),
current_effect_, current_control_);
}
Node* GraphAssembler::Unreachable() {
return current_effect_ = graph()->NewNode(common()->Unreachable(),
current_effect_, current_control_);
}
Node* GraphAssembler::Store(StoreRepresentation rep, Node* object, Node* offset,
Node* value) {
value = InsertCompressionIfNeeded(rep.representation(), value);
return current_effect_ =
graph()->NewNode(machine()->Store(rep), object, offset, value,
current_effect_, current_control_);
}
Node* GraphAssembler::Load(MachineType type, Node* object, Node* offset) {
Node* value = current_effect_ = graph()->NewNode(
machine()->Load(type), object, offset, current_effect_, current_control_);
return InsertDecompressionIfNeeded(type.representation(), value);
}
Node* GraphAssembler::StoreUnaligned(MachineRepresentation rep, Node* object,
Node* offset, Node* value) {
Operator const* const op =
(rep == MachineRepresentation::kWord8 ||
machine()->UnalignedStoreSupported(rep))
? machine()->Store(StoreRepresentation(rep, kNoWriteBarrier))
: machine()->UnalignedStore(rep);
return current_effect_ = graph()->NewNode(op, object, offset, value,
current_effect_, current_control_);
}
Node* GraphAssembler::LoadUnaligned(MachineType type, Node* object,
Node* offset) {
Operator const* const op =
(type.representation() == MachineRepresentation::kWord8 ||
machine()->UnalignedLoadSupported(type.representation()))
? machine()->Load(type)
: machine()->UnalignedLoad(type);
return current_effect_ = graph()->NewNode(op, object, offset, current_effect_,
current_control_);
}
Node* GraphAssembler::Retain(Node* buffer) {
return current_effect_ =
graph()->NewNode(common()->Retain(), buffer, current_effect_);
}
Node* GraphAssembler::UnsafePointerAdd(Node* base, Node* external) {
return current_effect_ =
graph()->NewNode(machine()->UnsafePointerAdd(), base, external,
current_effect_, current_control_);
}
Node* GraphAssembler::ToNumber(Node* value) {
return current_effect_ =
graph()->NewNode(ToNumberOperator(), ToNumberBuiltinConstant(),
value, NoContextConstant(), current_effect_);
}
Node* GraphAssembler::BitcastWordToTagged(Node* value) {
return current_effect_ =
graph()->NewNode(machine()->BitcastWordToTagged(), value,
current_effect_, current_control_);
}
Node* GraphAssembler::BitcastTaggedToWord(Node* value) {
return current_effect_ =
graph()->NewNode(machine()->BitcastTaggedToWord(), value,
current_effect_, current_control_);
}
Node* GraphAssembler::BitcastTaggedSignedToWord(Node* value) {
return current_effect_ =
graph()->NewNode(machine()->BitcastTaggedSignedToWord(), value,
current_effect_, current_control_);
}
Node* GraphAssembler::Word32PoisonOnSpeculation(Node* value) {
return current_effect_ =
graph()->NewNode(machine()->Word32PoisonOnSpeculation(), value,
current_effect_, current_control_);
}
Node* GraphAssembler::DeoptimizeIf(DeoptimizeReason reason,
VectorSlotPair const& feedback,
Node* condition, Node* frame_state,
IsSafetyCheck is_safety_check) {
return current_control_ = current_effect_ = graph()->NewNode(
common()->DeoptimizeIf(DeoptimizeKind::kEager, reason, feedback,
is_safety_check),
condition, frame_state, current_effect_, current_control_);
}
Node* GraphAssembler::DeoptimizeIfNot(DeoptimizeReason reason,
VectorSlotPair const& feedback,
Node* condition, Node* frame_state,
IsSafetyCheck is_safety_check) {
return current_control_ = current_effect_ = graph()->NewNode(
common()->DeoptimizeUnless(DeoptimizeKind::kEager, reason,
feedback, is_safety_check),
condition, frame_state, current_effect_, current_control_);
}
void GraphAssembler::Branch(Node* condition, GraphAssemblerLabel<0u>* if_true,
GraphAssemblerLabel<0u>* if_false,
IsSafetyCheck is_safety_check) {
DCHECK_NOT_NULL(current_control_);
BranchHint hint = BranchHint::kNone;
if (if_true->IsDeferred() != if_false->IsDeferred()) {
hint = if_false->IsDeferred() ? BranchHint::kTrue : BranchHint::kFalse;
}
Node* branch = graph()->NewNode(common()->Branch(hint, is_safety_check),
condition, current_control_);
current_control_ = graph()->NewNode(common()->IfTrue(), branch);
MergeState(if_true);
current_control_ = graph()->NewNode(common()->IfFalse(), branch);
MergeState(if_false);
current_control_ = nullptr;
current_effect_ = nullptr;
}
// Extractors (should be only used when destructing the assembler.
Node* GraphAssembler::ExtractCurrentControl() {
Node* result = current_control_;
current_control_ = nullptr;
return result;
}
Node* GraphAssembler::ExtractCurrentEffect() {
Node* result = current_effect_;
current_effect_ = nullptr;
return result;
}
Node* GraphAssembler::InsertDecompressionIfNeeded(MachineRepresentation rep,
Node* value) {
if (COMPRESS_POINTERS_BOOL) {
switch (rep) {
case MachineRepresentation::kCompressedPointer:
value = graph()->NewNode(
machine()->ChangeCompressedPointerToTaggedPointer(), value);
break;
case MachineRepresentation::kCompressedSigned:
value = graph()->NewNode(
machine()->ChangeCompressedSignedToTaggedSigned(), value);
break;
case MachineRepresentation::kCompressed:
value = graph()->NewNode(machine()->ChangeCompressedToTagged(), value);
break;
default:
break;
}
}
return value;
}
Node* GraphAssembler::InsertCompressionIfNeeded(MachineRepresentation rep,
Node* value) {
if (COMPRESS_POINTERS_BOOL) {
switch (rep) {
case MachineRepresentation::kCompressedPointer:
value = graph()->NewNode(
machine()->ChangeTaggedPointerToCompressedPointer(), value);
break;
case MachineRepresentation::kCompressedSigned:
value = graph()->NewNode(
machine()->ChangeTaggedSignedToCompressedSigned(), value);
break;
case MachineRepresentation::kCompressed:
value = graph()->NewNode(machine()->ChangeTaggedToCompressed(), value);
break;
default:
break;
}
}
return value;
}
void GraphAssembler::Reset(Node* effect, Node* control) {
current_effect_ = effect;
current_control_ = control;
}
Operator const* GraphAssembler::ToNumberOperator() {
if (!to_number_operator_.is_set()) {
Callable callable =
Builtins::CallableFor(jsgraph()->isolate(), Builtins::kToNumber);
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
auto call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(),
callable.descriptor().GetStackParameterCount(), flags,
Operator::kEliminatable);
to_number_operator_.set(common()->Call(call_descriptor));
}
return to_number_operator_.get();
}
} // namespace compiler
} // namespace internal
} // namespace v8