blob: bbd28f5c4600e0b48a463815e351e6bb534986f1 [file] [log] [blame]
Nicolas Geoffray622d9c32014-05-12 16:11:02 +01001/*
2 * Copyright (C) 2014 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
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010018#include "builder.h"
19#include "dex_file.h"
20#include "dex_instruction.h"
21#include "nodes.h"
22#include "optimizing_unit_test.h"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010023#include "pretty_printer.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070024#include "ssa_liveness_analysis.h"
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010025
26#include "gtest/gtest.h"
27
28namespace art {
29
David Brazdilbadd8262016-02-02 16:28:56 +000030class FindLoopsTest : public CommonCompilerTest {};
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010031
David Brazdilbadd8262016-02-02 16:28:56 +000032TEST_F(FindLoopsTest, CFG1) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010033 // Constant is not used.
34 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
35 Instruction::CONST_4 | 0 | 0,
36 Instruction::RETURN_VOID);
37
38 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +010039 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +000040 HGraph* graph = CreateCFG(&allocator, data);
Vladimir Markofa6b93c2015-09-15 10:15:55 +010041 for (HBasicBlock* block : graph->GetBlocks()) {
42 ASSERT_EQ(block->GetLoopInformation(), nullptr);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010043 }
44}
45
David Brazdilbadd8262016-02-02 16:28:56 +000046TEST_F(FindLoopsTest, CFG2) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010047 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
48 Instruction::CONST_4 | 0 | 0,
49 Instruction::RETURN);
50
51 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +010052 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +000053 HGraph* graph = CreateCFG(&allocator, data);
Vladimir Markofa6b93c2015-09-15 10:15:55 +010054 for (HBasicBlock* block : graph->GetBlocks()) {
55 ASSERT_EQ(block->GetLoopInformation(), nullptr);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010056 }
57}
58
David Brazdilbadd8262016-02-02 16:28:56 +000059TEST_F(FindLoopsTest, CFG3) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010060 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
61 Instruction::CONST_4 | 3 << 12 | 0,
62 Instruction::CONST_4 | 4 << 12 | 1 << 8,
63 Instruction::ADD_INT_2ADDR | 1 << 12,
64 Instruction::GOTO | 0x100,
65 Instruction::RETURN);
66
67 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +010068 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +000069 HGraph* graph = CreateCFG(&allocator, data);
Vladimir Markofa6b93c2015-09-15 10:15:55 +010070 for (HBasicBlock* block : graph->GetBlocks()) {
71 ASSERT_EQ(block->GetLoopInformation(), nullptr);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010072 }
73}
74
David Brazdilbadd8262016-02-02 16:28:56 +000075TEST_F(FindLoopsTest, CFG4) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010076 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
77 Instruction::CONST_4 | 0 | 0,
78 Instruction::IF_EQ, 4,
79 Instruction::CONST_4 | 4 << 12 | 0,
80 Instruction::GOTO | 0x200,
81 Instruction::CONST_4 | 5 << 12 | 0,
82 Instruction::RETURN | 0 << 8);
83
84 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +010085 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +000086 HGraph* graph = CreateCFG(&allocator, data);
Vladimir Markofa6b93c2015-09-15 10:15:55 +010087 for (HBasicBlock* block : graph->GetBlocks()) {
88 ASSERT_EQ(block->GetLoopInformation(), nullptr);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010089 }
90}
91
David Brazdilbadd8262016-02-02 16:28:56 +000092TEST_F(FindLoopsTest, CFG5) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +010093 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
94 Instruction::CONST_4 | 0 | 0,
95 Instruction::IF_EQ, 3,
96 Instruction::CONST_4 | 4 << 12 | 0,
97 Instruction::RETURN | 0 << 8);
98
99 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100100 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000101 HGraph* graph = CreateCFG(&allocator, data);
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100102 for (HBasicBlock* block : graph->GetBlocks()) {
103 ASSERT_EQ(block->GetLoopInformation(), nullptr);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100104 }
105}
106
107static void TestBlock(HGraph* graph,
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100108 uint32_t block_id,
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100109 bool is_loop_header,
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100110 uint32_t parent_loop_header_id,
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100111 const int* blocks_in_loop = nullptr,
112 size_t number_of_blocks = 0) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100113 HBasicBlock* block = graph->GetBlocks()[block_id];
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100114 ASSERT_EQ(block->IsLoopHeader(), is_loop_header);
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100115 if (parent_loop_header_id == kInvalidBlockId) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100116 ASSERT_EQ(block->GetLoopInformation(), nullptr);
117 } else {
118 ASSERT_EQ(block->GetLoopInformation()->GetHeader()->GetBlockId(), parent_loop_header_id);
119 }
120
121 if (blocks_in_loop != nullptr) {
122 HLoopInformation* info = block->GetLoopInformation();
123 const BitVector& blocks = info->GetBlocks();
124 ASSERT_EQ(blocks.NumSetBits(), number_of_blocks);
125 for (size_t i = 0; i < number_of_blocks; ++i) {
126 ASSERT_TRUE(blocks.IsBitSet(blocks_in_loop[i]));
127 }
128 } else {
129 ASSERT_FALSE(block->IsLoopHeader());
130 }
131}
132
David Brazdilbadd8262016-02-02 16:28:56 +0000133TEST_F(FindLoopsTest, Loop1) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100134 // Simple loop with one preheader and one back edge.
135 // var a = 0;
136 // while (a == a) {
137 // }
138 // return;
139 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
140 Instruction::CONST_4 | 0 | 0,
141 Instruction::IF_EQ, 3,
142 Instruction::GOTO | 0xFE00,
143 Instruction::RETURN_VOID);
144
145 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100146 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000147 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100148
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100149 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
150 TestBlock(graph, 1, false, kInvalidBlockId); // pre header
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100151 const int blocks2[] = {2, 3};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100152 TestBlock(graph, 2, true, 2, blocks2, 2); // loop header
153 TestBlock(graph, 3, false, 2); // block in loop
154 TestBlock(graph, 4, false, kInvalidBlockId); // return block
155 TestBlock(graph, 5, false, kInvalidBlockId); // exit block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100156}
157
David Brazdilbadd8262016-02-02 16:28:56 +0000158TEST_F(FindLoopsTest, Loop2) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100159 // Make sure we support a preheader of a loop not being the first predecessor
160 // in the predecessor list of the header.
161 // var a = 0;
162 // while (a == a) {
163 // }
164 // return a;
165 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
166 Instruction::CONST_4 | 0 | 0,
167 Instruction::GOTO | 0x400,
168 Instruction::IF_EQ, 4,
169 Instruction::GOTO | 0xFE00,
170 Instruction::GOTO | 0xFD00,
171 Instruction::RETURN | 0 << 8);
172
173 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100174 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000175 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100176
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100177 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
178 TestBlock(graph, 1, false, kInvalidBlockId); // goto block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100179 const int blocks2[] = {2, 3};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100180 TestBlock(graph, 2, true, 2, blocks2, 2); // loop header
181 TestBlock(graph, 3, false, 2); // block in loop
182 TestBlock(graph, 4, false, kInvalidBlockId); // pre header
183 TestBlock(graph, 5, false, kInvalidBlockId); // return block
184 TestBlock(graph, 6, false, kInvalidBlockId); // exit block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100185}
186
David Brazdilbadd8262016-02-02 16:28:56 +0000187TEST_F(FindLoopsTest, Loop3) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100188 // Make sure we create a preheader of a loop when a header originally has two
189 // incoming blocks and one back edge.
190 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
191 Instruction::CONST_4 | 0 | 0,
192 Instruction::IF_EQ, 3,
193 Instruction::GOTO | 0x100,
194 Instruction::IF_EQ, 3,
195 Instruction::GOTO | 0xFE00,
196 Instruction::RETURN | 0 << 8);
197
198 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100199 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000200 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100201
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100202 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
203 TestBlock(graph, 1, false, kInvalidBlockId); // goto block
204 TestBlock(graph, 2, false, kInvalidBlockId);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100205 const int blocks2[] = {3, 4};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100206 TestBlock(graph, 3, true, 3, blocks2, 2); // loop header
207 TestBlock(graph, 4, false, 3); // block in loop
208 TestBlock(graph, 5, false, kInvalidBlockId); // pre header
209 TestBlock(graph, 6, false, kInvalidBlockId); // return block
210 TestBlock(graph, 7, false, kInvalidBlockId); // exit block
211 TestBlock(graph, 8, false, kInvalidBlockId); // synthesized pre header
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100212}
213
David Brazdilbadd8262016-02-02 16:28:56 +0000214TEST_F(FindLoopsTest, Loop4) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100215 // Test loop with originally two back edges.
216 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
217 Instruction::CONST_4 | 0 | 0,
218 Instruction::IF_EQ, 6,
219 Instruction::IF_EQ, 3,
220 Instruction::GOTO | 0xFC00,
221 Instruction::GOTO | 0xFB00,
222 Instruction::RETURN | 0 << 8);
223
224 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100225 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000226 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100227
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100228 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
229 TestBlock(graph, 1, false, kInvalidBlockId); // pre header
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100230 const int blocks2[] = {2, 3, 4, 5};
231 TestBlock(graph, 2, true, 2, blocks2, arraysize(blocks2)); // loop header
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100232 TestBlock(graph, 3, false, 2); // block in loop
233 TestBlock(graph, 4, false, 2); // back edge
234 TestBlock(graph, 5, false, 2); // back edge
235 TestBlock(graph, 6, false, kInvalidBlockId); // return block
236 TestBlock(graph, 7, false, kInvalidBlockId); // exit block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100237}
238
239
David Brazdilbadd8262016-02-02 16:28:56 +0000240TEST_F(FindLoopsTest, Loop5) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100241 // Test loop with two exit edges.
242 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
243 Instruction::CONST_4 | 0 | 0,
244 Instruction::IF_EQ, 6,
245 Instruction::IF_EQ, 3,
246 Instruction::GOTO | 0x0200,
247 Instruction::GOTO | 0xFB00,
248 Instruction::RETURN | 0 << 8);
249
250 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100251 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000252 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100253
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100254 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
255 TestBlock(graph, 1, false, kInvalidBlockId); // pre header
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100256 const int blocks2[] = {2, 3, 5};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100257 TestBlock(graph, 2, true, 2, blocks2, 3); // loop header
258 TestBlock(graph, 3, false, 2); // block in loop
259 TestBlock(graph, 4, false, kInvalidBlockId); // loop exit
260 TestBlock(graph, 5, false, 2); // back edge
261 TestBlock(graph, 6, false, kInvalidBlockId); // return block
262 TestBlock(graph, 7, false, kInvalidBlockId); // exit block
263 TestBlock(graph, 8, false, kInvalidBlockId); // synthesized block at the loop exit
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100264}
265
David Brazdilbadd8262016-02-02 16:28:56 +0000266TEST_F(FindLoopsTest, InnerLoop) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100267 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
268 Instruction::CONST_4 | 0 | 0,
269 Instruction::IF_EQ, 6,
270 Instruction::IF_EQ, 3,
271 Instruction::GOTO | 0xFE00, // inner loop
272 Instruction::GOTO | 0xFB00,
273 Instruction::RETURN | 0 << 8);
274
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100275 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100276 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000277 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100278
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100279 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
280 TestBlock(graph, 1, false, kInvalidBlockId); // pre header of outer loop
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100281 const int blocks2[] = {2, 3, 4, 5, 8};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100282 TestBlock(graph, 2, true, 2, blocks2, 5); // outer loop header
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100283 const int blocks3[] = {3, 4};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100284 TestBlock(graph, 3, true, 3, blocks3, 2); // inner loop header
285 TestBlock(graph, 4, false, 3); // back edge on inner loop
286 TestBlock(graph, 5, false, 2); // back edge on outer loop
287 TestBlock(graph, 6, false, kInvalidBlockId); // return block
288 TestBlock(graph, 7, false, kInvalidBlockId); // exit block
289 TestBlock(graph, 8, false, 2); // synthesized block as pre header of inner loop
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100290
Vladimir Markoec7802a2015-10-01 20:57:57 +0100291 ASSERT_TRUE(graph->GetBlocks()[3]->GetLoopInformation()->IsIn(
292 *graph->GetBlocks()[2]->GetLoopInformation()));
293 ASSERT_FALSE(graph->GetBlocks()[2]->GetLoopInformation()->IsIn(
294 *graph->GetBlocks()[3]->GetLoopInformation()));
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100295}
296
David Brazdilbadd8262016-02-02 16:28:56 +0000297TEST_F(FindLoopsTest, TwoLoops) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100298 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
299 Instruction::CONST_4 | 0 | 0,
300 Instruction::IF_EQ, 3,
301 Instruction::GOTO | 0xFE00, // first loop
302 Instruction::IF_EQ, 3,
303 Instruction::GOTO | 0xFE00, // second loop
304 Instruction::RETURN | 0 << 8);
305
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100306 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100307 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000308 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100309
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100310 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
311 TestBlock(graph, 1, false, kInvalidBlockId); // pre header of first loop
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100312 const int blocks2[] = {2, 3};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100313 TestBlock(graph, 2, true, 2, blocks2, 2); // first loop header
314 TestBlock(graph, 3, false, 2); // back edge of first loop
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100315 const int blocks4[] = {4, 5};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100316 TestBlock(graph, 4, true, 4, blocks4, 2); // second loop header
317 TestBlock(graph, 5, false, 4); // back edge of second loop
318 TestBlock(graph, 6, false, kInvalidBlockId); // return block
319 TestBlock(graph, 7, false, kInvalidBlockId); // exit block
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100320
Vladimir Markoec7802a2015-10-01 20:57:57 +0100321 ASSERT_FALSE(graph->GetBlocks()[4]->GetLoopInformation()->IsIn(
322 *graph->GetBlocks()[2]->GetLoopInformation()));
323 ASSERT_FALSE(graph->GetBlocks()[2]->GetLoopInformation()->IsIn(
324 *graph->GetBlocks()[4]->GetLoopInformation()));
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100325}
326
David Brazdilbadd8262016-02-02 16:28:56 +0000327TEST_F(FindLoopsTest, NonNaturalLoop) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100328 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
329 Instruction::CONST_4 | 0 | 0,
330 Instruction::IF_EQ, 3,
331 Instruction::GOTO | 0x0100,
332 Instruction::IF_EQ, 3,
333 Instruction::GOTO | 0xFD00,
334 Instruction::RETURN | 0 << 8);
335
336 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100337 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000338 HGraph* graph = CreateCFG(&allocator, data);
Vladimir Markoec7802a2015-10-01 20:57:57 +0100339 ASSERT_TRUE(graph->GetBlocks()[3]->IsLoopHeader());
340 HLoopInformation* info = graph->GetBlocks()[3]->GetLoopInformation();
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100341 ASSERT_EQ(1u, info->NumberOfBackEdges());
342 ASSERT_FALSE(info->GetHeader()->Dominates(info->GetBackEdges()[0]));
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100343}
344
David Brazdilbadd8262016-02-02 16:28:56 +0000345TEST_F(FindLoopsTest, DoWhileLoop) {
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100346 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
347 Instruction::CONST_4 | 0 | 0,
348 Instruction::GOTO | 0x0100,
349 Instruction::IF_EQ, 0xFFFF,
350 Instruction::RETURN | 0 << 8);
351
352 ArenaPool arena;
Nicolas Geoffraye6c96d12014-09-10 10:34:01 +0100353 ArenaAllocator allocator(&arena);
David Brazdilbadd8262016-02-02 16:28:56 +0000354 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100355
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100356 TestBlock(graph, 0, false, kInvalidBlockId); // entry block
357 TestBlock(graph, 1, false, kInvalidBlockId); // pre header of first loop
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100358 const int blocks2[] = {2, 3, 6};
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100359 TestBlock(graph, 2, true, 2, blocks2, 3); // loop header
360 TestBlock(graph, 3, false, 2); // back edge of first loop
361 TestBlock(graph, 4, false, kInvalidBlockId); // return block
362 TestBlock(graph, 5, false, kInvalidBlockId); // exit block
363 TestBlock(graph, 6, false, 2); // synthesized block to avoid a critical edge
Nicolas Geoffray622d9c32014-05-12 16:11:02 +0100364}
365
366} // namespace art