/* * 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