xref: /aosp_15_r20/art/compiler/optimizing/superblock_cloner_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 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 "base/macros.h"
18*795d594fSAndroid Build Coastguard Worker #include "graph_checker.h"
19*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
20*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
21*795d594fSAndroid Build Coastguard Worker #include "superblock_cloner.h"
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h"
24*795d594fSAndroid Build Coastguard Worker 
25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker using HBasicBlockMap = SuperblockCloner::HBasicBlockMap;
28*795d594fSAndroid Build Coastguard Worker using HInstructionMap = SuperblockCloner::HInstructionMap;
29*795d594fSAndroid Build Coastguard Worker using HBasicBlockSet = SuperblockCloner::HBasicBlockSet;
30*795d594fSAndroid Build Coastguard Worker using HEdgeSet = SuperblockCloner::HEdgeSet;
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker // This class provides methods and helpers for testing various cloning and copying routines:
33*795d594fSAndroid Build Coastguard Worker // individual instruction cloning and cloning of the more coarse-grain structures.
34*795d594fSAndroid Build Coastguard Worker class SuperblockClonerTest : public OptimizingUnitTest {
35*795d594fSAndroid Build Coastguard Worker  protected:
InitGraphAndParameters()36*795d594fSAndroid Build Coastguard Worker   HBasicBlock* InitGraphAndParameters() {
37*795d594fSAndroid Build Coastguard Worker     HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
38*795d594fSAndroid Build Coastguard Worker     param_ = MakeParam(DataType::Type::kInt32);
39*795d594fSAndroid Build Coastguard Worker     return return_block;
40*795d594fSAndroid Build Coastguard Worker   }
41*795d594fSAndroid Build Coastguard Worker 
CreateBasicLoopDataFlow(HBasicBlock * loop_header,HBasicBlock * loop_body)42*795d594fSAndroid Build Coastguard Worker   void CreateBasicLoopDataFlow(HBasicBlock* loop_header, HBasicBlock* loop_body) {
43*795d594fSAndroid Build Coastguard Worker     uint32_t dex_pc = 0;
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker     // Entry block.
46*795d594fSAndroid Build Coastguard Worker     HIntConstant* const_0 = graph_->GetIntConstant(0);
47*795d594fSAndroid Build Coastguard Worker     HIntConstant* const_1 = graph_->GetIntConstant(1);
48*795d594fSAndroid Build Coastguard Worker     HIntConstant* const_128 = graph_->GetIntConstant(128);
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker     // Header block.
51*795d594fSAndroid Build Coastguard Worker     auto [phi, induction_inc] = MakeLinearLoopVar(loop_header, loop_body, const_0, const_1);
52*795d594fSAndroid Build Coastguard Worker     std::initializer_list<HInstruction*> common_env{phi, const_128, param_};
53*795d594fSAndroid Build Coastguard Worker     HInstruction* suspend_check = MakeSuspendCheck(loop_header, common_env);
54*795d594fSAndroid Build Coastguard Worker     HInstruction* loop_check = MakeCondition(loop_header, kCondGE, phi, const_128);
55*795d594fSAndroid Build Coastguard Worker     MakeIf(loop_header, loop_check);
56*795d594fSAndroid Build Coastguard Worker 
57*795d594fSAndroid Build Coastguard Worker     // Loop body block.
58*795d594fSAndroid Build Coastguard Worker     HInstruction* null_check = MakeNullCheck(loop_body, param_, common_env, dex_pc);
59*795d594fSAndroid Build Coastguard Worker     HInstruction* array_length = MakeArrayLength(loop_body, null_check, dex_pc);
60*795d594fSAndroid Build Coastguard Worker     HInstruction* bounds_check = MakeBoundsCheck(loop_body, phi, array_length, common_env, dex_pc);
61*795d594fSAndroid Build Coastguard Worker     HInstruction* array_get =
62*795d594fSAndroid Build Coastguard Worker         MakeArrayGet(loop_body, null_check, bounds_check, DataType::Type::kInt32, dex_pc);
63*795d594fSAndroid Build Coastguard Worker     HInstruction* add =  MakeBinOp<HAdd>(loop_body, DataType::Type::kInt32, array_get, const_1);
64*795d594fSAndroid Build Coastguard Worker     HInstruction* array_set =
65*795d594fSAndroid Build Coastguard Worker         MakeArraySet(loop_body, null_check, bounds_check, add, DataType::Type::kInt32, dex_pc);
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker     graph_->SetHasBoundsChecks(true);
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker   HParameterValue* param_ = nullptr;
71*795d594fSAndroid Build Coastguard Worker };
72*795d594fSAndroid Build Coastguard Worker 
TEST_F(SuperblockClonerTest,IndividualInstrCloner)73*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, IndividualInstrCloner) {
74*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
75*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
76*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
77*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
78*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker   HSuspendCheck* old_suspend_check = header->GetLoopInformation()->GetSuspendCheck();
81*795d594fSAndroid Build Coastguard Worker   CloneAndReplaceInstructionVisitor visitor(graph_);
82*795d594fSAndroid Build Coastguard Worker   // Do instruction cloning and replacement twice with different visiting order.
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker   visitor.VisitInsertionOrder();
85*795d594fSAndroid Build Coastguard Worker   size_t instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount();
86*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(instr_replaced_by_clones_count, 14u);
87*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
88*795d594fSAndroid Build Coastguard Worker 
89*795d594fSAndroid Build Coastguard Worker   visitor.VisitReversePostOrder();
90*795d594fSAndroid Build Coastguard Worker   instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount();
91*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(instr_replaced_by_clones_count, 28u);
92*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker   HSuspendCheck* new_suspend_check = header->GetLoopInformation()->GetSuspendCheck();
95*795d594fSAndroid Build Coastguard Worker   EXPECT_NE(new_suspend_check, old_suspend_check);
96*795d594fSAndroid Build Coastguard Worker   EXPECT_NE(new_suspend_check, nullptr);
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker // Tests SuperblockCloner::CloneBasicBlocks - check instruction cloning and initial remapping of
100*795d594fSAndroid Build Coastguard Worker // instructions' inputs.
TEST_F(SuperblockClonerTest,CloneBasicBlocks)101*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, CloneBasicBlocks) {
102*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* arena = GetAllocator();
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
105*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
106*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
107*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
108*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(CheckGraph());
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker   ArenaBitVector orig_bb_set(
111*795d594fSAndroid Build Coastguard Worker       arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
112*795d594fSAndroid Build Coastguard Worker   HBasicBlockMap bb_map(std::less<HBasicBlock*>(), arena->Adapter(kArenaAllocSuperblockCloner));
113*795d594fSAndroid Build Coastguard Worker   HInstructionMap hir_map(std::less<HInstruction*>(), arena->Adapter(kArenaAllocSuperblockCloner));
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
116*795d594fSAndroid Build Coastguard Worker   orig_bb_set.Union(&loop_info->GetBlocks());
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker   SuperblockCloner cloner(graph_,
119*795d594fSAndroid Build Coastguard Worker                           &orig_bb_set,
120*795d594fSAndroid Build Coastguard Worker                           &bb_map,
121*795d594fSAndroid Build Coastguard Worker                           &hir_map,
122*795d594fSAndroid Build Coastguard Worker                           /* induction_range= */ nullptr);
123*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(cloner.IsSubgraphClonable());
124*795d594fSAndroid Build Coastguard Worker 
125*795d594fSAndroid Build Coastguard Worker   cloner.CloneBasicBlocks();
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(bb_map.size(), 2u);
128*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(hir_map.size(), 12u);
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker   for (auto it : hir_map) {
131*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_instr = it.first;
132*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_instr = it.second;
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker     EXPECT_EQ(cloner.GetBlockCopy(orig_instr->GetBlock()), copy_instr->GetBlock());
135*795d594fSAndroid Build Coastguard Worker     EXPECT_EQ(orig_instr->GetKind(), copy_instr->GetKind());
136*795d594fSAndroid Build Coastguard Worker     EXPECT_EQ(orig_instr->GetType(), copy_instr->GetType());
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker     if (orig_instr->IsPhi()) {
139*795d594fSAndroid Build Coastguard Worker       continue;
140*795d594fSAndroid Build Coastguard Worker     }
141*795d594fSAndroid Build Coastguard Worker 
142*795d594fSAndroid Build Coastguard Worker     EXPECT_EQ(orig_instr->InputCount(), copy_instr->InputCount());
143*795d594fSAndroid Build Coastguard Worker 
144*795d594fSAndroid Build Coastguard Worker     // Check that inputs match.
145*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0, e = orig_instr->InputCount(); i < e; i++) {
146*795d594fSAndroid Build Coastguard Worker       HInstruction* orig_input = orig_instr->InputAt(i);
147*795d594fSAndroid Build Coastguard Worker       HInstruction* copy_input = copy_instr->InputAt(i);
148*795d594fSAndroid Build Coastguard Worker       if (cloner.IsInOrigBBSet(orig_input->GetBlock())) {
149*795d594fSAndroid Build Coastguard Worker         EXPECT_EQ(cloner.GetInstrCopy(orig_input), copy_input);
150*795d594fSAndroid Build Coastguard Worker       } else {
151*795d594fSAndroid Build Coastguard Worker         EXPECT_EQ(orig_input, copy_input);
152*795d594fSAndroid Build Coastguard Worker       }
153*795d594fSAndroid Build Coastguard Worker     }
154*795d594fSAndroid Build Coastguard Worker 
155*795d594fSAndroid Build Coastguard Worker     EXPECT_EQ(orig_instr->HasEnvironment(), copy_instr->HasEnvironment());
156*795d594fSAndroid Build Coastguard Worker 
157*795d594fSAndroid Build Coastguard Worker     // Check that environments match.
158*795d594fSAndroid Build Coastguard Worker     if (orig_instr->HasEnvironment()) {
159*795d594fSAndroid Build Coastguard Worker       HEnvironment* orig_env = orig_instr->GetEnvironment();
160*795d594fSAndroid Build Coastguard Worker       HEnvironment* copy_env = copy_instr->GetEnvironment();
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker       EXPECT_EQ(copy_env->GetParent(), nullptr);
163*795d594fSAndroid Build Coastguard Worker       EXPECT_EQ(orig_env->Size(), copy_env->Size());
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker       for (size_t i = 0, e = orig_env->Size(); i < e; i++) {
166*795d594fSAndroid Build Coastguard Worker         HInstruction* orig_input = orig_env->GetInstructionAt(i);
167*795d594fSAndroid Build Coastguard Worker         HInstruction* copy_input = copy_env->GetInstructionAt(i);
168*795d594fSAndroid Build Coastguard Worker         if (cloner.IsInOrigBBSet(orig_input->GetBlock())) {
169*795d594fSAndroid Build Coastguard Worker           EXPECT_EQ(cloner.GetInstrCopy(orig_input), copy_input);
170*795d594fSAndroid Build Coastguard Worker         } else {
171*795d594fSAndroid Build Coastguard Worker           EXPECT_EQ(orig_input, copy_input);
172*795d594fSAndroid Build Coastguard Worker         }
173*795d594fSAndroid Build Coastguard Worker       }
174*795d594fSAndroid Build Coastguard Worker     }
175*795d594fSAndroid Build Coastguard Worker   }
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker // SuperblockCloner::CleanUpControlFlow - checks algorithms of local adjustments of the control
179*795d594fSAndroid Build Coastguard Worker // flow.
TEST_F(SuperblockClonerTest,AdjustControlFlowInfo)180*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, AdjustControlFlowInfo) {
181*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* arena = GetAllocator();
182*795d594fSAndroid Build Coastguard Worker 
183*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
184*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
185*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
186*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
187*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(CheckGraph());
188*795d594fSAndroid Build Coastguard Worker 
189*795d594fSAndroid Build Coastguard Worker   ArenaBitVector orig_bb_set(
190*795d594fSAndroid Build Coastguard Worker       arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
191*795d594fSAndroid Build Coastguard Worker 
192*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
193*795d594fSAndroid Build Coastguard Worker   orig_bb_set.Union(&loop_info->GetBlocks());
194*795d594fSAndroid Build Coastguard Worker 
195*795d594fSAndroid Build Coastguard Worker   SuperblockCloner cloner(graph_,
196*795d594fSAndroid Build Coastguard Worker                           &orig_bb_set,
197*795d594fSAndroid Build Coastguard Worker                           /* bb_map= */ nullptr,
198*795d594fSAndroid Build Coastguard Worker                           /* hir_map= */ nullptr,
199*795d594fSAndroid Build Coastguard Worker                           /* induction_range= */ nullptr);
200*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(cloner.IsSubgraphClonable());
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker   cloner.FindAndSetLocalAreaForAdjustments();
203*795d594fSAndroid Build Coastguard Worker   cloner.CleanUpControlFlow();
204*795d594fSAndroid Build Coastguard Worker 
205*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(entry_block_->Dominates(header));
208*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(entry_block_->Dominates(exit_block_));
209*795d594fSAndroid Build Coastguard Worker 
210*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(header->GetLoopInformation(), loop_info);
211*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetHeader(), header);
212*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop_info->Contains(*loop_body));
213*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop_info->IsBackEdge(*loop_body));
214*795d594fSAndroid Build Coastguard Worker }
215*795d594fSAndroid Build Coastguard Worker 
216*795d594fSAndroid Build Coastguard Worker // Tests IsSubgraphConnected function for negative case.
TEST_F(SuperblockClonerTest,IsGraphConnected)217*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, IsGraphConnected) {
218*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* arena = GetAllocator();
219*795d594fSAndroid Build Coastguard Worker 
220*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
221*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
222*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
223*795d594fSAndroid Build Coastguard Worker   HBasicBlock* unreachable_block = AddNewBlock();
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker   HBasicBlockSet bb_set(
226*795d594fSAndroid Build Coastguard Worker       arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
227*795d594fSAndroid Build Coastguard Worker   bb_set.SetBit(header->GetBlockId());
228*795d594fSAndroid Build Coastguard Worker   bb_set.SetBit(loop_body->GetBlockId());
229*795d594fSAndroid Build Coastguard Worker   bb_set.SetBit(unreachable_block->GetBlockId());
230*795d594fSAndroid Build Coastguard Worker 
231*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(IsSubgraphConnected(&bb_set, graph_));
232*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(bb_set.NumSetBits(), 1u);
233*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(bb_set.IsBitSet(unreachable_block->GetBlockId()));
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker // Tests SuperblockCloner for loop peeling case.
237*795d594fSAndroid Build Coastguard Worker //
238*795d594fSAndroid Build Coastguard Worker // See an ASCII graphics example near LoopClonerHelper::DoPeeling.
TEST_F(SuperblockClonerTest,LoopPeeling)239*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, LoopPeeling) {
240*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
241*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
242*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
243*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
244*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
245*795d594fSAndroid Build Coastguard Worker 
246*795d594fSAndroid Build Coastguard Worker   HBasicBlockMap bb_map(
247*795d594fSAndroid Build Coastguard Worker       std::less<HBasicBlock*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
248*795d594fSAndroid Build Coastguard Worker   HInstructionMap hir_map(
249*795d594fSAndroid Build Coastguard Worker       std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
250*795d594fSAndroid Build Coastguard Worker 
251*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
252*795d594fSAndroid Build Coastguard Worker   LoopClonerHelper helper(loop_info, &bb_map, &hir_map, /* induction_range= */ nullptr);
253*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(helper.IsLoopClonable());
254*795d594fSAndroid Build Coastguard Worker   HBasicBlock* new_header = helper.DoPeeling();
255*795d594fSAndroid Build Coastguard Worker   HLoopInformation* new_loop_info = new_header->GetLoopInformation();
256*795d594fSAndroid Build Coastguard Worker 
257*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   // Check loop body successors.
260*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_body->GetSingleSuccessor(), header);
261*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(bb_map.Get(loop_body)->GetSingleSuccessor(), header);
262*795d594fSAndroid Build Coastguard Worker 
263*795d594fSAndroid Build Coastguard Worker   // Check loop structure.
264*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(header, new_header);
265*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(new_loop_info->GetHeader(), header);
266*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(new_loop_info->GetBackEdges().size(), 1u);
267*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(new_loop_info->GetBackEdges()[0], loop_body);
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker 
270*795d594fSAndroid Build Coastguard Worker // Tests SuperblockCloner for loop unrolling case.
271*795d594fSAndroid Build Coastguard Worker //
272*795d594fSAndroid Build Coastguard Worker // See an ASCII graphics example near LoopClonerHelper::DoUnrolling.
TEST_F(SuperblockClonerTest,LoopUnrolling)273*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, LoopUnrolling) {
274*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
275*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
276*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
277*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
278*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
279*795d594fSAndroid Build Coastguard Worker 
280*795d594fSAndroid Build Coastguard Worker   HBasicBlockMap bb_map(
281*795d594fSAndroid Build Coastguard Worker       std::less<HBasicBlock*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
282*795d594fSAndroid Build Coastguard Worker   HInstructionMap hir_map(
283*795d594fSAndroid Build Coastguard Worker       std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
284*795d594fSAndroid Build Coastguard Worker 
285*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
286*795d594fSAndroid Build Coastguard Worker   LoopClonerHelper helper(loop_info, &bb_map, &hir_map, /* induction_range= */ nullptr);
287*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(helper.IsLoopClonable());
288*795d594fSAndroid Build Coastguard Worker   HBasicBlock* new_header = helper.DoUnrolling();
289*795d594fSAndroid Build Coastguard Worker 
290*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
291*795d594fSAndroid Build Coastguard Worker 
292*795d594fSAndroid Build Coastguard Worker   // Check loop body successors.
293*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_body->GetSingleSuccessor(), bb_map.Get(header));
294*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(bb_map.Get(loop_body)->GetSingleSuccessor(), header);
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker   // Check loop structure.
297*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(header, new_header);
298*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info, new_header->GetLoopInformation());
299*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetHeader(), new_header);
300*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetBackEdges().size(), 1u);
301*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetBackEdges()[0], bb_map.Get(loop_body));
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker 
304*795d594fSAndroid Build Coastguard Worker // Tests SuperblockCloner for loop versioning case.
305*795d594fSAndroid Build Coastguard Worker //
306*795d594fSAndroid Build Coastguard Worker // See an ASCII graphics example near LoopClonerHelper::DoVersioning.
TEST_F(SuperblockClonerTest,LoopVersioning)307*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, LoopVersioning) {
308*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
309*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
310*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
311*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
312*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
313*795d594fSAndroid Build Coastguard Worker 
314*795d594fSAndroid Build Coastguard Worker   HBasicBlockMap bb_map(
315*795d594fSAndroid Build Coastguard Worker       std::less<HBasicBlock*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
316*795d594fSAndroid Build Coastguard Worker   HInstructionMap hir_map(
317*795d594fSAndroid Build Coastguard Worker       std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
318*795d594fSAndroid Build Coastguard Worker 
319*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
320*795d594fSAndroid Build Coastguard Worker   HBasicBlock* original_preheader = loop_info->GetPreHeader();
321*795d594fSAndroid Build Coastguard Worker   LoopClonerHelper helper(loop_info, &bb_map, &hir_map, /* induction_range= */ nullptr);
322*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(helper.IsLoopClonable());
323*795d594fSAndroid Build Coastguard Worker   HBasicBlock* new_header = helper.DoVersioning();
324*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(header, new_header);
325*795d594fSAndroid Build Coastguard Worker 
326*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
327*795d594fSAndroid Build Coastguard Worker 
328*795d594fSAndroid Build Coastguard Worker   HBasicBlock* second_header = bb_map.Get(header);
329*795d594fSAndroid Build Coastguard Worker   HBasicBlock* second_body = bb_map.Get(loop_body);
330*795d594fSAndroid Build Coastguard Worker   HLoopInformation* second_loop_info = second_header->GetLoopInformation();
331*795d594fSAndroid Build Coastguard Worker 
332*795d594fSAndroid Build Coastguard Worker   // Check loop body successors.
333*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_body->GetSingleSuccessor(), header);
334*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(second_body->GetSingleSuccessor(), second_header);
335*795d594fSAndroid Build Coastguard Worker 
336*795d594fSAndroid Build Coastguard Worker   // Check loop structure.
337*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info, header->GetLoopInformation());
338*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetHeader(), header);
339*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(second_loop_info->GetHeader(), second_header);
340*795d594fSAndroid Build Coastguard Worker 
341*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetBackEdges().size(), 1u);
342*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(second_loop_info->GetBackEdges().size(), 1u);
343*795d594fSAndroid Build Coastguard Worker 
344*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop_info->GetBackEdges()[0], loop_body);
345*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(second_loop_info->GetBackEdges()[0], second_body);
346*795d594fSAndroid Build Coastguard Worker 
347*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(original_preheader->GetSuccessors().size(), 2u);
348*795d594fSAndroid Build Coastguard Worker }
349*795d594fSAndroid Build Coastguard Worker 
350*795d594fSAndroid Build Coastguard Worker // Checks that loop unrolling works fine for a loop with multiple back edges. Tests that after
351*795d594fSAndroid Build Coastguard Worker // the transformation the loop has a single preheader.
TEST_F(SuperblockClonerTest,LoopPeelingMultipleBackEdges)352*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, LoopPeelingMultipleBackEdges) {
353*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
354*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
355*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
356*795d594fSAndroid Build Coastguard Worker 
357*795d594fSAndroid Build Coastguard Worker   // Transform a basic loop to have multiple back edges.
358*795d594fSAndroid Build Coastguard Worker   HBasicBlock* latch = header->GetSuccessors()[1];
359*795d594fSAndroid Build Coastguard Worker   HBasicBlock* if_block = AddNewBlock();
360*795d594fSAndroid Build Coastguard Worker   HBasicBlock* temp1 = AddNewBlock();
361*795d594fSAndroid Build Coastguard Worker   header->ReplaceSuccessor(latch, if_block);
362*795d594fSAndroid Build Coastguard Worker   if_block->AddSuccessor(latch);
363*795d594fSAndroid Build Coastguard Worker   if_block->AddSuccessor(temp1);
364*795d594fSAndroid Build Coastguard Worker   temp1->AddSuccessor(header);
365*795d594fSAndroid Build Coastguard Worker 
366*795d594fSAndroid Build Coastguard Worker   MakeIf(if_block, param_);
367*795d594fSAndroid Build Coastguard Worker 
368*795d594fSAndroid Build Coastguard Worker   HInstructionIterator it(header->GetPhis());
369*795d594fSAndroid Build Coastguard Worker   DCHECK(!it.Done());
370*795d594fSAndroid Build Coastguard Worker   HPhi* loop_phi = it.Current()->AsPhi();
371*795d594fSAndroid Build Coastguard Worker   HInstruction* temp_add =
372*795d594fSAndroid Build Coastguard Worker       MakeBinOp<HAdd>(temp1, DataType::Type::kInt32, loop_phi, graph_->GetIntConstant(2));
373*795d594fSAndroid Build Coastguard Worker   MakeGoto(temp1);
374*795d594fSAndroid Build Coastguard Worker   loop_phi->AddInput(temp_add);
375*795d594fSAndroid Build Coastguard Worker 
376*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
377*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
378*795d594fSAndroid Build Coastguard Worker 
379*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
380*795d594fSAndroid Build Coastguard Worker   LoopClonerSimpleHelper helper(loop_info, /* induction_range= */ nullptr);
381*795d594fSAndroid Build Coastguard Worker   HBasicBlock* new_header = helper.DoPeeling();
382*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(header, new_header);
383*795d594fSAndroid Build Coastguard Worker 
384*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
385*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(header->GetPredecessors().size(), 3u);
386*795d594fSAndroid Build Coastguard Worker }
387*795d594fSAndroid Build Coastguard Worker 
CheckLoopStructureForLoopPeelingNested(HBasicBlock * loop1_header,HBasicBlock * loop2_header,HBasicBlock * loop3_header)388*795d594fSAndroid Build Coastguard Worker static void CheckLoopStructureForLoopPeelingNested(HBasicBlock* loop1_header,
389*795d594fSAndroid Build Coastguard Worker                                                    HBasicBlock* loop2_header,
390*795d594fSAndroid Build Coastguard Worker                                                    HBasicBlock* loop3_header) {
391*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop1_header->GetLoopInformation()->GetHeader(), loop1_header);
392*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop2_header->GetLoopInformation()->GetHeader(), loop2_header);
393*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop3_header->GetLoopInformation()->GetHeader(), loop3_header);
394*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop1_header->GetLoopInformation()->GetPreHeader()->GetLoopInformation(), nullptr);
395*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop2_header->GetLoopInformation()->GetPreHeader()->GetLoopInformation(), nullptr);
396*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop3_header->GetLoopInformation()->GetPreHeader()->GetLoopInformation()->GetHeader(),
397*795d594fSAndroid Build Coastguard Worker             loop2_header);
398*795d594fSAndroid Build Coastguard Worker }
399*795d594fSAndroid Build Coastguard Worker 
TEST_F(SuperblockClonerTest,LoopPeelingNested)400*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, LoopPeelingNested) {
401*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
402*795d594fSAndroid Build Coastguard Worker 
403*795d594fSAndroid Build Coastguard Worker   // Create the following nested structure of loops
404*795d594fSAndroid Build Coastguard Worker   //   Headers:  1    2 3
405*795d594fSAndroid Build Coastguard Worker   //             [ ], [ [ ] ]
406*795d594fSAndroid Build Coastguard Worker   auto [preheader1, header1, body1] = CreateWhileLoop(return_block);
407*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header1, body1);
408*795d594fSAndroid Build Coastguard Worker 
409*795d594fSAndroid Build Coastguard Worker   auto [preheader2, header2, body2_end] = CreateWhileLoop(return_block);
410*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header2, body2_end);
411*795d594fSAndroid Build Coastguard Worker 
412*795d594fSAndroid Build Coastguard Worker   auto [preheader3, header3, body3] = CreateWhileLoop(body2_end);
413*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header3, body3);
414*795d594fSAndroid Build Coastguard Worker 
415*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
416*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
417*795d594fSAndroid Build Coastguard Worker 
418*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop2_info_before = header2->GetLoopInformation();
419*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop3_info_before = header3->GetLoopInformation();
420*795d594fSAndroid Build Coastguard Worker 
421*795d594fSAndroid Build Coastguard Worker   // Check nested loops structure.
422*795d594fSAndroid Build Coastguard Worker   CheckLoopStructureForLoopPeelingNested(header1, header2, header3);
423*795d594fSAndroid Build Coastguard Worker   LoopClonerSimpleHelper helper(header1->GetLoopInformation(), /* induction_range= */ nullptr);
424*795d594fSAndroid Build Coastguard Worker   helper.DoPeeling();
425*795d594fSAndroid Build Coastguard Worker   // Check that nested loops structure has not changed after the transformation.
426*795d594fSAndroid Build Coastguard Worker   CheckLoopStructureForLoopPeelingNested(header1, header2, header3);
427*795d594fSAndroid Build Coastguard Worker 
428*795d594fSAndroid Build Coastguard Worker   // Test that the loop info is preserved.
429*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop2_info_before, header2->GetLoopInformation());
430*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop3_info_before, header3->GetLoopInformation());
431*795d594fSAndroid Build Coastguard Worker 
432*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop3_info_before->GetPreHeader()->GetLoopInformation(), loop2_info_before);
433*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop2_info_before->GetPreHeader()->GetLoopInformation(), nullptr);
434*795d594fSAndroid Build Coastguard Worker 
435*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(helper.GetRegionToBeAdjusted(), nullptr);
436*795d594fSAndroid Build Coastguard Worker 
437*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker 
440*795d594fSAndroid Build Coastguard Worker // Checks that the loop population is correctly propagated after an inner loop is peeled.
TEST_F(SuperblockClonerTest,OuterLoopPopulationAfterInnerPeeled)441*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, OuterLoopPopulationAfterInnerPeeled) {
442*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
443*795d594fSAndroid Build Coastguard Worker 
444*795d594fSAndroid Build Coastguard Worker   // Create the following nested structure of loops
445*795d594fSAndroid Build Coastguard Worker   //   Headers:  1 2 3        4
446*795d594fSAndroid Build Coastguard Worker   //             [ [ [ ] ] ], [ ]
447*795d594fSAndroid Build Coastguard Worker   auto [preheader1, header1, body1_end] = CreateWhileLoop(return_block);
448*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header1, body1_end);
449*795d594fSAndroid Build Coastguard Worker 
450*795d594fSAndroid Build Coastguard Worker   auto [preheader2, header2, body2_end] = CreateWhileLoop(body1_end);
451*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header2, body2_end);
452*795d594fSAndroid Build Coastguard Worker 
453*795d594fSAndroid Build Coastguard Worker   auto [preheader3, header3, body3] = CreateWhileLoop(body2_end);
454*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header3, body3);
455*795d594fSAndroid Build Coastguard Worker 
456*795d594fSAndroid Build Coastguard Worker   auto [preheader4, header4, body4] = CreateWhileLoop(return_block);
457*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header4, body4);
458*795d594fSAndroid Build Coastguard Worker 
459*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
460*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
461*795d594fSAndroid Build Coastguard Worker 
462*795d594fSAndroid Build Coastguard Worker   LoopClonerSimpleHelper helper(header3->GetLoopInformation(), /* induction_range= */ nullptr);
463*795d594fSAndroid Build Coastguard Worker   helper.DoPeeling();
464*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop1 = header1->GetLoopInformation();
465*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop2 = header2->GetLoopInformation();
466*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop3 = header3->GetLoopInformation();
467*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop4 = header4->GetLoopInformation();
468*795d594fSAndroid Build Coastguard Worker 
469*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->Contains(*header2));
470*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->Contains(*header3));
471*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->Contains(*header3->GetLoopInformation()->GetPreHeader()));
472*795d594fSAndroid Build Coastguard Worker 
473*795d594fSAndroid Build Coastguard Worker   // Check that loop4 info has not been touched after local run of AnalyzeLoops.
474*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop4, header4->GetLoopInformation());
475*795d594fSAndroid Build Coastguard Worker 
476*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->IsIn(*loop1));
477*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop2->IsIn(*loop1));
478*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop3->IsIn(*loop1));
479*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop3->IsIn(*loop2));
480*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(!loop4->IsIn(*loop1));
481*795d594fSAndroid Build Coastguard Worker 
482*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop4->GetPreHeader()->GetLoopInformation(), nullptr);
483*795d594fSAndroid Build Coastguard Worker 
484*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(helper.GetRegionToBeAdjusted(), loop2);
485*795d594fSAndroid Build Coastguard Worker 
486*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
487*795d594fSAndroid Build Coastguard Worker }
488*795d594fSAndroid Build Coastguard Worker 
489*795d594fSAndroid Build Coastguard Worker // Checks the case when inner loop have an exit not to its immediate outer_loop but some other loop
490*795d594fSAndroid Build Coastguard Worker // in the hierarchy. Loop population information must be valid after loop peeling.
TEST_F(SuperblockClonerTest,NestedCaseExitToOutermost)491*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, NestedCaseExitToOutermost) {
492*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
493*795d594fSAndroid Build Coastguard Worker 
494*795d594fSAndroid Build Coastguard Worker   // Create the following nested structure of loops then peel loop3.
495*795d594fSAndroid Build Coastguard Worker   //   Headers:  1 2 3
496*795d594fSAndroid Build Coastguard Worker   //             [ [ [ ] ] ]
497*795d594fSAndroid Build Coastguard Worker   auto [preheader1, header1, body1_end] = CreateWhileLoop(return_block);
498*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header1, body1_end);
499*795d594fSAndroid Build Coastguard Worker 
500*795d594fSAndroid Build Coastguard Worker   auto [preheader2, header2, body2_end] = CreateWhileLoop(body1_end);
501*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header2, body2_end);
502*795d594fSAndroid Build Coastguard Worker 
503*795d594fSAndroid Build Coastguard Worker   auto [preheader3, header3, body3] = CreateWhileLoop(body2_end);
504*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header3, body3);
505*795d594fSAndroid Build Coastguard Worker 
506*795d594fSAndroid Build Coastguard Worker   // Change the loop3 - insert an exit which leads to loop1.
507*795d594fSAndroid Build Coastguard Worker   HBasicBlock* loop3_extra_if_block = AddNewBlock();
508*795d594fSAndroid Build Coastguard Worker   MakeIf(loop3_extra_if_block, param_);
509*795d594fSAndroid Build Coastguard Worker 
510*795d594fSAndroid Build Coastguard Worker   header3->ReplaceSuccessor(body3, loop3_extra_if_block);
511*795d594fSAndroid Build Coastguard Worker   // Note: After this, both edges to `body1_end` shall be critical edges.
512*795d594fSAndroid Build Coastguard Worker   loop3_extra_if_block->AddSuccessor(body1_end);  // Long exit.
513*795d594fSAndroid Build Coastguard Worker   loop3_extra_if_block->AddSuccessor(body3);
514*795d594fSAndroid Build Coastguard Worker 
515*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
516*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
517*795d594fSAndroid Build Coastguard Worker 
518*795d594fSAndroid Build Coastguard Worker   HBasicBlock* loop3_long_exit = loop3_extra_if_block->GetSuccessors()[0];
519*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(header1->GetLoopInformation()->Contains(*loop3_long_exit));
520*795d594fSAndroid Build Coastguard Worker 
521*795d594fSAndroid Build Coastguard Worker   LoopClonerSimpleHelper helper(header3->GetLoopInformation(), /* induction_range= */ nullptr);
522*795d594fSAndroid Build Coastguard Worker   helper.DoPeeling();
523*795d594fSAndroid Build Coastguard Worker 
524*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop1 = header1->GetLoopInformation();
525*795d594fSAndroid Build Coastguard Worker   // Check that after the transformation the local area for CF adjustments has been chosen
526*795d594fSAndroid Build Coastguard Worker   // correctly and loop population has been updated.
527*795d594fSAndroid Build Coastguard Worker   loop3_long_exit = loop3_extra_if_block->GetSuccessors()[0];
528*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->Contains(*loop3_long_exit));
529*795d594fSAndroid Build Coastguard Worker 
530*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(helper.GetRegionToBeAdjusted(), loop1);
531*795d594fSAndroid Build Coastguard Worker 
532*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->Contains(*header3));
533*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->Contains(*header3->GetLoopInformation()->GetPreHeader()));
534*795d594fSAndroid Build Coastguard Worker 
535*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
536*795d594fSAndroid Build Coastguard Worker }
537*795d594fSAndroid Build Coastguard Worker 
TEST_F(SuperblockClonerTest,FastCaseCheck)538*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, FastCaseCheck) {
539*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* arena = GetAllocator();
540*795d594fSAndroid Build Coastguard Worker 
541*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
542*795d594fSAndroid Build Coastguard Worker   auto [preheader, header, loop_body] = CreateWhileLoop(return_block);
543*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header, loop_body);
544*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
545*795d594fSAndroid Build Coastguard Worker 
546*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop_info = header->GetLoopInformation();
547*795d594fSAndroid Build Coastguard Worker 
548*795d594fSAndroid Build Coastguard Worker   ArenaBitVector orig_bb_set(
549*795d594fSAndroid Build Coastguard Worker       arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
550*795d594fSAndroid Build Coastguard Worker   orig_bb_set.Union(&loop_info->GetBlocks());
551*795d594fSAndroid Build Coastguard Worker 
552*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_orig_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
553*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_copy_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
554*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_incoming(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
555*795d594fSAndroid Build Coastguard Worker 
556*795d594fSAndroid Build Coastguard Worker   CollectRemappingInfoForPeelUnroll(true,
557*795d594fSAndroid Build Coastguard Worker                                     loop_info,
558*795d594fSAndroid Build Coastguard Worker                                     &remap_orig_internal,
559*795d594fSAndroid Build Coastguard Worker                                     &remap_copy_internal,
560*795d594fSAndroid Build Coastguard Worker                                     &remap_incoming);
561*795d594fSAndroid Build Coastguard Worker 
562*795d594fSAndroid Build Coastguard Worker   // Insert some extra nodes and edges.
563*795d594fSAndroid Build Coastguard Worker   ASSERT_EQ(preheader, loop_info->GetPreHeader());
564*795d594fSAndroid Build Coastguard Worker   orig_bb_set.SetBit(preheader->GetBlockId());
565*795d594fSAndroid Build Coastguard Worker 
566*795d594fSAndroid Build Coastguard Worker   // Adjust incoming edges.
567*795d594fSAndroid Build Coastguard Worker   remap_incoming.clear();
568*795d594fSAndroid Build Coastguard Worker   remap_incoming.insert(HEdge(preheader->GetSinglePredecessor(), preheader));
569*795d594fSAndroid Build Coastguard Worker 
570*795d594fSAndroid Build Coastguard Worker   HBasicBlockMap bb_map(std::less<HBasicBlock*>(), arena->Adapter(kArenaAllocSuperblockCloner));
571*795d594fSAndroid Build Coastguard Worker   HInstructionMap hir_map(std::less<HInstruction*>(), arena->Adapter(kArenaAllocSuperblockCloner));
572*795d594fSAndroid Build Coastguard Worker 
573*795d594fSAndroid Build Coastguard Worker   SuperblockCloner cloner(graph_,
574*795d594fSAndroid Build Coastguard Worker                           &orig_bb_set,
575*795d594fSAndroid Build Coastguard Worker                           &bb_map,
576*795d594fSAndroid Build Coastguard Worker                           &hir_map,
577*795d594fSAndroid Build Coastguard Worker                           /* induction_range= */ nullptr);
578*795d594fSAndroid Build Coastguard Worker   cloner.SetSuccessorRemappingInfo(&remap_orig_internal, &remap_copy_internal, &remap_incoming);
579*795d594fSAndroid Build Coastguard Worker 
580*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(cloner.IsFastCase());
581*795d594fSAndroid Build Coastguard Worker }
582*795d594fSAndroid Build Coastguard Worker 
583*795d594fSAndroid Build Coastguard Worker // Helper for FindCommonLoop which also check that FindCommonLoop is symmetric.
FindCommonLoopCheck(HLoopInformation * loop1,HLoopInformation * loop2)584*795d594fSAndroid Build Coastguard Worker static HLoopInformation* FindCommonLoopCheck(HLoopInformation* loop1, HLoopInformation* loop2) {
585*795d594fSAndroid Build Coastguard Worker   HLoopInformation* common_loop12 = FindCommonLoop(loop1, loop2);
586*795d594fSAndroid Build Coastguard Worker   HLoopInformation* common_loop21 = FindCommonLoop(loop2, loop1);
587*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(common_loop21, common_loop12);
588*795d594fSAndroid Build Coastguard Worker   return common_loop12;
589*795d594fSAndroid Build Coastguard Worker }
590*795d594fSAndroid Build Coastguard Worker 
591*795d594fSAndroid Build Coastguard Worker // Tests FindCommonLoop function on a loop nest.
TEST_F(SuperblockClonerTest,FindCommonLoop)592*795d594fSAndroid Build Coastguard Worker TEST_F(SuperblockClonerTest, FindCommonLoop) {
593*795d594fSAndroid Build Coastguard Worker   HBasicBlock* header = nullptr;
594*795d594fSAndroid Build Coastguard Worker   HBasicBlock* loop_body = nullptr;
595*795d594fSAndroid Build Coastguard Worker 
596*795d594fSAndroid Build Coastguard Worker   HBasicBlock* return_block = InitGraphAndParameters();
597*795d594fSAndroid Build Coastguard Worker 
598*795d594fSAndroid Build Coastguard Worker   // Create the following nested structure of loops
599*795d594fSAndroid Build Coastguard Worker   //   Headers:  1 2 3      4      5
600*795d594fSAndroid Build Coastguard Worker   //             [ [ [ ] ], [ ] ], [ ]
601*795d594fSAndroid Build Coastguard Worker   auto [preheader1, header1, body1_end] = CreateWhileLoop(return_block);
602*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header1, body1_end);
603*795d594fSAndroid Build Coastguard Worker 
604*795d594fSAndroid Build Coastguard Worker   auto [preheader2, header2, body2_end] = CreateWhileLoop(body1_end);
605*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header2, body2_end);
606*795d594fSAndroid Build Coastguard Worker 
607*795d594fSAndroid Build Coastguard Worker   auto [preheader3, header3, body3] = CreateWhileLoop(body2_end);
608*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header3, body3);
609*795d594fSAndroid Build Coastguard Worker 
610*795d594fSAndroid Build Coastguard Worker   auto [preheader4, header4, body4] = CreateWhileLoop(body1_end);
611*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header4, body4);
612*795d594fSAndroid Build Coastguard Worker 
613*795d594fSAndroid Build Coastguard Worker   auto [preheader5, header5, body5] = CreateWhileLoop(return_block);
614*795d594fSAndroid Build Coastguard Worker   CreateBasicLoopDataFlow(header5, body5);
615*795d594fSAndroid Build Coastguard Worker 
616*795d594fSAndroid Build Coastguard Worker   graph_->BuildDominatorTree();
617*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(CheckGraph());
618*795d594fSAndroid Build Coastguard Worker 
619*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop1 = header1->GetLoopInformation();
620*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop2 = header2->GetLoopInformation();
621*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop3 = header3->GetLoopInformation();
622*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop4 = header4->GetLoopInformation();
623*795d594fSAndroid Build Coastguard Worker   HLoopInformation* loop5 = header5->GetLoopInformation();
624*795d594fSAndroid Build Coastguard Worker 
625*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop1->IsIn(*loop1));
626*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop2->IsIn(*loop1));
627*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop3->IsIn(*loop1));
628*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop3->IsIn(*loop2));
629*795d594fSAndroid Build Coastguard Worker   EXPECT_TRUE(loop4->IsIn(*loop1));
630*795d594fSAndroid Build Coastguard Worker 
631*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(loop5->IsIn(*loop1));
632*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(loop4->IsIn(*loop2));
633*795d594fSAndroid Build Coastguard Worker   EXPECT_FALSE(loop4->IsIn(*loop3));
634*795d594fSAndroid Build Coastguard Worker 
635*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop1->GetPreHeader()->GetLoopInformation(), nullptr);
636*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(loop4->GetPreHeader()->GetLoopInformation(), loop1);
637*795d594fSAndroid Build Coastguard Worker 
638*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(nullptr, nullptr), nullptr);
639*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop2, nullptr), nullptr);
640*795d594fSAndroid Build Coastguard Worker 
641*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop1, loop1), loop1);
642*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop1, loop2), loop1);
643*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop1, loop3), loop1);
644*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop1, loop4), loop1);
645*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop1, loop5), nullptr);
646*795d594fSAndroid Build Coastguard Worker 
647*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop2, loop3), loop2);
648*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop2, loop4), loop1);
649*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop2, loop5), nullptr);
650*795d594fSAndroid Build Coastguard Worker 
651*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop3, loop4), loop1);
652*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop3, loop5), nullptr);
653*795d594fSAndroid Build Coastguard Worker 
654*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop4, loop5), nullptr);
655*795d594fSAndroid Build Coastguard Worker 
656*795d594fSAndroid Build Coastguard Worker   EXPECT_EQ(FindCommonLoopCheck(loop5, loop5), loop5);
657*795d594fSAndroid Build Coastguard Worker }
658*795d594fSAndroid Build Coastguard Worker 
659*795d594fSAndroid Build Coastguard Worker }  // namespace art
660