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