Commit e96b8564 authored by Victor Gomes's avatar Victor Gomes Committed by V8 LUCI CQ

[maglev] Remove unnecessary CheckedSmiTag and CheckedSmiUntag

We track untagged values through the InterpreterFrameState, that allows
us to re-use already emitted CheckedSmiUntag and elide CheckedSmiTag
whenever the next node wants the untagged value as input.

It uses LoadRegisterTaggedValue, LoadRegisterSmiUntaggedValue and
accumulator variants as helper in the graph builder.

Spilled values can now be untagged, since we currently do not
support stack slot re-use, we use a ZoneVector to keep track of
the stack slot representation.

We tag (lazily) any value that will be passed as input to a Phi node.

Bug: v8:7700

Change-Id: I34cb69c8f1fbeb6a8158a251a4dd2e114e894ea0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3574559Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79939}
parent d609cd98
...@@ -266,6 +266,17 @@ class ThreadedListBase final : public BaseClass { ...@@ -266,6 +266,17 @@ class ThreadedListBase final : public BaseClass {
return true; return true;
} }
void RevalidateTail() {
T* last = *tail_;
if (last != nullptr) {
while (*TLTraits::next(last) != nullptr) {
last = *TLTraits::next(last);
}
tail_ = TLTraits::next(last);
}
SLOW_DCHECK(Verify());
}
private: private:
T* head_; T* head_;
T** tail_; T** tail_;
......
...@@ -53,6 +53,8 @@ class MaglevCodeGenState { ...@@ -53,6 +53,8 @@ class MaglevCodeGenState {
const std::vector<LazyDeoptInfo*>& lazy_deopts() const { const std::vector<LazyDeoptInfo*>& lazy_deopts() const {
return lazy_deopts_; return lazy_deopts_;
} }
inline void DefineSafepointStackSlots(
SafepointTableBuilder::Safepoint& safepoint) const;
compiler::NativeContextRef native_context() const { compiler::NativeContextRef native_context() const {
return broker()->target_native_context(); return broker()->target_native_context();
...@@ -144,6 +146,19 @@ inline MemOperand ToMemOperand(const ValueLocation& location) { ...@@ -144,6 +146,19 @@ inline MemOperand ToMemOperand(const ValueLocation& location) {
return ToMemOperand(location.operand()); return ToMemOperand(location.operand());
} }
inline void MaglevCodeGenState::DefineSafepointStackSlots(
SafepointTableBuilder::Safepoint& safepoint) const {
DCHECK_EQ(compilation_unit()->stack_value_repr().size(), vreg_slots());
int stack_slot = 0;
for (ValueRepresentation repr : compilation_unit()->stack_value_repr()) {
if (repr == ValueRepresentation::kTagged) {
safepoint.DefineTaggedStackSlot(
GetSafepointIndexForStackSlot(stack_slot));
}
stack_slot++;
}
}
} // namespace maglev } // namespace maglev
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -78,13 +78,11 @@ class MaglevCodeGeneratingNodeProcessor { ...@@ -78,13 +78,11 @@ class MaglevCodeGeneratingNodeProcessor {
} }
// We don't emit proper safepoint data yet; instead, define a single // We don't emit proper safepoint data yet; instead, define a single
// safepoint at the end of the code object, with all-tagged stack slots. // safepoint at the end of the code object.
// TODO(jgruber): Real safepoint handling. // TODO(v8:7700): Add better safepoint handling when we support stack reuse.
SafepointTableBuilder::Safepoint safepoint = SafepointTableBuilder::Safepoint safepoint =
safepoint_table_builder()->DefineSafepoint(masm()); safepoint_table_builder()->DefineSafepoint(masm());
for (int i = 0; i < code_gen_state_->vreg_slots(); i++) { code_gen_state_->DefineSafepointStackSlots(safepoint);
safepoint.DefineTaggedStackSlot(GetSafepointIndexForStackSlot(i));
}
} }
void PostProcessGraph(MaglevCompilationUnit*, Graph*) {} void PostProcessGraph(MaglevCompilationUnit*, Graph*) {}
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/compiler/js-heap-broker.h" #include "src/compiler/js-heap-broker.h"
#include "src/maglev/maglev-compilation-info.h" #include "src/maglev/maglev-compilation-info.h"
#include "src/maglev/maglev-graph-labeller.h"
#include "src/objects/js-function-inl.h" #include "src/objects/js-function-inl.h"
namespace v8 { namespace v8 {
...@@ -21,7 +22,8 @@ MaglevCompilationUnit::MaglevCompilationUnit(MaglevCompilationInfo* info, ...@@ -21,7 +22,8 @@ MaglevCompilationUnit::MaglevCompilationUnit(MaglevCompilationInfo* info,
bytecode_analysis_(bytecode_.object(), zone(), BytecodeOffset::None(), bytecode_analysis_(bytecode_.object(), zone(), BytecodeOffset::None(),
true), true),
register_count_(bytecode_.register_count()), register_count_(bytecode_.register_count()),
parameter_count_(bytecode_.parameter_count()) {} parameter_count_(bytecode_.parameter_count()),
stack_value_repr_(info->zone()) {}
compiler::JSHeapBroker* MaglevCompilationUnit::broker() const { compiler::JSHeapBroker* MaglevCompilationUnit::broker() const {
return info_->broker(); return info_->broker();
...@@ -40,6 +42,12 @@ MaglevGraphLabeller* MaglevCompilationUnit::graph_labeller() const { ...@@ -40,6 +42,12 @@ MaglevGraphLabeller* MaglevCompilationUnit::graph_labeller() const {
return info_->graph_labeller(); return info_->graph_labeller();
} }
void MaglevCompilationUnit::RegisterNodeInGraphLabeller(const Node* node) {
if (has_graph_labeller()) {
graph_labeller()->RegisterNode(node);
}
}
} // namespace maglev } // namespace maglev
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -13,8 +13,10 @@ namespace v8 { ...@@ -13,8 +13,10 @@ namespace v8 {
namespace internal { namespace internal {
namespace maglev { namespace maglev {
enum class ValueRepresentation;
class MaglevCompilationInfo; class MaglevCompilationInfo;
class MaglevGraphLabeller; class MaglevGraphLabeller;
class Node;
// Per-unit data, i.e. once per top-level function and once per inlined // Per-unit data, i.e. once per top-level function and once per inlined
// function. // function.
...@@ -45,6 +47,16 @@ class MaglevCompilationUnit : public ZoneObject { ...@@ -45,6 +47,16 @@ class MaglevCompilationUnit : public ZoneObject {
return bytecode_analysis_; return bytecode_analysis_;
} }
void RegisterNodeInGraphLabeller(const Node* node);
const ZoneVector<ValueRepresentation>& stack_value_repr() const {
return stack_value_repr_;
}
void push_stack_value_repr(ValueRepresentation r) {
stack_value_repr_.push_back(r);
}
private: private:
MaglevCompilationInfo* const info_; MaglevCompilationInfo* const info_;
const compiler::SharedFunctionInfoRef shared_function_info_; const compiler::SharedFunctionInfoRef shared_function_info_;
...@@ -53,6 +65,10 @@ class MaglevCompilationUnit : public ZoneObject { ...@@ -53,6 +65,10 @@ class MaglevCompilationUnit : public ZoneObject {
const compiler::BytecodeAnalysis bytecode_analysis_; const compiler::BytecodeAnalysis bytecode_analysis_;
const int register_count_; const int register_count_;
const int parameter_count_; const int parameter_count_;
// TODO(victorgomes): Compress these values, if only tagged/untagged, we could
// use a binary vector? We might also want to deal with safepoints properly.
ZoneVector<ValueRepresentation> stack_value_repr_;
}; };
} // namespace maglev } // namespace maglev
......
...@@ -142,15 +142,15 @@ using GenericNodeForOperation = ...@@ -142,15 +142,15 @@ using GenericNodeForOperation =
template <Operation kOperation> template <Operation kOperation>
void MaglevGraphBuilder::BuildGenericUnaryOperationNode() { void MaglevGraphBuilder::BuildGenericUnaryOperationNode() {
FeedbackSlot slot_index = GetSlotOperand(0); FeedbackSlot slot_index = GetSlotOperand(0);
ValueNode* value = GetAccumulator(); ValueNode* value = GetAccumulatorTaggedValue();
SetAccumulator(AddNewNode<GenericNodeForOperation<kOperation>>( SetAccumulator(AddNewNode<GenericNodeForOperation<kOperation>>(
{value}, compiler::FeedbackSource{feedback(), slot_index})); {value}, compiler::FeedbackSource{feedback(), slot_index}));
} }
template <Operation kOperation> template <Operation kOperation>
void MaglevGraphBuilder::BuildGenericBinaryOperationNode() { void MaglevGraphBuilder::BuildGenericBinaryOperationNode() {
ValueNode* left = LoadRegister(0); ValueNode* left = LoadRegisterTaggedValue(0);
ValueNode* right = GetAccumulator(); ValueNode* right = GetAccumulatorTaggedValue();
FeedbackSlot slot_index = GetSlotOperand(1); FeedbackSlot slot_index = GetSlotOperand(1);
SetAccumulator(AddNewNode<GenericNodeForOperation<kOperation>>( SetAccumulator(AddNewNode<GenericNodeForOperation<kOperation>>(
{left, right}, compiler::FeedbackSource{feedback(), slot_index})); {left, right}, compiler::FeedbackSource{feedback(), slot_index}));
...@@ -158,7 +158,7 @@ void MaglevGraphBuilder::BuildGenericBinaryOperationNode() { ...@@ -158,7 +158,7 @@ void MaglevGraphBuilder::BuildGenericBinaryOperationNode() {
template <Operation kOperation> template <Operation kOperation>
void MaglevGraphBuilder::BuildGenericBinarySmiOperationNode() { void MaglevGraphBuilder::BuildGenericBinarySmiOperationNode() {
ValueNode* left = GetAccumulator(); ValueNode* left = GetAccumulatorTaggedValue();
Smi constant = Smi::FromInt(iterator_.GetImmediateOperand(0)); Smi constant = Smi::FromInt(iterator_.GetImmediateOperand(0));
ValueNode* right = AddNewNode<SmiConstant>({}, constant); ValueNode* right = AddNewNode<SmiConstant>({}, constant);
FeedbackSlot slot_index = GetSlotOperand(1); FeedbackSlot slot_index = GetSlotOperand(1);
...@@ -181,12 +181,16 @@ void MaglevGraphBuilder::VisitBinaryOperation() { ...@@ -181,12 +181,16 @@ void MaglevGraphBuilder::VisitBinaryOperation() {
BinaryOperationHint hint = nexus.GetBinaryOperationFeedback(); BinaryOperationHint hint = nexus.GetBinaryOperationFeedback();
if (hint == BinaryOperationHint::kSignedSmall) { if (hint == BinaryOperationHint::kSignedSmall) {
ValueNode* left = AddNewNode<CheckedSmiUntag>({LoadRegister(0)}); ValueNode *left, *right;
ValueNode* right = AddNewNode<CheckedSmiUntag>({GetAccumulator()}); if (IsRegisterEqualToAccumulator(0)) {
left = right = LoadRegisterSmiUntaggedValue(0);
} else {
left = LoadRegisterSmiUntaggedValue(0);
right = GetAccumulatorSmiUntaggedValue();
}
if (kOperation == Operation::kAdd) { if (kOperation == Operation::kAdd) {
ValueNode* result = AddNewNode<Int32AddWithOverflow>({left, right}); SetAccumulator(AddNewNode<Int32AddWithOverflow>({left, right}));
SetAccumulator(AddNewNode<CheckedSmiTag>({result}));
return; return;
} }
} }
...@@ -206,7 +210,7 @@ void MaglevGraphBuilder::VisitBinarySmiOperation() { ...@@ -206,7 +210,7 @@ void MaglevGraphBuilder::VisitBinarySmiOperation() {
BinaryOperationHint hint = nexus.GetBinaryOperationFeedback(); BinaryOperationHint hint = nexus.GetBinaryOperationFeedback();
if (hint == BinaryOperationHint::kSignedSmall) { if (hint == BinaryOperationHint::kSignedSmall) {
ValueNode* left = AddNewNode<CheckedSmiUntag>({GetAccumulator()}); ValueNode* left = GetAccumulatorSmiUntaggedValue();
int32_t constant = iterator_.GetImmediateOperand(0); int32_t constant = iterator_.GetImmediateOperand(0);
if (kOperation == Operation::kAdd) { if (kOperation == Operation::kAdd) {
...@@ -218,8 +222,7 @@ void MaglevGraphBuilder::VisitBinarySmiOperation() { ...@@ -218,8 +222,7 @@ void MaglevGraphBuilder::VisitBinarySmiOperation() {
// TODO(victorgomes): We could create an Int32Add node that receives // TODO(victorgomes): We could create an Int32Add node that receives
// a constant and avoid a register move. // a constant and avoid a register move.
ValueNode* right = AddNewNode<Int32Constant>({}, constant); ValueNode* right = AddNewNode<Int32Constant>({}, constant);
ValueNode* result = AddNewNode<Int32AddWithOverflow>({left, right}); SetAccumulator(AddNewNode<Int32AddWithOverflow>({left, right}));
SetAccumulator(AddNewNode<CheckedSmiTag>({result}));
return; return;
} }
} }
...@@ -392,7 +395,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(LdaLookupGlobalSlotInsideTypeof) ...@@ -392,7 +395,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(LdaLookupGlobalSlotInsideTypeof)
MAGLEV_UNIMPLEMENTED_BYTECODE(StaLookupSlot) MAGLEV_UNIMPLEMENTED_BYTECODE(StaLookupSlot)
void MaglevGraphBuilder::VisitGetNamedProperty() { void MaglevGraphBuilder::VisitGetNamedProperty() {
// GetNamedProperty <object> <name_index> <slot> // GetNamedProperty <object> <name_index> <slot>
ValueNode* object = LoadRegister(0); ValueNode* object = LoadRegisterTaggedValue(0);
compiler::NameRef name = GetRefOperand<Name>(1); compiler::NameRef name = GetRefOperand<Name>(1);
FeedbackSlot slot = GetSlotOperand(2); FeedbackSlot slot = GetSlotOperand(2);
compiler::FeedbackSource feedback_source{feedback(), slot}; compiler::FeedbackSource feedback_source{feedback(), slot};
...@@ -446,7 +449,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(StaModuleVariable) ...@@ -446,7 +449,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(StaModuleVariable)
void MaglevGraphBuilder::VisitSetNamedProperty() { void MaglevGraphBuilder::VisitSetNamedProperty() {
// SetNamedProperty <object> <name_index> <slot> // SetNamedProperty <object> <name_index> <slot>
ValueNode* object = LoadRegister(0); ValueNode* object = LoadRegisterTaggedValue(0);
compiler::NameRef name = GetRefOperand<Name>(1); compiler::NameRef name = GetRefOperand<Name>(1);
FeedbackSlot slot = GetSlotOperand(2); FeedbackSlot slot = GetSlotOperand(2);
compiler::FeedbackSource feedback_source{feedback(), slot}; compiler::FeedbackSource feedback_source{feedback(), slot};
...@@ -474,7 +477,7 @@ void MaglevGraphBuilder::VisitSetNamedProperty() { ...@@ -474,7 +477,7 @@ void MaglevGraphBuilder::VisitSetNamedProperty() {
StoreHandler::Kind kind = StoreHandler::KindBits::decode(smi_handler); StoreHandler::Kind kind = StoreHandler::KindBits::decode(smi_handler);
if (kind == StoreHandler::Kind::kField) { if (kind == StoreHandler::Kind::kField) {
AddNewNode<CheckMaps>({object}, named_feedback.maps()[0]); AddNewNode<CheckMaps>({object}, named_feedback.maps()[0]);
ValueNode* value = GetAccumulator(); ValueNode* value = GetAccumulatorTaggedValue();
AddNewNode<StoreField>({object, value}, smi_handler); AddNewNode<StoreField>({object, value}, smi_handler);
return; return;
} }
...@@ -592,7 +595,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(GetSuperConstructor) ...@@ -592,7 +595,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(GetSuperConstructor)
// TODO(v8:7700): Read feedback and implement inlining // TODO(v8:7700): Read feedback and implement inlining
void MaglevGraphBuilder::BuildCallFromRegisterList( void MaglevGraphBuilder::BuildCallFromRegisterList(
ConvertReceiverMode receiver_mode) { ConvertReceiverMode receiver_mode) {
ValueNode* function = LoadRegister(0); ValueNode* function = LoadRegisterTaggedValue(0);
interpreter::RegisterList args = iterator_.GetRegisterListOperand(1); interpreter::RegisterList args = iterator_.GetRegisterListOperand(1);
ValueNode* context = GetContext(); ValueNode* context = GetContext();
...@@ -622,7 +625,7 @@ void MaglevGraphBuilder::BuildCallFromRegisterList( ...@@ -622,7 +625,7 @@ void MaglevGraphBuilder::BuildCallFromRegisterList(
void MaglevGraphBuilder::BuildCallFromRegisters( void MaglevGraphBuilder::BuildCallFromRegisters(
int argc_count, ConvertReceiverMode receiver_mode) { int argc_count, ConvertReceiverMode receiver_mode) {
DCHECK_LE(argc_count, 2); DCHECK_LE(argc_count, 2);
ValueNode* function = LoadRegister(0); ValueNode* function = LoadRegisterTaggedValue(0);
ValueNode* context = GetContext(); ValueNode* context = GetContext();
int argc_count_with_recv = argc_count + 1; int argc_count_with_recv = argc_count + 1;
...@@ -643,7 +646,7 @@ void MaglevGraphBuilder::BuildCallFromRegisters( ...@@ -643,7 +646,7 @@ void MaglevGraphBuilder::BuildCallFromRegisters(
call->set_arg(arg_index++, undefined_constant); call->set_arg(arg_index++, undefined_constant);
} }
for (int i = 0; i < reg_count; i++) { for (int i = 0; i < reg_count; i++) {
call->set_arg(arg_index++, LoadRegister(i + 1)); call->set_arg(arg_index++, LoadRegisterTaggedValue(i + 1));
} }
SetAccumulator(call); SetAccumulator(call);
...@@ -804,19 +807,19 @@ void MaglevGraphBuilder::BuildBranchIfToBooleanTrue(ValueNode* node, ...@@ -804,19 +807,19 @@ void MaglevGraphBuilder::BuildBranchIfToBooleanTrue(ValueNode* node,
MergeIntoFrameState(block, iterator_.GetJumpTargetOffset()); MergeIntoFrameState(block, iterator_.GetJumpTargetOffset());
} }
void MaglevGraphBuilder::VisitJumpIfToBooleanTrue() { void MaglevGraphBuilder::VisitJumpIfToBooleanTrue() {
BuildBranchIfToBooleanTrue(GetAccumulator(), iterator_.GetJumpTargetOffset(), BuildBranchIfToBooleanTrue(GetAccumulatorTaggedValue(),
next_offset()); iterator_.GetJumpTargetOffset(), next_offset());
} }
void MaglevGraphBuilder::VisitJumpIfToBooleanFalse() { void MaglevGraphBuilder::VisitJumpIfToBooleanFalse() {
BuildBranchIfToBooleanTrue(GetAccumulator(), next_offset(), BuildBranchIfToBooleanTrue(GetAccumulatorTaggedValue(), next_offset(),
iterator_.GetJumpTargetOffset()); iterator_.GetJumpTargetOffset());
} }
void MaglevGraphBuilder::VisitJumpIfTrue() { void MaglevGraphBuilder::VisitJumpIfTrue() {
BuildBranchIfTrue(GetAccumulator(), iterator_.GetJumpTargetOffset(), BuildBranchIfTrue(GetAccumulatorTaggedValue(),
next_offset()); iterator_.GetJumpTargetOffset(), next_offset());
} }
void MaglevGraphBuilder::VisitJumpIfFalse() { void MaglevGraphBuilder::VisitJumpIfFalse() {
BuildBranchIfTrue(GetAccumulator(), next_offset(), BuildBranchIfTrue(GetAccumulatorTaggedValue(), next_offset(),
iterator_.GetJumpTargetOffset()); iterator_.GetJumpTargetOffset());
} }
MAGLEV_UNIMPLEMENTED_BYTECODE(JumpIfNull) MAGLEV_UNIMPLEMENTED_BYTECODE(JumpIfNull)
...@@ -835,7 +838,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(SetPendingMessage) ...@@ -835,7 +838,7 @@ MAGLEV_UNIMPLEMENTED_BYTECODE(SetPendingMessage)
MAGLEV_UNIMPLEMENTED_BYTECODE(Throw) MAGLEV_UNIMPLEMENTED_BYTECODE(Throw)
MAGLEV_UNIMPLEMENTED_BYTECODE(ReThrow) MAGLEV_UNIMPLEMENTED_BYTECODE(ReThrow)
void MaglevGraphBuilder::VisitReturn() { void MaglevGraphBuilder::VisitReturn() {
FinishBlock<Return>(next_offset(), {GetAccumulator()}); FinishBlock<Return>(next_offset(), {GetAccumulatorTaggedValue()});
} }
MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowReferenceErrorIfHole) MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowReferenceErrorIfHole)
MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowSuperNotCalledIfHole) MAGLEV_UNIMPLEMENTED_BYTECODE(ThrowSuperNotCalledIfHole)
......
...@@ -34,6 +34,14 @@ class MaglevGraphBuilder { ...@@ -34,6 +34,14 @@ class MaglevGraphBuilder {
// TODO(v8:7700): Clean up after all bytecodes are supported. // TODO(v8:7700): Clean up after all bytecodes are supported.
if (found_unsupported_bytecode()) break; if (found_unsupported_bytecode()) break;
} }
// During InterpreterFrameState merge points, we might emit CheckedSmiTags
// and add them unsafely to the basic blocks. This addition might break a
// list invariant (namely `tail_` might not point to the last element).
// We revalidate this invariant here in all basic blocks.
for (BasicBlock* block : *graph_) {
block->nodes().RevalidateTail();
}
} }
Graph* graph() const { return graph_; } Graph* graph() const { return graph_; }
...@@ -210,20 +218,59 @@ class MaglevGraphBuilder { ...@@ -210,20 +218,59 @@ class MaglevGraphBuilder {
current_interpreter_frame_.set(dst, current_interpreter_frame_.get(src)); current_interpreter_frame_.set(dst, current_interpreter_frame_.get(src));
} }
template <typename NodeT> ValueNode* GetTaggedValue(interpreter::Register reg) {
void SetAccumulator(NodeT* node) { // TODO(victorgomes): Add the representation (Tagged/Untagged) in the
// Accumulator stores are equivalent to stores to the virtual accumulator // InterpreterFrameState, so that we don't need to derefence a node.
// register. ValueNode* value = current_interpreter_frame_.get(reg);
StoreRegister(interpreter::Register::virtual_accumulator(), node); if (!value->IsUntaggedValue()) return value;
if (value->Is<CheckedSmiUntag>()) {
return value->input(0).node();
}
DCHECK(value->Is<Int32AddWithOverflow>() || value->Is<Int32Constant>());
ValueNode* tagged = AddNewNode<CheckedSmiTag>({value});
current_interpreter_frame_.set(reg, tagged);
return tagged;
}
ValueNode* GetSmiUntaggedValue(interpreter::Register reg) {
// TODO(victorgomes): Add the representation (Tagged/Untagged) in the
// InterpreterFrameState, so that we don't need to derefence a node.
ValueNode* value = current_interpreter_frame_.get(reg);
if (value->IsUntaggedValue()) return value;
if (value->Is<CheckedSmiTag>()) return value->input(0).node();
// Untag any other value.
ValueNode* untagged = AddNewNode<CheckedSmiUntag>({value});
current_interpreter_frame_.set(reg, untagged);
return untagged;
}
ValueNode* GetAccumulatorTaggedValue() {
return GetTaggedValue(interpreter::Register::virtual_accumulator());
} }
ValueNode* GetAccumulator() const { ValueNode* GetAccumulatorSmiUntaggedValue() {
return current_interpreter_frame_.accumulator(); return GetSmiUntaggedValue(interpreter::Register::virtual_accumulator());
} }
ValueNode* LoadRegister(int operand_index) { bool IsRegisterEqualToAccumulator(int operand_index) {
interpreter::Register source = iterator_.GetRegisterOperand(operand_index); interpreter::Register source = iterator_.GetRegisterOperand(operand_index);
return current_interpreter_frame_.get(source); return current_interpreter_frame_.get(source) ==
current_interpreter_frame_.accumulator();
}
ValueNode* LoadRegisterTaggedValue(int operand_index) {
return GetTaggedValue(iterator_.GetRegisterOperand(operand_index));
}
ValueNode* LoadRegisterSmiUntaggedValue(int operand_index) {
return GetSmiUntaggedValue(iterator_.GetRegisterOperand(operand_index));
}
template <typename NodeT>
void SetAccumulator(NodeT* node) {
// Accumulator stores are equivalent to stores to the virtual accumulator
// register.
StoreRegister(interpreter::Register::virtual_accumulator(), node);
} }
template <typename NodeT> template <typename NodeT>
......
...@@ -285,7 +285,7 @@ class MergePointInterpreterFrameState { ...@@ -285,7 +285,7 @@ class MergePointInterpreterFrameState {
// Merges an unmerged framestate with a possibly merged framestate into |this| // Merges an unmerged framestate with a possibly merged framestate into |this|
// framestate. // framestate.
void Merge(const MaglevCompilationUnit& compilation_unit, void Merge(MaglevCompilationUnit& compilation_unit,
const InterpreterFrameState& unmerged, BasicBlock* predecessor, const InterpreterFrameState& unmerged, BasicBlock* predecessor,
int merge_offset) { int merge_offset) {
DCHECK_GT(predecessor_count_, 1); DCHECK_GT(predecessor_count_, 1);
...@@ -296,8 +296,8 @@ class MergePointInterpreterFrameState { ...@@ -296,8 +296,8 @@ class MergePointInterpreterFrameState {
compilation_unit, [&](ValueNode*& value, interpreter::Register reg) { compilation_unit, [&](ValueNode*& value, interpreter::Register reg) {
CheckIsLoopPhiIfNeeded(compilation_unit, merge_offset, reg, value); CheckIsLoopPhiIfNeeded(compilation_unit, merge_offset, reg, value);
value = MergeValue(compilation_unit.zone(), reg, value, value = MergeValue(compilation_unit, reg, value, unmerged.get(reg),
unmerged.get(reg), merge_offset); merge_offset);
}); });
predecessors_so_far_++; predecessors_so_far_++;
DCHECK_LE(predecessors_so_far_, predecessor_count_); DCHECK_LE(predecessors_so_far_, predecessor_count_);
...@@ -348,9 +348,40 @@ class MergePointInterpreterFrameState { ...@@ -348,9 +348,40 @@ class MergePointInterpreterFrameState {
const MaglevCompilationUnit& info, const MaglevCompilationUnit& info,
const MergePointInterpreterFrameState& state); const MergePointInterpreterFrameState& state);
ValueNode* MergeValue(Zone* zone, interpreter::Register owner, ValueNode* TagValue(MaglevCompilationUnit& compilation_unit,
ValueNode* merged, ValueNode* unmerged, ValueNode* value) {
int merge_offset) { DCHECK(value->IsUntaggedValue());
if (value->Is<CheckedSmiUntag>()) {
return value->input(0).node();
}
DCHECK(value->Is<Int32AddWithOverflow>() || value->Is<Int32Constant>());
// Check if the next Node in the block after value is its CheckedSmiTag
// version and reuse it.
if (value->NextNode()) {
CheckedSmiTag* tagged = value->NextNode()->TryCast<CheckedSmiTag>();
if (tagged != nullptr && value == tagged->input().node()) {
return tagged;
}
}
// Otherwise create a tagged version.
ValueNode* tagged =
Node::New<CheckedSmiTag, std::initializer_list<ValueNode*>>(
compilation_unit.zone(), compilation_unit,
value->eager_deopt_info()->state, {value});
value->AddNodeAfter(tagged);
compilation_unit.RegisterNodeInGraphLabeller(tagged);
return tagged;
}
ValueNode* EnsureTagged(MaglevCompilationUnit& compilation_unit,
ValueNode* value) {
if (value->IsUntaggedValue()) return TagValue(compilation_unit, value);
return value;
}
ValueNode* MergeValue(MaglevCompilationUnit& compilation_unit,
interpreter::Register owner, ValueNode* merged,
ValueNode* unmerged, int merge_offset) {
// If the merged node is null, this is a pre-created loop header merge // If the merged node is null, this is a pre-created loop header merge
// frame will null values for anything that isn't a loop Phi. // frame will null values for anything that isn't a loop Phi.
if (merged == nullptr) { if (merged == nullptr) {
...@@ -364,12 +395,24 @@ class MergePointInterpreterFrameState { ...@@ -364,12 +395,24 @@ class MergePointInterpreterFrameState {
// It's possible that merged == unmerged at this point since loop-phis are // It's possible that merged == unmerged at this point since loop-phis are
// not dropped if they are only assigned to themselves in the loop. // not dropped if they are only assigned to themselves in the loop.
DCHECK_EQ(result->owner(), owner); DCHECK_EQ(result->owner(), owner);
if (unmerged->IsUntaggedValue()) {
unmerged = TagValue(compilation_unit, unmerged);
}
result->set_input(predecessors_so_far_, unmerged); result->set_input(predecessors_so_far_, unmerged);
return result; return result;
} }
if (merged == unmerged) return merged; if (merged == unmerged) return merged;
// We guarantee that the values are tagged.
// TODO(victorgomes): Support Phi nodes of untagged values.
merged = EnsureTagged(compilation_unit, merged);
unmerged = EnsureTagged(compilation_unit, unmerged);
// Tagged versions could point to the same value, avoid Phi nodes in this
// case.
if (merged == unmerged) return merged;
// Up to this point all predecessors had the same value for this interpreter // Up to this point all predecessors had the same value for this interpreter
// frame slot. Now that we find a distinct value, insert a copy of the first // frame slot. Now that we find a distinct value, insert a copy of the first
// value for each predecessor seen so far, in addition to the new value. // value for each predecessor seen so far, in addition to the new value.
...@@ -378,7 +421,8 @@ class MergePointInterpreterFrameState { ...@@ -378,7 +421,8 @@ class MergePointInterpreterFrameState {
// the frame slot. In that case we only need the inputs for representation // the frame slot. In that case we only need the inputs for representation
// selection, and hence could remove duplicate inputs. We'd likely need to // selection, and hence could remove duplicate inputs. We'd likely need to
// attach the interpreter register to the phi in that case? // attach the interpreter register to the phi in that case?
result = Node::New<Phi>(zone, predecessor_count_, owner, merge_offset); result = Node::New<Phi>(compilation_unit.zone(), predecessor_count_, owner,
merge_offset);
for (int i = 0; i < predecessors_so_far_; i++) result->set_input(i, merged); for (int i = 0; i < predecessors_so_far_; i++) result->set_input(i, merged);
result->set_input(predecessors_so_far_, unmerged); result->set_input(predecessors_so_far_, unmerged);
......
...@@ -832,9 +832,7 @@ void Call::GenerateCode(MaglevCodeGenState* code_gen_state, ...@@ -832,9 +832,7 @@ void Call::GenerateCode(MaglevCodeGenState* code_gen_state,
SafepointTableBuilder::Safepoint safepoint = SafepointTableBuilder::Safepoint safepoint =
code_gen_state->safepoint_table_builder()->DefineSafepoint( code_gen_state->safepoint_table_builder()->DefineSafepoint(
code_gen_state->masm()); code_gen_state->masm());
for (int i = 0; i < code_gen_state->vreg_slots(); i++) { code_gen_state->DefineSafepointStackSlots(safepoint);
safepoint.DefineTaggedStackSlot(GetSafepointIndexForStackSlot(i));
}
} }
// --- // ---
......
...@@ -165,6 +165,11 @@ class ConditionalControlNode; ...@@ -165,6 +165,11 @@ class ConditionalControlNode;
class UnconditionalControlNode; class UnconditionalControlNode;
class ValueNode; class ValueNode;
enum class ValueRepresentation {
kTagged,
kUntagged,
};
#define DEF_FORWARD_DECLARATION(type, ...) class type; #define DEF_FORWARD_DECLARATION(type, ...) class type;
NODE_BASE_LIST(DEF_FORWARD_DECLARATION) NODE_BASE_LIST(DEF_FORWARD_DECLARATION)
#undef DEF_FORWARD_DECLARATION #undef DEF_FORWARD_DECLARATION
...@@ -651,12 +656,24 @@ class Node : public NodeBase { ...@@ -651,12 +656,24 @@ class Node : public NodeBase {
inline ValueLocation& result(); inline ValueLocation& result();
// This might break ThreadedList invariants.
// Run ThreadedList::RevalidateTail afterwards.
void AddNodeAfter(Node* node) {
DCHECK_NOT_NULL(node);
DCHECK_NULL(node->next_);
node->next_ = next_;
next_ = node;
}
Node* NextNode() const { return next_; }
protected: protected:
using NodeBase::NodeBase; using NodeBase::NodeBase;
private: private:
Node** next() { return &next_; } Node** next() { return &next_; }
Node* next_ = nullptr; Node* next_ = nullptr;
friend List; friend List;
friend base::ThreadedListTraits<Node>; friend base::ThreadedListTraits<Node>;
}; };
...@@ -749,6 +766,12 @@ class ValueNode : public Node { ...@@ -749,6 +766,12 @@ class ValueNode : public Node {
return compiler::AllocatedOperand::cast(spill_or_hint_); return compiler::AllocatedOperand::cast(spill_or_hint_);
} }
bool IsUntaggedValue() const {
// TODO(victorgomes): Make this check faster somehow.
return Is<CheckedSmiUntag>() || Is<Int32AddWithOverflow>() ||
Is<Int32Constant>();
}
protected: protected:
explicit ValueNode(uint32_t bitfield) explicit ValueNode(uint32_t bitfield)
: Node(bitfield), : Node(bitfield),
......
...@@ -649,6 +649,9 @@ void StraightForwardRegisterAllocator::SpillAndClearRegisters() { ...@@ -649,6 +649,9 @@ void StraightForwardRegisterAllocator::SpillAndClearRegisters() {
void StraightForwardRegisterAllocator::AllocateSpillSlot(ValueNode* node) { void StraightForwardRegisterAllocator::AllocateSpillSlot(ValueNode* node) {
DCHECK(!node->is_spilled()); DCHECK(!node->is_spilled());
uint32_t free_slot = top_of_stack_++; uint32_t free_slot = top_of_stack_++;
compilation_unit_->push_stack_value_repr(node->IsUntaggedValue()
? ValueRepresentation::kUntagged
: ValueRepresentation::kTagged);
node->Spill(compiler::AllocatedOperand(compiler::AllocatedOperand::STACK_SLOT, node->Spill(compiler::AllocatedOperand(compiler::AllocatedOperand::STACK_SLOT,
MachineRepresentation::kTagged, MachineRepresentation::kTagged,
free_slot)); free_slot));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment