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