blob: cbb7b2f1c589e9933f045ad1f76662c7746a6337 [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
34// Note: the register allocator tests rely on the fact that constants have live
35// intervals and registers get allocated to them.
36
David Brazdil4833f5a2015-12-16 10:37:39 +000037class RegisterAllocatorTest : public CommonCompilerTest {};
38
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010039static bool Check(const uint16_t* data) {
40 ArenaPool pool;
41 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000042 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -040043 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
44 X86InstructionSetFeatures::FromCppDefines());
45 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +010046 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010047 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070048 RegisterAllocator* register_allocator = RegisterAllocator::Create(&allocator, &codegen, liveness);
49 register_allocator->AllocateRegisters();
50 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010051}
52
53/**
54 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
55 * tests are based on this validation method.
56 */
David Brazdil4833f5a2015-12-16 10:37:39 +000057TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010058 ArenaPool pool;
59 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010060 HGraph* graph = CreateGraph(&allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -040061 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
62 X86InstructionSetFeatures::FromCppDefines());
63 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010064 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010065
66 // Test with two intervals of the same range.
67 {
68 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010069 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 0));
70 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010071 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010072 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010073
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010074 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010075 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010076 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010077 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010078 }
79
80 // Test with two non-intersecting intervals.
81 {
82 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010083 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010084 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010085 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010086 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010087 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010088
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010089 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010090 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010091 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010092 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093 }
94
95 // Test with two non-intersecting intervals, with one with a lifetime hole.
96 {
97 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010098 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010099 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100100 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100101 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100102 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100103
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100104 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100105 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100106 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100107 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100108 }
109
110 // Test with intersecting intervals.
111 {
112 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100113 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100114 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100115 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100116 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100117 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100119 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100120 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100121 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100122 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100123 }
124
125 // Test with siblings.
126 {
127 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100128 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
129 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100130 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100131 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100132 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100133 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100134
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100135 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100136 // Sibling of the first interval has no register allocated to it.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100137 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100138 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100139
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100140 intervals[0]->GetNextSibling()->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100141 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100142 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100143 }
144}
145
David Brazdil4833f5a2015-12-16 10:37:39 +0000146TEST_F(RegisterAllocatorTest, CFG1) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100147 /*
148 * Test the following snippet:
149 * return 0;
150 *
151 * Which becomes the following graph:
152 * constant0
153 * goto
154 * |
155 * return
156 * |
157 * exit
158 */
159 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
160 Instruction::CONST_4 | 0 | 0,
161 Instruction::RETURN);
162
163 ASSERT_TRUE(Check(data));
164}
165
David Brazdil4833f5a2015-12-16 10:37:39 +0000166TEST_F(RegisterAllocatorTest, Loop1) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100167 /*
168 * Test the following snippet:
169 * int a = 0;
170 * while (a == a) {
171 * a = 4;
172 * }
173 * return 5;
174 *
175 * Which becomes the following graph:
176 * constant0
177 * constant4
178 * constant5
179 * goto
180 * |
181 * goto
182 * |
183 * phi
184 * equal
185 * if +++++
186 * | \ +
187 * | goto
188 * |
189 * return
190 * |
191 * exit
192 */
193
194 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
195 Instruction::CONST_4 | 0 | 0,
196 Instruction::IF_EQ, 4,
197 Instruction::CONST_4 | 4 << 12 | 0,
198 Instruction::GOTO | 0xFD00,
199 Instruction::CONST_4 | 5 << 12 | 1 << 8,
200 Instruction::RETURN | 1 << 8);
201
202 ASSERT_TRUE(Check(data));
203}
204
David Brazdil4833f5a2015-12-16 10:37:39 +0000205TEST_F(RegisterAllocatorTest, Loop2) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100206 /*
207 * Test the following snippet:
208 * int a = 0;
209 * while (a == 8) {
210 * a = 4 + 5;
211 * }
212 * return 6 + 7;
213 *
214 * Which becomes the following graph:
215 * constant0
216 * constant4
217 * constant5
218 * constant6
219 * constant7
220 * constant8
221 * goto
222 * |
223 * goto
224 * |
225 * phi
226 * equal
227 * if +++++
228 * | \ +
229 * | 4 + 5
230 * | goto
231 * |
232 * 6 + 7
233 * return
234 * |
235 * exit
236 */
237
238 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
239 Instruction::CONST_4 | 0 | 0,
240 Instruction::CONST_4 | 8 << 12 | 1 << 8,
241 Instruction::IF_EQ | 1 << 8, 7,
242 Instruction::CONST_4 | 4 << 12 | 0 << 8,
243 Instruction::CONST_4 | 5 << 12 | 1 << 8,
244 Instruction::ADD_INT, 1 << 8 | 0,
245 Instruction::GOTO | 0xFA00,
246 Instruction::CONST_4 | 6 << 12 | 1 << 8,
247 Instruction::CONST_4 | 7 << 12 | 1 << 8,
248 Instruction::ADD_INT, 1 << 8 | 0,
249 Instruction::RETURN | 1 << 8);
250
251 ASSERT_TRUE(Check(data));
252}
253
David Brazdil4833f5a2015-12-16 10:37:39 +0000254TEST_F(RegisterAllocatorTest, Loop3) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100255 /*
256 * Test the following snippet:
257 * int a = 0
258 * do {
259 * b = a;
260 * a++;
261 * } while (a != 5)
262 * return b;
263 *
264 * Which becomes the following graph:
265 * constant0
266 * constant1
267 * constant5
268 * goto
269 * |
270 * goto
271 * |++++++++++++
272 * phi +
273 * a++ +
274 * equals +
275 * if +
276 * |++++++++++++
277 * return
278 * |
279 * exit
280 */
281
282 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
283 Instruction::CONST_4 | 0 | 0,
284 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
285 Instruction::CONST_4 | 5 << 12 | 2 << 8,
286 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
287 Instruction::RETURN | 0 << 8,
288 Instruction::MOVE | 1 << 12 | 0 << 8,
289 Instruction::GOTO | 0xF900);
290
291 ArenaPool pool;
292 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000293 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400294 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
295 X86InstructionSetFeatures::FromCppDefines());
296 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100297 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100298 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700299 RegisterAllocator* register_allocator = RegisterAllocator::Create(&allocator, &codegen, liveness);
300 register_allocator->AllocateRegisters();
301 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100302
Vladimir Markoec7802a2015-10-01 20:57:57 +0100303 HBasicBlock* loop_header = graph->GetBlocks()[2];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100304 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
305
306 LiveInterval* phi_interval = phi->GetLiveInterval();
307 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
308 ASSERT_TRUE(phi_interval->HasRegister());
309 ASSERT_TRUE(loop_update->HasRegister());
310 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
311
Vladimir Markoec7802a2015-10-01 20:57:57 +0100312 HBasicBlock* return_block = graph->GetBlocks()[3];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100313 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100314 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
315}
316
David Brazdil4833f5a2015-12-16 10:37:39 +0000317TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100318 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
319 Instruction::CONST_4 | 0 | 0,
Mark Mendell09b84632015-02-13 17:48:38 -0500320 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
321 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
322 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100323 Instruction::RETURN_VOID);
324
325 ArenaPool pool;
326 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000327 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400328 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
329 X86InstructionSetFeatures::FromCppDefines());
330 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100331 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100332 liveness.Analyze();
333
Vladimir Markoec7802a2015-10-01 20:57:57 +0100334 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
335 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
Mark Mendell09b84632015-02-13 17:48:38 -0500336 ASSERT_EQ(last_xor->InputAt(0), first_xor);
337 LiveInterval* interval = first_xor->GetLiveInterval();
338 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100339 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
340
341 // We need a register for the output of the instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500342 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100343
344 // Split at the next instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500345 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100346 // The user of the split is the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500347 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100348
349 // Split before the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500350 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100351 // Ensure the current interval has no register use...
352 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
353 // And the new interval has it for the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500354 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100355}
356
David Brazdil4833f5a2015-12-16 10:37:39 +0000357TEST_F(RegisterAllocatorTest, DeadPhi) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100358 /* Test for a dead loop phi taking as back-edge input a phi that also has
359 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
360 * does not solve the problem because the loop phi will be visited last.
361 *
362 * Test the following snippet:
363 * int a = 0
364 * do {
365 * if (true) {
366 * a = 2;
367 * }
368 * } while (true);
369 */
370
371 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
372 Instruction::CONST_4 | 0 | 0,
373 Instruction::CONST_4 | 1 << 8 | 0,
374 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
375 Instruction::CONST_4 | 2 << 12 | 0 << 8,
376 Instruction::GOTO | 0xFD00,
377 Instruction::RETURN_VOID);
378
379 ArenaPool pool;
380 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000381 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100382 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400383 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
384 X86InstructionSetFeatures::FromCppDefines());
385 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100386 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100387 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700388 RegisterAllocator* register_allocator = RegisterAllocator::Create(&allocator, &codegen, liveness);
389 register_allocator->AllocateRegisters();
390 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100391}
392
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100393/**
394 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
395 * that share the same register. It should split the interval it is currently
396 * allocating for at the minimum lifetime position between the two inactive intervals.
397 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000398TEST_F(RegisterAllocatorTest, FreeUntil) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100399 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
400 Instruction::CONST_4 | 0 | 0,
401 Instruction::RETURN);
402
403 ArenaPool pool;
404 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000405 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100406 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400407 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
408 X86InstructionSetFeatures::FromCppDefines());
409 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100410 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100411 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700412 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100413
414 // Add an artifical range to cover the temps that will be put in the unhandled list.
415 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
416 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100417
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100418 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100419 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100420 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100421 graph->GetEntryBlock()->GetFirstInstruction());
422 }
423
Mingyao Yang296bd602014-10-06 16:47:28 -0700424 // For SSA value intervals, only an interval resulted from a split may intersect
425 // with inactive intervals.
426 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100427
428 // Add three temps holding the same register, and starting at different positions.
429 // Put the one that should be picked in the middle of the inactive list to ensure
430 // we do not depend on an order.
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100431 LiveInterval* interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100432 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100433 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100434
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100435 interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100436 interval->AddRange(20, 30);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100437 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100438
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100439 interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100440 interval->AddRange(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100441 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100442
443 register_allocator.number_of_registers_ = 1;
444 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
445 register_allocator.processing_core_registers_ = true;
446 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
447
Mingyao Yang296bd602014-10-06 16:47:28 -0700448 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100449
450 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100451 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100452 // Check that we know need to find a new register where the next interval
453 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100454 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100455}
456
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100457static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
458 HPhi** phi,
459 HInstruction** input1,
460 HInstruction** input2) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100461 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100462 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800463 ScopedNullHandle<mirror::DexCache> dex_cache;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100464 graph->AddBlock(entry);
465 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000466 HInstruction* parameter = new (allocator) HParameterValue(
467 graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100468 entry->AddInstruction(parameter);
469
470 HBasicBlock* block = new (allocator) HBasicBlock(graph);
471 graph->AddBlock(block);
472 entry->AddSuccessor(block);
473
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100474 HInstruction* test = new (allocator) HInstanceFieldGet(parameter,
475 Primitive::kPrimBoolean,
476 MemberOffset(22),
477 false,
478 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700479 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700480 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100481 dex_cache,
482 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100483 block->AddInstruction(test);
484 block->AddInstruction(new (allocator) HIf(test));
485 HBasicBlock* then = new (allocator) HBasicBlock(graph);
486 HBasicBlock* else_ = new (allocator) HBasicBlock(graph);
487 HBasicBlock* join = new (allocator) HBasicBlock(graph);
488 graph->AddBlock(then);
489 graph->AddBlock(else_);
490 graph->AddBlock(join);
491
492 block->AddSuccessor(then);
493 block->AddSuccessor(else_);
494 then->AddSuccessor(join);
495 else_->AddSuccessor(join);
496 then->AddInstruction(new (allocator) HGoto());
497 else_->AddInstruction(new (allocator) HGoto());
498
499 *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
500 join->AddPhi(*phi);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100501 *input1 = new (allocator) HInstanceFieldGet(parameter,
502 Primitive::kPrimInt,
503 MemberOffset(42),
504 false,
505 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700506 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700507 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100508 dex_cache,
509 0);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100510*input2 = new (allocator) HInstanceFieldGet(parameter,
511 Primitive::kPrimInt,
512 MemberOffset(42),
513 false,
514 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700515 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700516 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100517 dex_cache,
518 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100519 then->AddInstruction(*input1);
520 else_->AddInstruction(*input2);
521 join->AddInstruction(new (allocator) HExit());
522 (*phi)->AddInput(*input1);
523 (*phi)->AddInput(*input2);
524
525 graph->BuildDominatorTree();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000526 graph->AnalyzeLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100527 return graph;
528}
529
David Brazdil4833f5a2015-12-16 10:37:39 +0000530TEST_F(RegisterAllocatorTest, PhiHint) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100531 ArenaPool pool;
532 ArenaAllocator allocator(&pool);
533 HPhi *phi;
534 HInstruction *input1, *input2;
535
536 {
537 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400538 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
539 X86InstructionSetFeatures::FromCppDefines());
540 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100541 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100542 liveness.Analyze();
543
544 // Check that the register allocator is deterministic.
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700545 RegisterAllocator* register_allocator =
546 RegisterAllocator::Create(&allocator, &codegen, liveness);
547 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100548
549 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
550 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
551 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
552 }
553
554 {
555 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400556 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
557 X86InstructionSetFeatures::FromCppDefines());
558 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100559 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100560 liveness.Analyze();
561
562 // Set the phi to a specific register, and check that the inputs get allocated
563 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000564 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700565 RegisterAllocator* register_allocator =
566 RegisterAllocator::Create(&allocator, &codegen, liveness);
567 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100568
569 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
570 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
571 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
572 }
573
574 {
575 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400576 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
577 X86InstructionSetFeatures::FromCppDefines());
578 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100579 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100580 liveness.Analyze();
581
582 // Set input1 to a specific register, and check that the phi and other input get allocated
583 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000584 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700585 RegisterAllocator* register_allocator =
586 RegisterAllocator::Create(&allocator, &codegen, liveness);
587 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100588
589 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
590 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
591 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
592 }
593
594 {
595 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400596 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
597 X86InstructionSetFeatures::FromCppDefines());
598 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100599 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100600 liveness.Analyze();
601
602 // Set input2 to a specific register, and check that the phi and other input get allocated
603 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000604 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700605 RegisterAllocator* register_allocator =
606 RegisterAllocator::Create(&allocator, &codegen, liveness);
607 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100608
609 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
610 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
611 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
612 }
613}
614
615static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
616 HInstruction** field,
617 HInstruction** ret) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100618 HGraph* graph = CreateGraph(allocator);
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800619 ScopedNullHandle<mirror::DexCache> dex_cache;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100620 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
621 graph->AddBlock(entry);
622 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000623 HInstruction* parameter = new (allocator) HParameterValue(
624 graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100625 entry->AddInstruction(parameter);
626
627 HBasicBlock* block = new (allocator) HBasicBlock(graph);
628 graph->AddBlock(block);
629 entry->AddSuccessor(block);
630
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100631 *field = new (allocator) HInstanceFieldGet(parameter,
632 Primitive::kPrimInt,
633 MemberOffset(42),
634 false,
635 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700636 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700637 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100638 dex_cache,
639 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100640 block->AddInstruction(*field);
641 *ret = new (allocator) HReturn(*field);
642 block->AddInstruction(*ret);
643
644 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
645 graph->AddBlock(exit);
646 block->AddSuccessor(exit);
647 exit->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000648
649 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100650 return graph;
651}
652
David Brazdil4833f5a2015-12-16 10:37:39 +0000653TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100654 ArenaPool pool;
655 ArenaAllocator allocator(&pool);
656 HInstruction *field, *ret;
657
658 {
659 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400660 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
661 X86InstructionSetFeatures::FromCppDefines());
662 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100663 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100664 liveness.Analyze();
665
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700666 RegisterAllocator* register_allocator =
667 RegisterAllocator::Create(&allocator, &codegen, liveness);
668 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100669
670 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
671 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
672 }
673
674 {
675 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400676 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
677 X86InstructionSetFeatures::FromCppDefines());
678 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100679 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100680 liveness.Analyze();
681
682 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000683 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100684 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100685
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700686 RegisterAllocator* register_allocator =
687 RegisterAllocator::Create(&allocator, &codegen, liveness);
688 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100689
690 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
691 }
692}
693
Mark Mendell09b84632015-02-13 17:48:38 -0500694static HGraph* BuildTwoSubs(ArenaAllocator* allocator,
695 HInstruction** first_sub,
696 HInstruction** second_sub) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100697 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100698 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
699 graph->AddBlock(entry);
700 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000701 HInstruction* parameter = new (allocator) HParameterValue(
702 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100703 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000704
705 HInstruction* constant1 = graph->GetIntConstant(1);
706 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100707
708 HBasicBlock* block = new (allocator) HBasicBlock(graph);
709 graph->AddBlock(block);
710 entry->AddSuccessor(block);
711
Mark Mendell09b84632015-02-13 17:48:38 -0500712 *first_sub = new (allocator) HSub(Primitive::kPrimInt, parameter, constant1);
713 block->AddInstruction(*first_sub);
714 *second_sub = new (allocator) HSub(Primitive::kPrimInt, *first_sub, constant2);
715 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100716
717 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000718
719 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100720 return graph;
721}
722
David Brazdil4833f5a2015-12-16 10:37:39 +0000723TEST_F(RegisterAllocatorTest, SameAsFirstInputHint) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100724 ArenaPool pool;
725 ArenaAllocator allocator(&pool);
Mark Mendell09b84632015-02-13 17:48:38 -0500726 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100727
728 {
Mark Mendell09b84632015-02-13 17:48:38 -0500729 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400730 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
731 X86InstructionSetFeatures::FromCppDefines());
732 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100733 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100734 liveness.Analyze();
735
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700736 RegisterAllocator* register_allocator =
737 RegisterAllocator::Create(&allocator, &codegen, liveness);
738 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100739
740 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500741 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
742 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100743 }
744
745 {
Mark Mendell09b84632015-02-13 17:48:38 -0500746 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400747 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
748 X86InstructionSetFeatures::FromCppDefines());
749 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100750 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100751 liveness.Analyze();
752
753 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000754 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500755 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
756 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
757 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100758
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700759 RegisterAllocator* register_allocator =
760 RegisterAllocator::Create(&allocator, &codegen, liveness);
761 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100762
Mark Mendell09b84632015-02-13 17:48:38 -0500763 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
764 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100765 }
766}
767
Calin Juravled0d48522014-11-04 16:40:20 +0000768static HGraph* BuildDiv(ArenaAllocator* allocator,
769 HInstruction** div) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100770 HGraph* graph = CreateGraph(allocator);
Calin Juravled0d48522014-11-04 16:40:20 +0000771 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
772 graph->AddBlock(entry);
773 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000774 HInstruction* first = new (allocator) HParameterValue(
775 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
776 HInstruction* second = new (allocator) HParameterValue(
777 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
Calin Juravled0d48522014-11-04 16:40:20 +0000778 entry->AddInstruction(first);
779 entry->AddInstruction(second);
780
781 HBasicBlock* block = new (allocator) HBasicBlock(graph);
782 graph->AddBlock(block);
783 entry->AddSuccessor(block);
784
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000785 *div = new (allocator) HDiv(Primitive::kPrimInt, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000786 block->AddInstruction(*div);
787
788 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000789
790 graph->BuildDominatorTree();
Calin Juravled0d48522014-11-04 16:40:20 +0000791 return graph;
792}
793
David Brazdil4833f5a2015-12-16 10:37:39 +0000794TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) {
Calin Juravled0d48522014-11-04 16:40:20 +0000795 ArenaPool pool;
796 ArenaAllocator allocator(&pool);
797 HInstruction *div;
798
799 {
800 HGraph* graph = BuildDiv(&allocator, &div);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400801 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
802 X86InstructionSetFeatures::FromCppDefines());
803 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100804 SsaLivenessAnalysis liveness(graph, &codegen);
Calin Juravled0d48522014-11-04 16:40:20 +0000805 liveness.Analyze();
806
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700807 RegisterAllocator* register_allocator =
808 RegisterAllocator::Create(&allocator, &codegen, liveness);
809 register_allocator->AllocateRegisters();
Calin Juravled0d48522014-11-04 16:40:20 +0000810
811 // div on x86 requires its first input in eax and the output be the same as the first input.
812 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
813 }
814}
815
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000816// Test a bug in the register allocator, where allocating a blocked
817// register would lead to spilling an inactive interval at the wrong
818// position.
David Brazdil4833f5a2015-12-16 10:37:39 +0000819TEST_F(RegisterAllocatorTest, SpillInactive) {
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000820 ArenaPool pool;
821
822 // Create a synthesized graph to please the register_allocator and
823 // ssa_liveness_analysis code.
824 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100825 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000826 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
827 graph->AddBlock(entry);
828 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000829 HInstruction* one = new (&allocator) HParameterValue(
830 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
831 HInstruction* two = new (&allocator) HParameterValue(
832 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
833 HInstruction* three = new (&allocator) HParameterValue(
834 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
835 HInstruction* four = new (&allocator) HParameterValue(
836 graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000837 entry->AddInstruction(one);
838 entry->AddInstruction(two);
839 entry->AddInstruction(three);
840 entry->AddInstruction(four);
841
842 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
843 graph->AddBlock(block);
844 entry->AddSuccessor(block);
845 block->AddInstruction(new (&allocator) HExit());
846
847 // We create a synthesized user requesting a register, to avoid just spilling the
848 // intervals.
849 HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, Primitive::kPrimInt);
850 user->AddInput(one);
851 user->SetBlock(block);
852 LocationSummary* locations = new (&allocator) LocationSummary(user, LocationSummary::kNoCall);
853 locations->SetInAt(0, Location::RequiresRegister());
854 static constexpr size_t phi_ranges[][2] = {{20, 30}};
855 BuildInterval(phi_ranges, arraysize(phi_ranges), &allocator, -1, user);
856
857 // Create an interval with lifetime holes.
858 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
859 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), &allocator, -1, one);
860 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, first->first_use_);
861 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 7, first->first_use_);
862 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 6, first->first_use_);
863
864 locations = new (&allocator) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
865 locations->SetOut(Location::RequiresRegister());
866 first = first->SplitAt(1);
867
868 // Create an interval that conflicts with the next interval, to force the next
869 // interval to call `AllocateBlockedReg`.
870 static constexpr size_t ranges2[][2] = {{2, 4}};
871 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), &allocator, -1, two);
872 locations = new (&allocator) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
873 locations->SetOut(Location::RequiresRegister());
874
875 // Create an interval that will lead to splitting the first interval. The bug occured
876 // by splitting at a wrong position, in this case at the next intersection between
877 // this interval and the first interval. We would have then put the interval with ranges
878 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
879 // before lifetime position 6 yet.
880 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
881 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), &allocator, -1, three);
882 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, third->first_use_);
883 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 4, third->first_use_);
884 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 3, third->first_use_);
885 locations = new (&allocator) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
886 locations->SetOut(Location::RequiresRegister());
887 third = third->SplitAt(3);
888
889 // Because the first part of the split interval was considered handled, this interval
890 // was free to allocate the same register, even though it conflicts with it.
891 static constexpr size_t ranges4[][2] = {{4, 6}};
892 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), &allocator, -1, four);
893 locations = new (&allocator) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
894 locations->SetOut(Location::RequiresRegister());
895
Mark Mendellfb8d2792015-03-31 22:16:59 -0400896 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
897 X86InstructionSetFeatures::FromCppDefines());
898 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100899 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100900 // Populate the instructions in the liveness object, to please the register allocator.
901 for (size_t i = 0; i < 32; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100902 liveness.instructions_from_lifetime_position_.push_back(user);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100903 }
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000904
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700905 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100906 register_allocator.unhandled_core_intervals_.push_back(fourth);
907 register_allocator.unhandled_core_intervals_.push_back(third);
908 register_allocator.unhandled_core_intervals_.push_back(second);
909 register_allocator.unhandled_core_intervals_.push_back(first);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000910
911 // Set just one register available to make all intervals compete for the same.
912 register_allocator.number_of_registers_ = 1;
913 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
914 register_allocator.processing_core_registers_ = true;
915 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
916 register_allocator.LinearScan();
917
918 // Test that there is no conflicts between intervals.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100919 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
920 intervals.push_back(first);
921 intervals.push_back(second);
922 intervals.push_back(third);
923 intervals.push_back(fourth);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000924 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
925 intervals, 0, 0, codegen, &allocator, true, false));
926}
927
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100928} // namespace art