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 "code_generator.h"
21*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file.h"
22*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
23*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_options.h"
24*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
25*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
26*795d594fSAndroid Build Coastguard Worker #include "prepare_for_register_allocation.h"
27*795d594fSAndroid Build Coastguard Worker #include "ssa_liveness_analysis.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 LiveRangesTest : public CommonCompilerTest, public OptimizingUnitTestHelper {
32*795d594fSAndroid Build Coastguard Worker protected:
33*795d594fSAndroid Build Coastguard Worker HGraph* BuildGraph(const std::vector<uint16_t>& data);
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CompilerOptions> compiler_options_;
36*795d594fSAndroid Build Coastguard Worker };
37*795d594fSAndroid Build Coastguard Worker
BuildGraph(const std::vector<uint16_t> & data)38*795d594fSAndroid Build Coastguard Worker HGraph* LiveRangesTest::BuildGraph(const std::vector<uint16_t>& data) {
39*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
40*795d594fSAndroid Build Coastguard Worker compiler_options_ = CommonCompilerTest::CreateCompilerOptions(kRuntimeISA, "default");
41*795d594fSAndroid Build Coastguard Worker // Suspend checks implementation may change in the future, and this test relies
42*795d594fSAndroid Build Coastguard Worker // on how instructions are ordered.
43*795d594fSAndroid Build Coastguard Worker RemoveSuspendChecks(graph);
44*795d594fSAndroid Build Coastguard Worker // `Inline` conditions into ifs.
45*795d594fSAndroid Build Coastguard Worker PrepareForRegisterAllocation(graph, *compiler_options_).Run();
46*795d594fSAndroid Build Coastguard Worker return graph;
47*795d594fSAndroid Build Coastguard Worker }
48*795d594fSAndroid Build Coastguard Worker
TEST_F(LiveRangesTest,CFG1)49*795d594fSAndroid Build Coastguard Worker TEST_F(LiveRangesTest, CFG1) {
50*795d594fSAndroid Build Coastguard Worker /*
51*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
52*795d594fSAndroid Build Coastguard Worker * return 0;
53*795d594fSAndroid Build Coastguard Worker *
54*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph (numbered by lifetime position):
55*795d594fSAndroid Build Coastguard Worker * 2: constant0
56*795d594fSAndroid Build Coastguard Worker * 4: goto
57*795d594fSAndroid Build Coastguard Worker * |
58*795d594fSAndroid Build Coastguard Worker * 8: return
59*795d594fSAndroid Build Coastguard Worker * |
60*795d594fSAndroid Build Coastguard Worker * 12: exit
61*795d594fSAndroid Build Coastguard Worker */
62*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
63*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
64*795d594fSAndroid Build Coastguard Worker Instruction::RETURN);
65*795d594fSAndroid Build Coastguard Worker
66*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildGraph(data);
67*795d594fSAndroid Build Coastguard Worker
68*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
69*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
70*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
73*795d594fSAndroid Build Coastguard Worker LiveRange* range = interval->GetFirstRange();
74*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(2u, range->GetStart());
75*795d594fSAndroid Build Coastguard Worker // Last use is the return instruction.
76*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(8u, range->GetEnd());
77*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = graph->GetBlocks()[1];
78*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
79*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
80*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker
TEST_F(LiveRangesTest,CFG2)83*795d594fSAndroid Build Coastguard Worker TEST_F(LiveRangesTest, CFG2) {
84*795d594fSAndroid Build Coastguard Worker /*
85*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
86*795d594fSAndroid Build Coastguard Worker * var a = 0;
87*795d594fSAndroid Build Coastguard Worker * if (0 == 0) {
88*795d594fSAndroid Build Coastguard Worker * } else {
89*795d594fSAndroid Build Coastguard Worker * }
90*795d594fSAndroid Build Coastguard Worker * return a;
91*795d594fSAndroid Build Coastguard Worker *
92*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph (numbered by lifetime position):
93*795d594fSAndroid Build Coastguard Worker * 2: constant0
94*795d594fSAndroid Build Coastguard Worker * 4: goto
95*795d594fSAndroid Build Coastguard Worker * |
96*795d594fSAndroid Build Coastguard Worker * 8: equal
97*795d594fSAndroid Build Coastguard Worker * 10: if
98*795d594fSAndroid Build Coastguard Worker * / \
99*795d594fSAndroid Build Coastguard Worker * 14: goto 18: goto
100*795d594fSAndroid Build Coastguard Worker * \ /
101*795d594fSAndroid Build Coastguard Worker * 22: return
102*795d594fSAndroid Build Coastguard Worker * |
103*795d594fSAndroid Build Coastguard Worker * 26: exit
104*795d594fSAndroid Build Coastguard Worker */
105*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
106*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
107*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
108*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x100,
109*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
110*795d594fSAndroid Build Coastguard Worker
111*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildGraph(data);
112*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
113*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
114*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
117*795d594fSAndroid Build Coastguard Worker LiveRange* range = interval->GetFirstRange();
118*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(2u, range->GetStart());
119*795d594fSAndroid Build Coastguard Worker // Last use is the return instruction.
120*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, range->GetEnd());
121*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = graph->GetBlocks()[3];
122*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
123*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
124*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker
TEST_F(LiveRangesTest,CFG3)127*795d594fSAndroid Build Coastguard Worker TEST_F(LiveRangesTest, CFG3) {
128*795d594fSAndroid Build Coastguard Worker /*
129*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
130*795d594fSAndroid Build Coastguard Worker * var a = 0;
131*795d594fSAndroid Build Coastguard Worker * if (0 == 0) {
132*795d594fSAndroid Build Coastguard Worker * } else {
133*795d594fSAndroid Build Coastguard Worker * a = 4;
134*795d594fSAndroid Build Coastguard Worker * }
135*795d594fSAndroid Build Coastguard Worker * return a;
136*795d594fSAndroid Build Coastguard Worker *
137*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph (numbered by lifetime position):
138*795d594fSAndroid Build Coastguard Worker * 2: constant0
139*795d594fSAndroid Build Coastguard Worker * 4: constant4
140*795d594fSAndroid Build Coastguard Worker * 6: goto
141*795d594fSAndroid Build Coastguard Worker * |
142*795d594fSAndroid Build Coastguard Worker * 10: equal
143*795d594fSAndroid Build Coastguard Worker * 12: if
144*795d594fSAndroid Build Coastguard Worker * / \
145*795d594fSAndroid Build Coastguard Worker * 16: goto 20: goto
146*795d594fSAndroid Build Coastguard Worker * \ /
147*795d594fSAndroid Build Coastguard Worker * 22: phi
148*795d594fSAndroid Build Coastguard Worker * 24: return
149*795d594fSAndroid Build Coastguard Worker * |
150*795d594fSAndroid Build Coastguard Worker * 28: exit
151*795d594fSAndroid Build Coastguard Worker */
152*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
153*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
154*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 3,
155*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 0,
156*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
157*795d594fSAndroid Build Coastguard Worker
158*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildGraph(data);
159*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
160*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
161*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
162*795d594fSAndroid Build Coastguard Worker
163*795d594fSAndroid Build Coastguard Worker // Test for the 4 constant.
164*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
165*795d594fSAndroid Build Coastguard Worker LiveRange* range = interval->GetFirstRange();
166*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(4u, range->GetStart());
167*795d594fSAndroid Build Coastguard Worker // Last use is the phi at the return block so instruction is live until
168*795d594fSAndroid Build Coastguard Worker // the end of the then block.
169*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(18u, range->GetEnd());
170*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
171*795d594fSAndroid Build Coastguard Worker
172*795d594fSAndroid Build Coastguard Worker // Test for the 0 constant.
173*795d594fSAndroid Build Coastguard Worker interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
174*795d594fSAndroid Build Coastguard Worker // The then branch is a hole for this constant, therefore its interval has 2 ranges.
175*795d594fSAndroid Build Coastguard Worker // First range starts from the definition and ends at the if block.
176*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
177*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(2u, range->GetStart());
178*795d594fSAndroid Build Coastguard Worker // 14 is the end of the if block.
179*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(14u, range->GetEnd());
180*795d594fSAndroid Build Coastguard Worker // Second range is the else block.
181*795d594fSAndroid Build Coastguard Worker range = range->GetNext();
182*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(18u, range->GetStart());
183*795d594fSAndroid Build Coastguard Worker // Last use is the phi at the return block.
184*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, range->GetEnd());
185*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
186*795d594fSAndroid Build Coastguard Worker
187*795d594fSAndroid Build Coastguard Worker // Test for the phi.
188*795d594fSAndroid Build Coastguard Worker interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
189*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
190*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition());
191*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, range->GetStart());
192*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(24u, range->GetEnd());
193*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
194*795d594fSAndroid Build Coastguard Worker }
195*795d594fSAndroid Build Coastguard Worker
TEST_F(LiveRangesTest,Loop1)196*795d594fSAndroid Build Coastguard Worker TEST_F(LiveRangesTest, Loop1) {
197*795d594fSAndroid Build Coastguard Worker /*
198*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
199*795d594fSAndroid Build Coastguard Worker * var a = 0;
200*795d594fSAndroid Build Coastguard Worker * while (a == a) {
201*795d594fSAndroid Build Coastguard Worker * a = 4;
202*795d594fSAndroid Build Coastguard Worker * }
203*795d594fSAndroid Build Coastguard Worker * return 5;
204*795d594fSAndroid Build Coastguard Worker *
205*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph (numbered by lifetime position):
206*795d594fSAndroid Build Coastguard Worker * 2: constant0
207*795d594fSAndroid Build Coastguard Worker * 4: constant5
208*795d594fSAndroid Build Coastguard Worker * 6: constant4
209*795d594fSAndroid Build Coastguard Worker * 8: goto
210*795d594fSAndroid Build Coastguard Worker * |
211*795d594fSAndroid Build Coastguard Worker * 12: goto
212*795d594fSAndroid Build Coastguard Worker * |
213*795d594fSAndroid Build Coastguard Worker * 14: phi
214*795d594fSAndroid Build Coastguard Worker * 16: equal
215*795d594fSAndroid Build Coastguard Worker * 18: if +++++
216*795d594fSAndroid Build Coastguard Worker * | \ +
217*795d594fSAndroid Build Coastguard Worker * | 22: goto
218*795d594fSAndroid Build Coastguard Worker * |
219*795d594fSAndroid Build Coastguard Worker * 26: return
220*795d594fSAndroid Build Coastguard Worker * |
221*795d594fSAndroid Build Coastguard Worker * 30: exit
222*795d594fSAndroid Build Coastguard Worker */
223*795d594fSAndroid Build Coastguard Worker
224*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
225*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
226*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 4,
227*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 0,
228*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFD00,
229*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 5 << 12 | 1 << 8,
230*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 1 << 8);
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildGraph(data);
233*795d594fSAndroid Build Coastguard Worker RemoveSuspendChecks(graph);
234*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
235*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
236*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard Worker // Test for the 0 constant.
239*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = graph->GetIntConstant(0)->GetLiveInterval();
240*795d594fSAndroid Build Coastguard Worker LiveRange* range = interval->GetFirstRange();
241*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(2u, range->GetStart());
242*795d594fSAndroid Build Coastguard Worker // Last use is the loop phi so instruction is live until
243*795d594fSAndroid Build Coastguard Worker // the end of the pre loop header.
244*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(14u, range->GetEnd());
245*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
246*795d594fSAndroid Build Coastguard Worker
247*795d594fSAndroid Build Coastguard Worker // Test for the 4 constant.
248*795d594fSAndroid Build Coastguard Worker interval = graph->GetIntConstant(4)->GetLiveInterval();
249*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
250*795d594fSAndroid Build Coastguard Worker // The instruction is live until the end of the loop.
251*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(6u, range->GetStart());
252*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(24u, range->GetEnd());
253*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
254*795d594fSAndroid Build Coastguard Worker
255*795d594fSAndroid Build Coastguard Worker // Test for the 5 constant.
256*795d594fSAndroid Build Coastguard Worker interval = graph->GetIntConstant(5)->GetLiveInterval();
257*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
258*795d594fSAndroid Build Coastguard Worker // The instruction is live until the return instruction after the loop.
259*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(4u, range->GetStart());
260*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(26u, range->GetEnd());
261*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker // Test for the phi.
264*795d594fSAndroid Build Coastguard Worker interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
265*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
266*795d594fSAndroid Build Coastguard Worker // Instruction is input of non-materialized Equal and hence live until If.
267*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(14u, range->GetStart());
268*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(19u, range->GetEnd());
269*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
270*795d594fSAndroid Build Coastguard Worker }
271*795d594fSAndroid Build Coastguard Worker
TEST_F(LiveRangesTest,Loop2)272*795d594fSAndroid Build Coastguard Worker TEST_F(LiveRangesTest, Loop2) {
273*795d594fSAndroid Build Coastguard Worker /*
274*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
275*795d594fSAndroid Build Coastguard Worker * var a = 0;
276*795d594fSAndroid Build Coastguard Worker * while (a == a) {
277*795d594fSAndroid Build Coastguard Worker * a = a + a;
278*795d594fSAndroid Build Coastguard Worker * }
279*795d594fSAndroid Build Coastguard Worker * return a;
280*795d594fSAndroid Build Coastguard Worker *
281*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph (numbered by lifetime position):
282*795d594fSAndroid Build Coastguard Worker * 2: constant0
283*795d594fSAndroid Build Coastguard Worker * 4: goto
284*795d594fSAndroid Build Coastguard Worker * |
285*795d594fSAndroid Build Coastguard Worker * 8: goto
286*795d594fSAndroid Build Coastguard Worker * |
287*795d594fSAndroid Build Coastguard Worker * 10: phi
288*795d594fSAndroid Build Coastguard Worker * 12: equal
289*795d594fSAndroid Build Coastguard Worker * 14: if +++++
290*795d594fSAndroid Build Coastguard Worker * | \ +
291*795d594fSAndroid Build Coastguard Worker * | 18: add
292*795d594fSAndroid Build Coastguard Worker * | 20: goto
293*795d594fSAndroid Build Coastguard Worker * |
294*795d594fSAndroid Build Coastguard Worker * 24: return
295*795d594fSAndroid Build Coastguard Worker * |
296*795d594fSAndroid Build Coastguard Worker * 28: exit
297*795d594fSAndroid Build Coastguard Worker *
298*795d594fSAndroid Build Coastguard Worker * We want to make sure the phi at 10 has a lifetime hole after the add at 20.
299*795d594fSAndroid Build Coastguard Worker */
300*795d594fSAndroid Build Coastguard Worker
301*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
302*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
303*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 6,
304*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT, 0, 0,
305*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFB00,
306*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8);
307*795d594fSAndroid Build Coastguard Worker
308*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildGraph(data);
309*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
310*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
311*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker // Test for the 0 constant.
314*795d594fSAndroid Build Coastguard Worker HIntConstant* constant = liveness.GetInstructionFromSsaIndex(0)->AsIntConstant();
315*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = constant->GetLiveInterval();
316*795d594fSAndroid Build Coastguard Worker LiveRange* range = interval->GetFirstRange();
317*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(2u, range->GetStart());
318*795d594fSAndroid Build Coastguard Worker // Last use is the loop phi so instruction is live until
319*795d594fSAndroid Build Coastguard Worker // the end of the pre loop header.
320*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(10u, range->GetEnd());
321*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
322*795d594fSAndroid Build Coastguard Worker
323*795d594fSAndroid Build Coastguard Worker // Test for the loop phi.
324*795d594fSAndroid Build Coastguard Worker HPhi* phi = liveness.GetInstructionFromSsaIndex(1)->AsPhi();
325*795d594fSAndroid Build Coastguard Worker interval = phi->GetLiveInterval();
326*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
327*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(10u, range->GetStart());
328*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(19u, range->GetEnd());
329*795d594fSAndroid Build Coastguard Worker range = range->GetNext();
330*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range != nullptr);
331*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, range->GetStart());
332*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(24u, range->GetEnd());
333*795d594fSAndroid Build Coastguard Worker
334*795d594fSAndroid Build Coastguard Worker // Test for the add instruction.
335*795d594fSAndroid Build Coastguard Worker HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
336*795d594fSAndroid Build Coastguard Worker interval = add->GetLiveInterval();
337*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
338*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(18u, range->GetStart());
339*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, range->GetEnd());
340*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
341*795d594fSAndroid Build Coastguard Worker }
342*795d594fSAndroid Build Coastguard Worker
TEST_F(LiveRangesTest,CFG4)343*795d594fSAndroid Build Coastguard Worker TEST_F(LiveRangesTest, CFG4) {
344*795d594fSAndroid Build Coastguard Worker /*
345*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
346*795d594fSAndroid Build Coastguard Worker * var a = 0;
347*795d594fSAndroid Build Coastguard Worker * var b = 4;
348*795d594fSAndroid Build Coastguard Worker * if (a == a) {
349*795d594fSAndroid Build Coastguard Worker * a = b + a;
350*795d594fSAndroid Build Coastguard Worker * } else {
351*795d594fSAndroid Build Coastguard Worker * a = b + a
352*795d594fSAndroid Build Coastguard Worker * }
353*795d594fSAndroid Build Coastguard Worker * return b;
354*795d594fSAndroid Build Coastguard Worker *
355*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph (numbered by lifetime position):
356*795d594fSAndroid Build Coastguard Worker * 2: constant0
357*795d594fSAndroid Build Coastguard Worker * 4: constant4
358*795d594fSAndroid Build Coastguard Worker * 6: goto
359*795d594fSAndroid Build Coastguard Worker * |
360*795d594fSAndroid Build Coastguard Worker * 10: equal
361*795d594fSAndroid Build Coastguard Worker * 12: if
362*795d594fSAndroid Build Coastguard Worker * / \
363*795d594fSAndroid Build Coastguard Worker * 16: add 22: add
364*795d594fSAndroid Build Coastguard Worker * 18: goto 24: goto
365*795d594fSAndroid Build Coastguard Worker * \ /
366*795d594fSAndroid Build Coastguard Worker * 26: phi
367*795d594fSAndroid Build Coastguard Worker * 28: return
368*795d594fSAndroid Build Coastguard Worker * |
369*795d594fSAndroid Build Coastguard Worker * 32: exit
370*795d594fSAndroid Build Coastguard Worker *
371*795d594fSAndroid Build Coastguard Worker * We want to make sure the constant0 has a lifetime hole after the 16: add.
372*795d594fSAndroid Build Coastguard Worker */
373*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
374*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
375*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 1 << 8,
376*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 5,
377*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT, 1 << 8,
378*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0x300,
379*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT, 1 << 8,
380*795d594fSAndroid Build Coastguard Worker Instruction::RETURN);
381*795d594fSAndroid Build Coastguard Worker
382*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildGraph(data);
383*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
384*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
385*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
386*795d594fSAndroid Build Coastguard Worker
387*795d594fSAndroid Build Coastguard Worker // Test for the 0 constant.
388*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
389*795d594fSAndroid Build Coastguard Worker LiveRange* range = interval->GetFirstRange();
390*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(2u, range->GetStart());
391*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(17u, range->GetEnd());
392*795d594fSAndroid Build Coastguard Worker range = range->GetNext();
393*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range != nullptr);
394*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(20u, range->GetStart());
395*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(23u, range->GetEnd());
396*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
397*795d594fSAndroid Build Coastguard Worker
398*795d594fSAndroid Build Coastguard Worker // Test for the 4 constant.
399*795d594fSAndroid Build Coastguard Worker interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
400*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
401*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(4u, range->GetStart());
402*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(17u, range->GetEnd());
403*795d594fSAndroid Build Coastguard Worker range = range->GetNext();
404*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(20u, range->GetStart());
405*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(23u, range->GetEnd());
406*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
407*795d594fSAndroid Build Coastguard Worker
408*795d594fSAndroid Build Coastguard Worker // Test for the first add.
409*795d594fSAndroid Build Coastguard Worker HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
410*795d594fSAndroid Build Coastguard Worker interval = add->GetLiveInterval();
411*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
412*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(16u, range->GetStart());
413*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(20u, range->GetEnd());
414*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
415*795d594fSAndroid Build Coastguard Worker
416*795d594fSAndroid Build Coastguard Worker // Test for the second add.
417*795d594fSAndroid Build Coastguard Worker add = liveness.GetInstructionFromSsaIndex(3)->AsAdd();
418*795d594fSAndroid Build Coastguard Worker interval = add->GetLiveInterval();
419*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
420*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(22u, range->GetStart());
421*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(26u, range->GetEnd());
422*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
423*795d594fSAndroid Build Coastguard Worker
424*795d594fSAndroid Build Coastguard Worker HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi();
425*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(phi->GetUses().HasExactlyOneElement());
426*795d594fSAndroid Build Coastguard Worker interval = phi->GetLiveInterval();
427*795d594fSAndroid Build Coastguard Worker range = interval->GetFirstRange();
428*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(26u, range->GetStart());
429*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(28u, range->GetEnd());
430*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(range->GetNext() == nullptr);
431*795d594fSAndroid Build Coastguard Worker }
432*795d594fSAndroid Build Coastguard Worker
433*795d594fSAndroid Build Coastguard Worker } // namespace art
434