c35d70dd5c
Bug: v8:11074 Change-Id: I6d58d523254915a6b0d6542d8f80ddc6cee71dee Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2520907 Reviewed-by: Zhi An Ng <zhin@chromium.org> Commit-Queue: Nico Hartmann <nicohartmann@chromium.org> Cr-Commit-Position: refs/heads/master@{#71003}
321 lines
12 KiB
C++
321 lines
12 KiB
C++
// Copyright 2013 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef V8_COMPILER_SCHEDULE_H_
|
|
#define V8_COMPILER_SCHEDULE_H_
|
|
|
|
#include <iosfwd>
|
|
|
|
#include "src/base/compiler-specific.h"
|
|
#include "src/common/globals.h"
|
|
#include "src/zone/zone-containers.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
// Forward declarations.
|
|
class BasicBlock;
|
|
class BasicBlockInstrumentor;
|
|
class Node;
|
|
|
|
using BasicBlockVector = ZoneVector<BasicBlock*>;
|
|
using NodeVector = ZoneVector<Node*>;
|
|
|
|
// A basic block contains an ordered list of nodes and ends with a control
|
|
// node. Note that if a basic block has phis, then all phis must appear as the
|
|
// first nodes in the block.
|
|
class V8_EXPORT_PRIVATE BasicBlock final
|
|
: public NON_EXPORTED_BASE(ZoneObject) {
|
|
public:
|
|
// Possible control nodes that can end a block.
|
|
enum Control {
|
|
kNone, // Control not initialized yet.
|
|
kGoto, // Goto a single successor block.
|
|
kCall, // Call with continuation as first successor, exception
|
|
// second.
|
|
kBranch, // Branch if true to first successor, otherwise second.
|
|
kSwitch, // Table dispatch to one of the successor blocks.
|
|
kDeoptimize, // Return a value from this method.
|
|
kTailCall, // Tail call another method from this method.
|
|
kReturn, // Return a value from this method.
|
|
kThrow // Throw an exception.
|
|
};
|
|
|
|
class Id {
|
|
public:
|
|
int ToInt() const { return static_cast<int>(index_); }
|
|
size_t ToSize() const { return index_; }
|
|
static Id FromSize(size_t index) { return Id(index); }
|
|
static Id FromInt(int index) { return Id(static_cast<size_t>(index)); }
|
|
|
|
private:
|
|
explicit Id(size_t index) : index_(index) {}
|
|
size_t index_;
|
|
};
|
|
|
|
BasicBlock(Zone* zone, Id id);
|
|
BasicBlock(const BasicBlock&) = delete;
|
|
BasicBlock& operator=(const BasicBlock&) = delete;
|
|
|
|
Id id() const { return id_; }
|
|
#if DEBUG
|
|
void set_debug_info(AssemblerDebugInfo debug_info) {
|
|
debug_info_ = debug_info;
|
|
}
|
|
AssemblerDebugInfo debug_info() const { return debug_info_; }
|
|
#endif // DEBUG
|
|
|
|
void Print();
|
|
|
|
// Predecessors.
|
|
BasicBlockVector& predecessors() { return predecessors_; }
|
|
const BasicBlockVector& predecessors() const { return predecessors_; }
|
|
size_t PredecessorCount() const { return predecessors_.size(); }
|
|
BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; }
|
|
void ClearPredecessors() { predecessors_.clear(); }
|
|
void AddPredecessor(BasicBlock* predecessor);
|
|
void RemovePredecessor(size_t index);
|
|
|
|
// Successors.
|
|
BasicBlockVector& successors() { return successors_; }
|
|
const BasicBlockVector& successors() const { return successors_; }
|
|
size_t SuccessorCount() const { return successors_.size(); }
|
|
BasicBlock* SuccessorAt(size_t index) { return successors_[index]; }
|
|
void ClearSuccessors() { successors_.clear(); }
|
|
void AddSuccessor(BasicBlock* successor);
|
|
|
|
// Nodes in the basic block.
|
|
using value_type = Node*;
|
|
bool empty() const { return nodes_.empty(); }
|
|
size_t size() const { return nodes_.size(); }
|
|
Node* NodeAt(size_t index) { return nodes_[index]; }
|
|
size_t NodeCount() const { return nodes_.size(); }
|
|
|
|
value_type& front() { return nodes_.front(); }
|
|
value_type const& front() const { return nodes_.front(); }
|
|
|
|
using iterator = NodeVector::iterator;
|
|
iterator begin() { return nodes_.begin(); }
|
|
iterator end() { return nodes_.end(); }
|
|
|
|
void RemoveNode(iterator it) { nodes_.erase(it); }
|
|
|
|
using const_iterator = NodeVector::const_iterator;
|
|
const_iterator begin() const { return nodes_.begin(); }
|
|
const_iterator end() const { return nodes_.end(); }
|
|
|
|
using reverse_iterator = NodeVector::reverse_iterator;
|
|
reverse_iterator rbegin() { return nodes_.rbegin(); }
|
|
reverse_iterator rend() { return nodes_.rend(); }
|
|
|
|
void AddNode(Node* node);
|
|
template <class InputIterator>
|
|
void InsertNodes(iterator insertion_point, InputIterator insertion_start,
|
|
InputIterator insertion_end) {
|
|
nodes_.insert(insertion_point, insertion_start, insertion_end);
|
|
}
|
|
|
|
// Trim basic block to end at {new_end}.
|
|
void TrimNodes(iterator new_end);
|
|
|
|
void ResetRPOInfo();
|
|
|
|
// Accessors.
|
|
Control control() const { return control_; }
|
|
void set_control(Control control);
|
|
|
|
Node* control_input() const { return control_input_; }
|
|
void set_control_input(Node* control_input);
|
|
|
|
bool deferred() const { return deferred_; }
|
|
void set_deferred(bool deferred) { deferred_ = deferred; }
|
|
|
|
int32_t dominator_depth() const { return dominator_depth_; }
|
|
void set_dominator_depth(int32_t depth) { dominator_depth_ = depth; }
|
|
|
|
BasicBlock* dominator() const { return dominator_; }
|
|
void set_dominator(BasicBlock* dominator) { dominator_ = dominator; }
|
|
|
|
BasicBlock* rpo_next() const { return rpo_next_; }
|
|
void set_rpo_next(BasicBlock* rpo_next) { rpo_next_ = rpo_next; }
|
|
|
|
BasicBlock* loop_header() const { return loop_header_; }
|
|
void set_loop_header(BasicBlock* loop_header);
|
|
|
|
BasicBlock* loop_end() const { return loop_end_; }
|
|
void set_loop_end(BasicBlock* loop_end);
|
|
|
|
int32_t loop_depth() const { return loop_depth_; }
|
|
void set_loop_depth(int32_t loop_depth);
|
|
|
|
int32_t loop_number() const { return loop_number_; }
|
|
void set_loop_number(int32_t loop_number) { loop_number_ = loop_number; }
|
|
|
|
int32_t rpo_number() const { return rpo_number_; }
|
|
void set_rpo_number(int32_t rpo_number);
|
|
|
|
NodeVector* nodes() { return &nodes_; }
|
|
|
|
// Loop membership helpers.
|
|
inline bool IsLoopHeader() const { return loop_end_ != nullptr; }
|
|
bool LoopContains(BasicBlock* block) const;
|
|
|
|
// Computes the immediate common dominator of {b1} and {b2}. The worst time
|
|
// complexity is O(N) where N is the height of the dominator tree.
|
|
static BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2);
|
|
|
|
private:
|
|
int32_t loop_number_; // loop number of the block.
|
|
int32_t rpo_number_; // special RPO number of the block.
|
|
bool deferred_; // true if the block contains deferred code.
|
|
int32_t dominator_depth_; // Depth within the dominator tree.
|
|
BasicBlock* dominator_; // Immediate dominator of the block.
|
|
BasicBlock* rpo_next_; // Link to next block in special RPO order.
|
|
BasicBlock* loop_header_; // Pointer to dominating loop header basic block,
|
|
// nullptr if none. For loop headers, this points to
|
|
// enclosing loop header.
|
|
BasicBlock* loop_end_; // end of the loop, if this block is a loop header.
|
|
int32_t loop_depth_; // loop nesting, 0 is top-level
|
|
|
|
Control control_; // Control at the end of the block.
|
|
Node* control_input_; // Input value for control.
|
|
NodeVector nodes_; // nodes of this block in forward order.
|
|
|
|
BasicBlockVector successors_;
|
|
BasicBlockVector predecessors_;
|
|
#if DEBUG
|
|
AssemblerDebugInfo debug_info_;
|
|
#endif
|
|
Id id_;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream&, const BasicBlock&);
|
|
std::ostream& operator<<(std::ostream&, const BasicBlock::Control&);
|
|
std::ostream& operator<<(std::ostream&, const BasicBlock::Id&);
|
|
|
|
// A schedule represents the result of assigning nodes to basic blocks
|
|
// and ordering them within basic blocks. Prior to computing a schedule,
|
|
// a graph has no notion of control flow ordering other than that induced
|
|
// by the graph's dependencies. A schedule is required to generate code.
|
|
class V8_EXPORT_PRIVATE Schedule final : public NON_EXPORTED_BASE(ZoneObject) {
|
|
public:
|
|
explicit Schedule(Zone* zone, size_t node_count_hint = 0);
|
|
Schedule(const Schedule&) = delete;
|
|
Schedule& operator=(const Schedule&) = delete;
|
|
|
|
// Return the block which contains {node}, if any.
|
|
BasicBlock* block(Node* node) const;
|
|
|
|
bool IsScheduled(Node* node);
|
|
BasicBlock* GetBlockById(BasicBlock::Id block_id);
|
|
void ClearBlockById(BasicBlock::Id block_id);
|
|
|
|
size_t BasicBlockCount() const { return all_blocks_.size(); }
|
|
size_t RpoBlockCount() const { return rpo_order_.size(); }
|
|
|
|
// Check if nodes {a} and {b} are in the same block.
|
|
bool SameBasicBlock(Node* a, Node* b) const;
|
|
|
|
// BasicBlock building: create a new block.
|
|
BasicBlock* NewBasicBlock();
|
|
|
|
// BasicBlock building: records that a node will later be added to a block but
|
|
// doesn't actually add the node to the block.
|
|
void PlanNode(BasicBlock* block, Node* node);
|
|
|
|
// BasicBlock building: add a node to the end of the block.
|
|
void AddNode(BasicBlock* block, Node* node);
|
|
|
|
// BasicBlock building: add a goto to the end of {block}.
|
|
void AddGoto(BasicBlock* block, BasicBlock* succ);
|
|
|
|
// BasicBlock building: add a call at the end of {block}.
|
|
void AddCall(BasicBlock* block, Node* call, BasicBlock* success_block,
|
|
BasicBlock* exception_block);
|
|
|
|
// BasicBlock building: add a branch at the end of {block}.
|
|
void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
|
|
BasicBlock* fblock);
|
|
|
|
// BasicBlock building: add a switch at the end of {block}.
|
|
void AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
|
|
size_t succ_count);
|
|
|
|
// BasicBlock building: add a deoptimize at the end of {block}.
|
|
void AddDeoptimize(BasicBlock* block, Node* input);
|
|
|
|
// BasicBlock building: add a tailcall at the end of {block}.
|
|
void AddTailCall(BasicBlock* block, Node* input);
|
|
|
|
// BasicBlock building: add a return at the end of {block}.
|
|
void AddReturn(BasicBlock* block, Node* input);
|
|
|
|
// BasicBlock building: add a throw at the end of {block}.
|
|
void AddThrow(BasicBlock* block, Node* input);
|
|
|
|
// BasicBlock mutation: insert a branch into the end of {block}.
|
|
void InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
|
|
BasicBlock* tblock, BasicBlock* fblock);
|
|
|
|
// BasicBlock mutation: insert a switch into the end of {block}.
|
|
void InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw,
|
|
BasicBlock** succ_blocks, size_t succ_count);
|
|
|
|
// Exposed publicly for testing only.
|
|
void AddSuccessorForTesting(BasicBlock* block, BasicBlock* succ) {
|
|
return AddSuccessor(block, succ);
|
|
}
|
|
|
|
const BasicBlockVector* all_blocks() const { return &all_blocks_; }
|
|
BasicBlockVector* rpo_order() { return &rpo_order_; }
|
|
const BasicBlockVector* rpo_order() const { return &rpo_order_; }
|
|
|
|
BasicBlock* start() { return start_; }
|
|
BasicBlock* end() { return end_; }
|
|
|
|
Zone* zone() const { return zone_; }
|
|
|
|
private:
|
|
friend class GraphAssembler;
|
|
friend class Scheduler;
|
|
friend class BasicBlockInstrumentor;
|
|
friend class RawMachineAssembler;
|
|
|
|
// For CSA/Torque: Ensure properties of the CFG assumed by further stages.
|
|
void EnsureCFGWellFormedness();
|
|
// For CSA/Torque: Eliminates unnecessary phi nodes, including phis with a
|
|
// single input. The latter is necessary to ensure the property required for
|
|
// SSA deconstruction that the target block of a control flow split has no
|
|
// phis.
|
|
void EliminateRedundantPhiNodes();
|
|
// Ensure split-edge form for a hand-assembled schedule.
|
|
void EnsureSplitEdgeForm(BasicBlock* block);
|
|
// Move Phi operands to newly created merger blocks
|
|
void MovePhis(BasicBlock* from, BasicBlock* to);
|
|
// Copy deferred block markers down as far as possible
|
|
void PropagateDeferredMark();
|
|
|
|
void AddSuccessor(BasicBlock* block, BasicBlock* succ);
|
|
void MoveSuccessors(BasicBlock* from, BasicBlock* to);
|
|
|
|
void SetControlInput(BasicBlock* block, Node* node);
|
|
void SetBlockForNode(BasicBlock* block, Node* node);
|
|
|
|
Zone* zone_;
|
|
BasicBlockVector all_blocks_; // All basic blocks in the schedule.
|
|
BasicBlockVector nodeid_to_block_; // Map from node to containing block.
|
|
BasicBlockVector rpo_order_; // Reverse-post-order block list.
|
|
BasicBlock* start_;
|
|
BasicBlock* end_;
|
|
};
|
|
|
|
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, const Schedule&);
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_COMPILER_SCHEDULE_H_
|