blob: 80cecd41dc7887f74fa5fad2b15132ed5d932df3 [file] [log] [blame]
Aart Bik96202302016-10-04 17:33:56 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "linear_order.h"
18
19namespace art {
20
21static bool InSameLoop(HLoopInformation* first_loop, HLoopInformation* second_loop) {
22 return first_loop == second_loop;
23}
24
25static bool IsLoop(HLoopInformation* info) {
26 return info != nullptr;
27}
28
29static bool IsInnerLoop(HLoopInformation* outer, HLoopInformation* inner) {
30 return (inner != outer)
31 && (inner != nullptr)
32 && (outer != nullptr)
33 && inner->IsIn(*outer);
34}
35
36// Helper method to update work list for linear order.
37static void AddToListForLinearization(ArenaVector<HBasicBlock*>* worklist, HBasicBlock* block) {
38 HLoopInformation* block_loop = block->GetLoopInformation();
39 auto insert_pos = worklist->rbegin(); // insert_pos.base() will be the actual position.
40 for (auto end = worklist->rend(); insert_pos != end; ++insert_pos) {
41 HBasicBlock* current = *insert_pos;
42 HLoopInformation* current_loop = current->GetLoopInformation();
43 if (InSameLoop(block_loop, current_loop)
44 || !IsLoop(current_loop)
45 || IsInnerLoop(current_loop, block_loop)) {
46 // The block can be processed immediately.
47 break;
48 }
49 }
50 worklist->insert(insert_pos.base(), block);
51}
52
53// Helper method to validate linear order.
54static bool IsLinearOrderWellFormed(const HGraph* graph, ArenaVector<HBasicBlock*>* linear_order) {
55 for (HBasicBlock* header : graph->GetBlocks()) {
56 if (header == nullptr || !header->IsLoopHeader()) {
57 continue;
58 }
59 HLoopInformation* loop = header->GetLoopInformation();
60 size_t num_blocks = loop->GetBlocks().NumSetBits();
61 size_t found_blocks = 0u;
62 for (HBasicBlock* block : *linear_order) {
63 if (loop->Contains(*block)) {
64 found_blocks++;
65 if (found_blocks == 1u && block != header) {
66 // First block is not the header.
67 return false;
68 } else if (found_blocks == num_blocks && !loop->IsBackEdge(*block)) {
69 // Last block is not a back edge.
70 return false;
71 }
72 } else if (found_blocks != 0u && found_blocks != num_blocks) {
73 // Blocks are not adjacent.
74 return false;
75 }
76 }
77 DCHECK_EQ(found_blocks, num_blocks);
78 }
79 return true;
80}
81
82void LinearizeGraph(const HGraph* graph,
83 ArenaAllocator* allocator,
84 ArenaVector<HBasicBlock*>* linear_order) {
85 DCHECK(linear_order->empty());
86 // Create a reverse post ordering with the following properties:
87 // - Blocks in a loop are consecutive,
88 // - Back-edge is the last block before loop exits.
89 //
90 // (1): Record the number of forward predecessors for each block. This is to
91 // ensure the resulting order is reverse post order. We could use the
92 // current reverse post order in the graph, but it would require making
93 // order queries to a GrowableArray, which is not the best data structure
94 // for it.
95 ArenaVector<uint32_t> forward_predecessors(graph->GetBlocks().size(),
96 allocator->Adapter(kArenaAllocLinearOrder));
Vladimir Marko2c45bc92016-10-25 16:54:12 +010097 for (HBasicBlock* block : graph->GetReversePostOrder()) {
Aart Bik96202302016-10-04 17:33:56 -070098 size_t number_of_forward_predecessors = block->GetPredecessors().size();
99 if (block->IsLoopHeader()) {
100 number_of_forward_predecessors -= block->GetLoopInformation()->NumberOfBackEdges();
101 }
102 forward_predecessors[block->GetBlockId()] = number_of_forward_predecessors;
103 }
104 // (2): Following a worklist approach, first start with the entry block, and
105 // iterate over the successors. When all non-back edge predecessors of a
106 // successor block are visited, the successor block is added in the worklist
107 // following an order that satisfies the requirements to build our linear graph.
108 linear_order->reserve(graph->GetReversePostOrder().size());
109 ArenaVector<HBasicBlock*> worklist(allocator->Adapter(kArenaAllocLinearOrder));
110 worklist.push_back(graph->GetEntryBlock());
111 do {
112 HBasicBlock* current = worklist.back();
113 worklist.pop_back();
114 linear_order->push_back(current);
115 for (HBasicBlock* successor : current->GetSuccessors()) {
116 int block_id = successor->GetBlockId();
117 size_t number_of_remaining_predecessors = forward_predecessors[block_id];
118 if (number_of_remaining_predecessors == 1) {
119 AddToListForLinearization(&worklist, successor);
120 }
121 forward_predecessors[block_id] = number_of_remaining_predecessors - 1;
122 }
123 } while (!worklist.empty());
124
125 DCHECK(graph->HasIrreducibleLoops() || IsLinearOrderWellFormed(graph, linear_order));
126}
127
128} // namespace art