1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 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/arena_allocator.h"
18*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
19*795d594fSAndroid Build Coastguard Worker #include "builder.h"
20*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file.h"
21*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
22*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
23*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
24*795d594fSAndroid Build Coastguard Worker #include "pretty_printer.h"
25*795d594fSAndroid Build Coastguard Worker #include "ssa_liveness_analysis.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h"
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker
31*795d594fSAndroid Build Coastguard Worker class FindLoopsTest : public CommonCompilerTest, public OptimizingUnitTestHelper {};
32*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,CFG1)33*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, CFG1) {
34*795d594fSAndroid Build Coastguard Worker // Constant is not used.
35*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
36*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
37*795d594fSAndroid Build Coastguard Worker Instruction::RETURN_VOID);
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
40*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetBlocks()) {
41*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation(), nullptr);
42*795d594fSAndroid Build Coastguard Worker }
43*795d594fSAndroid Build Coastguard Worker }
44*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,CFG2)45*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, CFG2) {
46*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
47*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
48*795d594fSAndroid Build Coastguard Worker Instruction::RETURN);
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
51*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetBlocks()) {
52*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation(), nullptr);
53*795d594fSAndroid Build Coastguard Worker }
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,CFG3)56*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, CFG3) {
57*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
58*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 3 << 12 | 0,
59*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 1 << 8,
60*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT_2ADDR | 1 << 12,
61*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x100,
62*795d594fSAndroid Build Coastguard Worker Instruction::RETURN);
63*795d594fSAndroid Build Coastguard Worker
64*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
65*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetBlocks()) {
66*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation(), nullptr);
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,CFG4)70*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, CFG4) {
71*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
72*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
73*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 4,
74*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 0,
75*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x200,
76*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 5 << 12 | 0,
77*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
78*795d594fSAndroid Build Coastguard Worker
79*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
80*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetBlocks()) {
81*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation(), nullptr);
82*795d594fSAndroid Build Coastguard Worker }
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,CFG5)85*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, CFG5) {
86*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
87*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
88*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
89*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 0,
90*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
93*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetBlocks()) {
94*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation(), nullptr);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker
TestBlock(HGraph * graph,uint32_t block_id,bool is_loop_header,uint32_t parent_loop_header_id,const int * blocks_in_loop=nullptr,size_t number_of_blocks=0)98*795d594fSAndroid Build Coastguard Worker static void TestBlock(HGraph* graph,
99*795d594fSAndroid Build Coastguard Worker uint32_t block_id,
100*795d594fSAndroid Build Coastguard Worker bool is_loop_header,
101*795d594fSAndroid Build Coastguard Worker uint32_t parent_loop_header_id,
102*795d594fSAndroid Build Coastguard Worker const int* blocks_in_loop = nullptr,
103*795d594fSAndroid Build Coastguard Worker size_t number_of_blocks = 0) {
104*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = graph->GetBlocks()[block_id];
105*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->IsLoopHeader(), is_loop_header);
106*795d594fSAndroid Build Coastguard Worker if (parent_loop_header_id == kInvalidBlockId) {
107*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation(), nullptr);
108*795d594fSAndroid Build Coastguard Worker } else {
109*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(block->GetLoopInformation()->GetHeader()->GetBlockId(), parent_loop_header_id);
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker if (blocks_in_loop != nullptr) {
113*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = block->GetLoopInformation();
114*795d594fSAndroid Build Coastguard Worker const BitVector& blocks = info->GetBlocks();
115*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(blocks.NumSetBits(), number_of_blocks);
116*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < number_of_blocks; ++i) {
117*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(blocks.IsBitSet(blocks_in_loop[i]));
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker } else {
120*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(block->IsLoopHeader());
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,Loop1)124*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, Loop1) {
125*795d594fSAndroid Build Coastguard Worker // Simple loop with one preheader and one back edge.
126*795d594fSAndroid Build Coastguard Worker // var a = 0;
127*795d594fSAndroid Build Coastguard Worker // while (a == a) {
128*795d594fSAndroid Build Coastguard Worker // }
129*795d594fSAndroid Build Coastguard Worker // return;
130*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
131*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
132*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
133*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFE00,
134*795d594fSAndroid Build Coastguard Worker Instruction::RETURN_VOID);
135*795d594fSAndroid Build Coastguard Worker
136*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
139*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // pre header
140*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3};
141*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, 2); // loop header
142*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, false, 2); // block in loop
143*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, kInvalidBlockId); // return block
144*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, kInvalidBlockId); // exit block
145*795d594fSAndroid Build Coastguard Worker }
146*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,Loop2)147*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, Loop2) {
148*795d594fSAndroid Build Coastguard Worker // Make sure we support a preheader of a loop not being the first predecessor
149*795d594fSAndroid Build Coastguard Worker // in the predecessor list of the header.
150*795d594fSAndroid Build Coastguard Worker // var a = 0;
151*795d594fSAndroid Build Coastguard Worker // while (a == a) {
152*795d594fSAndroid Build Coastguard Worker // }
153*795d594fSAndroid Build Coastguard Worker // return a;
154*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
155*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
156*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x400,
157*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 4,
158*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFE00,
159*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFD00,
160*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
161*795d594fSAndroid Build Coastguard Worker
162*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
165*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // goto block
166*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3};
167*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, 2); // loop header
168*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, false, 2); // block in loop
169*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, kInvalidBlockId); // pre header
170*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, kInvalidBlockId); // return block
171*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, kInvalidBlockId); // exit block
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,Loop3)174*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, Loop3) {
175*795d594fSAndroid Build Coastguard Worker // Make sure we create a preheader of a loop when a header originally has two
176*795d594fSAndroid Build Coastguard Worker // incoming blocks and one back edge.
177*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
178*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
179*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
180*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x100,
181*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
182*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFE00,
183*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
184*795d594fSAndroid Build Coastguard Worker
185*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
186*795d594fSAndroid Build Coastguard Worker
187*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
188*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // goto block
189*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, false, kInvalidBlockId);
190*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {3, 4};
191*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, true, 3, blocks2, 2); // loop header
192*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, 3); // block in loop
193*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, kInvalidBlockId); // pre header
194*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, kInvalidBlockId); // return block
195*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 7, false, kInvalidBlockId); // exit block
196*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 8, false, kInvalidBlockId); // synthesized pre header
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,Loop4)199*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, Loop4) {
200*795d594fSAndroid Build Coastguard Worker // Test loop with originally two back edges.
201*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
202*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
203*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 6,
204*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
205*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFC00,
206*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFB00,
207*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
208*795d594fSAndroid Build Coastguard Worker
209*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
210*795d594fSAndroid Build Coastguard Worker
211*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
212*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // pre header
213*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3, 4, 5};
214*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, arraysize(blocks2)); // loop header
215*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, false, 2); // block in loop
216*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, 2); // back edge
217*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, 2); // back edge
218*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, kInvalidBlockId); // return block
219*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 7, false, kInvalidBlockId); // exit block
220*795d594fSAndroid Build Coastguard Worker }
221*795d594fSAndroid Build Coastguard Worker
222*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,Loop5)223*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, Loop5) {
224*795d594fSAndroid Build Coastguard Worker // Test loop with two exit edges.
225*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
226*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
227*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 6,
228*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
229*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x0200,
230*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFB00,
231*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
232*795d594fSAndroid Build Coastguard Worker
233*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
234*795d594fSAndroid Build Coastguard Worker
235*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
236*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // pre header
237*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3, 5};
238*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, 3); // loop header
239*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, false, 2); // block in loop
240*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, kInvalidBlockId); // loop exit
241*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, 2); // back edge
242*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, kInvalidBlockId); // return block
243*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 7, false, kInvalidBlockId); // exit block
244*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 8, false, kInvalidBlockId); // synthesized block at the loop exit
245*795d594fSAndroid Build Coastguard Worker }
246*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,InnerLoop)247*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, InnerLoop) {
248*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
249*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
250*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 6,
251*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
252*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFE00, // inner loop
253*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFB00,
254*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
255*795d594fSAndroid Build Coastguard Worker
256*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
257*795d594fSAndroid Build Coastguard Worker
258*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
259*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // pre header of outer loop
260*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3, 4, 5, 8};
261*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, 5); // outer loop header
262*795d594fSAndroid Build Coastguard Worker const int blocks3[] = {3, 4};
263*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, true, 3, blocks3, 2); // inner loop header
264*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, 3); // back edge on inner loop
265*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, 2); // back edge on outer loop
266*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, kInvalidBlockId); // return block
267*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 7, false, kInvalidBlockId); // exit block
268*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 8, false, 2); // synthesized block as pre header of inner loop
269*795d594fSAndroid Build Coastguard Worker
270*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(graph->GetBlocks()[3]->GetLoopInformation()->IsIn(
271*795d594fSAndroid Build Coastguard Worker *graph->GetBlocks()[2]->GetLoopInformation()));
272*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(graph->GetBlocks()[2]->GetLoopInformation()->IsIn(
273*795d594fSAndroid Build Coastguard Worker *graph->GetBlocks()[3]->GetLoopInformation()));
274*795d594fSAndroid Build Coastguard Worker }
275*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,TwoLoops)276*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, TwoLoops) {
277*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
278*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
279*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
280*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFE00, // first loop
281*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
282*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFE00, // second loop
283*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
284*795d594fSAndroid Build Coastguard Worker
285*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
286*795d594fSAndroid Build Coastguard Worker
287*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
288*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // pre header of first loop
289*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3};
290*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, 2); // first loop header
291*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, false, 2); // back edge of first loop
292*795d594fSAndroid Build Coastguard Worker const int blocks4[] = {4, 5};
293*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, true, 4, blocks4, 2); // second loop header
294*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, 4); // back edge of second loop
295*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, kInvalidBlockId); // return block
296*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 7, false, kInvalidBlockId); // exit block
297*795d594fSAndroid Build Coastguard Worker
298*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(graph->GetBlocks()[4]->GetLoopInformation()->IsIn(
299*795d594fSAndroid Build Coastguard Worker *graph->GetBlocks()[2]->GetLoopInformation()));
300*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(graph->GetBlocks()[2]->GetLoopInformation()->IsIn(
301*795d594fSAndroid Build Coastguard Worker *graph->GetBlocks()[4]->GetLoopInformation()));
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,NonNaturalLoop)304*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, NonNaturalLoop) {
305*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
306*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
307*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
308*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x0100,
309*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
310*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFD00,
311*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
314*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(graph->GetBlocks()[3]->IsLoopHeader());
315*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = graph->GetBlocks()[3]->GetLoopInformation();
316*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(1u, info->NumberOfBackEdges());
317*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(info->GetHeader()->Dominates(info->GetBackEdges()[0]));
318*795d594fSAndroid Build Coastguard Worker }
319*795d594fSAndroid Build Coastguard Worker
TEST_F(FindLoopsTest,DoWhileLoop)320*795d594fSAndroid Build Coastguard Worker TEST_F(FindLoopsTest, DoWhileLoop) {
321*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
322*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
323*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x0100,
324*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 0xFFFF,
325*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
326*795d594fSAndroid Build Coastguard Worker
327*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
328*795d594fSAndroid Build Coastguard Worker
329*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 0, false, kInvalidBlockId); // entry block
330*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 1, false, kInvalidBlockId); // pre header of first loop
331*795d594fSAndroid Build Coastguard Worker const int blocks2[] = {2, 3, 6};
332*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 2, true, 2, blocks2, 3); // loop header
333*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 3, false, 2); // back edge of first loop
334*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 4, false, kInvalidBlockId); // return block
335*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 5, false, kInvalidBlockId); // exit block
336*795d594fSAndroid Build Coastguard Worker TestBlock(graph, 6, false, 2); // synthesized block to avoid a critical edge
337*795d594fSAndroid Build Coastguard Worker }
338*795d594fSAndroid Build Coastguard Worker
339*795d594fSAndroid Build Coastguard Worker } // namespace art
340