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