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