#ifndef V8_MAGLEV_MAGLEV_BASIC_BLOCK_H_
#define V8_MAGLEV_MAGLEV_BASIC_BLOCK_H_
#include <vector>
#include "src/base/small-vector.h"
#include "src/codegen/label.h"
#include "src/compiler/turboshaft/snapshot-table.h"
#include "src/maglev/maglev-interpreter-frame-state.h"
#include "src/maglev/maglev-ir.h"
#include "src/zone/zone-list.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
namespace maglev {
using NodeIterator = ZoneVector<Node*>::iterator;
using NodeConstIterator = ZoneVector<Node*>::const_iterator;
class BasicBlock {
public:
explicit BasicBlock(MergePointInterpreterFrameState* state, Zone* zone)
: type_(state ? kMerge : kOther),
nodes_(zone),
control_node_(nullptr),
state_(state) {}
NodeIdT first_id() const {
DCHECK(!is_dead());
if (has_phi()) return phis()->first()->id();
return first_non_phi_id();
}
void Print() const;
NodeIdT first_non_phi_id() const {
for (const Node* node : nodes_) {
if (node == nullptr) continue;
if (!node->Is<Identity>()) return node->id();
}
return control_node()->id();
}
NodeIdT FirstNonGapMoveId() const {
if (has_phi()) return phis()->first()->id();
for (const Node* node : nodes_) {
if (node == nullptr) continue;
if (IsGapMoveNode(node->opcode())) continue;
if (node->Is<Identity>()) continue;
return node->id();
}
return control_node()->id();
}
ZoneVector<Node*>& nodes() {
DCHECK(!is_dead());
return nodes_;
}
ControlNode* control_node() const { return control_node_; }
void set_control_node(ControlNode* control_node) {
DCHECK_NULL(control_node_);
control_node_ = control_node;
}
ControlNode* reset_control_node() {
DCHECK_NOT_NULL(control_node_);
ControlNode* control = control_node_;
control_node_ = nullptr;
return control;
}
ZoneVector<Node*> Split(Node* node, Zone* zone) {
size_t split = 0;
for (; split < nodes_.size(); split++) {
if (nodes_[split] == node) break;
}
DCHECK_NE(split, nodes_.size());
ZoneVector<Node*> result(nodes_.size() - split, zone);
for (size_t i = 0; i < result.size(); i++) {
result[i] = nodes_[i + split];
}
nodes_.resize(split);
return result;
}
bool has_phi() const { return has_state() && state_->has_phi(); }
bool is_merge_block() const { return type_ == kMerge; }
bool is_edge_split_block() const { return type_ == kEdgeSplit; }
bool is_loop() const { return has_state() && state()->is_loop(); }
MergePointRegisterState& edge_split_block_register_state() {
DCHECK_EQ(type_, kEdgeSplit);
DCHECK_NOT_NULL(edge_split_block_register_state_);
return *edge_split_block_register_state_;
}
bool contains_node_id(NodeIdT id) const {
return id >= first_id() && id <= control_node()->id();
}
void set_edge_split_block_register_state(
MergePointRegisterState* register_state) {
DCHECK_EQ(type_, kEdgeSplit);
edge_split_block_register_state_ = register_state;
}
void set_edge_split_block(BasicBlock* predecessor) {
DCHECK_EQ(type_, kOther);
DCHECK(nodes_.empty());
DCHECK(control_node()->Is<Jump>());
type_ = kEdgeSplit;
predecessor_ = predecessor;
}
BasicBlock* predecessor() const {
DCHECK(type_ == kEdgeSplit || type_ == kOther);
return predecessor_;
}
void set_predecessor(BasicBlock* predecessor) {
DCHECK(type_ == kEdgeSplit || type_ == kOther);
DCHECK_NULL(edge_split_block_register_state_);
predecessor_ = predecessor;
}
bool is_start_block_of_switch_case() const {
return is_start_block_of_switch_case_;
}
void set_start_block_of_switch_case(bool value) {
is_start_block_of_switch_case_ = value;
}
bool is_dead() const { return is_dead_; }
void mark_dead() { is_dead_ = true; }
Phi::List* phis() const {
DCHECK(has_phi());
return state_->phis();
}
void AddPhi(Phi* phi) const {
DCHECK(has_state());
state_->phis()->Add(phi);
}
ExceptionHandlerInfo::List& exception_handlers() {
return exception_handlers_;
}
void AddExceptionHandler(ExceptionHandlerInfo* handler) {
exception_handlers_.Add(handler);
}
int predecessor_count() const {
DCHECK(has_state());
return state()->predecessor_count();
}
bool IsUnreachable() const {
if (has_state()) return state()->IsUnreachable();
return predecessor_ == nullptr && id_ != 0;
}
BasicBlock* predecessor_at(int i) const {
DCHECK(has_state());
return state_->predecessor_at(i);
}
BasicBlock* backedge_predecessor() const {
DCHECK(is_loop());
return predecessor_at(predecessor_count() - 1);
}
int predecessor_id() const {
return control_node()->Cast<UnconditionalControlNode>()->predecessor_id();
}
void set_predecessor_id(int id) {
control_node()->Cast<UnconditionalControlNode>()->set_predecessor_id(id);
}
base::SmallVector<BasicBlock*, 2> successors() const;
template <typename Func>
void ForEachPredecessor(Func&& functor) const {
if (type_ == kEdgeSplit || type_ == kOther) {
BasicBlock* predecessor_block = predecessor();
if (predecessor_block) {
functor(predecessor_block);
}
} else {
for (int i = 0; i < predecessor_count(); i++) {
functor(predecessor_at(i));
}
}
}
template <typename Func>
bool ForAllPredecessors(Func&& functor) const {
if (type_ == kEdgeSplit || type_ == kOther) {
BasicBlock* predecessor_block = predecessor();
if (predecessor_block) {
if (!functor(predecessor_block)) {
return false;
}
}
} else {
for (int i = 0; i < predecessor_count(); i++) {
if (!functor(predecessor_at(i))) {
return false;
}
}
}
return true;
}
template <typename Func>
static void ForEachSuccessorFollowing(ControlNode* control, Func&& functor) {
if (auto unconditional_control =
control->TryCast<UnconditionalControlNode>()) {
functor(unconditional_control->target());
} else if (auto branch = control->TryCast<BranchControlNode>()) {
functor(branch->if_true());
functor(branch->if_false());
} else if (auto switch_node = control->TryCast<Switch>()) {
for (int i = 0; i < switch_node->size(); i++) {
functor(switch_node->targets()[i].block_ptr());
}
if (switch_node->has_fallthrough()) {
functor(switch_node->fallthrough());
}
}
}
template <typename Func>
void ForEachSuccessor(Func&& functor) const {
ControlNode* control = control_node();
ForEachSuccessorFollowing(control, functor);
}
Label* label() {
DCHECK_EQ(this, ComputeRealJumpTarget());
return &label_;
}
MergePointInterpreterFrameState* state() const {
DCHECK(has_state());
return state_;
}
bool has_state() const { return type_ == kMerge && state_ != nullptr; }
bool is_exception_handler_block() const {
return has_state() && state_->is_exception_handler();
}
bool is_inline() const { return has_state() && state_->is_inline(); }
BasicBlock* ComputeRealJumpTarget() {
BasicBlock* current = this;
while (true) {
if (!current->nodes_.empty() || current->is_loop() ||
current->is_exception_handler_block() ||
current->HasPhisOrRegisterMerges()) {
break;
}
Jump* control = current->control_node()->TryCast<Jump>();
if (!control) {
break;
}
BasicBlock* next = control->target();
if (next->HasPhisOrRegisterMerges()) {
break;
}
current = next;
}
return current;
}
void RemovePredecessorFollowing(ControlNode* control) {
ForEachSuccessorFollowing(control, [&](BasicBlock* succ) {
if (!succ->has_state()) {
succ->set_predecessor(nullptr);
return;
}
if (succ->is_loop() && succ->backedge_predecessor() == this) {
succ->state()->TurnLoopIntoRegularBlock();
return;
}
for (int i = succ->predecessor_count() - 1; i >= 0; i--) {
if (succ->predecessor_at(i) == this) {
succ->state()->RemovePredecessorAt(i);
}
}
});
}
bool is_deferred() const { return deferred_; }
void set_deferred(bool deferred) { deferred_ = deferred; }
using Id = uint32_t;
constexpr static Id kInvalidBlockId = 0xffffffff;
void set_id(Id id) {
DCHECK(!has_id());
id_ = id;
}
bool has_id() const { return id_ != kInvalidBlockId; }
Id id() const {
DCHECK(has_id());
return id_;
}
private:
bool HasPhisOrRegisterMerges() const {
if (!has_state()) {
return false;
}
if (has_phi()) {
return true;
}
bool has_register_merge = false;
#ifdef V8_ENABLE_MAGLEV
if (!state()->register_state().is_initialized()) {
return true;
}
state()->register_state().ForEachGeneralRegister(
[&](Register reg, RegisterState& state) {
ValueNode* node;
RegisterMerge* merge;
if (LoadMergeState(state, &node, &merge)) {
has_register_merge = true;
}
});
state()->register_state().ForEachDoubleRegister(
[&](DoubleRegister reg, RegisterState& state) {
ValueNode* node;
RegisterMerge* merge;
if (LoadMergeState(state, &node, &merge)) {
has_register_merge = true;
}
});
#endif
return has_register_merge;
}
enum : uint8_t { kMerge, kEdgeSplit, kOther } type_;
bool deferred_ : 1 = false;
bool is_start_block_of_switch_case_ : 1 = false;
bool is_dead_ : 1 = false;
Id id_ = kInvalidBlockId;
ZoneVector<Node*> nodes_;
ControlNode* control_node_;
ExceptionHandlerInfo::List exception_handlers_;
union {
MergePointInterpreterFrameState* state_;
MergePointRegisterState* edge_split_block_register_state_;
};
BasicBlock* predecessor_ = nullptr;
Label label_;
inline void check_layout();
};
void BasicBlock::check_layout() {
static_assert(offsetof(BasicBlock, nodes_) == 8);
}
inline base::SmallVector<BasicBlock*, 2> BasicBlock::successors() const {
ControlNode* control = control_node();
if (auto unconditional_control =
control->TryCast<UnconditionalControlNode>()) {
return {unconditional_control->target()};
} else if (auto branch = control->TryCast<BranchControlNode>()) {
return {branch->if_true(), branch->if_false()};
} else if (auto switch_node = control->TryCast<Switch>()) {
base::SmallVector<BasicBlock*, 2> succs;
for (int i = 0; i < switch_node->size(); i++) {
succs.push_back(switch_node->targets()[i].block_ptr());
}
if (switch_node->has_fallthrough()) {
succs.push_back(switch_node->fallthrough());
}
return succs;
} else {
return base::SmallVector<BasicBlock*, 2>();
}
}
}
}
}
#endif