Commit 213194f7 authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[maglev] Allow deopts from registers and untagged values

Remove the "bad idea" of spilling whenever there's a deopt, and instead
use the deoptimizer's register support.

In addition, allow untagged int32 inputs into deopts -- if tagging these
overflows, then the deoptimizer will automagically create a HeapNumber
for us. Hooray for code reuse!

Drive-bys:
    1. Print input locations for deopt checkpoints.
    2. Fix ordering of UpdateUse(input)/UpdateUse(deopt) to match the
       use marker.

Bug: v8:7700
Change-Id: I8069f5bc1bdcd7746a516c7a5cc7e26a15d4e5cb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3578805Reviewed-by: 's avatarVictor Gomes <victorgomes@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79950}
parent f5012c1a
......@@ -401,9 +401,9 @@ class MaglevCodeGeneratorImpl final {
deopt_info->state.bytecode_position, kFunctionLiteralIndex,
code_gen_state_.register_count(), return_offset, return_count);
EmitDeoptFrameValues(*code_gen_state_.compilation_unit(),
deopt_info->state.register_frame,
interpreter::Register::invalid_value());
EmitDeoptFrameValues(
*code_gen_state_.compilation_unit(), deopt_info->state.register_frame,
deopt_info->input_locations, interpreter::Register::invalid_value());
}
void EmitLazyDeopt(LazyDeoptInfo* deopt_info) {
......@@ -441,20 +441,47 @@ class MaglevCodeGeneratorImpl final {
deopt_info->state.bytecode_position, kFunctionLiteralIndex,
code_gen_state_.register_count(), return_offset, return_count);
EmitDeoptFrameValues(*code_gen_state_.compilation_unit(),
deopt_info->state.register_frame,
deopt_info->result_location);
EmitDeoptFrameValues(
*code_gen_state_.compilation_unit(), deopt_info->state.register_frame,
deopt_info->input_locations, deopt_info->result_location);
}
void EmitDeoptFrameSingleValue(ValueNode* value,
const InputLocation& input_location) {
const compiler::AllocatedOperand& operand =
compiler::AllocatedOperand::cast(input_location.operand());
if (operand.IsRegister()) {
if (value->properties().is_untagged_value()) {
translation_array_builder_.StoreInt32Register(operand.GetRegister());
} else {
translation_array_builder_.StoreRegister(operand.GetRegister());
}
} else {
if (value->properties().is_untagged_value()) {
translation_array_builder_.StoreInt32StackSlot(
DeoptStackSlotFromStackSlot(operand));
} else {
translation_array_builder_.StoreStackSlot(
DeoptStackSlotFromStackSlot(operand));
}
}
}
void EmitDeoptFrameValues(
const MaglevCompilationUnit& compilation_unit,
const CompactInterpreterFrameState* checkpoint_state,
const InputLocation* input_locations,
interpreter::Register result_location) {
// Closure
int closure_index = DeoptStackSlotIndexFromFPOffset(
StandardFrameConstants::kFunctionOffset);
translation_array_builder_.StoreStackSlot(closure_index);
// TODO(leszeks): The input locations array happens to be in the same order
// as parameters+locals+accumulator are accessed here. We should make this
// clearer and guard against this invariant failing.
const InputLocation* input_location = input_locations;
// Parameters
{
int i = 0;
......@@ -462,13 +489,13 @@ class MaglevCodeGeneratorImpl final {
compilation_unit, [&](ValueNode* value, interpreter::Register reg) {
DCHECK_EQ(reg.ToParameterIndex(), i);
if (reg != result_location) {
translation_array_builder_.StoreStackSlot(
DeoptStackSlotFromStackSlot(value->spill_slot()));
EmitDeoptFrameSingleValue(value, *input_location);
} else {
translation_array_builder_.StoreLiteral(
kOptimizedOutConstantIndex);
}
i++;
input_location++;
});
}
......@@ -483,16 +510,19 @@ class MaglevCodeGeneratorImpl final {
checkpoint_state->ForEachLocal(
compilation_unit, [&](ValueNode* value, interpreter::Register reg) {
DCHECK_LE(i, reg.index());
if (reg == result_location) return;
if (reg == result_location) {
input_location++;
return;
}
while (i < reg.index()) {
translation_array_builder_.StoreLiteral(
kOptimizedOutConstantIndex);
i++;
}
DCHECK_EQ(i, reg.index());
translation_array_builder_.StoreStackSlot(
DeoptStackSlotFromStackSlot(value->spill_slot()));
EmitDeoptFrameSingleValue(value, *input_location);
i++;
input_location++;
});
while (i < code_gen_state_.register_count()) {
translation_array_builder_.StoreLiteral(kOptimizedOutConstantIndex);
......@@ -505,9 +535,7 @@ class MaglevCodeGeneratorImpl final {
if (checkpoint_state->liveness()->AccumulatorIsLive() &&
result_location != interpreter::Register::virtual_accumulator()) {
ValueNode* value = checkpoint_state->accumulator(compilation_unit);
translation_array_builder_.StoreStackSlot(
DeoptStackSlotFromStackSlot(value->spill_slot()));
EmitDeoptFrameSingleValue(value, *input_location);
} else {
translation_array_builder_.StoreLiteral(kOptimizedOutConstantIndex);
}
......
......@@ -314,6 +314,7 @@ void PrintEagerDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
EagerDeoptInfo* deopt_info = node->eager_deopt_info();
os << " ↱ eager @" << deopt_info->state.bytecode_position << " : {";
bool first = true;
int index = 0;
deopt_info->state.register_frame->ForEachValue(
*state.compilation_unit(),
[&](ValueNode* node, interpreter::Register reg) {
......@@ -322,7 +323,9 @@ void PrintEagerDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
} else {
os << ", ";
}
os << reg.ToString() << ":" << PrintNodeLabel(graph_labeller, node);
os << reg.ToString() << ":" << PrintNodeLabel(graph_labeller, node)
<< ":" << deopt_info->input_locations[index].operand();
index++;
});
os << "}\n";
}
......@@ -351,6 +354,7 @@ void PrintLazyDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
LazyDeoptInfo* deopt_info = node->lazy_deopt_info();
os << " ↳ lazy @" << deopt_info->state.bytecode_position << " : {";
bool first = true;
int index = 0;
deopt_info->state.register_frame->ForEachValue(
*state.compilation_unit(),
[&](ValueNode* node, interpreter::Register reg) {
......@@ -363,8 +367,10 @@ void PrintLazyDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
if (reg == deopt_info->result_location) {
os << "<result>";
} else {
os << PrintNodeLabel(graph_labeller, node);
os << PrintNodeLabel(graph_labeller, node) << ":"
<< deopt_info->input_locations[index].operand();
}
index++;
});
os << "}\n";
}
......
......@@ -351,7 +351,15 @@ DeoptInfo::DeoptInfo(Zone* zone, const MaglevCompilationUnit& compilation_unit,
CheckpointedInterpreterState state)
: state(state),
input_locations(zone->NewArray<InputLocation>(
state.register_frame->size(compilation_unit))) {}
state.register_frame->size(compilation_unit))) {
// Default initialise if we're printing the graph, to avoid printing junk
// values.
if (FLAG_print_maglev_graph) {
for (size_t i = 0; i < state.register_frame->size(compilation_unit); ++i) {
new (&input_locations[i]) InputLocation();
}
}
}
// ---
// Nodes
......@@ -718,8 +726,13 @@ void CheckedSmiUntag::AllocateVreg(MaglevVregAllocationState* vreg_state,
void CheckedSmiUntag::GenerateCode(MaglevCodeGenState* code_gen_state,
const ProcessingState& state) {
__ sarl(ToRegister(input()), Immediate(1));
EmitEagerDeoptIf(carry, code_gen_state, this);
Register value = ToRegister(input());
// TODO(leszeks): Consider optimizing away this test and using the carry bit
// of the `sarl` for cases where the deopt uses the value from a different
// register.
__ testb(value, Immediate(1));
EmitEagerDeoptIf(not_zero, code_gen_state, this);
__ sarl(value, Immediate(1));
}
void CheckedSmiTag::AllocateVreg(MaglevVregAllocationState* vreg_state,
......
......@@ -347,16 +347,12 @@ void StraightForwardRegisterAllocator::UpdateUse(
void StraightForwardRegisterAllocator::AllocateNode(Node* node) {
for (Input& input : *node) AssignInput(input);
AssignTemporaries(node);
for (Input& input : *node) UpdateUse(&input);
if (node->properties().can_eager_deopt()) {
UpdateUse(*node->eager_deopt_info());
}
for (Input& input : *node) UpdateUse(&input);
if (node->properties().is_call()) SpillAndClearRegisters();
// TODO(verwaest): This isn't a good idea :)
if (node->properties().can_eager_deopt() ||
node->properties().can_lazy_deopt())
SpillRegisters();
// Allocate node output.
if (node->Is<ValueNode>()) AllocateNodeResult(node->Cast<ValueNode>());
......
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