blob: 66660662e46808308afe97cfdf5d025a1cb875e4 [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"
David Sehr9e734c72018-01-04 17:56:19 -080022#include "dex/dex_file.h"
23#include "dex/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
Vladimir Markoca6fff82017-10-03 14:49:14 +010032class LiveRangesTest : public OptimizingUnitTest {
33 public:
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080034 HGraph* BuildGraph(const std::vector<uint16_t>& data);
Vladimir Markoca6fff82017-10-03 14:49:14 +010035};
David Brazdil4833f5a2015-12-16 10:37:39 +000036
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080037HGraph* LiveRangesTest::BuildGraph(const std::vector<uint16_t>& data) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010038 HGraph* graph = CreateCFG(data);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000039 // Suspend checks implementation may change in the future, and this test relies
40 // on how instructions are ordered.
41 RemoveSuspendChecks(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +010042 // `Inline` conditions into ifs.
43 PrepareForRegisterAllocation(graph).Run();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010044 return graph;
45}
46
David Brazdil4833f5a2015-12-16 10:37:39 +000047TEST_F(LiveRangesTest, CFG1) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010048 /*
49 * Test the following snippet:
50 * return 0;
51 *
52 * Which becomes the following graph (numbered by lifetime position):
53 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010054 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010055 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010056 * 8: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010057 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010058 * 12: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010059 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080060 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010061 Instruction::CONST_4 | 0 | 0,
62 Instruction::RETURN);
63
Vladimir Markoca6fff82017-10-03 14:49:14 +010064 HGraph* graph = BuildGraph(data);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010065
Mark Mendellfb8d2792015-03-31 22:16:59 -040066 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
67 X86InstructionSetFeatures::FromCppDefines());
68 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +010069 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010070 liveness.Analyze();
71
72 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010073 LiveRange* range = interval->GetFirstRange();
74 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010075 // Last use is the return instruction.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +010076 ASSERT_EQ(8u, range->GetEnd());
Vladimir Markoec7802a2015-10-01 20:57:57 +010077 HBasicBlock* block = graph->GetBlocks()[1];
Roland Levillain476df552014-10-09 17:51:36 +010078 ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010079 ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition());
80 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010081}
82
David Brazdil4833f5a2015-12-16 10:37:39 +000083TEST_F(LiveRangesTest, CFG2) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010084 /*
85 * Test the following snippet:
86 * var a = 0;
87 * if (0 == 0) {
88 * } else {
89 * }
90 * return a;
91 *
92 * Which becomes the following graph (numbered by lifetime position):
93 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010094 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010095 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010096 * 8: equal
97 * 10: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010098 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010099 * 14: goto 18: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100100 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100101 * 22: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100102 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100103 * 26: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100104 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800105 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100106 Instruction::CONST_4 | 0 | 0,
107 Instruction::IF_EQ, 3,
108 Instruction::GOTO | 0x100,
109 Instruction::RETURN | 0 << 8);
110
Vladimir Markoca6fff82017-10-03 14:49:14 +0100111 HGraph* graph = BuildGraph(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400112 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
113 X86InstructionSetFeatures::FromCppDefines());
114 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100115 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100116 liveness.Analyze();
117
118 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100119 LiveRange* range = interval->GetFirstRange();
120 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100121 // Last use is the return instruction.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100122 ASSERT_EQ(22u, range->GetEnd());
Vladimir Markoec7802a2015-10-01 20:57:57 +0100123 HBasicBlock* block = graph->GetBlocks()[3];
Roland Levillain476df552014-10-09 17:51:36 +0100124 ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100125 ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
126 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100127}
128
David Brazdil4833f5a2015-12-16 10:37:39 +0000129TEST_F(LiveRangesTest, CFG3) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100130 /*
131 * Test the following snippet:
132 * var a = 0;
133 * if (0 == 0) {
134 * } else {
135 * a = 4;
136 * }
137 * return a;
138 *
139 * Which becomes the following graph (numbered by lifetime position):
140 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100141 * 4: constant4
142 * 6: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100143 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100144 * 10: equal
145 * 12: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100146 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100147 * 16: goto 20: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100148 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100149 * 22: phi
150 * 24: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100151 * |
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100152 * 28: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100153 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800154 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100155 Instruction::CONST_4 | 0 | 0,
156 Instruction::IF_EQ, 3,
157 Instruction::CONST_4 | 4 << 12 | 0,
158 Instruction::RETURN | 0 << 8);
159
Vladimir Markoca6fff82017-10-03 14:49:14 +0100160 HGraph* graph = BuildGraph(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400161 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
162 X86InstructionSetFeatures::FromCppDefines());
163 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100164 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100165 liveness.Analyze();
166
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100167 // Test for the 4 constant.
168 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100169 LiveRange* range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100170 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100171 // Last use is the phi at the return block so instruction is live until
172 // the end of the then block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100173 ASSERT_EQ(18u, range->GetEnd());
174 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100175
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100176 // Test for the 0 constant.
177 interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100178 // The then branch is a hole for this constant, therefore its interval has 2 ranges.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100179 // First range starts from the definition and ends at the if block.
180 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100181 ASSERT_EQ(2u, range->GetStart());
182 // 14 is the end of the if block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100183 ASSERT_EQ(14u, range->GetEnd());
184 // Second range is the else block.
185 range = range->GetNext();
186 ASSERT_EQ(18u, range->GetStart());
187 // Last use is the phi at the return block.
188 ASSERT_EQ(22u, range->GetEnd());
189 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100190
191 // Test for the phi.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100192 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100193 range = interval->GetFirstRange();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100194 ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100195 ASSERT_EQ(22u, range->GetStart());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100196 ASSERT_EQ(24u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100197 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100198}
199
David Brazdil4833f5a2015-12-16 10:37:39 +0000200TEST_F(LiveRangesTest, Loop1) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100201 /*
202 * Test the following snippet:
203 * var a = 0;
204 * while (a == a) {
205 * a = 4;
206 * }
207 * return 5;
208 *
209 * Which becomes the following graph (numbered by lifetime position):
210 * 2: constant0
David Brazdildee58d62016-04-07 09:54:26 +0000211 * 4: constant5
212 * 6: constant4
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100213 * 8: goto
214 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100215 * 12: goto
216 * |
217 * 14: phi
218 * 16: equal
219 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100220 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100221 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100222 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100223 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100224 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100225 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100226 */
227
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800228 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100229 Instruction::CONST_4 | 0 | 0,
230 Instruction::IF_EQ, 4,
231 Instruction::CONST_4 | 4 << 12 | 0,
232 Instruction::GOTO | 0xFD00,
233 Instruction::CONST_4 | 5 << 12 | 1 << 8,
234 Instruction::RETURN | 1 << 8);
235
Vladimir Markoca6fff82017-10-03 14:49:14 +0100236 HGraph* graph = BuildGraph(data);
Nicolas Geoffray9ebc72c2014-09-25 16:33:42 +0100237 RemoveSuspendChecks(graph);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400238 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
239 X86InstructionSetFeatures::FromCppDefines());
240 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100241 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100242 liveness.Analyze();
243
244 // Test for the 0 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000245 LiveInterval* interval = graph->GetIntConstant(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100246 LiveRange* range = interval->GetFirstRange();
247 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100248 // Last use is the loop phi so instruction is live until
249 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100250 ASSERT_EQ(14u, range->GetEnd());
251 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100252
253 // Test for the 4 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000254 interval = graph->GetIntConstant(4)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100255 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100256 // The instruction is live until the end of the loop.
David Brazdildee58d62016-04-07 09:54:26 +0000257 ASSERT_EQ(6u, range->GetStart());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100258 ASSERT_EQ(24u, range->GetEnd());
259 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100260
261 // Test for the 5 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000262 interval = graph->GetIntConstant(5)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100263 range = interval->GetFirstRange();
264 // The instruction is live until the return instruction after the loop.
David Brazdildee58d62016-04-07 09:54:26 +0000265 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100266 ASSERT_EQ(26u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100267 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100268
269 // Test for the phi.
270 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100271 range = interval->GetFirstRange();
David Brazdilb3e773e2016-01-26 11:28:37 +0000272 // Instruction is input of non-materialized Equal and hence live until If.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100273 ASSERT_EQ(14u, range->GetStart());
David Brazdilb3e773e2016-01-26 11:28:37 +0000274 ASSERT_EQ(19u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100275 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100276}
277
David Brazdil4833f5a2015-12-16 10:37:39 +0000278TEST_F(LiveRangesTest, Loop2) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100279 /*
280 * Test the following snippet:
281 * var a = 0;
282 * while (a == a) {
283 * a = a + a;
284 * }
285 * return a;
286 *
287 * Which becomes the following graph (numbered by lifetime position):
288 * 2: constant0
289 * 4: goto
290 * |
291 * 8: goto
292 * |
293 * 10: phi
294 * 12: equal
295 * 14: if +++++
296 * | \ +
David Brazdilbadd8262016-02-02 16:28:56 +0000297 * | 18: add
298 * | 20: goto
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100299 * |
David Brazdilbadd8262016-02-02 16:28:56 +0000300 * 24: return
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100301 * |
David Brazdilbadd8262016-02-02 16:28:56 +0000302 * 28: exit
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100303 *
304 * We want to make sure the phi at 10 has a lifetime hole after the add at 20.
305 */
306
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800307 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100308 Instruction::CONST_4 | 0 | 0,
309 Instruction::IF_EQ, 6,
310 Instruction::ADD_INT, 0, 0,
311 Instruction::GOTO | 0xFB00,
312 Instruction::RETURN | 0 << 8);
313
Vladimir Markoca6fff82017-10-03 14:49:14 +0100314 HGraph* graph = BuildGraph(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400315 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
316 X86InstructionSetFeatures::FromCppDefines());
317 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100318 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100319 liveness.Analyze();
320
321 // Test for the 0 constant.
322 HIntConstant* constant = liveness.GetInstructionFromSsaIndex(0)->AsIntConstant();
323 LiveInterval* interval = constant->GetLiveInterval();
324 LiveRange* range = interval->GetFirstRange();
325 ASSERT_EQ(2u, range->GetStart());
326 // Last use is the loop phi so instruction is live until
327 // the end of the pre loop header.
328 ASSERT_EQ(10u, range->GetEnd());
329 ASSERT_TRUE(range->GetNext() == nullptr);
330
331 // Test for the loop phi.
332 HPhi* phi = liveness.GetInstructionFromSsaIndex(1)->AsPhi();
333 interval = phi->GetLiveInterval();
334 range = interval->GetFirstRange();
335 ASSERT_EQ(10u, range->GetStart());
David Brazdilbadd8262016-02-02 16:28:56 +0000336 ASSERT_EQ(19u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100337 range = range->GetNext();
338 ASSERT_TRUE(range != nullptr);
David Brazdilbadd8262016-02-02 16:28:56 +0000339 ASSERT_EQ(22u, range->GetStart());
340 ASSERT_EQ(24u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100341
342 // Test for the add instruction.
343 HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
344 interval = add->GetLiveInterval();
345 range = interval->GetFirstRange();
David Brazdilbadd8262016-02-02 16:28:56 +0000346 ASSERT_EQ(18u, range->GetStart());
347 ASSERT_EQ(22u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100348 ASSERT_TRUE(range->GetNext() == nullptr);
349}
350
David Brazdil4833f5a2015-12-16 10:37:39 +0000351TEST_F(LiveRangesTest, CFG4) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100352 /*
353 * Test the following snippet:
354 * var a = 0;
355 * var b = 4;
356 * if (a == a) {
357 * a = b + a;
358 * } else {
359 * a = b + a
360 * }
361 * return b;
362 *
363 * Which becomes the following graph (numbered by lifetime position):
364 * 2: constant0
365 * 4: constant4
366 * 6: goto
367 * |
368 * 10: equal
369 * 12: if
370 * / \
371 * 16: add 22: add
372 * 18: goto 24: goto
373 * \ /
374 * 26: phi
375 * 28: return
376 * |
377 * 32: exit
378 *
379 * We want to make sure the constant0 has a lifetime hole after the 16: add.
380 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800381 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100382 Instruction::CONST_4 | 0 | 0,
383 Instruction::CONST_4 | 4 << 12 | 1 << 8,
384 Instruction::IF_EQ, 5,
385 Instruction::ADD_INT, 1 << 8,
386 Instruction::GOTO | 0x300,
387 Instruction::ADD_INT, 1 << 8,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000388 Instruction::RETURN);
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100389
Vladimir Markoca6fff82017-10-03 14:49:14 +0100390 HGraph* graph = BuildGraph(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400391 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
392 X86InstructionSetFeatures::FromCppDefines());
393 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100394 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100395 liveness.Analyze();
396
397 // Test for the 0 constant.
398 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
399 LiveRange* range = interval->GetFirstRange();
400 ASSERT_EQ(2u, range->GetStart());
Mark Mendell09b84632015-02-13 17:48:38 -0500401 ASSERT_EQ(17u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100402 range = range->GetNext();
403 ASSERT_TRUE(range != nullptr);
404 ASSERT_EQ(20u, range->GetStart());
Mark Mendell09b84632015-02-13 17:48:38 -0500405 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100406 ASSERT_TRUE(range->GetNext() == nullptr);
407
408 // Test for the 4 constant.
409 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
410 range = interval->GetFirstRange();
411 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000412 ASSERT_EQ(17u, range->GetEnd());
413 range = range->GetNext();
414 ASSERT_EQ(20u, range->GetStart());
415 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100416 ASSERT_TRUE(range->GetNext() == nullptr);
417
418 // Test for the first add.
419 HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
420 interval = add->GetLiveInterval();
421 range = interval->GetFirstRange();
422 ASSERT_EQ(16u, range->GetStart());
423 ASSERT_EQ(20u, range->GetEnd());
424 ASSERT_TRUE(range->GetNext() == nullptr);
425
426 // Test for the second add.
427 add = liveness.GetInstructionFromSsaIndex(3)->AsAdd();
428 interval = add->GetLiveInterval();
429 range = interval->GetFirstRange();
430 ASSERT_EQ(22u, range->GetStart());
431 ASSERT_EQ(26u, range->GetEnd());
432 ASSERT_TRUE(range->GetNext() == nullptr);
433
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100434 HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi();
Vladimir Marko46817b82016-03-29 12:21:58 +0100435 ASSERT_TRUE(phi->GetUses().HasExactlyOneElement());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100436 interval = phi->GetLiveInterval();
437 range = interval->GetFirstRange();
438 ASSERT_EQ(26u, range->GetStart());
439 ASSERT_EQ(28u, range->GetEnd());
440 ASSERT_TRUE(range->GetNext() == nullptr);
441}
442
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100443} // namespace art