blob: fb1a23eef4bd7a32660bd2771092408b3760ba46 [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
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Vladimír Marko434d9682022-11-04 14:04:17 +000018#include "base/macros.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010019#include "builder.h"
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010020#include "code_generator.h"
David Sehr9e734c72018-01-04 17:56:19 -080021#include "dex/dex_file.h"
22#include "dex/dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000023#include "driver/compiler_options.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010024#include "nodes.h"
25#include "optimizing_unit_test.h"
Nicolas Geoffray360231a2014-10-08 21:07:48 +010026#include "prepare_for_register_allocation.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010027#include "ssa_liveness_analysis.h"
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010028
Vladimír Marko434d9682022-11-04 14:04:17 +000029namespace art HIDDEN {
David Brazdild9510df2015-11-04 23:30:22 +000030
Santiago Aboy Solanes2c50b3a2023-02-10 10:25:31 +000031class LiveRangesTest : public CommonCompilerTest, public OptimizingUnitTestHelper {
Vladimir Markof91fc122020-05-13 09:21:00 +010032 protected:
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080033 HGraph* BuildGraph(const std::vector<uint16_t>& data);
Vladimir Markof91fc122020-05-13 09:21:00 +010034
35 std::unique_ptr<CompilerOptions> compiler_options_;
Vladimir Markoca6fff82017-10-03 14:49:14 +010036};
David Brazdil4833f5a2015-12-16 10:37:39 +000037
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080038HGraph* LiveRangesTest::BuildGraph(const std::vector<uint16_t>& data) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010039 HGraph* graph = CreateCFG(data);
Vladimir Markof91fc122020-05-13 09:21:00 +010040 compiler_options_ = CommonCompilerTest::CreateCompilerOptions(kRuntimeISA, "default");
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000041 // Suspend checks implementation may change in the future, and this test relies
42 // on how instructions are ordered.
43 RemoveSuspendChecks(graph);
Nicolas Geoffray360231a2014-10-08 21:07:48 +010044 // `Inline` conditions into ifs.
Nicolas Geoffray61ba8d22018-08-07 09:55:57 +010045 PrepareForRegisterAllocation(graph, *compiler_options_).Run();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010046 return graph;
47}
48
David Brazdil4833f5a2015-12-16 10:37:39 +000049TEST_F(LiveRangesTest, CFG1) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010050 /*
51 * Test the following snippet:
52 * return 0;
53 *
54 * Which becomes the following graph (numbered by lifetime position):
55 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010056 * 4: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010057 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010058 * 8: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010059 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010060 * 12: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010061 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080062 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +010063 Instruction::CONST_4 | 0 | 0,
64 Instruction::RETURN);
65
Vladimir Markoca6fff82017-10-03 14:49:14 +010066 HGraph* graph = BuildGraph(data);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010067
Vladimir Markoa0431112018-06-25 09:32:54 +010068 std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
69 SsaLivenessAnalysis liveness(graph, codegen.get(), 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);
Vladimir Markoa0431112018-06-25 09:32:54 +0100112 std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
113 SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100114 liveness.Analyze();
115
116 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100117 LiveRange* range = interval->GetFirstRange();
118 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100119 // Last use is the return instruction.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100120 ASSERT_EQ(22u, range->GetEnd());
Vladimir Markoec7802a2015-10-01 20:57:57 +0100121 HBasicBlock* block = graph->GetBlocks()[3];
Roland Levillain476df552014-10-09 17:51:36 +0100122 ASSERT_TRUE(block->GetLastInstruction()->IsReturn());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100123 ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition());
124 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100125}
126
David Brazdil4833f5a2015-12-16 10:37:39 +0000127TEST_F(LiveRangesTest, CFG3) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100128 /*
129 * Test the following snippet:
130 * var a = 0;
131 * if (0 == 0) {
132 * } else {
133 * a = 4;
134 * }
135 * return a;
136 *
137 * Which becomes the following graph (numbered by lifetime position):
138 * 2: constant0
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100139 * 4: constant4
140 * 6: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100141 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142 * 10: equal
143 * 12: if
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100144 * / \
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100145 * 16: goto 20: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100146 * \ /
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100147 * 22: phi
148 * 24: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100149 * |
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100150 * 28: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100151 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800152 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100153 Instruction::CONST_4 | 0 | 0,
154 Instruction::IF_EQ, 3,
155 Instruction::CONST_4 | 4 << 12 | 0,
156 Instruction::RETURN | 0 << 8);
157
Vladimir Markoca6fff82017-10-03 14:49:14 +0100158 HGraph* graph = BuildGraph(data);
Vladimir Markoa0431112018-06-25 09:32:54 +0100159 std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
160 SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100161 liveness.Analyze();
162
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100163 // Test for the 4 constant.
164 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100165 LiveRange* range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100166 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100167 // Last use is the phi at the return block so instruction is live until
168 // the end of the then block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100169 ASSERT_EQ(18u, range->GetEnd());
170 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100171
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100172 // Test for the 0 constant.
173 interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100174 // The then branch is a hole for this constant, therefore its interval has 2 ranges.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100175 // First range starts from the definition and ends at the if block.
176 range = interval->GetFirstRange();
Nicolas Geoffrayec7e4722014-06-06 11:24:33 +0100177 ASSERT_EQ(2u, range->GetStart());
178 // 14 is the end of the if block.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100179 ASSERT_EQ(14u, range->GetEnd());
180 // Second range is the else block.
181 range = range->GetNext();
182 ASSERT_EQ(18u, range->GetStart());
183 // Last use is the phi at the return block.
184 ASSERT_EQ(22u, range->GetEnd());
185 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100186
187 // Test for the phi.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100188 interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100189 range = interval->GetFirstRange();
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100190 ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100191 ASSERT_EQ(22u, range->GetStart());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100192 ASSERT_EQ(24u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100193 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100194}
195
David Brazdil4833f5a2015-12-16 10:37:39 +0000196TEST_F(LiveRangesTest, Loop1) {
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100197 /*
198 * Test the following snippet:
199 * var a = 0;
200 * while (a == a) {
201 * a = 4;
202 * }
203 * return 5;
204 *
205 * Which becomes the following graph (numbered by lifetime position):
206 * 2: constant0
David Brazdildee58d62016-04-07 09:54:26 +0000207 * 4: constant5
208 * 6: constant4
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100209 * 8: goto
210 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100211 * 12: goto
212 * |
213 * 14: phi
214 * 16: equal
215 * 18: if +++++
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100216 * | \ +
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100217 * | 22: goto
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100218 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100219 * 26: return
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100220 * |
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100221 * 30: exit
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100222 */
223
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800224 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100225 Instruction::CONST_4 | 0 | 0,
226 Instruction::IF_EQ, 4,
227 Instruction::CONST_4 | 4 << 12 | 0,
228 Instruction::GOTO | 0xFD00,
229 Instruction::CONST_4 | 5 << 12 | 1 << 8,
230 Instruction::RETURN | 1 << 8);
231
Vladimir Markoca6fff82017-10-03 14:49:14 +0100232 HGraph* graph = BuildGraph(data);
Nicolas Geoffray9ebc72c2014-09-25 16:33:42 +0100233 RemoveSuspendChecks(graph);
Vladimir Markoa0431112018-06-25 09:32:54 +0100234 std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
235 SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100236 liveness.Analyze();
237
238 // Test for the 0 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000239 LiveInterval* interval = graph->GetIntConstant(0)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100240 LiveRange* range = interval->GetFirstRange();
241 ASSERT_EQ(2u, range->GetStart());
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100242 // Last use is the loop phi so instruction is live until
243 // the end of the pre loop header.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100244 ASSERT_EQ(14u, range->GetEnd());
245 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100246
247 // Test for the 4 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000248 interval = graph->GetIntConstant(4)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100249 range = interval->GetFirstRange();
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100250 // The instruction is live until the end of the loop.
David Brazdildee58d62016-04-07 09:54:26 +0000251 ASSERT_EQ(6u, range->GetStart());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100252 ASSERT_EQ(24u, range->GetEnd());
253 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100254
255 // Test for the 5 constant.
David Brazdildee58d62016-04-07 09:54:26 +0000256 interval = graph->GetIntConstant(5)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100257 range = interval->GetFirstRange();
258 // The instruction is live until the return instruction after the loop.
David Brazdildee58d62016-04-07 09:54:26 +0000259 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100260 ASSERT_EQ(26u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100261 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100262
263 // Test for the phi.
264 interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100265 range = interval->GetFirstRange();
David Brazdilb3e773e2016-01-26 11:28:37 +0000266 // Instruction is input of non-materialized Equal and hence live until If.
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100267 ASSERT_EQ(14u, range->GetStart());
David Brazdilb3e773e2016-01-26 11:28:37 +0000268 ASSERT_EQ(19u, range->GetEnd());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100269 ASSERT_TRUE(range->GetNext() == nullptr);
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100270}
271
David Brazdil4833f5a2015-12-16 10:37:39 +0000272TEST_F(LiveRangesTest, Loop2) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100273 /*
274 * Test the following snippet:
275 * var a = 0;
276 * while (a == a) {
277 * a = a + a;
278 * }
279 * return a;
280 *
281 * Which becomes the following graph (numbered by lifetime position):
282 * 2: constant0
283 * 4: goto
284 * |
285 * 8: goto
286 * |
287 * 10: phi
288 * 12: equal
289 * 14: if +++++
290 * | \ +
David Brazdilbadd8262016-02-02 16:28:56 +0000291 * | 18: add
292 * | 20: goto
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100293 * |
David Brazdilbadd8262016-02-02 16:28:56 +0000294 * 24: return
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100295 * |
David Brazdilbadd8262016-02-02 16:28:56 +0000296 * 28: exit
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100297 *
298 * We want to make sure the phi at 10 has a lifetime hole after the add at 20.
299 */
300
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800301 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100302 Instruction::CONST_4 | 0 | 0,
303 Instruction::IF_EQ, 6,
304 Instruction::ADD_INT, 0, 0,
305 Instruction::GOTO | 0xFB00,
306 Instruction::RETURN | 0 << 8);
307
Vladimir Markoca6fff82017-10-03 14:49:14 +0100308 HGraph* graph = BuildGraph(data);
Vladimir Markoa0431112018-06-25 09:32:54 +0100309 std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
310 SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100311 liveness.Analyze();
312
313 // Test for the 0 constant.
314 HIntConstant* constant = liveness.GetInstructionFromSsaIndex(0)->AsIntConstant();
315 LiveInterval* interval = constant->GetLiveInterval();
316 LiveRange* range = interval->GetFirstRange();
317 ASSERT_EQ(2u, range->GetStart());
318 // Last use is the loop phi so instruction is live until
319 // the end of the pre loop header.
320 ASSERT_EQ(10u, range->GetEnd());
321 ASSERT_TRUE(range->GetNext() == nullptr);
322
323 // Test for the loop phi.
324 HPhi* phi = liveness.GetInstructionFromSsaIndex(1)->AsPhi();
325 interval = phi->GetLiveInterval();
326 range = interval->GetFirstRange();
327 ASSERT_EQ(10u, range->GetStart());
David Brazdilbadd8262016-02-02 16:28:56 +0000328 ASSERT_EQ(19u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100329 range = range->GetNext();
330 ASSERT_TRUE(range != nullptr);
David Brazdilbadd8262016-02-02 16:28:56 +0000331 ASSERT_EQ(22u, range->GetStart());
332 ASSERT_EQ(24u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100333
334 // Test for the add instruction.
335 HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
336 interval = add->GetLiveInterval();
337 range = interval->GetFirstRange();
David Brazdilbadd8262016-02-02 16:28:56 +0000338 ASSERT_EQ(18u, range->GetStart());
339 ASSERT_EQ(22u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100340 ASSERT_TRUE(range->GetNext() == nullptr);
341}
342
David Brazdil4833f5a2015-12-16 10:37:39 +0000343TEST_F(LiveRangesTest, CFG4) {
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100344 /*
345 * Test the following snippet:
346 * var a = 0;
347 * var b = 4;
348 * if (a == a) {
349 * a = b + a;
350 * } else {
351 * a = b + a
352 * }
353 * return b;
354 *
355 * Which becomes the following graph (numbered by lifetime position):
356 * 2: constant0
357 * 4: constant4
358 * 6: goto
359 * |
360 * 10: equal
361 * 12: if
362 * / \
363 * 16: add 22: add
364 * 18: goto 24: goto
365 * \ /
366 * 26: phi
367 * 28: return
368 * |
369 * 32: exit
370 *
371 * We want to make sure the constant0 has a lifetime hole after the 16: add.
372 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800373 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100374 Instruction::CONST_4 | 0 | 0,
375 Instruction::CONST_4 | 4 << 12 | 1 << 8,
376 Instruction::IF_EQ, 5,
377 Instruction::ADD_INT, 1 << 8,
378 Instruction::GOTO | 0x300,
379 Instruction::ADD_INT, 1 << 8,
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000380 Instruction::RETURN);
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100381
Vladimir Markoca6fff82017-10-03 14:49:14 +0100382 HGraph* graph = BuildGraph(data);
Vladimir Markoa0431112018-06-25 09:32:54 +0100383 std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options_);
384 SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100385 liveness.Analyze();
386
387 // Test for the 0 constant.
388 LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval();
389 LiveRange* range = interval->GetFirstRange();
390 ASSERT_EQ(2u, range->GetStart());
Mark Mendell09b84632015-02-13 17:48:38 -0500391 ASSERT_EQ(17u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100392 range = range->GetNext();
393 ASSERT_TRUE(range != nullptr);
394 ASSERT_EQ(20u, range->GetStart());
Mark Mendell09b84632015-02-13 17:48:38 -0500395 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100396 ASSERT_TRUE(range->GetNext() == nullptr);
397
398 // Test for the 4 constant.
399 interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
400 range = interval->GetFirstRange();
401 ASSERT_EQ(4u, range->GetStart());
Nicolas Geoffraya3c00e52014-11-25 11:18:37 +0000402 ASSERT_EQ(17u, range->GetEnd());
403 range = range->GetNext();
404 ASSERT_EQ(20u, range->GetStart());
405 ASSERT_EQ(23u, range->GetEnd());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100406 ASSERT_TRUE(range->GetNext() == nullptr);
407
408 // Test for the first add.
409 HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
410 interval = add->GetLiveInterval();
411 range = interval->GetFirstRange();
412 ASSERT_EQ(16u, range->GetStart());
413 ASSERT_EQ(20u, range->GetEnd());
414 ASSERT_TRUE(range->GetNext() == nullptr);
415
416 // Test for the second add.
417 add = liveness.GetInstructionFromSsaIndex(3)->AsAdd();
418 interval = add->GetLiveInterval();
419 range = interval->GetFirstRange();
420 ASSERT_EQ(22u, range->GetStart());
421 ASSERT_EQ(26u, range->GetEnd());
422 ASSERT_TRUE(range->GetNext() == nullptr);
423
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100424 HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi();
Vladimir Marko46817b82016-03-29 12:21:58 +0100425 ASSERT_TRUE(phi->GetUses().HasExactlyOneElement());
Nicolas Geoffray8ddb00c2014-09-29 12:00:40 +0100426 interval = phi->GetLiveInterval();
427 range = interval->GetFirstRange();
428 ASSERT_EQ(26u, range->GetStart());
429 ASSERT_EQ(28u, range->GetEnd());
430 ASSERT_TRUE(range->GetNext() == nullptr);
431}
432
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100433} // namespace art