Commit 518de889 authored by jameslahm's avatar jameslahm Committed by V8 LUCI CQ

[maglev] Support CallRuntimeForPair

Bug: v8:7700
Change-Id: Ib27a3a818189acb5c1a1f39543762b3f0fcd9d69
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3815485Reviewed-by: 's avatarVictor Gomes <victorgomes@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: 王澳 <wangao.james@bytedance.com>
Cr-Commit-Position: refs/heads/main@{#82269}
parent 90a39679
......@@ -286,7 +286,8 @@ class TranslationArrayProcessor {
unit.register_count(), return_offset, return_count);
return EmitDeoptFrameValues(unit, state.register_frame, input_locations,
interpreter::Register::invalid_value());
interpreter::Register::invalid_value(),
return_count);
}
void EmitEagerDeopt(EagerDeoptInfo* deopt_info) {
......@@ -341,15 +342,14 @@ class TranslationArrayProcessor {
return_offset =
unit.register_count() - deopt_info->result_location.index();
}
// TODO(leszeks): Support lazy deopts with multiple return values.
int return_count = 1;
translation_array_builder().BeginInterpretedFrame(
deopt_info->state.bytecode_position,
GetDeoptLiteral(*unit.shared_function_info().object()),
unit.register_count(), return_offset, return_count);
unit.register_count(), return_offset, deopt_info->result_size);
EmitDeoptFrameValues(unit, deopt_info->state.register_frame,
input_locations, deopt_info->result_location);
input_locations, deopt_info->result_location,
deopt_info->result_size);
}
void EmitDeoptStoreRegister(const compiler::AllocatedOperand& operand,
......@@ -424,11 +424,20 @@ class TranslationArrayProcessor {
GetFramePointerOffsetForStackSlot(operand));
}
bool InReturnValues(interpreter::Register reg,
interpreter::Register result_location, int result_size) {
if (result_size == 0) {
return false;
}
return base::IsInRange(reg.index(), result_location.index(),
result_location.index() + result_size - 1);
}
const InputLocation* EmitDeoptFrameValues(
const MaglevCompilationUnit& compilation_unit,
const CompactInterpreterFrameState* checkpoint_state,
const InputLocation* input_locations,
interpreter::Register result_location) {
interpreter::Register result_location, int result_size) {
// Closure
if (compilation_unit.inlining_depth() == 0) {
int closure_index = DeoptStackSlotIndexFromFPOffset(
......@@ -450,10 +459,10 @@ class TranslationArrayProcessor {
checkpoint_state->ForEachParameter(
compilation_unit, [&](ValueNode* value, interpreter::Register reg) {
DCHECK_EQ(reg.ToParameterIndex(), i);
if (reg != result_location) {
EmitDeoptFrameSingleValue(value, *input_location);
} else {
if (InReturnValues(reg, result_location, result_size)) {
translation_array_builder().StoreOptimizedOut();
} else {
EmitDeoptFrameSingleValue(value, *input_location);
}
i++;
input_location++;
......@@ -471,7 +480,7 @@ class TranslationArrayProcessor {
checkpoint_state->ForEachLocal(
compilation_unit, [&](ValueNode* value, interpreter::Register reg) {
DCHECK_LE(i, reg.index());
if (reg == result_location) {
if (InReturnValues(reg, result_location, result_size)) {
input_location++;
return;
}
......@@ -493,7 +502,8 @@ class TranslationArrayProcessor {
// Accumulator
{
if (checkpoint_state->liveness()->AccumulatorIsLive() &&
result_location != interpreter::Register::virtual_accumulator()) {
!InReturnValues(interpreter::Register::virtual_accumulator(),
result_location, result_size)) {
ValueNode* value = checkpoint_state->accumulator(compilation_unit);
EmitDeoptFrameSingleValue(value, *input_location);
} else {
......
......@@ -1762,8 +1762,6 @@ void MaglevGraphBuilder::VisitCallRuntime() {
SetAccumulator(AddNode(call_runtime));
}
MAGLEV_UNIMPLEMENTED_BYTECODE(CallRuntimeForPair)
void MaglevGraphBuilder::VisitCallJSRuntime() {
// Get the function to call from the native context.
compiler::NativeContextRef native_context = broker()->target_native_context();
......@@ -1787,6 +1785,20 @@ void MaglevGraphBuilder::VisitCallJSRuntime() {
SetAccumulator(AddNode(call));
}
void MaglevGraphBuilder::VisitCallRuntimeForPair() {
Runtime::FunctionId function_id = iterator_.GetRuntimeIdOperand(0);
interpreter::RegisterList args = iterator_.GetRegisterListOperand(1);
ValueNode* context = GetContext();
size_t input_count = args.register_count() + CallRuntime::kFixedInputCount;
CallRuntime* call_runtime =
AddNewNode<CallRuntime>(input_count, function_id, context);
for (int i = 0; i < args.register_count(); ++i) {
call_runtime->set_arg(i, GetTaggedValue(args[i]));
}
StoreRegisterPair(iterator_.GetRegisterOperand(3), call_runtime);
}
void MaglevGraphBuilder::VisitInvokeIntrinsic() {
// InvokeIntrinsic <function_id> <first_arg> <arg_count>
Runtime::FunctionId intrinsic_id = iterator_.GetIntrinsicIdOperand(0);
......
......@@ -617,7 +617,11 @@ class MaglevGraphBuilder {
// to a value node. Since the previous node must have been a builtin
// call, the register is available in the register allocator. No gap moves
// would be emitted between these two nodes.
DCHECK_EQ(result->opcode(), Opcode::kForInPrepare);
if (result->opcode() == Opcode::kCallRuntime) {
DCHECK_EQ(result->Cast<CallRuntime>()->ReturnCount(), 2);
} else {
DCHECK_EQ(result->opcode(), Opcode::kForInPrepare);
}
// {result} must be the last node in the current block.
DCHECK(current_block_->nodes().Contains(result));
DCHECK_EQ(result->NextNode(), nullptr);
......@@ -636,6 +640,19 @@ class MaglevGraphBuilder {
current_interpreter_frame_.set(target, value);
}
void StoreRegisterPair(interpreter::Register target, CallRuntime* value) {
DCHECK_EQ(value->ReturnCount(), 2);
DCHECK_NE(0, new_nodes_.count(value));
MarkAsLazyDeoptResult(value, target, value->ReturnCount());
current_interpreter_frame_.set(target, value);
ValueNode* second_value = GetSecondValue(value);
DCHECK_NE(0, new_nodes_.count(second_value));
current_interpreter_frame_.set(interpreter::Register(target.index() + 1),
second_value);
}
CheckpointedInterpreterState GetLatestCheckpointedState() {
if (!latest_checkpointed_state_) {
latest_checkpointed_state_.emplace(
......@@ -663,13 +680,15 @@ class MaglevGraphBuilder {
template <typename NodeT>
void MarkAsLazyDeoptResult(NodeT* value,
interpreter::Register result_location) {
interpreter::Register result_location,
int result_size = 1) {
DCHECK_EQ(NodeT::kProperties.can_lazy_deopt(),
value->properties().can_lazy_deopt());
if constexpr (NodeT::kProperties.can_lazy_deopt()) {
DCHECK(result_location.is_valid());
DCHECK(!value->lazy_deopt_info()->result_location.is_valid());
value->lazy_deopt_info()->result_location = result_location;
value->lazy_deopt_info()->result_size = result_size;
}
}
......
......@@ -550,6 +550,7 @@ class LazyDeoptInfo : public DeoptInfo {
int deopting_call_return_pc = -1;
interpreter::Register result_location =
interpreter::Register::invalid_value();
int result_size = 1;
};
// Dummy type for the initial raw allocation.
......@@ -3109,6 +3110,10 @@ class CallRuntime : public ValueNodeT<CallRuntime> {
set_input(i + kFixedInputCount, node);
}
int ReturnCount() {
return Runtime::FunctionForId(function_id())->result_size;
}
void AllocateVreg(MaglevVregAllocationState*);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
......
// 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 --no-always-turbofan
function bar(x){
return x
}
function foo(x) {
with(bar){
return bar(x);
}
}
%PrepareFunctionForOptimization(foo);
assertEquals(1, foo(1));
assertEquals(2, foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(1, foo(1));
assertEquals(2, foo(2));
assertTrue(isMaglevved(foo));
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