xref: /aosp_15_r20/art/compiler/optimizing/linear_order.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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