v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
maglev-basic-block.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_BASIC_BLOCK_H_
6#define V8_MAGLEV_MAGLEV_BASIC_BLOCK_H_
7
8#include <vector>
9
11#include "src/codegen/label.h"
15#include "src/zone/zone-list.h"
16#include "src/zone/zone.h"
17
18namespace v8 {
19namespace internal {
20namespace maglev {
21
24
26 public:
28 : type_(state ? kMerge : kOther),
29 nodes_(zone),
30 control_node_(nullptr),
31 state_(state) {}
32
33 NodeIdT first_id() const {
34 if (has_phi()) return phis()->first()->id();
35 return first_non_phi_id();
36 }
37
38 // For GDB: Print any basic block with `print bb->Print()`.
39 void Print() const;
40
42 for (const Node* node : nodes_) {
43 if (node == nullptr) continue;
44 if (!node->Is<Identity>()) return node->id();
45 }
46 return control_node()->id();
47 }
48
50 if (has_phi()) return phis()->first()->id();
51 for (const Node* node : nodes_) {
52 if (node == nullptr) continue;
53 if (IsGapMoveNode(node->opcode())) continue;
54 if (node->Is<Identity>()) continue;
55 return node->id();
56 }
57 return control_node()->id();
58 }
59
61
67
70 ControlNode* control = control_node_;
71 control_node_ = nullptr;
72 return control;
73 }
74
75 // Moves all nodes after |node| to the resulting ZoneVector, while keeping all
76 // nodes before |node| in the basic block. |node| itself is dropped.
78 size_t split = 0;
79 for (; split < nodes_.size(); split++) {
80 if (nodes_[split] == node) break;
81 }
82 DCHECK_NE(split, nodes_.size());
83 size_t after_split = split + 1;
84 ZoneVector<Node*> result(nodes_.size() - after_split, zone);
85 for (size_t i = 0; i < result.size(); i++) {
86 result[i] = nodes_[i + after_split];
87 }
88 nodes_.resize(split);
89 return result;
90 }
91
92 bool has_phi() const { return has_state() && state_->has_phi(); }
93
94 bool is_merge_block() const { return type_ == kMerge; }
95 bool is_edge_split_block() const { return type_ == kEdgeSplit; }
96
97 bool is_loop() const { return has_state() && state()->is_loop(); }
98
104
105 bool contains_node_id(NodeIdT id) const {
106 return id >= first_id() && id <= control_node()->id();
107 }
108
114
122
125 return predecessor_;
126 }
132
139
140 bool is_dead() const { return is_dead_; }
141
142 void mark_dead() { is_dead_ = true; }
143
144 Phi::List* phis() const {
145 DCHECK(has_phi());
146 return state_->phis();
147 }
148 void AddPhi(Phi* phi) const {
149 DCHECK(has_state());
150 state_->phis()->Add(phi);
151 }
152
156
160
161 int predecessor_count() const {
162 DCHECK(has_state());
163 return state()->predecessor_count();
164 }
165
167 DCHECK(has_state());
168 return state_->predecessor_at(i);
169 }
170
175
182
184
185 template <typename Func>
186 void ForEachPredecessor(Func&& functor) const {
187 if (type_ == kEdgeSplit || type_ == kOther) {
188 BasicBlock* predecessor_block = predecessor();
189 if (predecessor_block) {
190 functor(predecessor_block);
191 }
192 } else {
193 for (int i = 0; i < predecessor_count(); i++) {
194 functor(predecessor_at(i));
195 }
196 }
197 }
198
199 template <typename Func>
200 static void ForEachSuccessorFollowing(ControlNode* control, Func&& functor) {
201 if (auto unconditional_control =
202 control->TryCast<UnconditionalControlNode>()) {
203 functor(unconditional_control->target());
204 } else if (auto branch = control->TryCast<BranchControlNode>()) {
205 functor(branch->if_true());
206 functor(branch->if_false());
207 } else if (auto switch_node = control->TryCast<Switch>()) {
208 for (int i = 0; i < switch_node->size(); i++) {
209 functor(switch_node->targets()[i].block_ptr());
210 }
211 if (switch_node->has_fallthrough()) {
212 functor(switch_node->fallthrough());
213 }
214 }
215 }
216
217 template <typename Func>
218 void ForEachSuccessor(Func&& functor) const {
219 ControlNode* control = control_node();
220 ForEachSuccessorFollowing(control, functor);
221 }
222
224 // If this fails, jump threading is missing for the node. See
225 // MaglevCodeGeneratingNodeProcessor::PatchJumps.
227 return &label_;
228 }
230 DCHECK(has_state());
231 return state_;
232 }
233 bool has_state() const { return type_ == kMerge && state_ != nullptr; }
234
237 }
238
239 // If the basic block is an empty (unnecessary) block containing only an
240 // unconditional jump to the successor block, return the successor block.
242 BasicBlock* current = this;
243 while (true) {
244 if (!current->nodes_.empty() || current->is_loop() ||
245 current->is_exception_handler_block() ||
246 current->HasPhisOrRegisterMerges()) {
247 break;
248 }
249 Jump* control = current->control_node()->TryCast<Jump>();
250 if (!control) {
251 break;
252 }
253 BasicBlock* next = control->target();
254 if (next->HasPhisOrRegisterMerges()) {
255 break;
256 }
257 current = next;
258 }
259 return current;
260 }
261
262 bool is_deferred() const { return deferred_; }
263 void set_deferred(bool deferred) { deferred_ = deferred; }
264
265 using Id = uint32_t;
266 constexpr static Id kInvalidBlockId = 0xffffffff;
267
268 void set_id(Id id) {
269 DCHECK(!has_id());
270 id_ = id;
271 }
272 bool has_id() const { return id_ != kInvalidBlockId; }
273 Id id() const {
274 DCHECK(has_id());
275 return id_;
276 }
277
278 private:
280 if (!has_state()) {
281 return false;
282 }
283 if (has_phi()) {
284 return true;
285 }
286 bool has_register_merge = false;
287#ifdef V8_ENABLE_MAGLEV
288 if (!state()->register_state().is_initialized()) {
289 // This can happen when the graph has disconnected blocks; bail out and
290 // don't jump thread them.
291 return true;
292 }
293
294 state()->register_state().ForEachGeneralRegister(
295 [&](Register reg, RegisterState& state) {
297 RegisterMerge* merge;
298 if (LoadMergeState(state, &node, &merge)) {
299 has_register_merge = true;
300 }
301 });
302 state()->register_state().ForEachDoubleRegister(
303 [&](DoubleRegister reg, RegisterState& state) {
305 RegisterMerge* merge;
306 if (LoadMergeState(state, &node, &merge)) {
307 has_register_merge = true;
308 }
309 });
310#endif // V8_ENABLE_MAGLEV
311 return has_register_merge;
312 }
313
314 enum : uint8_t { kMerge, kEdgeSplit, kOther } type_;
315 bool deferred_ : 1 = false;
317 bool is_dead_ : 1 = false;
318
320
324
325 union {
328 };
329 // For kEdgeSplit and kOther blocks.
332
333 inline void check_layout();
334};
335
337 // Ensure non pointer sized values are nicely packed.
338 static_assert(offsetof(BasicBlock, nodes_) == 8);
339}
340
342 ControlNode* control = control_node();
343 if (auto unconditional_control =
344 control->TryCast<UnconditionalControlNode>()) {
345 return {unconditional_control->target()};
346 } else if (auto branch = control->TryCast<BranchControlNode>()) {
347 return {branch->if_true(), branch->if_false()};
348 } else if (auto switch_node = control->TryCast<Switch>()) {
350 for (int i = 0; i < switch_node->size(); i++) {
351 succs.push_back(switch_node->targets()[i].block_ptr());
352 }
353 if (switch_node->has_fallthrough()) {
354 succs.push_back(switch_node->fallthrough());
355 }
356 return succs;
357 } else {
359 }
360}
361
362} // namespace maglev
363} // namespace internal
364} // namespace v8
365
366#endif // V8_MAGLEV_MAGLEV_BASIC_BLOCK_H_
void resize(size_t new_size)
void set_control_node(ControlNode *control_node)
BasicBlock(MergePointInterpreterFrameState *state, Zone *zone)
BasicBlock * backedge_predecessor() const
bool contains_node_id(NodeIdT id) const
MergePointRegisterState & edge_split_block_register_state()
base::SmallVector< BasicBlock *, 2 > successors() const
MergePointRegisterState * edge_split_block_register_state_
ExceptionHandlerInfo::List exception_handlers_
static void ForEachSuccessorFollowing(ControlNode *control, Func &&functor)
void ForEachPredecessor(Func &&functor) const
MergePointInterpreterFrameState * state_
void ForEachSuccessor(Func &&functor) const
void AddExceptionHandler(ExceptionHandlerInfo *handler)
void set_edge_split_block(BasicBlock *predecessor)
BasicBlock * predecessor_at(int i) const
enum v8::internal::maglev::BasicBlock::@85 type_
ExceptionHandlerInfo::List & exception_handlers()
void set_predecessor(BasicBlock *predecessor)
void set_edge_split_block_register_state(MergePointRegisterState *register_state)
MergePointInterpreterFrameState * state() const
ZoneVector< Node * > Split(Node *node, Zone *zone)
constexpr NodeIdT id() const
Definition maglev-ir.h:1998
LineAndColumn current
Node * node
ZoneVector< RpoNumber > & result
LiftoffRegister reg
ZoneVector< Node * >::iterator NodeIterator
bool LoadMergeState(RegisterState state, RegisterMerge **merge)
constexpr bool IsGapMoveNode(Opcode opcode)
Definition maglev-ir.h:523
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
return value
Definition map-inl.h:893
#define DCHECK_NULL(val)
Definition logging.h:491
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485