blob: 55ea99e59231c74a48a36b594ffd71c228e8fcc2 [file] [log] [blame]
Nicolas Geoffraya7062e02014-05-22 12:50:17 +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 Geoffraya7062e02014-05-22 12:50:17 +010019#include "builder.h"
20#include "code_generator.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010021#include "code_generator_x86.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010022#include "dex_file.h"
23#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000024#include "driver/compiler_options.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010025#include "nodes.h"
26#include "optimizing_unit_test.h"
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070027#include "register_allocator.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070028#include "register_allocator_linear_scan.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010029#include "ssa_liveness_analysis.h"
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010030#include "ssa_phi_elimination.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010031
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010032namespace art {
33
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070034using Strategy = RegisterAllocator::Strategy;
35
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010036// Note: the register allocator tests rely on the fact that constants have live
37// intervals and registers get allocated to them.
38
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070039class RegisterAllocatorTest : public CommonCompilerTest {
40 protected:
41 // These functions need to access private variables of LocationSummary, so we declare it
42 // as a member of RegisterAllocatorTest, which we make a friend class.
43 static void SameAsFirstInputHint(Strategy strategy);
44 static void ExpectedInRegisterHint(Strategy strategy);
45};
David Brazdil4833f5a2015-12-16 10:37:39 +000046
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070047// This macro should include all register allocation strategies that should be tested.
48#define TEST_ALL_STRATEGIES(test_name)\
49TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
50 test_name(Strategy::kRegisterAllocatorLinearScan);\
51}\
52TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
53 test_name(Strategy::kRegisterAllocatorGraphColor);\
54}
55
56static bool Check(const uint16_t* data, Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010057 ArenaPool pool;
58 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000059 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -040060 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
61 X86InstructionSetFeatures::FromCppDefines());
62 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +010063 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010064 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070065 RegisterAllocator* register_allocator =
66 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070067 register_allocator->AllocateRegisters();
68 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010069}
70
71/**
72 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
73 * tests are based on this validation method.
74 */
David Brazdil4833f5a2015-12-16 10:37:39 +000075TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010076 ArenaPool pool;
77 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010078 HGraph* graph = CreateGraph(&allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -040079 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
80 X86InstructionSetFeatures::FromCppDefines());
81 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010082 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010083
84 // Test with two intervals of the same range.
85 {
86 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010087 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 0));
88 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010089 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010090 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010091
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010092 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010093 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010094 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010095 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010096 }
97
98 // Test with two non-intersecting intervals.
99 {
100 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100101 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100102 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100103 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100104 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100105 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100106
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100107 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100108 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100109 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100110 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100111 }
112
113 // Test with two non-intersecting intervals, with one with a lifetime hole.
114 {
115 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100116 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100117 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100118 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100119 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100120 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100121
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100122 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100123 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100124 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100125 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100126 }
127
128 // Test with intersecting intervals.
129 {
130 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100131 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100132 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100133 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100134 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100135 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100136
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100137 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100138 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100139 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100140 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100141 }
142
143 // Test with siblings.
144 {
145 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100146 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
147 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100148 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100149 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100150 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100151 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100152
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100153 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100154 // Sibling of the first interval has no register allocated to it.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100155 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100156 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100157
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100158 intervals[0]->GetNextSibling()->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100159 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100160 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100161 }
162}
163
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700164static void CFG1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100165 /*
166 * Test the following snippet:
167 * return 0;
168 *
169 * Which becomes the following graph:
170 * constant0
171 * goto
172 * |
173 * return
174 * |
175 * exit
176 */
177 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
178 Instruction::CONST_4 | 0 | 0,
179 Instruction::RETURN);
180
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700181 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100182}
183
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700184TEST_ALL_STRATEGIES(CFG1);
185
186static void Loop1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100187 /*
188 * Test the following snippet:
189 * int a = 0;
190 * while (a == a) {
191 * a = 4;
192 * }
193 * return 5;
194 *
195 * Which becomes the following graph:
196 * constant0
197 * constant4
198 * constant5
199 * goto
200 * |
201 * goto
202 * |
203 * phi
204 * equal
205 * if +++++
206 * | \ +
207 * | goto
208 * |
209 * return
210 * |
211 * exit
212 */
213
214 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
215 Instruction::CONST_4 | 0 | 0,
216 Instruction::IF_EQ, 4,
217 Instruction::CONST_4 | 4 << 12 | 0,
218 Instruction::GOTO | 0xFD00,
219 Instruction::CONST_4 | 5 << 12 | 1 << 8,
220 Instruction::RETURN | 1 << 8);
221
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700222 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100223}
224
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700225TEST_ALL_STRATEGIES(Loop1);
226
227static void Loop2(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100228 /*
229 * Test the following snippet:
230 * int a = 0;
231 * while (a == 8) {
232 * a = 4 + 5;
233 * }
234 * return 6 + 7;
235 *
236 * Which becomes the following graph:
237 * constant0
238 * constant4
239 * constant5
240 * constant6
241 * constant7
242 * constant8
243 * goto
244 * |
245 * goto
246 * |
247 * phi
248 * equal
249 * if +++++
250 * | \ +
251 * | 4 + 5
252 * | goto
253 * |
254 * 6 + 7
255 * return
256 * |
257 * exit
258 */
259
260 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
261 Instruction::CONST_4 | 0 | 0,
262 Instruction::CONST_4 | 8 << 12 | 1 << 8,
263 Instruction::IF_EQ | 1 << 8, 7,
264 Instruction::CONST_4 | 4 << 12 | 0 << 8,
265 Instruction::CONST_4 | 5 << 12 | 1 << 8,
266 Instruction::ADD_INT, 1 << 8 | 0,
267 Instruction::GOTO | 0xFA00,
268 Instruction::CONST_4 | 6 << 12 | 1 << 8,
269 Instruction::CONST_4 | 7 << 12 | 1 << 8,
270 Instruction::ADD_INT, 1 << 8 | 0,
271 Instruction::RETURN | 1 << 8);
272
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700273 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100274}
275
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700276TEST_ALL_STRATEGIES(Loop2);
277
278static void Loop3(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100279 /*
280 * Test the following snippet:
281 * int a = 0
282 * do {
283 * b = a;
284 * a++;
285 * } while (a != 5)
286 * return b;
287 *
288 * Which becomes the following graph:
289 * constant0
290 * constant1
291 * constant5
292 * goto
293 * |
294 * goto
295 * |++++++++++++
296 * phi +
297 * a++ +
298 * equals +
299 * if +
300 * |++++++++++++
301 * return
302 * |
303 * exit
304 */
305
306 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
307 Instruction::CONST_4 | 0 | 0,
308 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
309 Instruction::CONST_4 | 5 << 12 | 2 << 8,
310 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
311 Instruction::RETURN | 0 << 8,
312 Instruction::MOVE | 1 << 12 | 0 << 8,
313 Instruction::GOTO | 0xF900);
314
315 ArenaPool pool;
316 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000317 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400318 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
319 X86InstructionSetFeatures::FromCppDefines());
320 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100321 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100322 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700323 RegisterAllocator* register_allocator =
324 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700325 register_allocator->AllocateRegisters();
326 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100327
Vladimir Markoec7802a2015-10-01 20:57:57 +0100328 HBasicBlock* loop_header = graph->GetBlocks()[2];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100329 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
330
331 LiveInterval* phi_interval = phi->GetLiveInterval();
332 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
333 ASSERT_TRUE(phi_interval->HasRegister());
334 ASSERT_TRUE(loop_update->HasRegister());
335 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
336
Vladimir Markoec7802a2015-10-01 20:57:57 +0100337 HBasicBlock* return_block = graph->GetBlocks()[3];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100338 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100339 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
340}
341
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700342TEST_ALL_STRATEGIES(Loop3);
343
David Brazdil4833f5a2015-12-16 10:37:39 +0000344TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100345 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
346 Instruction::CONST_4 | 0 | 0,
Mark Mendell09b84632015-02-13 17:48:38 -0500347 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
348 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
349 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100350 Instruction::RETURN_VOID);
351
352 ArenaPool pool;
353 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000354 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400355 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
356 X86InstructionSetFeatures::FromCppDefines());
357 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100358 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100359 liveness.Analyze();
360
Vladimir Markoec7802a2015-10-01 20:57:57 +0100361 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
362 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
Mark Mendell09b84632015-02-13 17:48:38 -0500363 ASSERT_EQ(last_xor->InputAt(0), first_xor);
364 LiveInterval* interval = first_xor->GetLiveInterval();
365 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100366 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
367
368 // We need a register for the output of the instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500369 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100370
371 // Split at the next instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500372 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100373 // The user of the split is the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500374 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100375
376 // Split before the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500377 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100378 // Ensure the current interval has no register use...
379 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
380 // And the new interval has it for the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500381 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100382}
383
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700384static void DeadPhi(Strategy strategy) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100385 /* Test for a dead loop phi taking as back-edge input a phi that also has
386 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
387 * does not solve the problem because the loop phi will be visited last.
388 *
389 * Test the following snippet:
390 * int a = 0
391 * do {
392 * if (true) {
393 * a = 2;
394 * }
395 * } while (true);
396 */
397
398 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
399 Instruction::CONST_4 | 0 | 0,
400 Instruction::CONST_4 | 1 << 8 | 0,
401 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
402 Instruction::CONST_4 | 2 << 12 | 0 << 8,
403 Instruction::GOTO | 0xFD00,
404 Instruction::RETURN_VOID);
405
406 ArenaPool pool;
407 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000408 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100409 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400410 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
411 X86InstructionSetFeatures::FromCppDefines());
412 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100413 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100414 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700415 RegisterAllocator* register_allocator =
416 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700417 register_allocator->AllocateRegisters();
418 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100419}
420
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700421TEST_ALL_STRATEGIES(DeadPhi);
422
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100423/**
424 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
425 * that share the same register. It should split the interval it is currently
426 * allocating for at the minimum lifetime position between the two inactive intervals.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700427 * This test only applies to the linear scan allocator.
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100428 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000429TEST_F(RegisterAllocatorTest, FreeUntil) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100430 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
431 Instruction::CONST_4 | 0 | 0,
432 Instruction::RETURN);
433
434 ArenaPool pool;
435 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000436 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100437 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400438 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
439 X86InstructionSetFeatures::FromCppDefines());
440 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100441 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100442 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700443 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100444
445 // Add an artifical range to cover the temps that will be put in the unhandled list.
446 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
447 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100448
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100449 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100450 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100451 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100452 graph->GetEntryBlock()->GetFirstInstruction());
453 }
454
Mingyao Yang296bd602014-10-06 16:47:28 -0700455 // For SSA value intervals, only an interval resulted from a split may intersect
456 // with inactive intervals.
457 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100458
459 // Add three temps holding the same register, and starting at different positions.
460 // Put the one that should be picked in the middle of the inactive list to ensure
461 // we do not depend on an order.
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100462 LiveInterval* interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100463 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100464 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100465
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100466 interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100467 interval->AddRange(20, 30);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100468 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100469
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100470 interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100471 interval->AddRange(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100472 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100473
474 register_allocator.number_of_registers_ = 1;
475 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
476 register_allocator.processing_core_registers_ = true;
477 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
478
Mingyao Yang296bd602014-10-06 16:47:28 -0700479 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100480
481 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100482 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100483 // Check that we know need to find a new register where the next interval
484 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100485 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100486}
487
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100488static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
489 HPhi** phi,
490 HInstruction** input1,
491 HInstruction** input2) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100492 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100493 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800494 ScopedNullHandle<mirror::DexCache> dex_cache;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100495 graph->AddBlock(entry);
496 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000497 HInstruction* parameter = new (allocator) HParameterValue(
498 graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100499 entry->AddInstruction(parameter);
500
501 HBasicBlock* block = new (allocator) HBasicBlock(graph);
502 graph->AddBlock(block);
503 entry->AddSuccessor(block);
504
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100505 HInstruction* test = new (allocator) HInstanceFieldGet(parameter,
506 Primitive::kPrimBoolean,
507 MemberOffset(22),
508 false,
509 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700510 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700511 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100512 dex_cache,
513 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100514 block->AddInstruction(test);
515 block->AddInstruction(new (allocator) HIf(test));
516 HBasicBlock* then = new (allocator) HBasicBlock(graph);
517 HBasicBlock* else_ = new (allocator) HBasicBlock(graph);
518 HBasicBlock* join = new (allocator) HBasicBlock(graph);
519 graph->AddBlock(then);
520 graph->AddBlock(else_);
521 graph->AddBlock(join);
522
523 block->AddSuccessor(then);
524 block->AddSuccessor(else_);
525 then->AddSuccessor(join);
526 else_->AddSuccessor(join);
527 then->AddInstruction(new (allocator) HGoto());
528 else_->AddInstruction(new (allocator) HGoto());
529
530 *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
531 join->AddPhi(*phi);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100532 *input1 = new (allocator) HInstanceFieldGet(parameter,
533 Primitive::kPrimInt,
534 MemberOffset(42),
535 false,
536 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700537 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700538 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100539 dex_cache,
540 0);
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700541 *input2 = new (allocator) HInstanceFieldGet(parameter,
542 Primitive::kPrimInt,
543 MemberOffset(42),
544 false,
545 kUnknownFieldIndex,
546 kUnknownClassDefIndex,
547 graph->GetDexFile(),
548 dex_cache,
549 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100550 then->AddInstruction(*input1);
551 else_->AddInstruction(*input2);
552 join->AddInstruction(new (allocator) HExit());
553 (*phi)->AddInput(*input1);
554 (*phi)->AddInput(*input2);
555
556 graph->BuildDominatorTree();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000557 graph->AnalyzeLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100558 return graph;
559}
560
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700561static void PhiHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100562 ArenaPool pool;
563 ArenaAllocator allocator(&pool);
564 HPhi *phi;
565 HInstruction *input1, *input2;
566
567 {
568 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400569 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
570 X86InstructionSetFeatures::FromCppDefines());
571 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100572 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100573 liveness.Analyze();
574
575 // Check that the register allocator is deterministic.
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700576 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700577 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700578 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100579
580 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
581 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
582 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
583 }
584
585 {
586 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400587 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
588 X86InstructionSetFeatures::FromCppDefines());
589 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100590 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100591 liveness.Analyze();
592
593 // Set the phi to a specific register, and check that the inputs get allocated
594 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000595 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700596 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700597 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700598 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100599
600 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
601 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
602 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
603 }
604
605 {
606 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400607 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
608 X86InstructionSetFeatures::FromCppDefines());
609 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100610 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100611 liveness.Analyze();
612
613 // Set input1 to a specific register, and check that the phi and other input get allocated
614 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000615 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700616 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700617 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700618 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100619
620 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
621 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
622 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
623 }
624
625 {
626 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400627 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
628 X86InstructionSetFeatures::FromCppDefines());
629 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100630 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100631 liveness.Analyze();
632
633 // Set input2 to a specific register, and check that the phi and other input get allocated
634 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000635 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700636 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700637 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700638 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100639
640 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
641 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
642 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
643 }
644}
645
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700646// TODO: Enable this test for graph coloring register allocation when iterative move
647// coalescing is merged.
648TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) {
649 PhiHint(Strategy::kRegisterAllocatorLinearScan);
650}
651
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100652static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
653 HInstruction** field,
654 HInstruction** ret) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100655 HGraph* graph = CreateGraph(allocator);
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800656 ScopedNullHandle<mirror::DexCache> dex_cache;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100657 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
658 graph->AddBlock(entry);
659 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000660 HInstruction* parameter = new (allocator) HParameterValue(
661 graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100662 entry->AddInstruction(parameter);
663
664 HBasicBlock* block = new (allocator) HBasicBlock(graph);
665 graph->AddBlock(block);
666 entry->AddSuccessor(block);
667
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100668 *field = new (allocator) HInstanceFieldGet(parameter,
669 Primitive::kPrimInt,
670 MemberOffset(42),
671 false,
672 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700673 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700674 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100675 dex_cache,
676 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100677 block->AddInstruction(*field);
678 *ret = new (allocator) HReturn(*field);
679 block->AddInstruction(*ret);
680
681 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
682 graph->AddBlock(exit);
683 block->AddSuccessor(exit);
684 exit->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000685
686 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100687 return graph;
688}
689
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700690void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100691 ArenaPool pool;
692 ArenaAllocator allocator(&pool);
693 HInstruction *field, *ret;
694
695 {
696 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400697 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
698 X86InstructionSetFeatures::FromCppDefines());
699 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100700 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100701 liveness.Analyze();
702
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700703 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700704 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700705 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100706
707 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
708 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
709 }
710
711 {
712 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400713 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
714 X86InstructionSetFeatures::FromCppDefines());
715 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100716 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100717 liveness.Analyze();
718
719 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000720 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100721 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100722
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700723 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700724 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700725 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100726
727 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
728 }
729}
730
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700731// TODO: Enable this test for graph coloring register allocation when iterative move
732// coalescing is merged.
733TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
734 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
735}
736
Mark Mendell09b84632015-02-13 17:48:38 -0500737static HGraph* BuildTwoSubs(ArenaAllocator* allocator,
738 HInstruction** first_sub,
739 HInstruction** second_sub) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100740 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100741 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
742 graph->AddBlock(entry);
743 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000744 HInstruction* parameter = new (allocator) HParameterValue(
745 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100746 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000747
748 HInstruction* constant1 = graph->GetIntConstant(1);
749 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100750
751 HBasicBlock* block = new (allocator) HBasicBlock(graph);
752 graph->AddBlock(block);
753 entry->AddSuccessor(block);
754
Mark Mendell09b84632015-02-13 17:48:38 -0500755 *first_sub = new (allocator) HSub(Primitive::kPrimInt, parameter, constant1);
756 block->AddInstruction(*first_sub);
757 *second_sub = new (allocator) HSub(Primitive::kPrimInt, *first_sub, constant2);
758 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100759
760 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000761
762 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100763 return graph;
764}
765
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700766void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100767 ArenaPool pool;
768 ArenaAllocator allocator(&pool);
Mark Mendell09b84632015-02-13 17:48:38 -0500769 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100770
771 {
Mark Mendell09b84632015-02-13 17:48:38 -0500772 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400773 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
774 X86InstructionSetFeatures::FromCppDefines());
775 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100776 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100777 liveness.Analyze();
778
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700779 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700780 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700781 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100782
783 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500784 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
785 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100786 }
787
788 {
Mark Mendell09b84632015-02-13 17:48:38 -0500789 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400790 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
791 X86InstructionSetFeatures::FromCppDefines());
792 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100793 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100794 liveness.Analyze();
795
796 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000797 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500798 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
799 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
800 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100801
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700802 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700803 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700804 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100805
Mark Mendell09b84632015-02-13 17:48:38 -0500806 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
807 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100808 }
809}
810
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700811// TODO: Enable this test for graph coloring register allocation when iterative move
812// coalescing is merged.
813TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
814 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
815}
816
Calin Juravled0d48522014-11-04 16:40:20 +0000817static HGraph* BuildDiv(ArenaAllocator* allocator,
818 HInstruction** div) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100819 HGraph* graph = CreateGraph(allocator);
Calin Juravled0d48522014-11-04 16:40:20 +0000820 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
821 graph->AddBlock(entry);
822 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000823 HInstruction* first = new (allocator) HParameterValue(
824 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
825 HInstruction* second = new (allocator) HParameterValue(
826 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
Calin Juravled0d48522014-11-04 16:40:20 +0000827 entry->AddInstruction(first);
828 entry->AddInstruction(second);
829
830 HBasicBlock* block = new (allocator) HBasicBlock(graph);
831 graph->AddBlock(block);
832 entry->AddSuccessor(block);
833
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000834 *div = new (allocator) HDiv(Primitive::kPrimInt, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000835 block->AddInstruction(*div);
836
837 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000838
839 graph->BuildDominatorTree();
Calin Juravled0d48522014-11-04 16:40:20 +0000840 return graph;
841}
842
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700843static void ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
Calin Juravled0d48522014-11-04 16:40:20 +0000844 ArenaPool pool;
845 ArenaAllocator allocator(&pool);
846 HInstruction *div;
847
848 {
849 HGraph* graph = BuildDiv(&allocator, &div);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400850 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
851 X86InstructionSetFeatures::FromCppDefines());
852 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100853 SsaLivenessAnalysis liveness(graph, &codegen);
Calin Juravled0d48522014-11-04 16:40:20 +0000854 liveness.Analyze();
855
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700856 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700857 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700858 register_allocator->AllocateRegisters();
Calin Juravled0d48522014-11-04 16:40:20 +0000859
860 // div on x86 requires its first input in eax and the output be the same as the first input.
861 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
862 }
863}
864
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700865// TODO: Enable this test for graph coloring register allocation when iterative move
866// coalescing is merged.
867TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) {
868 ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan);
869}
870
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000871// Test a bug in the register allocator, where allocating a blocked
872// register would lead to spilling an inactive interval at the wrong
873// position.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700874// This test only applies to the linear scan allocator.
David Brazdil4833f5a2015-12-16 10:37:39 +0000875TEST_F(RegisterAllocatorTest, SpillInactive) {
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000876 ArenaPool pool;
877
878 // Create a synthesized graph to please the register_allocator and
879 // ssa_liveness_analysis code.
880 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100881 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000882 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
883 graph->AddBlock(entry);
884 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000885 HInstruction* one = new (&allocator) HParameterValue(
886 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
887 HInstruction* two = new (&allocator) HParameterValue(
888 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
889 HInstruction* three = new (&allocator) HParameterValue(
890 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
891 HInstruction* four = new (&allocator) HParameterValue(
892 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000893 entry->AddInstruction(one);
894 entry->AddInstruction(two);
895 entry->AddInstruction(three);
896 entry->AddInstruction(four);
897
898 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
899 graph->AddBlock(block);
900 entry->AddSuccessor(block);
901 block->AddInstruction(new (&allocator) HExit());
902
903 // We create a synthesized user requesting a register, to avoid just spilling the
904 // intervals.
905 HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, Primitive::kPrimInt);
906 user->AddInput(one);
907 user->SetBlock(block);
908 LocationSummary* locations = new (&allocator) LocationSummary(user, LocationSummary::kNoCall);
909 locations->SetInAt(0, Location::RequiresRegister());
910 static constexpr size_t phi_ranges[][2] = {{20, 30}};
911 BuildInterval(phi_ranges, arraysize(phi_ranges), &allocator, -1, user);
912
913 // Create an interval with lifetime holes.
914 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
915 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), &allocator, -1, one);
916 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, first->first_use_);
917 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 7, first->first_use_);
918 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 6, first->first_use_);
919
920 locations = new (&allocator) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
921 locations->SetOut(Location::RequiresRegister());
922 first = first->SplitAt(1);
923
924 // Create an interval that conflicts with the next interval, to force the next
925 // interval to call `AllocateBlockedReg`.
926 static constexpr size_t ranges2[][2] = {{2, 4}};
927 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), &allocator, -1, two);
928 locations = new (&allocator) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
929 locations->SetOut(Location::RequiresRegister());
930
931 // Create an interval that will lead to splitting the first interval. The bug occured
932 // by splitting at a wrong position, in this case at the next intersection between
933 // this interval and the first interval. We would have then put the interval with ranges
934 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
935 // before lifetime position 6 yet.
936 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
937 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), &allocator, -1, three);
938 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, third->first_use_);
939 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 4, third->first_use_);
940 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 3, third->first_use_);
941 locations = new (&allocator) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
942 locations->SetOut(Location::RequiresRegister());
943 third = third->SplitAt(3);
944
945 // Because the first part of the split interval was considered handled, this interval
946 // was free to allocate the same register, even though it conflicts with it.
947 static constexpr size_t ranges4[][2] = {{4, 6}};
948 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), &allocator, -1, four);
949 locations = new (&allocator) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
950 locations->SetOut(Location::RequiresRegister());
951
Mark Mendellfb8d2792015-03-31 22:16:59 -0400952 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
953 X86InstructionSetFeatures::FromCppDefines());
954 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100955 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100956 // Populate the instructions in the liveness object, to please the register allocator.
957 for (size_t i = 0; i < 32; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100958 liveness.instructions_from_lifetime_position_.push_back(user);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100959 }
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000960
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700961 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100962 register_allocator.unhandled_core_intervals_.push_back(fourth);
963 register_allocator.unhandled_core_intervals_.push_back(third);
964 register_allocator.unhandled_core_intervals_.push_back(second);
965 register_allocator.unhandled_core_intervals_.push_back(first);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000966
967 // Set just one register available to make all intervals compete for the same.
968 register_allocator.number_of_registers_ = 1;
969 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
970 register_allocator.processing_core_registers_ = true;
971 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
972 register_allocator.LinearScan();
973
974 // Test that there is no conflicts between intervals.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100975 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
976 intervals.push_back(first);
977 intervals.push_back(second);
978 intervals.push_back(third);
979 intervals.push_back(fourth);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000980 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
981 intervals, 0, 0, codegen, &allocator, true, false));
982}
983
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100984} // namespace art