blob: fa60e4a474946e57f8772963392572311547625b [file] [log] [blame]
Artem Serovcced8ba2017-07-19 18:18:09 +01001/*
2 * Copyright (C) 2017 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
Vladimir Markoe2727152019-10-10 10:46:42 +010017#include "base/macros.h"
Artem Serovcced8ba2017-07-19 18:18:09 +010018#include "graph_checker.h"
19#include "nodes.h"
20#include "optimizing_unit_test.h"
Artem Serov7f4aff62017-06-21 17:02:18 +010021#include "superblock_cloner.h"
Artem Serovcced8ba2017-07-19 18:18:09 +010022
23#include "gtest/gtest.h"
24
Vladimir Markoe2727152019-10-10 10:46:42 +010025namespace art HIDDEN {
Artem Serovcced8ba2017-07-19 18:18:09 +010026
Artem Serov7f4aff62017-06-21 17:02:18 +010027using HBasicBlockMap = SuperblockCloner::HBasicBlockMap;
28using HInstructionMap = SuperblockCloner::HInstructionMap;
Artem Serov02eebcf2017-12-13 19:48:31 +000029using HBasicBlockSet = SuperblockCloner::HBasicBlockSet;
30using HEdgeSet = SuperblockCloner::HEdgeSet;
Artem Serov7f4aff62017-06-21 17:02:18 +010031
Artem Serovcced8ba2017-07-19 18:18:09 +010032// This class provides methods and helpers for testing various cloning and copying routines:
33// individual instruction cloning and cloning of the more coarse-grain structures.
Artem Serov15f95b12018-06-29 15:30:36 +010034class SuperblockClonerTest : public ImprovedOptimizingUnitTest {
Artem Serovcced8ba2017-07-19 18:18:09 +010035 public:
Artem Serov02eebcf2017-12-13 19:48:31 +000036 void CreateBasicLoopControlFlow(HBasicBlock* position,
37 HBasicBlock* successor,
38 /* out */ HBasicBlock** header_p,
39 /* out */ HBasicBlock** body_p) {
40 HBasicBlock* loop_preheader = new (GetAllocator()) HBasicBlock(graph_);
41 HBasicBlock* loop_header = new (GetAllocator()) HBasicBlock(graph_);
42 HBasicBlock* loop_body = new (GetAllocator()) HBasicBlock(graph_);
43
44 graph_->AddBlock(loop_preheader);
45 graph_->AddBlock(loop_header);
46 graph_->AddBlock(loop_body);
47
48 position->ReplaceSuccessor(successor, loop_preheader);
49
50 loop_preheader->AddSuccessor(loop_header);
51 // Loop exit first to have a proper exit condition/target for HIf.
52 loop_header->AddSuccessor(successor);
53 loop_header->AddSuccessor(loop_body);
54 loop_body->AddSuccessor(loop_header);
55
56 *header_p = loop_header;
57 *body_p = loop_body;
58 }
59
Artem Serovcced8ba2017-07-19 18:18:09 +010060 void CreateBasicLoopDataFlow(HBasicBlock* loop_header, HBasicBlock* loop_body) {
61 uint32_t dex_pc = 0;
62
63 // Entry block.
64 HIntConstant* const_0 = graph_->GetIntConstant(0);
65 HIntConstant* const_1 = graph_->GetIntConstant(1);
66 HIntConstant* const_128 = graph_->GetIntConstant(128);
67
68 // Header block.
69 HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
70 HInstruction* suspend_check = new (GetAllocator()) HSuspendCheck();
Artem Serov02eebcf2017-12-13 19:48:31 +000071 HInstruction* loop_check = new (GetAllocator()) HGreaterThanOrEqual(phi, const_128);
Artem Serovcced8ba2017-07-19 18:18:09 +010072
73 loop_header->AddPhi(phi);
74 loop_header->AddInstruction(suspend_check);
Artem Serov02eebcf2017-12-13 19:48:31 +000075 loop_header->AddInstruction(loop_check);
76 loop_header->AddInstruction(new (GetAllocator()) HIf(loop_check));
Artem Serovcced8ba2017-07-19 18:18:09 +010077
78 // Loop body block.
79 HInstruction* null_check = new (GetAllocator()) HNullCheck(parameter_, dex_pc);
80 HInstruction* array_length = new (GetAllocator()) HArrayLength(null_check, dex_pc);
81 HInstruction* bounds_check = new (GetAllocator()) HBoundsCheck(phi, array_length, dex_pc);
82 HInstruction* array_get =
83 new (GetAllocator()) HArrayGet(null_check, bounds_check, DataType::Type::kInt32, dex_pc);
84 HInstruction* add = new (GetAllocator()) HAdd(DataType::Type::kInt32, array_get, const_1);
Artem Serov02eebcf2017-12-13 19:48:31 +000085 HInstruction* array_set = new (GetAllocator()) HArraySet(
86 null_check, bounds_check, add, DataType::Type::kInt32, dex_pc);
Artem Serovcced8ba2017-07-19 18:18:09 +010087 HInstruction* induction_inc = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi, const_1);
88
89 loop_body->AddInstruction(null_check);
90 loop_body->AddInstruction(array_length);
91 loop_body->AddInstruction(bounds_check);
92 loop_body->AddInstruction(array_get);
93 loop_body->AddInstruction(add);
94 loop_body->AddInstruction(array_set);
95 loop_body->AddInstruction(induction_inc);
96 loop_body->AddInstruction(new (GetAllocator()) HGoto());
97
98 phi->AddInput(const_0);
99 phi->AddInput(induction_inc);
100
101 graph_->SetHasBoundsChecks(true);
102
103 // Adjust HEnvironment for each instruction which require that.
104 ArenaVector<HInstruction*> current_locals({phi, const_128, parameter_},
105 GetAllocator()->Adapter(kArenaAllocInstruction));
106
107 HEnvironment* env = ManuallyBuildEnvFor(suspend_check, &current_locals);
108 null_check->CopyEnvironmentFrom(env);
109 bounds_check->CopyEnvironmentFrom(env);
110 }
Artem Serovcced8ba2017-07-19 18:18:09 +0100111};
112
Artem Serov5e399b82017-12-21 14:28:35 +0000113TEST_F(SuperblockClonerTest, IndividualInstrCloner) {
Artem Serovcced8ba2017-07-19 18:18:09 +0100114 HBasicBlock* header = nullptr;
115 HBasicBlock* loop_body = nullptr;
116
Artem Serov02eebcf2017-12-13 19:48:31 +0000117 InitGraph();
118 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
Artem Serovcced8ba2017-07-19 18:18:09 +0100119 CreateBasicLoopDataFlow(header, loop_body);
120 graph_->BuildDominatorTree();
Artem Serov02eebcf2017-12-13 19:48:31 +0000121 EXPECT_TRUE(CheckGraph());
Artem Serovcced8ba2017-07-19 18:18:09 +0100122
123 HSuspendCheck* old_suspend_check = header->GetLoopInformation()->GetSuspendCheck();
124 CloneAndReplaceInstructionVisitor visitor(graph_);
125 // Do instruction cloning and replacement twice with different visiting order.
126
127 visitor.VisitInsertionOrder();
128 size_t instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount();
129 EXPECT_EQ(instr_replaced_by_clones_count, 12u);
130 EXPECT_TRUE(CheckGraph());
131
132 visitor.VisitReversePostOrder();
133 instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount();
134 EXPECT_EQ(instr_replaced_by_clones_count, 24u);
135 EXPECT_TRUE(CheckGraph());
136
137 HSuspendCheck* new_suspend_check = header->GetLoopInformation()->GetSuspendCheck();
138 EXPECT_NE(new_suspend_check, old_suspend_check);
139 EXPECT_NE(new_suspend_check, nullptr);
140}
141
Artem Serov7f4aff62017-06-21 17:02:18 +0100142// Tests SuperblockCloner::CloneBasicBlocks - check instruction cloning and initial remapping of
143// instructions' inputs.
144TEST_F(SuperblockClonerTest, CloneBasicBlocks) {
145 HBasicBlock* header = nullptr;
146 HBasicBlock* loop_body = nullptr;
147 ArenaAllocator* arena = graph_->GetAllocator();
148
Artem Serov02eebcf2017-12-13 19:48:31 +0000149 InitGraph();
150 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
Artem Serov7f4aff62017-06-21 17:02:18 +0100151 CreateBasicLoopDataFlow(header, loop_body);
152 graph_->BuildDominatorTree();
153 ASSERT_TRUE(CheckGraph());
154
155 ArenaBitVector orig_bb_set(
156 arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
157 HBasicBlockMap bb_map(std::less<HBasicBlock*>(), arena->Adapter(kArenaAllocSuperblockCloner));
158 HInstructionMap hir_map(std::less<HInstruction*>(), arena->Adapter(kArenaAllocSuperblockCloner));
159
160 HLoopInformation* loop_info = header->GetLoopInformation();
161 orig_bb_set.Union(&loop_info->GetBlocks());
162
163 SuperblockCloner cloner(graph_,
164 &orig_bb_set,
165 &bb_map,
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100166 &hir_map,
167 /* induction_range= */ nullptr);
Artem Serov7f4aff62017-06-21 17:02:18 +0100168 EXPECT_TRUE(cloner.IsSubgraphClonable());
169
170 cloner.CloneBasicBlocks();
171
172 EXPECT_EQ(bb_map.size(), 2u);
173 EXPECT_EQ(hir_map.size(), 12u);
174
175 for (auto it : hir_map) {
176 HInstruction* orig_instr = it.first;
177 HInstruction* copy_instr = it.second;
178
179 EXPECT_EQ(cloner.GetBlockCopy(orig_instr->GetBlock()), copy_instr->GetBlock());
180 EXPECT_EQ(orig_instr->GetKind(), copy_instr->GetKind());
181 EXPECT_EQ(orig_instr->GetType(), copy_instr->GetType());
182
183 if (orig_instr->IsPhi()) {
184 continue;
185 }
186
187 EXPECT_EQ(orig_instr->InputCount(), copy_instr->InputCount());
188
189 // Check that inputs match.
190 for (size_t i = 0, e = orig_instr->InputCount(); i < e; i++) {
191 HInstruction* orig_input = orig_instr->InputAt(i);
192 HInstruction* copy_input = copy_instr->InputAt(i);
193 if (cloner.IsInOrigBBSet(orig_input->GetBlock())) {
194 EXPECT_EQ(cloner.GetInstrCopy(orig_input), copy_input);
195 } else {
196 EXPECT_EQ(orig_input, copy_input);
197 }
198 }
199
200 EXPECT_EQ(orig_instr->HasEnvironment(), copy_instr->HasEnvironment());
201
202 // Check that environments match.
203 if (orig_instr->HasEnvironment()) {
204 HEnvironment* orig_env = orig_instr->GetEnvironment();
205 HEnvironment* copy_env = copy_instr->GetEnvironment();
206
207 EXPECT_EQ(copy_env->GetParent(), nullptr);
208 EXPECT_EQ(orig_env->Size(), copy_env->Size());
209
210 for (size_t i = 0, e = orig_env->Size(); i < e; i++) {
211 HInstruction* orig_input = orig_env->GetInstructionAt(i);
212 HInstruction* copy_input = copy_env->GetInstructionAt(i);
213 if (cloner.IsInOrigBBSet(orig_input->GetBlock())) {
214 EXPECT_EQ(cloner.GetInstrCopy(orig_input), copy_input);
215 } else {
216 EXPECT_EQ(orig_input, copy_input);
217 }
218 }
219 }
220 }
221}
222
223// SuperblockCloner::CleanUpControlFlow - checks algorithms of local adjustments of the control
224// flow.
225TEST_F(SuperblockClonerTest, AdjustControlFlowInfo) {
226 HBasicBlock* header = nullptr;
227 HBasicBlock* loop_body = nullptr;
228 ArenaAllocator* arena = graph_->GetAllocator();
229
Artem Serov02eebcf2017-12-13 19:48:31 +0000230 InitGraph();
231 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
Artem Serov7f4aff62017-06-21 17:02:18 +0100232 CreateBasicLoopDataFlow(header, loop_body);
233 graph_->BuildDominatorTree();
234 ASSERT_TRUE(CheckGraph());
235
236 ArenaBitVector orig_bb_set(
237 arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
238
239 HLoopInformation* loop_info = header->GetLoopInformation();
240 orig_bb_set.Union(&loop_info->GetBlocks());
241
242 SuperblockCloner cloner(graph_,
243 &orig_bb_set,
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100244 /* bb_map= */ nullptr,
245 /* hir_map= */ nullptr,
246 /* induction_range= */ nullptr);
Artem Serov7f4aff62017-06-21 17:02:18 +0100247 EXPECT_TRUE(cloner.IsSubgraphClonable());
248
249 cloner.FindAndSetLocalAreaForAdjustments();
250 cloner.CleanUpControlFlow();
251
252 EXPECT_TRUE(CheckGraph());
253
254 EXPECT_TRUE(entry_block_->Dominates(header));
255 EXPECT_TRUE(entry_block_->Dominates(exit_block_));
256
257 EXPECT_EQ(header->GetLoopInformation(), loop_info);
258 EXPECT_EQ(loop_info->GetHeader(), header);
259 EXPECT_TRUE(loop_info->Contains(*loop_body));
260 EXPECT_TRUE(loop_info->IsBackEdge(*loop_body));
261}
262
Artem Serov02eebcf2017-12-13 19:48:31 +0000263// Tests IsSubgraphConnected function for negative case.
264TEST_F(SuperblockClonerTest, IsGraphConnected) {
265 HBasicBlock* header = nullptr;
266 HBasicBlock* loop_body = nullptr;
267 ArenaAllocator* arena = graph_->GetAllocator();
268
269 InitGraph();
270 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
271 CreateBasicLoopDataFlow(header, loop_body);
272 HBasicBlock* unreachable_block = new (GetAllocator()) HBasicBlock(graph_);
273 graph_->AddBlock(unreachable_block);
274
275 HBasicBlockSet bb_set(
276 arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
277 bb_set.SetBit(header->GetBlockId());
278 bb_set.SetBit(loop_body->GetBlockId());
279 bb_set.SetBit(unreachable_block->GetBlockId());
280
281 EXPECT_FALSE(IsSubgraphConnected(&bb_set, graph_));
282 EXPECT_EQ(bb_set.NumSetBits(), 1u);
283 EXPECT_TRUE(bb_set.IsBitSet(unreachable_block->GetBlockId()));
284}
285
286// Tests SuperblockCloner for loop peeling case.
287//
288// Control Flow of the example (ignoring critical edges splitting).
289//
290// Before After
291//
292// |B| |B|
293// | |
294// v v
295// |1| |1|
296// | |
297// v v
298// |2|<-\ (6) |2A|
299// / \ / / \
300// v v/ / v
301// |4| |3| / |3A| (7)
302// | / /
303// v | v
304// |E| \ |2|<-\
305// \ / \ /
306// v v /
307// |4| |3|
308// |
309// v
310// |E|
311TEST_F(SuperblockClonerTest, LoopPeeling) {
312 HBasicBlock* header = nullptr;
313 HBasicBlock* loop_body = nullptr;
314
315 InitGraph();
316 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
317 CreateBasicLoopDataFlow(header, loop_body);
318 graph_->BuildDominatorTree();
319 EXPECT_TRUE(CheckGraph());
320
321 HBasicBlockMap bb_map(
322 std::less<HBasicBlock*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
323 HInstructionMap hir_map(
324 std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
325
326 HLoopInformation* loop_info = header->GetLoopInformation();
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100327 PeelUnrollHelper helper(loop_info, &bb_map, &hir_map, /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000328 EXPECT_TRUE(helper.IsLoopClonable());
329 HBasicBlock* new_header = helper.DoPeeling();
330 HLoopInformation* new_loop_info = new_header->GetLoopInformation();
331
332 EXPECT_TRUE(CheckGraph());
333
334 // Check loop body successors.
335 EXPECT_EQ(loop_body->GetSingleSuccessor(), header);
336 EXPECT_EQ(bb_map.Get(loop_body)->GetSingleSuccessor(), header);
337
338 // Check loop structure.
339 EXPECT_EQ(header, new_header);
340 EXPECT_EQ(new_loop_info->GetHeader(), header);
341 EXPECT_EQ(new_loop_info->GetBackEdges().size(), 1u);
342 EXPECT_EQ(new_loop_info->GetBackEdges()[0], loop_body);
343}
344
345// Tests SuperblockCloner for loop unrolling case.
346//
347// Control Flow of the example (ignoring critical edges splitting).
348//
349// Before After
350//
351// |B| |B|
352// | |
353// v v
354// |1| |1|
355// | |
356// v v
357// |2|<-\ (6) |2A|<-\
358// / \ / / \ \
359// v v/ / v \
360// |4| |3| /(7)|3A| |
361// | / / /
362// v | v /
363// |E| \ |2| /
364// \ / \ /
365// v v/
366// |4| |3|
367// |
368// v
369// |E|
370TEST_F(SuperblockClonerTest, LoopUnrolling) {
371 HBasicBlock* header = nullptr;
372 HBasicBlock* loop_body = nullptr;
373
374 InitGraph();
375 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
376 CreateBasicLoopDataFlow(header, loop_body);
377 graph_->BuildDominatorTree();
378 EXPECT_TRUE(CheckGraph());
379
380 HBasicBlockMap bb_map(
381 std::less<HBasicBlock*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
382 HInstructionMap hir_map(
383 std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
384
385 HLoopInformation* loop_info = header->GetLoopInformation();
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100386 PeelUnrollHelper helper(loop_info, &bb_map, &hir_map, /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000387 EXPECT_TRUE(helper.IsLoopClonable());
388 HBasicBlock* new_header = helper.DoUnrolling();
389
390 EXPECT_TRUE(CheckGraph());
391
392 // Check loop body successors.
393 EXPECT_EQ(loop_body->GetSingleSuccessor(), bb_map.Get(header));
394 EXPECT_EQ(bb_map.Get(loop_body)->GetSingleSuccessor(), header);
395
396 // Check loop structure.
397 EXPECT_EQ(header, new_header);
398 EXPECT_EQ(loop_info, new_header->GetLoopInformation());
399 EXPECT_EQ(loop_info->GetHeader(), new_header);
400 EXPECT_EQ(loop_info->GetBackEdges().size(), 1u);
401 EXPECT_EQ(loop_info->GetBackEdges()[0], bb_map.Get(loop_body));
402}
403
404// Checks that loop unrolling works fine for a loop with multiple back edges. Tests that after
405// the transformation the loop has a single preheader.
406TEST_F(SuperblockClonerTest, LoopPeelingMultipleBackEdges) {
407 HBasicBlock* header = nullptr;
408 HBasicBlock* loop_body = nullptr;
409
410 InitGraph();
411 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
412 CreateBasicLoopDataFlow(header, loop_body);
413
414 // Transform a basic loop to have multiple back edges.
415 HBasicBlock* latch = header->GetSuccessors()[1];
416 HBasicBlock* if_block = new (GetAllocator()) HBasicBlock(graph_);
417 HBasicBlock* temp1 = new (GetAllocator()) HBasicBlock(graph_);
418 graph_->AddBlock(if_block);
419 graph_->AddBlock(temp1);
420 header->ReplaceSuccessor(latch, if_block);
421 if_block->AddSuccessor(latch);
422 if_block->AddSuccessor(temp1);
423 temp1->AddSuccessor(header);
424
425 if_block->AddInstruction(new (GetAllocator()) HIf(parameter_));
426
427 HInstructionIterator it(header->GetPhis());
428 DCHECK(!it.Done());
429 HPhi* loop_phi = it.Current()->AsPhi();
430 HInstruction* temp_add = new (GetAllocator()) HAdd(DataType::Type::kInt32,
431 loop_phi,
432 graph_->GetIntConstant(2));
433 temp1->AddInstruction(temp_add);
434 temp1->AddInstruction(new (GetAllocator()) HGoto());
435 loop_phi->AddInput(temp_add);
436
437 graph_->BuildDominatorTree();
438 EXPECT_TRUE(CheckGraph());
439
440 HLoopInformation* loop_info = header->GetLoopInformation();
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100441 PeelUnrollSimpleHelper helper(loop_info, /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000442 HBasicBlock* new_header = helper.DoPeeling();
443 EXPECT_EQ(header, new_header);
444
445 EXPECT_TRUE(CheckGraph());
446 EXPECT_EQ(header->GetPredecessors().size(), 3u);
447}
448
449static void CheckLoopStructureForLoopPeelingNested(HBasicBlock* loop1_header,
450 HBasicBlock* loop2_header,
451 HBasicBlock* loop3_header) {
452 EXPECT_EQ(loop1_header->GetLoopInformation()->GetHeader(), loop1_header);
453 EXPECT_EQ(loop2_header->GetLoopInformation()->GetHeader(), loop2_header);
454 EXPECT_EQ(loop3_header->GetLoopInformation()->GetHeader(), loop3_header);
455 EXPECT_EQ(loop1_header->GetLoopInformation()->GetPreHeader()->GetLoopInformation(), nullptr);
456 EXPECT_EQ(loop2_header->GetLoopInformation()->GetPreHeader()->GetLoopInformation(), nullptr);
457 EXPECT_EQ(loop3_header->GetLoopInformation()->GetPreHeader()->GetLoopInformation()->GetHeader(),
458 loop2_header);
459}
460
461TEST_F(SuperblockClonerTest, LoopPeelingNested) {
462 HBasicBlock* header = nullptr;
463 HBasicBlock* loop_body = nullptr;
464
465 InitGraph();
466
467 // Create the following nested structure of loops
468 // Headers: 1 2 3
469 // [ ], [ [ ] ]
470 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
471 CreateBasicLoopDataFlow(header, loop_body);
472 HBasicBlock* loop1_header = header;
473
474 CreateBasicLoopControlFlow(header, return_block_, &header, &loop_body);
475 CreateBasicLoopDataFlow(header, loop_body);
476 HBasicBlock* loop2_header = header;
477
478 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
479 CreateBasicLoopDataFlow(header, loop_body);
480 HBasicBlock* loop3_header = header;
481
482 graph_->BuildDominatorTree();
483 EXPECT_TRUE(CheckGraph());
484
485 HLoopInformation* loop2_info_before = loop2_header->GetLoopInformation();
486 HLoopInformation* loop3_info_before = loop3_header->GetLoopInformation();
487
488 // Check nested loops structure.
489 CheckLoopStructureForLoopPeelingNested(loop1_header, loop2_header, loop3_header);
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100490 PeelUnrollSimpleHelper helper(loop1_header->GetLoopInformation(), /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000491 helper.DoPeeling();
492 // Check that nested loops structure has not changed after the transformation.
493 CheckLoopStructureForLoopPeelingNested(loop1_header, loop2_header, loop3_header);
494
495 // Test that the loop info is preserved.
496 EXPECT_EQ(loop2_info_before, loop2_header->GetLoopInformation());
497 EXPECT_EQ(loop3_info_before, loop3_header->GetLoopInformation());
498
499 EXPECT_EQ(loop3_info_before->GetPreHeader()->GetLoopInformation(), loop2_info_before);
500 EXPECT_EQ(loop2_info_before->GetPreHeader()->GetLoopInformation(), nullptr);
501
502 EXPECT_EQ(helper.GetRegionToBeAdjusted(), nullptr);
503
504 EXPECT_TRUE(CheckGraph());
505}
506
507// Checks that the loop population is correctly propagated after an inner loop is peeled.
508TEST_F(SuperblockClonerTest, OuterLoopPopulationAfterInnerPeeled) {
509 HBasicBlock* header = nullptr;
510 HBasicBlock* loop_body = nullptr;
511
512 InitGraph();
513
514 // Create the following nested structure of loops
515 // Headers: 1 2 3 4
516 // [ [ [ ] ] ], [ ]
517 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
518 CreateBasicLoopDataFlow(header, loop_body);
519 HBasicBlock* loop1_header = header;
520
521 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
522 CreateBasicLoopDataFlow(header, loop_body);
523 HBasicBlock* loop2_header = header;
524
525 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
526 CreateBasicLoopDataFlow(header, loop_body);
527 HBasicBlock* loop3_header = header;
528
529 CreateBasicLoopControlFlow(loop1_header, return_block_, &header, &loop_body);
530 CreateBasicLoopDataFlow(header, loop_body);
531 HBasicBlock* loop4_header = header;
532
533 graph_->BuildDominatorTree();
534 EXPECT_TRUE(CheckGraph());
535
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100536 PeelUnrollSimpleHelper helper(loop3_header->GetLoopInformation(), /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000537 helper.DoPeeling();
538 HLoopInformation* loop1 = loop1_header->GetLoopInformation();
539 HLoopInformation* loop2 = loop2_header->GetLoopInformation();
540 HLoopInformation* loop3 = loop3_header->GetLoopInformation();
541 HLoopInformation* loop4 = loop4_header->GetLoopInformation();
542
543 EXPECT_TRUE(loop1->Contains(*loop2_header));
544 EXPECT_TRUE(loop1->Contains(*loop3_header));
545 EXPECT_TRUE(loop1->Contains(*loop3_header->GetLoopInformation()->GetPreHeader()));
546
547 // Check that loop4 info has not been touched after local run of AnalyzeLoops.
548 EXPECT_EQ(loop4, loop4_header->GetLoopInformation());
549
550 EXPECT_TRUE(loop1->IsIn(*loop1));
551 EXPECT_TRUE(loop2->IsIn(*loop1));
552 EXPECT_TRUE(loop3->IsIn(*loop1));
553 EXPECT_TRUE(loop3->IsIn(*loop2));
554 EXPECT_TRUE(!loop4->IsIn(*loop1));
555
556 EXPECT_EQ(loop4->GetPreHeader()->GetLoopInformation(), nullptr);
557
558 EXPECT_EQ(helper.GetRegionToBeAdjusted(), loop2);
559
560 EXPECT_TRUE(CheckGraph());
561}
562
563// Checks the case when inner loop have an exit not to its immediate outer_loop but some other loop
564// in the hierarchy. Loop population information must be valid after loop peeling.
565TEST_F(SuperblockClonerTest, NestedCaseExitToOutermost) {
566 HBasicBlock* header = nullptr;
567 HBasicBlock* loop_body = nullptr;
568
569 InitGraph();
570
571 // Create the following nested structure of loops then peel loop3.
572 // Headers: 1 2 3
573 // [ [ [ ] ] ]
574 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
575 CreateBasicLoopDataFlow(header, loop_body);
576 HBasicBlock* loop1_header = header;
577 HBasicBlock* loop_body1 = loop_body;
578
579 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
580 CreateBasicLoopDataFlow(header, loop_body);
581
582 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
583 CreateBasicLoopDataFlow(header, loop_body);
584 HBasicBlock* loop3_header = header;
585 HBasicBlock* loop_body3 = loop_body;
586
587 // Change the loop3 - insert an exit which leads to loop1.
588 HBasicBlock* loop3_extra_if_block = new (GetAllocator()) HBasicBlock(graph_);
589 graph_->AddBlock(loop3_extra_if_block);
590 loop3_extra_if_block->AddInstruction(new (GetAllocator()) HIf(parameter_));
591
592 loop3_header->ReplaceSuccessor(loop_body3, loop3_extra_if_block);
593 loop3_extra_if_block->AddSuccessor(loop_body1); // Long exit.
594 loop3_extra_if_block->AddSuccessor(loop_body3);
595
596 graph_->BuildDominatorTree();
597 EXPECT_TRUE(CheckGraph());
598
599 HBasicBlock* loop3_long_exit = loop3_extra_if_block->GetSuccessors()[0];
600 EXPECT_TRUE(loop1_header->GetLoopInformation()->Contains(*loop3_long_exit));
601
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100602 PeelUnrollSimpleHelper helper(loop3_header->GetLoopInformation(), /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000603 helper.DoPeeling();
604
605 HLoopInformation* loop1 = loop1_header->GetLoopInformation();
606 // Check that after the transformation the local area for CF adjustments has been chosen
607 // correctly and loop population has been updated.
608 loop3_long_exit = loop3_extra_if_block->GetSuccessors()[0];
609 EXPECT_TRUE(loop1->Contains(*loop3_long_exit));
610
611 EXPECT_EQ(helper.GetRegionToBeAdjusted(), loop1);
612
613 EXPECT_TRUE(loop1->Contains(*loop3_header));
614 EXPECT_TRUE(loop1->Contains(*loop3_header->GetLoopInformation()->GetPreHeader()));
615
616 EXPECT_TRUE(CheckGraph());
617}
618
619TEST_F(SuperblockClonerTest, FastCaseCheck) {
620 HBasicBlock* header = nullptr;
621 HBasicBlock* loop_body = nullptr;
622 ArenaAllocator* arena = graph_->GetAllocator();
623
624 InitGraph();
625 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
626 CreateBasicLoopDataFlow(header, loop_body);
627 graph_->BuildDominatorTree();
628
629 HLoopInformation* loop_info = header->GetLoopInformation();
630
631 ArenaBitVector orig_bb_set(
632 arena, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
633 orig_bb_set.Union(&loop_info->GetBlocks());
634
635 HEdgeSet remap_orig_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
636 HEdgeSet remap_copy_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
637 HEdgeSet remap_incoming(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
638
639 CollectRemappingInfoForPeelUnroll(true,
640 loop_info,
641 &remap_orig_internal,
642 &remap_copy_internal,
643 &remap_incoming);
644
645 // Insert some extra nodes and edges.
646 HBasicBlock* preheader = loop_info->GetPreHeader();
647 orig_bb_set.SetBit(preheader->GetBlockId());
648
649 // Adjust incoming edges.
Vladimir Marko54159c62018-06-20 14:30:08 +0100650 remap_incoming.clear();
651 remap_incoming.insert(HEdge(preheader->GetSinglePredecessor(), preheader));
Artem Serov02eebcf2017-12-13 19:48:31 +0000652
653 HBasicBlockMap bb_map(std::less<HBasicBlock*>(), arena->Adapter(kArenaAllocSuperblockCloner));
654 HInstructionMap hir_map(std::less<HInstruction*>(), arena->Adapter(kArenaAllocSuperblockCloner));
655
656 SuperblockCloner cloner(graph_,
657 &orig_bb_set,
658 &bb_map,
Nicolas Geoffray256c94b2019-04-29 10:55:09 +0100659 &hir_map,
660 /* induction_range= */ nullptr);
Artem Serov02eebcf2017-12-13 19:48:31 +0000661 cloner.SetSuccessorRemappingInfo(&remap_orig_internal, &remap_copy_internal, &remap_incoming);
662
663 EXPECT_FALSE(cloner.IsFastCase());
664}
665
666// Helper for FindCommonLoop which also check that FindCommonLoop is symmetric.
667static HLoopInformation* FindCommonLoopCheck(HLoopInformation* loop1, HLoopInformation* loop2) {
668 HLoopInformation* common_loop12 = FindCommonLoop(loop1, loop2);
669 HLoopInformation* common_loop21 = FindCommonLoop(loop2, loop1);
670 EXPECT_EQ(common_loop21, common_loop12);
671 return common_loop12;
672}
673
674// Tests FindCommonLoop function on a loop nest.
675TEST_F(SuperblockClonerTest, FindCommonLoop) {
676 HBasicBlock* header = nullptr;
677 HBasicBlock* loop_body = nullptr;
678
679 InitGraph();
680
681 // Create the following nested structure of loops
682 // Headers: 1 2 3 4 5
683 // [ [ [ ] ], [ ] ], [ ]
684 CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body);
685 CreateBasicLoopDataFlow(header, loop_body);
686 HBasicBlock* loop1_header = header;
687
688 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
689 CreateBasicLoopDataFlow(header, loop_body);
690 HBasicBlock* loop2_header = header;
691
692 CreateBasicLoopControlFlow(header, header->GetSuccessors()[1], &header, &loop_body);
693 CreateBasicLoopDataFlow(header, loop_body);
694 HBasicBlock* loop3_header = header;
695
696 CreateBasicLoopControlFlow(loop2_header, loop2_header->GetSuccessors()[0], &header, &loop_body);
697 CreateBasicLoopDataFlow(header, loop_body);
698 HBasicBlock* loop4_header = header;
699
700 CreateBasicLoopControlFlow(loop1_header, return_block_, &header, &loop_body);
701 CreateBasicLoopDataFlow(header, loop_body);
702 HBasicBlock* loop5_header = header;
703
704 graph_->BuildDominatorTree();
705 EXPECT_TRUE(CheckGraph());
706
707 HLoopInformation* loop1 = loop1_header->GetLoopInformation();
708 HLoopInformation* loop2 = loop2_header->GetLoopInformation();
709 HLoopInformation* loop3 = loop3_header->GetLoopInformation();
710 HLoopInformation* loop4 = loop4_header->GetLoopInformation();
711 HLoopInformation* loop5 = loop5_header->GetLoopInformation();
712
713 EXPECT_TRUE(loop1->IsIn(*loop1));
714 EXPECT_TRUE(loop2->IsIn(*loop1));
715 EXPECT_TRUE(loop3->IsIn(*loop1));
716 EXPECT_TRUE(loop3->IsIn(*loop2));
717 EXPECT_TRUE(loop4->IsIn(*loop1));
718
719 EXPECT_FALSE(loop5->IsIn(*loop1));
720 EXPECT_FALSE(loop4->IsIn(*loop2));
721 EXPECT_FALSE(loop4->IsIn(*loop3));
722
723 EXPECT_EQ(loop1->GetPreHeader()->GetLoopInformation(), nullptr);
724 EXPECT_EQ(loop4->GetPreHeader()->GetLoopInformation(), loop1);
725
726 EXPECT_EQ(FindCommonLoopCheck(nullptr, nullptr), nullptr);
727 EXPECT_EQ(FindCommonLoopCheck(loop2, nullptr), nullptr);
728
729 EXPECT_EQ(FindCommonLoopCheck(loop1, loop1), loop1);
730 EXPECT_EQ(FindCommonLoopCheck(loop1, loop2), loop1);
731 EXPECT_EQ(FindCommonLoopCheck(loop1, loop3), loop1);
732 EXPECT_EQ(FindCommonLoopCheck(loop1, loop4), loop1);
733 EXPECT_EQ(FindCommonLoopCheck(loop1, loop5), nullptr);
734
735 EXPECT_EQ(FindCommonLoopCheck(loop2, loop3), loop2);
736 EXPECT_EQ(FindCommonLoopCheck(loop2, loop4), loop1);
737 EXPECT_EQ(FindCommonLoopCheck(loop2, loop5), nullptr);
738
739 EXPECT_EQ(FindCommonLoopCheck(loop3, loop4), loop1);
740 EXPECT_EQ(FindCommonLoopCheck(loop3, loop5), nullptr);
741
742 EXPECT_EQ(FindCommonLoopCheck(loop4, loop5), nullptr);
743
744 EXPECT_EQ(FindCommonLoopCheck(loop5, loop5), loop5);
745}
746
Artem Serovcced8ba2017-07-19 18:18:09 +0100747} // namespace art