[maglev] Addition Smi nodes

If we have a smi operation in the feedback vector, we emit SmiTag
Int32AddWithOverflow and SmiUntag nodes, instead of a generic
operation binary node.


Change-Id: Idb9ce2b60289fbe492bf269793660b32de23e2b3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3560641
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79775}
This commit is contained in:
Victor Gomes 2022-04-05 13:50:17 +02:00 committed by V8 LUCI CQ
parent 8502508962
commit 3eeea13cf7
4 changed files with 153 additions and 4 deletions

View File

@ -155,6 +155,25 @@ void MaglevGraphBuilder::VisitUnaryOperation() {
template <Operation kOperation>
void MaglevGraphBuilder::VisitBinaryOperation() {
FeedbackNexus nexus = feedback_nexus(1);
if (nexus.ic_state() == InlineCacheState::MONOMORPHIC) {
if (nexus.kind() == FeedbackSlotKind::kBinaryOp) {
BinaryOperationHint hint = nexus.GetBinaryOperationFeedback();
if (hint == BinaryOperationHint::kSignedSmall) {
ValueNode* left = AddNewNode<CheckedSmiUntag>({LoadRegister(0)});
ValueNode* right = AddNewNode<CheckedSmiUntag>({GetAccumulator()});
if (kOperation == Operation::kAdd) {
ValueNode* result = AddNewNode<Int32AddWithOverflow>({left, right});
SetAccumulatorToNewNode<CheckedSmiTag>({result});
return;
}
}
}
}
// TODO(victorgomes): Use feedback info and create optimized versions.
BuildGenericBinaryOperationNode<kOperation>();
}

View File

@ -65,10 +65,7 @@ void DefineAsFixed(MaglevVregAllocationState* vreg_state, Node* node,
vreg_state->AllocateVirtualRegister());
}
// TODO(victorgomes): Use this for smi binary operation and remove attribute
// [[maybe_unused]].
[[maybe_unused]] void DefineSameAsFirst(MaglevVregAllocationState* vreg_state,
Node* node) {
void DefineSameAsFirst(MaglevVregAllocationState* vreg_state, Node* node) {
node->result().SetUnallocated(vreg_state->AllocateVirtualRegister(), 0);
}
@ -703,6 +700,46 @@ void BinaryWithFeedbackNode<Derived, kOperation>::GenerateCode(
GENERIC_OPERATIONS_NODE_LIST(DEF_OPERATION)
#undef DEF_OPERATION
void CheckedSmiUntag::AllocateVreg(MaglevVregAllocationState* vreg_state,
const ProcessingState& state) {
UseRegister(input());
DefineSameAsFirst(vreg_state, this);
}
void CheckedSmiUntag::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
__ sarl(ToRegister(input()), Immediate(1));
EmitEagerDeoptIf(carry, code_gen_state, this);
}
void CheckedSmiTag::AllocateVreg(MaglevVregAllocationState* vreg_state,
const ProcessingState& state) {
UseRegister(input());
DefineSameAsFirst(vreg_state, this);
}
void CheckedSmiTag::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
Register reg = ToRegister(input());
__ addl(reg, reg);
EmitEagerDeoptIf(overflow, code_gen_state, this);
}
void Int32AddWithOverflow::AllocateVreg(MaglevVregAllocationState* vreg_state,
const ProcessingState& state) {
UseRegister(left_input());
UseRegister(right_input());
DefineSameAsFirst(vreg_state, this);
}
void Int32AddWithOverflow::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
Register left = ToRegister(left_input());
Register right = ToRegister(right_input());
__ addl(left, right);
EmitEagerDeoptIf(overflow, code_gen_state, this);
}
void Phi::AllocateVreg(MaglevVregAllocationState* vreg_state,
const ProcessingState& state) {
// Phi inputs are processed in the post-process, once loop phis' inputs'

View File

@ -76,6 +76,9 @@ class CompactInterpreterFrameState;
V(RegisterInput) \
V(RootConstant) \
V(SmiConstant) \
V(CheckedSmiTag) \
V(CheckedSmiUntag) \
V(Int32AddWithOverflow) \
GENERIC_OPERATIONS_NODE_LIST(V)
#define NODE_LIST(V) \
@ -918,6 +921,55 @@ COMPARISON_OPERATION_LIST(DEF_BINARY_WITH_FEEDBACK_NODE)
#undef DEF_UNARY_WITH_FEEDBACK_NODE
#undef DEF_BINARY_WITH_FEEDBACK_NODE
class CheckedSmiTag : public FixedInputValueNodeT<1, CheckedSmiTag> {
using Base = FixedInputValueNodeT<1, CheckedSmiTag>;
public:
explicit CheckedSmiTag(uint32_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
Input& input() { return Node::input(0); }
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class CheckedSmiUntag : public FixedInputValueNodeT<1, CheckedSmiUntag> {
using Base = FixedInputValueNodeT<1, CheckedSmiUntag>;
public:
explicit CheckedSmiUntag(uint32_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
Input& input() { return Node::input(0); }
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class Int32AddWithOverflow
: public FixedInputValueNodeT<2, Int32AddWithOverflow> {
using Base = FixedInputValueNodeT<2, Int32AddWithOverflow>;
public:
explicit Int32AddWithOverflow(uint32_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties = OpProperties::EagerDeopt();
static constexpr int kLeftIndex = 0;
static constexpr int kRightIndex = 1;
Input& left_input() { return Node::input(kLeftIndex); }
Input& right_input() { return Node::input(kRightIndex); }
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
};
class InitialValue : public FixedInputValueNodeT<0, InitialValue> {
using Base = FixedInputValueNodeT<0, InitialValue>;

View File

@ -0,0 +1,41 @@
// Copyright 2022 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.
// Flags: --allow-natives-syntax --maglev --no-stress-opt
// Checks Smi add operation and deopt while untagging.
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(3, add(1, 2));
%OptimizeMaglevOnNextCall(add);
assertEquals(3, add(1, 2));
assertTrue(isMaglevved(add));
// We should deopt here in SmiUntag.
assertEquals(0x40000000, add(1, 0x3FFFFFFF));
assertFalse(isMaglevved(add));
})();
// Checks when we deopt due to tagging.
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(3, add(1, 2));
%OptimizeMaglevOnNextCall(add);
assertEquals(3, add(1, 2));
assertTrue(isMaglevved(add));
// We should deopt here in SmiTag.
assertEquals(3.2, add(1.2, 2));
assertFalse(isMaglevved(add));
})();