Make LinearizeGraph() public (and move it to nodes files)
Rationale:
It is strange that HLinearOrderIterator is defined (and visible)
in nodes.h, but clients have no way to build this order. This CL
makes the building available at the usual place.
Change-Id: Ib66f2edf6dfc8edd6b429bd4bea3ac7e37440b28
Tests: m test-art
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 8f37236..9cfa89b 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -460,6 +460,113 @@
return kAnalysisSuccess;
}
+static bool InSameLoop(HLoopInformation* first_loop, HLoopInformation* second_loop) {
+ return first_loop == second_loop;
+}
+
+static bool IsLoop(HLoopInformation* info) {
+ return info != nullptr;
+}
+
+static bool IsInnerLoop(HLoopInformation* outer, HLoopInformation* inner) {
+ return (inner != outer)
+ && (inner != nullptr)
+ && (outer != nullptr)
+ && inner->IsIn(*outer);
+}
+
+// Helper method to update work list for linear order.
+static void AddToListForLinearization(ArenaVector<HBasicBlock*>* worklist, HBasicBlock* block) {
+ HLoopInformation* block_loop = block->GetLoopInformation();
+ auto insert_pos = worklist->rbegin(); // insert_pos.base() will be the actual position.
+ for (auto end = worklist->rend(); insert_pos != end; ++insert_pos) {
+ HBasicBlock* current = *insert_pos;
+ HLoopInformation* current_loop = current->GetLoopInformation();
+ if (InSameLoop(block_loop, current_loop)
+ || !IsLoop(current_loop)
+ || IsInnerLoop(current_loop, block_loop)) {
+ // The block can be processed immediately.
+ break;
+ }
+ }
+ worklist->insert(insert_pos.base(), block);
+}
+
+// Helper method to validate linear order.
+static bool IsLinearOrderWellFormed(const HGraph& graph) {
+ for (HBasicBlock* header : graph.GetBlocks()) {
+ if (header == nullptr || !header->IsLoopHeader()) {
+ continue;
+ }
+ HLoopInformation* loop = header->GetLoopInformation();
+ size_t num_blocks = loop->GetBlocks().NumSetBits();
+ size_t found_blocks = 0u;
+ for (HLinearOrderIterator it(graph); !it.Done(); it.Advance()) {
+ HBasicBlock* current = it.Current();
+ if (loop->Contains(*current)) {
+ found_blocks++;
+ if (found_blocks == 1u && current != header) {
+ // First block is not the header.
+ return false;
+ } else if (found_blocks == num_blocks && !loop->IsBackEdge(*current)) {
+ // Last block is not a back edge.
+ return false;
+ }
+ } else if (found_blocks != 0u && found_blocks != num_blocks) {
+ // Blocks are not adjacent.
+ return false;
+ }
+ }
+ DCHECK_EQ(found_blocks, num_blocks);
+ }
+ return true;
+}
+
+void HGraph::Linearize() {
+ // Create a reverse post ordering with the following properties:
+ // - Blocks in a loop are consecutive,
+ // - Back-edge is the last block before loop exits.
+
+ // (1): Record the number of forward predecessors for each block. This is to
+ // ensure the resulting order is reverse post order. We could use the
+ // current reverse post order in the graph, but it would require making
+ // order queries to a GrowableArray, which is not the best data structure
+ // for it.
+ ArenaVector<uint32_t> forward_predecessors(blocks_.size(),
+ arena_->Adapter(kArenaAllocSsaLiveness));
+ for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
+ HBasicBlock* block = it.Current();
+ size_t number_of_forward_predecessors = block->GetPredecessors().size();
+ if (block->IsLoopHeader()) {
+ number_of_forward_predecessors -= block->GetLoopInformation()->NumberOfBackEdges();
+ }
+ forward_predecessors[block->GetBlockId()] = number_of_forward_predecessors;
+ }
+
+ // (2): Following a worklist approach, first start with the entry block, and
+ // iterate over the successors. When all non-back edge predecessors of a
+ // successor block are visited, the successor block is added in the worklist
+ // following an order that satisfies the requirements to build our linear graph.
+ linear_order_.reserve(GetReversePostOrder().size());
+ ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocSsaLiveness));
+ worklist.push_back(GetEntryBlock());
+ do {
+ HBasicBlock* current = worklist.back();
+ worklist.pop_back();
+ linear_order_.push_back(current);
+ for (HBasicBlock* successor : current->GetSuccessors()) {
+ int block_id = successor->GetBlockId();
+ size_t number_of_remaining_predecessors = forward_predecessors[block_id];
+ if (number_of_remaining_predecessors == 1) {
+ AddToListForLinearization(&worklist, successor);
+ }
+ forward_predecessors[block_id] = number_of_remaining_predecessors - 1;
+ }
+ } while (!worklist.empty());
+
+ DCHECK(HasIrreducibleLoops() || IsLinearOrderWellFormed(*this));
+}
+
void HLoopInformation::Dump(std::ostream& os) {
os << "header: " << header_->GetBlockId() << std::endl;
os << "pre header: " << GetPreHeader()->GetBlockId() << std::endl;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 119b62a..4c6d28f 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -365,6 +365,13 @@
// is a throw-catch loop, i.e. the header is a catch block.
GraphAnalysisResult AnalyzeLoops() const;
+ // Computes the linear order (should be called before using HLinearOrderIterator).
+ // Linearizes the graph such that:
+ // (1): a block is always after its dominator,
+ // (2): blocks of loops are contiguous.
+ // This creates a natural and efficient ordering when visualizing live ranges.
+ void Linearize();
+
// Iterate over blocks to compute try block membership. Needs reverse post
// order and loop information.
void ComputeTryBlockInformation();
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index a4d52d7..9ce34aa 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -23,119 +23,11 @@
namespace art {
void SsaLivenessAnalysis::Analyze() {
- LinearizeGraph();
+ graph_->Linearize();
NumberInstructions();
ComputeLiveness();
}
-static bool IsLoop(HLoopInformation* info) {
- return info != nullptr;
-}
-
-static bool InSameLoop(HLoopInformation* first_loop, HLoopInformation* second_loop) {
- return first_loop == second_loop;
-}
-
-static bool IsInnerLoop(HLoopInformation* outer, HLoopInformation* inner) {
- return (inner != outer)
- && (inner != nullptr)
- && (outer != nullptr)
- && inner->IsIn(*outer);
-}
-
-static void AddToListForLinearization(ArenaVector<HBasicBlock*>* worklist, HBasicBlock* block) {
- HLoopInformation* block_loop = block->GetLoopInformation();
- auto insert_pos = worklist->rbegin(); // insert_pos.base() will be the actual position.
- for (auto end = worklist->rend(); insert_pos != end; ++insert_pos) {
- HBasicBlock* current = *insert_pos;
- HLoopInformation* current_loop = current->GetLoopInformation();
- if (InSameLoop(block_loop, current_loop)
- || !IsLoop(current_loop)
- || IsInnerLoop(current_loop, block_loop)) {
- // The block can be processed immediately.
- break;
- }
- }
- worklist->insert(insert_pos.base(), block);
-}
-
-static bool IsLinearOrderWellFormed(const HGraph& graph) {
- for (HBasicBlock* header : graph.GetBlocks()) {
- if (header == nullptr || !header->IsLoopHeader()) {
- continue;
- }
-
- HLoopInformation* loop = header->GetLoopInformation();
- size_t num_blocks = loop->GetBlocks().NumSetBits();
- size_t found_blocks = 0u;
-
- for (HLinearOrderIterator it(graph); !it.Done(); it.Advance()) {
- HBasicBlock* current = it.Current();
- if (loop->Contains(*current)) {
- found_blocks++;
- if (found_blocks == 1u && current != header) {
- // First block is not the header.
- return false;
- } else if (found_blocks == num_blocks && !loop->IsBackEdge(*current)) {
- // Last block is not a back edge.
- return false;
- }
- } else if (found_blocks != 0u && found_blocks != num_blocks) {
- // Blocks are not adjacent.
- return false;
- }
- }
- DCHECK_EQ(found_blocks, num_blocks);
- }
-
- return true;
-}
-
-void SsaLivenessAnalysis::LinearizeGraph() {
- // Create a reverse post ordering with the following properties:
- // - Blocks in a loop are consecutive,
- // - Back-edge is the last block before loop exits.
-
- // (1): Record the number of forward predecessors for each block. This is to
- // ensure the resulting order is reverse post order. We could use the
- // current reverse post order in the graph, but it would require making
- // order queries to a GrowableArray, which is not the best data structure
- // for it.
- ArenaVector<uint32_t> forward_predecessors(graph_->GetBlocks().size(),
- graph_->GetArena()->Adapter(kArenaAllocSsaLiveness));
- for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
- HBasicBlock* block = it.Current();
- size_t number_of_forward_predecessors = block->GetPredecessors().size();
- if (block->IsLoopHeader()) {
- number_of_forward_predecessors -= block->GetLoopInformation()->NumberOfBackEdges();
- }
- forward_predecessors[block->GetBlockId()] = number_of_forward_predecessors;
- }
-
- // (2): Following a worklist approach, first start with the entry block, and
- // iterate over the successors. When all non-back edge predecessors of a
- // successor block are visited, the successor block is added in the worklist
- // following an order that satisfies the requirements to build our linear graph.
- graph_->linear_order_.reserve(graph_->GetReversePostOrder().size());
- ArenaVector<HBasicBlock*> worklist(graph_->GetArena()->Adapter(kArenaAllocSsaLiveness));
- worklist.push_back(graph_->GetEntryBlock());
- do {
- HBasicBlock* current = worklist.back();
- worklist.pop_back();
- graph_->linear_order_.push_back(current);
- for (HBasicBlock* successor : current->GetSuccessors()) {
- int block_id = successor->GetBlockId();
- size_t number_of_remaining_predecessors = forward_predecessors[block_id];
- if (number_of_remaining_predecessors == 1) {
- AddToListForLinearization(&worklist, successor);
- }
- forward_predecessors[block_id] = number_of_remaining_predecessors - 1;
- }
- } while (!worklist.empty());
-
- DCHECK(graph_->HasIrreducibleLoops() || IsLinearOrderWellFormed(*graph_));
-}
-
void SsaLivenessAnalysis::NumberInstructions() {
int ssa_index = 0;
size_t lifetime_position = 0;
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 0be1611..b62bf4e 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -1186,12 +1186,6 @@
static constexpr const char* kLivenessPassName = "liveness";
private:
- // Linearize the graph so that:
- // (1): a block is always after its dominator,
- // (2): blocks of loops are contiguous.
- // This creates a natural and efficient ordering when visualizing live ranges.
- void LinearizeGraph();
-
// Give an SSA number to each instruction that defines a value used by another instruction,
// and setup the lifetime information of each instruction and block.
void NumberInstructions();