You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
5.2 KiB
134 lines
5.2 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "linear_order.h"
|
|
|
|
#include "base/scoped_arena_allocator.h"
|
|
#include "base/scoped_arena_containers.h"
|
|
|
|
namespace art {
|
|
|
|
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(ScopedArenaVector<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, ArrayRef<HBasicBlock*> linear_order) {
|
|
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 (HBasicBlock* block : linear_order) {
|
|
if (loop->Contains(*block)) {
|
|
found_blocks++;
|
|
if (found_blocks == 1u && block != header) {
|
|
// First block is not the header.
|
|
return false;
|
|
} else if (found_blocks == num_blocks && !loop->IsBackEdge(*block)) {
|
|
// 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 LinearizeGraphInternal(const HGraph* graph, ArrayRef<HBasicBlock*> linear_order) {
|
|
DCHECK_EQ(linear_order.size(), graph->GetReversePostOrder().size());
|
|
// 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.
|
|
ScopedArenaAllocator allocator(graph->GetArenaStack());
|
|
ScopedArenaVector<uint32_t> forward_predecessors(graph->GetBlocks().size(),
|
|
allocator.Adapter(kArenaAllocLinearOrder));
|
|
for (HBasicBlock* block : graph->GetReversePostOrder()) {
|
|
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.
|
|
ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocLinearOrder));
|
|
worklist.push_back(graph->GetEntryBlock());
|
|
size_t num_added = 0u;
|
|
do {
|
|
HBasicBlock* current = worklist.back();
|
|
worklist.pop_back();
|
|
linear_order[num_added] = current;
|
|
++num_added;
|
|
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_EQ(num_added, linear_order.size());
|
|
|
|
DCHECK(graph->HasIrreducibleLoops() || IsLinearOrderWellFormed(graph, linear_order));
|
|
}
|
|
|
|
} // namespace art
|