blob: f9a955fb0ac73c24b8081227eb7132fd7a91db3d [file] [log] [blame]
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +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
Mark Mendellfb8d2792015-03-31 22:16:59 -040017#include "arch/x86/instruction_set_features_x86.h"
Mathieu Chartierb666f482015-02-18 14:33:14 -080018#include "base/arena_allocator.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010019#include "builder.h"
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010020#include "code_generator.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010021#include "code_generator_x86.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010022#include "dex_file.h"
23#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000024#include "driver/compiler_options.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010025#include "nodes.h"
26#include "optimizing_unit_test.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010027#include "prepare_for_register_allocation.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010028#include "ssa_liveness_analysis.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010029
Alex Light68289a52015-12-15 17:30:30 -080030namespace art {
David Brazdild9510df2015-11-04 23:30:22 +000031
David Brazdil4833f5a2015-12-16 10:37:39 +000032class LiveRangesTest : public CommonCompilerTest {};
33
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010034static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) {
David Brazdilbadd8262016-02-02 16:28:56 +000035 HGraph* graph = CreateCFG(allocator, data);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000036 // Suspend checks implementation may change in the future, and this test relies
37 // on how instructions are ordered.
38 RemoveSuspendChecks(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +010039 // `Inline` conditions into ifs.
40 PrepareForRegisterAllocation(graph).Run();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010041 return graph;
42}
43
David Brazdil4833f5a2015-12-16 10:37:39 +000044TEST_F(LiveRangesTest, CFG1) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010045 /*
46 * Test the following snippet:
47 * return 0;
48 *
49 * Which becomes the following graph (numbered by lifetime position):
50 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010051 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010052 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010053 * 8: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010054 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010055 * 12: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010056 */
57 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
58 Instruction::CONST_4 | 0 | 0,
59 Instruction::RETURN);
60
61 ArenaPool pool;
62 ArenaAllocator allocator(&pool);
63 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010064
Mark Mendellfb8d2792015-03-31 22:16:59 -040065 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
66 X86InstructionSetFeatures::FromCppDefines());
67 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +010068 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010069 liveness.Analyze();
70
71 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010072 LiveRange* range = interval->GetFirstRange();
73 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010074 // Last use is the return instruction.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +010075 ASSERT_EQ(8u, range->GetEnd());
Vladimir Markoec7802a2015-10-01 20:57:57 +010076 HBasicBlock* block = graph->GetBlocks()[1];
Roland Levillain476df552014-10-09 17:51:36 +010077 ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010078 ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
79 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010080}
81
David Brazdil4833f5a2015-12-16 10:37:39 +000082TEST_F(LiveRangesTest, CFG2) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010083 /*
84 * Test the following snippet:
85 * var a = 0;
86 * if (0 == 0) {
87 * } else {
88 * }
89 * return a;
90 *
91 * Which becomes the following graph (numbered by lifetime position):
92 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010094 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010095 * 8: equal
96 * 10: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010097 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010098 * 14: goto 18: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010099 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100100 * 22: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100101 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100102 * 26: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100103 */
104 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
105 Instruction::CONST_4 | 0 | 0,
106 Instruction::IF_EQ, 3,
107 Instruction::GOTO | 0x100,
108 Instruction::RETURN | 0 << 8);
109
110 ArenaPool pool;
111 ArenaAllocator allocator(&pool);
112 HGraph* graph = BuildGraph(data, &allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400113 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
114 X86InstructionSetFeatures::FromCppDefines());
115 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100116 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100117 liveness.Analyze();
118
119 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100120 LiveRange* range = interval->GetFirstRange();
121 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100122 // Last use is the return instruction.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100123 ASSERT_EQ(22u, range->GetEnd());
Vladimir Markoec7802a2015-10-01 20:57:57 +0100124 HBasicBlock* block = graph->GetBlocks()[3];
Roland Levillain476df552014-10-09 17:51:36 +0100125 ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100126 ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
127 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100128}
129
David Brazdil4833f5a2015-12-16 10:37:39 +0000130TEST_F(LiveRangesTest, CFG3) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100131 /*
132 * Test the following snippet:
133 * var a = 0;
134 * if (0 == 0) {
135 * } else {
136 * a = 4;
137 * }
138 * return a;
139 *
140 * Which becomes the following graph (numbered by lifetime position):
141 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142 * 4: constant4
143 * 6: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100144 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100145 * 10: equal
146 * 12: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100147 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100148 * 16: goto 20: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100149 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100150 * 22: phi
151 * 24: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100152 * |
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100153 * 28: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100154 */
155 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
156 Instruction::CONST_4 | 0 | 0,
157 Instruction::IF_EQ, 3,
158 Instruction::CONST_4 | 4 << 12 | 0,
159 Instruction::RETURN | 0 << 8);
160
161 ArenaPool pool;
162 ArenaAllocator allocator(&pool);
163 HGraph* graph = BuildGraph(data, &allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400164 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
165 X86InstructionSetFeatures::FromCppDefines());
166 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100167 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100168 liveness.Analyze();
169
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100170 // Test for the 4 constant.
171 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100172 LiveRange* range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100173 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100174 // Last use is the phi at the return block so instruction is live until
175 // the end of the then block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100176 ASSERT_EQ(18u, range->GetEnd());
177 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100178
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100179 // Test for the 0 constant.
180 interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100181 // The then branch is a hole for this constant, therefore its interval has 2 ranges.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100182 // First range starts from the definition and ends at the if block.
183 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100184 ASSERT_EQ(2u, range->GetStart());
185 // 14 is the end of the if block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100186 ASSERT_EQ(14u, range->GetEnd());
187 // Second range is the else block.
188 range = range->GetNext();
189 ASSERT_EQ(18u, range->GetStart());
190 // Last use is the phi at the return block.
191 ASSERT_EQ(22u, range->GetEnd());
192 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100193
194 // Test for the phi.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100195 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100196 range = interval->GetFirstRange();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100197 ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100198 ASSERT_EQ(22u, range->GetStart());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100199 ASSERT_EQ(24u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100200 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100201}
202
David Brazdil4833f5a2015-12-16 10:37:39 +0000203TEST_F(LiveRangesTest, Loop1) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100204 /*
205 * Test the following snippet:
206 * var a = 0;
207 * while (a == a) {
208 * a = 4;
209 * }
210 * return 5;
211 *
212 * Which becomes the following graph (numbered by lifetime position):
213 * 2: constant0
David Brazdildee58d62016-04-07 09:54:26 +0000214 * 4: constant5
215 * 6: constant4
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100216 * 8: goto
217 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100218 * 12: goto
219 * |
220 * 14: phi
221 * 16: equal
222 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100223 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100224 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100225 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100226 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100227 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100228 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100229 */
230
231 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
232 Instruction::CONST_4 | 0 | 0,
233 Instruction::IF_EQ, 4,
234 Instruction::CONST_4 | 4 << 12 | 0,
235 Instruction::GOTO | 0xFD00,
236 Instruction::CONST_4 | 5 << 12 | 1 << 8,
237 Instruction::RETURN | 1 << 8);
238
239 ArenaPool pool;
240 ArenaAllocator allocator(&pool);
241 HGraph* graph = BuildGraph(data, &allocator);
Nicolas Geoffray9ebc72c2014-09-25 16:33:42 +0100242 RemoveSuspendChecks(graph);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400243 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
244 X86InstructionSetFeatures::FromCppDefines());
245 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100246 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100247 liveness.Analyze();
248
249 // Test for the 0 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000250 LiveInterval* interval = graph->GetIntConstant(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100251 LiveRange* range = interval->GetFirstRange();
252 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100253 // Last use is the loop phi so instruction is live until
254 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100255 ASSERT_EQ(14u, range->GetEnd());
256 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100257
258 // Test for the 4 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000259 interval = graph->GetIntConstant(4)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100260 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100261 // The instruction is live until the end of the loop.
David Brazdildee58d62016-04-07 09:54:26 +0000262 ASSERT_EQ(6u, range->GetStart());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100263 ASSERT_EQ(24u, range->GetEnd());
264 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100265
266 // Test for the 5 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000267 interval = graph->GetIntConstant(5)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100268 range = interval->GetFirstRange();
269 // The instruction is live until the return instruction after the loop.
David Brazdildee58d62016-04-07 09:54:26 +0000270 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100271 ASSERT_EQ(26u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100272 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100273
274 // Test for the phi.
275 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100276 range = interval->GetFirstRange();
David Brazdilb3e773e2016-01-26 11:28:37 +0000277 // Instruction is input of non-materialized Equal and hence live until If.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100278 ASSERT_EQ(14u, range->GetStart());
David Brazdilb3e773e2016-01-26 11:28:37 +0000279 ASSERT_EQ(19u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100280 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100281}
282
David Brazdil4833f5a2015-12-16 10:37:39 +0000283TEST_F(LiveRangesTest, Loop2) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100284 /*
285 * Test the following snippet:
286 * var a = 0;
287 * while (a == a) {
288 * a = a + a;
289 * }
290 * return a;
291 *
292 * Which becomes the following graph (numbered by lifetime position):
293 * 2: constant0
294 * 4: goto
295 * |
296 * 8: goto
297 * |
298 * 10: phi
299 * 12: equal
300 * 14: if +++++
301 * | \ +
David Brazdilbadd8262016-02-02 16:28:56 +0000302 * | 18: add
303 * | 20: goto
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100304 * |
David Brazdilbadd8262016-02-02 16:28:56 +0000305 * 24: return
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100306 * |
David Brazdilbadd8262016-02-02 16:28:56 +0000307 * 28: exit
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100308 *
309 * We want to make sure the phi at 10 has a lifetime hole after the add at 20.
310 */
311
312 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
313 Instruction::CONST_4 | 0 | 0,
314 Instruction::IF_EQ, 6,
315 Instruction::ADD_INT, 0, 0,
316 Instruction::GOTO | 0xFB00,
317 Instruction::RETURN | 0 << 8);
318
319 ArenaPool pool;
320 ArenaAllocator allocator(&pool);
321 HGraph* graph = BuildGraph(data, &allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400322 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
323 X86InstructionSetFeatures::FromCppDefines());
324 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100325 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100326 liveness.Analyze();
327
328 // Test for the 0 constant.
329 HIntConstant* constant = liveness.GetInstructionFromSsaIndex(0)->AsIntConstant();
330 LiveInterval* interval = constant->GetLiveInterval();
331 LiveRange* range = interval->GetFirstRange();
332 ASSERT_EQ(2u, range->GetStart());
333 // Last use is the loop phi so instruction is live until
334 // the end of the pre loop header.
335 ASSERT_EQ(10u, range->GetEnd());
336 ASSERT_TRUE(range->GetNext() == nullptr);
337
338 // Test for the loop phi.
339 HPhi* phi = liveness.GetInstructionFromSsaIndex(1)->AsPhi();
340 interval = phi->GetLiveInterval();
341 range = interval->GetFirstRange();
342 ASSERT_EQ(10u, range->GetStart());
David Brazdilbadd8262016-02-02 16:28:56 +0000343 ASSERT_EQ(19u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100344 range = range->GetNext();
345 ASSERT_TRUE(range != nullptr);
David Brazdilbadd8262016-02-02 16:28:56 +0000346 ASSERT_EQ(22u, range->GetStart());
347 ASSERT_EQ(24u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100348
349 // Test for the add instruction.
350 HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
351 interval = add->GetLiveInterval();
352 range = interval->GetFirstRange();
David Brazdilbadd8262016-02-02 16:28:56 +0000353 ASSERT_EQ(18u, range->GetStart());
354 ASSERT_EQ(22u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100355 ASSERT_TRUE(range->GetNext() == nullptr);
356}
357
David Brazdil4833f5a2015-12-16 10:37:39 +0000358TEST_F(LiveRangesTest, CFG4) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100359 /*
360 * Test the following snippet:
361 * var a = 0;
362 * var b = 4;
363 * if (a == a) {
364 * a = b + a;
365 * } else {
366 * a = b + a
367 * }
368 * return b;
369 *
370 * Which becomes the following graph (numbered by lifetime position):
371 * 2: constant0
372 * 4: constant4
373 * 6: goto
374 * |
375 * 10: equal
376 * 12: if
377 * / \
378 * 16: add 22: add
379 * 18: goto 24: goto
380 * \ /
381 * 26: phi
382 * 28: return
383 * |
384 * 32: exit
385 *
386 * We want to make sure the constant0 has a lifetime hole after the 16: add.
387 */
388 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
389 Instruction::CONST_4 | 0 | 0,
390 Instruction::CONST_4 | 4 << 12 | 1 << 8,
391 Instruction::IF_EQ, 5,
392 Instruction::ADD_INT, 1 << 8,
393 Instruction::GOTO | 0x300,
394 Instruction::ADD_INT, 1 << 8,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000395 Instruction::RETURN);
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100396
397 ArenaPool pool;
398 ArenaAllocator allocator(&pool);
399 HGraph* graph = BuildGraph(data, &allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400400 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
401 X86InstructionSetFeatures::FromCppDefines());
402 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100403 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100404 liveness.Analyze();
405
406 // Test for the 0 constant.
407 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
408 LiveRange* range = interval->GetFirstRange();
409 ASSERT_EQ(2u, range->GetStart());
Mark Mendell09b84632015-02-13 17:48:38 -0500410 ASSERT_EQ(17u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100411 range = range->GetNext();
412 ASSERT_TRUE(range != nullptr);
413 ASSERT_EQ(20u, range->GetStart());
Mark Mendell09b84632015-02-13 17:48:38 -0500414 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100415 ASSERT_TRUE(range->GetNext() == nullptr);
416
417 // Test for the 4 constant.
418 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
419 range = interval->GetFirstRange();
420 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000421 ASSERT_EQ(17u, range->GetEnd());
422 range = range->GetNext();
423 ASSERT_EQ(20u, range->GetStart());
424 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100425 ASSERT_TRUE(range->GetNext() == nullptr);
426
427 // Test for the first add.
428 HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
429 interval = add->GetLiveInterval();
430 range = interval->GetFirstRange();
431 ASSERT_EQ(16u, range->GetStart());
432 ASSERT_EQ(20u, range->GetEnd());
433 ASSERT_TRUE(range->GetNext() == nullptr);
434
435 // Test for the second add.
436 add = liveness.GetInstructionFromSsaIndex(3)->AsAdd();
437 interval = add->GetLiveInterval();
438 range = interval->GetFirstRange();
439 ASSERT_EQ(22u, range->GetStart());
440 ASSERT_EQ(26u, range->GetEnd());
441 ASSERT_TRUE(range->GetNext() == nullptr);
442
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100443 HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi();
Vladimir Marko46817b82016-03-29 12:21:58 +0100444 ASSERT_TRUE(phi->GetUses().HasExactlyOneElement());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100445 interval = phi->GetLiveInterval();
446 range = interval->GetFirstRange();
447 ASSERT_EQ(26u, range->GetStart());
448 ASSERT_EQ(28u, range->GetEnd());
449 ASSERT_TRUE(range->GetNext() == nullptr);
450}
451
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100452} // namespace art