v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
maglev-regalloc.h
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_MAGLEV_MAGLEV_REGALLOC_H_
6#define V8_MAGLEV_MAGLEV_REGALLOC_H_
7
15
16namespace v8 {
17namespace internal {
18namespace maglev {
19
20class MaglevCompilationInfo;
21class MaglevPrintingVisitor;
22class MergePointRegisterState;
23
26 // Hints about which nodes should be in registers or spilled when entering
27 // a loop.
30 explicit RegallocLoopInfo(Zone* zone)
31 : reload_hints_(0, zone), spill_hints_(0, zone) {}
32 };
33 absl::flat_hash_map<BasicBlock::Id, RegallocLoopInfo> loop_info_;
34};
35
36// Represents the state of the register frame during register allocation,
37// including current register values, and the state of each register.
38//
39// Register state encodes two orthogonal concepts:
40//
41// 1. Used/free registers: Which registers currently hold a valid value,
42// 2. Blocked/unblocked registers: Which registers can be modified during the
43// current allocation.
44//
45// The combination of these encodes values in different states:
46//
47// Free + unblocked: Completely unused registers which can be used for
48// anything.
49// Used + unblocked: Live values that can be spilled if there is register
50// pressure.
51// Used + blocked: Values that are in a register and are used as an input in
52// the current allocation.
53// Free + blocked: Unused registers that are reserved as temporaries, or
54// inputs that will get clobbered during the execution of the
55// node being allocated.
56template <typename RegisterT>
58 public:
59 static constexpr bool kIsGeneralRegister =
60 std::is_same<Register, RegisterT>();
61 static constexpr bool kIsDoubleRegister =
62 std::is_same<DoubleRegister, RegisterT>();
63
65 "RegisterFrameState should be used only for Register and "
66 "DoubleRegister.");
67
69
72 static constexpr RegTList kEmptyRegList = {};
73
74 RegTList empty() const { return kEmptyRegList; }
75 RegTList free() const { return free_; }
76 RegTList unblocked_free() const { return free_ - blocked_; }
77 RegTList used() const {
78 // Only allocatable registers should be free.
81 }
82
83 bool UnblockedFreeIsEmpty() const { return unblocked_free().is_empty(); }
84
85 template <typename Function>
86 void ForEachUsedRegister(Function&& f) const {
87 for (RegisterT reg : used()) {
88 f(reg, GetValue(reg));
89 }
90 }
91
92 void RemoveFromFree(RegisterT reg) { free_.clear(reg); }
93 void AddToFree(RegisterT reg) { free_.set(reg); }
94 void AddToFree(RegTList list) { free_ |= list; }
95
97 RegTList list = node->ClearRegisters<RegisterT>();
99 free_ |= list;
100 }
101
102 void SetValue(RegisterT reg, ValueNode* node) {
103 DCHECK(!free_.has(reg));
105 values_[reg.code()] = node;
106 block(reg);
107 node->AddRegister(reg);
108 }
109 void SetValueWithoutBlocking(RegisterT reg, ValueNode* node) {
110 DCHECK(!free_.has(reg));
112 values_[reg.code()] = node;
113 node->AddRegister(reg);
114 }
115 ValueNode* GetValue(RegisterT reg) const {
116 DCHECK(!free_.has(reg));
117 ValueNode* node = values_[reg.code()];
118 DCHECK_NOT_NULL(node);
119 return node;
120 }
121#ifdef DEBUG
122 // Like GetValue, but allow reading freed registers as long as they were also
123 // blocked. This allows us to DCHECK expected register state against node
124 // state, even if that node is dead or clobbered by the end of the current
125 // allocation.
126 ValueNode* GetValueMaybeFreeButBlocked(RegisterT reg) const {
128 ValueNode* node = values_[reg.code()];
129 DCHECK_NOT_NULL(node);
130 return node;
131 }
132#endif
133
134 RegTList blocked() const { return blocked_; }
135 void block(RegisterT reg) { blocked_.set(reg); }
136 void unblock(RegisterT reg) { blocked_.clear(reg); }
137 bool is_blocked(RegisterT reg) { return blocked_.has(reg); }
139
141 ValueNode* node, const compiler::InstructionOperand& hint =
145 ValueNode* node, const compiler::InstructionOperand& hint =
147
148 private:
149 ValueNode* values_[RegisterT::kNumRegisters];
152};
153
155 public:
157 Graph* graph, RegallocInfo* regalloc_info);
159
160 private:
163
174 struct SpillSlots {
175 int top = 0;
176 // Sorted from earliest freed_at_position to latest freed_at_position.
177 std::vector<SpillSlotInfo> free_slots;
178 };
179
182
184 void AllocateRegisters();
185
186 void PrintLiveRegs() const;
187
188 void UpdateUse(Input* input) { return UpdateUse(input->node(), input); }
189 void UpdateUse(ValueNode* node, InputLocation* input_location);
190
191 void MarkAsClobbered(ValueNode* node,
192 const compiler::AllocatedOperand& location);
193
194 void AllocateControlNode(ControlNode* node, BasicBlock* block);
195 void AllocateNode(Node* node);
196 void AllocateNodeResult(ValueNode* node);
197 void AllocateEagerDeopt(const EagerDeoptInfo& deopt_info);
198 void AllocateLazyDeopt(const LazyDeoptInfo& deopt_info);
199 void AssignFixedInput(Input& input);
200 void AssignArbitraryRegisterInput(NodeBase* result_node, Input& input);
201 void AssignAnyInput(Input& input);
202 void AssignInputs(NodeBase* node);
203 template <typename RegisterT>
205 NodeBase* node);
207 template <typename RegisterT>
209 NodeBase* node);
211 template <typename RegisterT>
212 void SetLoopPhiRegisterHint(Phi* phi, RegisterT reg);
213 void TryAllocateToInput(Phi* phi);
214
215 void VerifyInputs(NodeBase* node);
216 void VerifyRegisterState();
217
221
222 void AllocateSpillSlot(ValueNode* node);
223 void Spill(ValueNode* node);
224 void SpillRegisters();
225
226 template <typename RegisterT>
229
230 void SaveRegisterSnapshot(NodeBase* node);
231
232 void FreeRegistersUsedBy(ValueNode* node);
233 template <typename RegisterT>
234 RegisterT FreeUnblockedRegister(
236 template <typename RegisterT>
237 RegisterT PickRegisterToFree(RegListBase<RegisterT> reserved);
238
239 template <typename RegisterT>
241 if constexpr (std::is_same<RegisterT, Register>::value) {
242 return general_registers_;
243 } else {
244 return double_registers_;
245 }
246 }
247
248 template <typename RegisterT>
249 void DropRegisterValueAtEnd(RegisterT reg, bool force_spill = false);
251 template <typename RegisterT>
255
256 template <typename RegisterT>
258 RegisterT reg, bool force_spill = false);
261
263 ValueNode* node, const compiler::InstructionOperand& hint =
265
266 template <typename RegisterT>
272
273 template <typename Function>
275 MergePointRegisterState& merge_point_state, Function&& f);
276
277 void ClearRegisterValues();
279#ifdef DEBUG
280 bool IsInRegister(MergePointRegisterState& target_state, ValueNode* incoming);
281 bool IsForwardReachable(BasicBlock* start_block, NodeIdT first_id,
282 NodeIdT last_id);
283 bool AllUsedRegistersLiveAt(ConditionalControlNode* control_node,
284 BasicBlock* target);
285 bool AllUsedRegistersLiveAt(BasicBlock* target);
286#endif
287
288 template <typename RegisterT>
289 void HoistLoopReloads(BasicBlock* target,
291 void HoistLoopSpills(BasicBlock* target);
293 BasicBlock* target);
295 BasicBlock* target);
296 void InitializeBranchTargetPhis(int predecessor_id, BasicBlock* target);
298 BasicBlock* target);
299 void MergeRegisterValues(ControlNode* control, BasicBlock* target,
300 int predecessor_id);
301
302 void ApplyPatches(BasicBlock* block);
303
307
309 std::unique_ptr<MaglevPrintingVisitor> printing_visitor_;
311 struct BlockPatch {
312 ptrdiff_t diff;
314 };
316
319 // The current node, whether a Node in the body or the ControlNode.
322};
323
324} // namespace maglev
325} // namespace internal
326} // namespace v8
327
328#endif // V8_MAGLEV_MAGLEV_REGALLOC_H_
constexpr void set(RegisterT reg)
constexpr bool is_empty() const
constexpr bool has(RegisterT reg) const
constexpr void clear(RegisterT reg)
compiler::AllocatedOperand AllocateRegister(ValueNode *node, const compiler::InstructionOperand &hint=compiler::InstructionOperand())
ValueNode * GetValue(RegisterT reg) const
ValueNode * values_[RegisterT::kNumRegisters]
void SetValue(RegisterT reg, ValueNode *node)
compiler::InstructionOperand TryChooseInputRegister(ValueNode *node, const compiler::InstructionOperand &hint=compiler::InstructionOperand())
compiler::InstructionOperand TryChooseUnblockedInputRegister(ValueNode *node)
static constexpr RegTList kEmptyRegList
void SetValueWithoutBlocking(RegisterT reg, ValueNode *node)
static constexpr RegTList kAllocatableRegisters
void ForEachUsedRegister(Function &&f) const
compiler::AllocatedOperand AllocateRegisterAtEnd(ValueNode *node)
void DropRegisterValueAtEnd(RegisterT reg, bool force_spill=false)
RegisterT PickRegisterToFree(RegListBase< RegisterT > reserved)
StraightForwardRegisterAllocator(MaglevCompilationInfo *compilation_info, Graph *graph, RegallocInfo *regalloc_info)
void DropRegisterValue(RegisterFrameState< RegisterT > &registers, RegisterT reg, bool force_spill=false)
void ForEachMergePointRegisterState(MergePointRegisterState &merge_point_state, Function &&f)
void InitializeBranchTargetRegisterValues(ControlNode *source, BasicBlock *target)
RegisterT FreeUnblockedRegister(RegListBase< RegisterT > reserved=RegListBase< RegisterT >())
RegisterFrameState< DoubleRegister > double_registers_
compiler::AllocatedOperand AllocateRegister(ValueNode *node, const compiler::InstructionOperand &hint=compiler::InstructionOperand())
std::unique_ptr< MaglevPrintingVisitor > printing_visitor_
void InitializeEmptyBlockRegisterValues(ControlNode *source, BasicBlock *target)
void AllocateControlNode(ControlNode *node, BasicBlock *block)
void MarkAsClobbered(ValueNode *node, const compiler::AllocatedOperand &location)
void AssignArbitraryTemporaries(RegisterFrameState< RegisterT > &registers, NodeBase *node)
compiler::AllocatedOperand ForceAllocate(RegisterFrameState< RegisterT > &registers, RegisterT reg, ValueNode *node)
RegisterFrameState< RegisterT > & GetRegisterFrameState()
void HoistLoopReloads(BasicBlock *target, RegisterFrameState< RegisterT > &registers)
void InitializeBranchTargetPhis(int predecessor_id, BasicBlock *target)
void InitializeConditionalBranchTarget(ConditionalControlNode *source, BasicBlock *target)
void AddMoveBeforeCurrentNode(ValueNode *node, compiler::InstructionOperand source, compiler::AllocatedOperand target)
void EnsureFreeRegisterAtEnd(const compiler::InstructionOperand &hint=compiler::InstructionOperand())
void AllocateLazyDeopt(const LazyDeoptInfo &deopt_info)
void MergeRegisterValues(ControlNode *control, BasicBlock *target, int predecessor_id)
void InitializeRegisterValues(MergePointRegisterState &target_state)
void AssignFixedTemporaries(RegisterFrameState< RegisterT > &registers, NodeBase *node)
void AssignArbitraryRegisterInput(NodeBase *result_node, Input &input)
void AllocateEagerDeopt(const EagerDeoptInfo &deopt_info)
void AddRegister(Register reg)
Definition maglev-ir.h:2605
Node * node
RpoNumber block
LiftoffRegister reg
RegListBase< RegisterT > registers
ZoneVector< Node * >::iterator NodeIterator
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
absl::flat_hash_map< BasicBlock::Id, RegallocLoopInfo > loop_info_
SpillSlotInfo(uint32_t slot_index, NodeIdT freed_at_position, bool double_slot)