Commit 007076e5 authored by Toon Verwaest's avatar Toon Verwaest Committed by V8 LUCI CQ

[maglev] Add explicit EagerDeoptInfo and use in regalloc

This allows us to store per-eager-deopt site information.

Bug: v8:7700
Change-Id: I86c29aec28220fb96fcf09984e6665f650f22708
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3550275Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79674}
parent 56cfdd68
......@@ -67,7 +67,7 @@ class UseMarkingProcessor {
template <typename NodeT>
void Process(NodeT* node, const ProcessingState& state) {
if constexpr (NodeT::kProperties.can_deopt()) {
MarkCheckpointNodes(node, node->checkpoint(), state);
MarkCheckpointNodes(node, node->eager_deopt_info(), state);
}
for (Input& input : *node) {
input.node()->mark_use(node->id(), &input);
......@@ -104,15 +104,18 @@ class UseMarkingProcessor {
}
private:
void MarkCheckpointNodes(NodeBase* node, Checkpoint* checkpoint,
void MarkCheckpointNodes(NodeBase* node,
const EagerDeoptInfo* eager_deopt_info,
const ProcessingState& state) {
const CompactInterpreterFrameState* checkpoint_state = checkpoint->state;
const CompactInterpreterFrameState* checkpoint_state =
eager_deopt_info->checkpoint->state;
int use_id = node->id();
int index = 0;
checkpoint_state->ForEachValue(
*state.compilation_unit(),
[use_id](ValueNode* node, interpreter::Register reg) {
if (node) node->mark_use(use_id, nullptr);
[&](ValueNode* node, interpreter::Register reg) {
node->mark_use(use_id, &eager_deopt_info->input_locations[index++]);
});
}
};
......
......@@ -151,8 +151,8 @@ class MaglevGraphBuilder {
template <typename NodeT, typename... Args>
NodeT* CreateNewNode(Args&&... args) {
if constexpr (NodeT::kProperties.can_deopt()) {
return Node::New<NodeT>(zone(), std::forward<Args>(args)...,
GetCheckpoint());
return Node::New<NodeT>(zone(), *compilation_unit_, GetCheckpoint(),
std::forward<Args>(args)...);
} else {
return Node::New<NodeT>(zone(), std::forward<Args>(args)...);
}
......
......@@ -10,6 +10,7 @@
#include "src/compiler/bytecode-analysis.h"
#include "src/compiler/bytecode-liveness-map.h"
#include "src/interpreter/bytecode-register.h"
#include "src/maglev/maglev-compilation-unit.h"
#include "src/maglev/maglev-ir.h"
#include "src/maglev/maglev-regalloc-data.h"
#include "src/maglev/maglev-register-frame-array.h"
......@@ -175,9 +176,13 @@ class CompactInterpreterFrameState {
const compiler::BytecodeLivenessState* liveness() const { return liveness_; }
size_t size(const MaglevCompilationUnit& info) const {
return SizeFor(info, liveness_);
}
private:
static int SizeFor(const MaglevCompilationUnit& info,
const compiler::BytecodeLivenessState* liveness) {
static size_t SizeFor(const MaglevCompilationUnit& info,
const compiler::BytecodeLivenessState* liveness) {
return info.parameter_count() + liveness->live_value_count();
}
......
......@@ -349,6 +349,13 @@ void NodeBase::Print(std::ostream& os,
UNREACHABLE();
}
EagerDeoptInfo::EagerDeoptInfo(Zone* zone,
const MaglevCompilationUnit& compilation_unit,
Checkpoint* checkpoint)
: checkpoint(checkpoint),
input_locations(zone->NewArray<InputLocation>(
checkpoint->state->size(compilation_unit))) {}
// ---
// Nodes
// ---
......
......@@ -16,6 +16,7 @@
#include "src/compiler/backend/instruction.h"
#include "src/compiler/heap-refs.h"
#include "src/interpreter/bytecode-register.h"
#include "src/maglev/maglev-compilation-unit.h"
#include "src/objects/smi.h"
#include "src/roots/roots.h"
#include "src/zone/zone.h"
......@@ -27,6 +28,7 @@ namespace maglev {
class BasicBlock;
class ProcessingState;
class MaglevCodeGenState;
class MaglevCompilationUnit;
class MaglevGraphLabeller;
class MaglevVregAllocationState;
class CompactInterpreterFrameState;
......@@ -272,22 +274,25 @@ class ValueLocation {
compiler::InstructionOperand operand_;
};
class Input : public ValueLocation {
class InputLocation : public ValueLocation {
public:
explicit Input(ValueNode* node) : node_(node) {}
ValueNode* node() const { return node_; }
NodeIdT next_use_id() const { return next_use_id_; }
// Used in ValueNode::mark_use
NodeIdT* get_next_use_id_address() { return &next_use_id_; }
private:
ValueNode* node_;
NodeIdT next_use_id_ = kInvalidNodeId;
};
class Input : public InputLocation {
public:
explicit Input(ValueNode* node) : node_(node) {}
ValueNode* node() const { return node_; }
private:
ValueNode* node_;
};
class Checkpoint {
public:
Checkpoint(BytecodeOffset bytecode_position,
......@@ -300,6 +305,15 @@ class Checkpoint {
int deopt_index = -1;
};
class EagerDeoptInfo {
public:
EagerDeoptInfo(Zone* zone, const MaglevCompilationUnit& compilation_unit_,
Checkpoint* checkpoint);
Checkpoint* const checkpoint;
InputLocation* const input_locations;
};
// Dummy type for the initial raw allocation.
struct NodeWithInlineInputs {};
......@@ -353,6 +367,15 @@ class NodeBase : public ZoneObject {
return node;
}
template <class Derived, typename... Args>
static Derived* New(Zone* zone, const MaglevCompilationUnit& compilation_unit,
Checkpoint* checkpoint, Args&&... args) {
Derived* node = New<Derived>(zone, std::forward<Args>(args)...);
new (node->eager_deopt_info_address())
EagerDeoptInfo(zone, compilation_unit, checkpoint);
return node;
}
// Inputs must be initialized manually.
template <class Derived, typename... Args>
static Derived* New(Zone* zone, size_t input_count, Args&&... args) {
......@@ -443,6 +466,15 @@ class NodeBase : public ZoneObject {
void Print(std::ostream& os, MaglevGraphLabeller*) const;
const EagerDeoptInfo* eager_deopt_info() const {
DCHECK(properties().can_deopt());
return (reinterpret_cast<const EagerDeoptInfo*>(
input_address(input_count() - 1)) -
1);
}
Checkpoint* checkpoint() const { return eager_deopt_info()->checkpoint; }
protected:
explicit NodeBase(uint32_t bitfield) : bit_field_(bitfield) {}
......@@ -450,6 +482,7 @@ class NodeBase : public ZoneObject {
DCHECK_LT(index, input_count());
return reinterpret_cast<Input*>(this) - (index + 1);
}
const Input* input_address(int index) const {
DCHECK_LT(index, input_count());
return reinterpret_cast<const Input*>(this) - (index + 1);
......@@ -467,14 +500,22 @@ class NodeBase : public ZoneObject {
num_temporaries_needed_ = value;
}
EagerDeoptInfo* eager_deopt_info_address() {
DCHECK(properties().can_deopt());
return reinterpret_cast<EagerDeoptInfo*>(input_address(input_count() - 1)) -
1;
}
private:
template <class Derived, typename... Args>
static Derived* Allocate(Zone* zone, size_t input_count, Args&&... args) {
const size_t size = sizeof(Derived) + input_count * sizeof(Input);
const size_t size_before_node =
input_count * sizeof(Input) +
(Derived::kProperties.can_deopt() ? sizeof(EagerDeoptInfo) : 0);
const size_t size = size_before_node + sizeof(Derived);
intptr_t raw_buffer =
reinterpret_cast<intptr_t>(zone->Allocate<NodeWithInlineInputs>(size));
void* node_buffer =
reinterpret_cast<void*>(raw_buffer + input_count * sizeof(Input));
void* node_buffer = reinterpret_cast<void*>(raw_buffer + size_before_node);
uint32_t bitfield = OpcodeField::encode(opcode_of<Derived>) |
OpPropertiesField::encode(Derived::kProperties) |
InputCountField::encode(input_count);
......@@ -586,16 +627,14 @@ class ValueNode : public Node {
return compiler::AllocatedOperand::cast(spill_or_hint_);
}
void mark_use(NodeIdT id, Input* use) {
void mark_use(NodeIdT id, InputLocation* input_location) {
DCHECK_EQ(state_, kLastUse);
DCHECK_NE(id, kInvalidNodeId);
DCHECK_LT(start_id(), id);
DCHECK_IMPLIES(has_valid_live_range(), id >= end_id_);
end_id_ = id;
*last_uses_next_use_id_ = id;
if (use) {
last_uses_next_use_id_ = use->get_next_use_id_address();
}
last_uses_next_use_id_ = input_location->get_next_use_id_address();
}
struct LiveRange {
......@@ -893,28 +932,21 @@ class SoftDeopt : public FixedInputNodeT<0, SoftDeopt> {
using Base = FixedInputNodeT<0, SoftDeopt>;
public:
explicit SoftDeopt(uint32_t bitfield, Checkpoint* checkpoint)
: Base(bitfield), checkpoint_(checkpoint) {}
explicit SoftDeopt(uint32_t bitfield) : Base(bitfield) {}
static constexpr OpProperties kProperties = OpProperties::Deopt();
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
Checkpoint* checkpoint() { return checkpoint_; }
private:
Checkpoint* const checkpoint_;
};
class CheckMaps : public FixedInputNodeT<1, CheckMaps> {
using Base = FixedInputNodeT<1, CheckMaps>;
public:
explicit CheckMaps(uint32_t bitfield, const compiler::MapRef& map,
Checkpoint* checkpoint)
: Base(bitfield), map_(map), checkpoint_(checkpoint) {}
explicit CheckMaps(uint32_t bitfield, const compiler::MapRef& map)
: Base(bitfield), map_(map) {}
// TODO(verwaest): This just calls in deferred code, so probably we'll need to
// mark that to generate stack maps. Mark as call so we at least clear the
......@@ -931,11 +963,8 @@ class CheckMaps : public FixedInputNodeT<1, CheckMaps> {
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
void PrintParams(std::ostream&, MaglevGraphLabeller*) const;
Checkpoint* checkpoint() { return checkpoint_; }
private:
const compiler::MapRef map_;
Checkpoint* checkpoint_;
};
class LoadField : public FixedInputValueNodeT<1, LoadField> {
......
......@@ -60,9 +60,7 @@ ControlNode* NearestPostDominatingHole(ControlNode* node) {
bool IsLiveAtTarget(ValueNode* node, ControlNode* source, BasicBlock* target) {
DCHECK_NOT_NULL(node);
// TODO(leszeks): We shouldn't have any dead nodes passed into here.
if (node->is_dead()) return false;
DCHECK(!node->is_dead());
// If we're looping, a value can only be live if it was live before the loop.
if (target->control_node()->id() <= source->id()) {
......@@ -305,33 +303,43 @@ void StraightForwardRegisterAllocator::AllocateRegisters(Graph* graph) {
}
}
void StraightForwardRegisterAllocator::UpdateInputUse(uint32_t use,
const Input& input) {
ValueNode* node = input.node();
// The value was already cleared through a previous input.
if (node->is_dead()) return;
void StraightForwardRegisterAllocator::UpdateUse(
ValueNode* node, InputLocation* input_location) {
DCHECK(!node->is_dead());
// Update the next use.
node->set_next_use(input.next_use_id());
node->set_next_use(input_location->next_use_id());
if (!node->is_dead()) return;
// If a value is dead, make sure it's cleared.
if (node->is_dead()) {
FreeRegisters(node);
FreeRegisters(node);
// If the stack slot is a local slot, free it so it can be reused.
if (node->is_spilled()) {
compiler::AllocatedOperand slot = node->spill_slot();
if (slot.index() > 0) free_slots_.push_back(slot.index());
}
return;
// If the stack slot is a local slot, free it so it can be reused.
if (node->is_spilled()) {
compiler::AllocatedOperand slot = node->spill_slot();
if (slot.index() > 0) free_slots_.push_back(slot.index());
}
}
void StraightForwardRegisterAllocator::UpdateUse(
const EagerDeoptInfo& eager_deopt_info) {
const CompactInterpreterFrameState* checkpoint_state =
eager_deopt_info.checkpoint->state;
int index = 0;
checkpoint_state->ForEachValue(
*compilation_unit_, [&](ValueNode* node, interpreter::Register reg) {
InputLocation* input = &eager_deopt_info.input_locations[index++];
input->InjectAllocated(node->allocation());
UpdateUse(node, input);
});
}
void StraightForwardRegisterAllocator::AllocateNode(Node* node) {
for (Input& input : *node) AssignInput(input);
AssignTemporaries(node);
for (Input& input : *node) UpdateInputUse(node->id(), input);
for (Input& input : *node) UpdateUse(&input);
if (node->properties().can_deopt()) UpdateUse(*node->eager_deopt_info());
if (node->properties().is_call()) SpillAndClearRegisters();
// TODO(verwaest): This isn't a good idea :)
......@@ -474,7 +482,7 @@ void StraightForwardRegisterAllocator::AllocateControlNode(ControlNode* node,
BasicBlock* block) {
for (Input& input : *node) AssignInput(input);
AssignTemporaries(node);
for (Input& input : *node) UpdateInputUse(node->id(), input);
for (Input& input : *node) UpdateUse(&input);
if (node->properties().is_call()) SpillAndClearRegisters();
......@@ -487,9 +495,7 @@ void StraightForwardRegisterAllocator::AllocateControlNode(ControlNode* node,
Input& input = phi->input(block->predecessor_id());
input.InjectAllocated(input.node()->allocation());
}
for (Phi* phi : *phis) {
UpdateInputUse(phi->id(), phi->input(block->predecessor_id()));
}
for (Phi* phi : *phis) UpdateUse(&phi->input(block->predecessor_id()));
}
}
......
......@@ -46,7 +46,9 @@ class StraightForwardRegisterAllocator {
void PrintLiveRegs() const;
void UpdateInputUse(uint32_t use, const Input& input);
void UpdateUse(Input* input) { return UpdateUse(input->node(), input); }
void UpdateUse(ValueNode* node, InputLocation* input_location);
void UpdateUse(const EagerDeoptInfo& eager_deopt_info);
void AllocateControlNode(ControlNode* node, BasicBlock* block);
void AllocateNode(Node* node);
......
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