blob: 559f40923bfc55817f708c56dcf9fd9398904244 [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"
Andreas Gampea5b09a62016-11-17 15:21:22 -080023#include "dex_file_types.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010024#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000025#include "driver/compiler_options.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010026#include "nodes.h"
27#include "optimizing_unit_test.h"
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070028#include "register_allocator.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070029#include "register_allocator_linear_scan.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010030#include "ssa_liveness_analysis.h"
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010031#include "ssa_phi_elimination.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010032
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010033namespace art {
34
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070035using Strategy = RegisterAllocator::Strategy;
36
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010037// Note: the register allocator tests rely on the fact that constants have live
38// intervals and registers get allocated to them.
39
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070040class RegisterAllocatorTest : public CommonCompilerTest {
41 protected:
42 // These functions need to access private variables of LocationSummary, so we declare it
43 // as a member of RegisterAllocatorTest, which we make a friend class.
44 static void SameAsFirstInputHint(Strategy strategy);
45 static void ExpectedInRegisterHint(Strategy strategy);
46};
David Brazdil4833f5a2015-12-16 10:37:39 +000047
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070048// This macro should include all register allocation strategies that should be tested.
49#define TEST_ALL_STRATEGIES(test_name)\
50TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
51 test_name(Strategy::kRegisterAllocatorLinearScan);\
52}\
53TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
54 test_name(Strategy::kRegisterAllocatorGraphColor);\
55}
56
57static bool Check(const uint16_t* data, Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010058 ArenaPool pool;
59 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000060 HGraph* graph = CreateCFG(&allocator, data);
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());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +010064 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010065 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070066 RegisterAllocator* register_allocator =
67 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070068 register_allocator->AllocateRegisters();
69 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010070}
71
72/**
73 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
74 * tests are based on this validation method.
75 */
David Brazdil4833f5a2015-12-16 10:37:39 +000076TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010077 ArenaPool pool;
78 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010079 HGraph* graph = CreateGraph(&allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -040080 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
81 X86InstructionSetFeatures::FromCppDefines());
82 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010083 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010084
85 // Test with two intervals of the same range.
86 {
87 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010088 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 0));
89 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 1));
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));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010092
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010093 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010094 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010095 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010096 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010097 }
98
99 // Test with two non-intersecting intervals.
100 {
101 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100102 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100103 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100104 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
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));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100107
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100108 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100109 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100110 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100111 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100112 }
113
114 // Test with two non-intersecting intervals, with one with a lifetime hole.
115 {
116 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100117 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100119 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100120 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100121 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100122
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100123 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100124 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100125 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100126 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100127 }
128
129 // Test with intersecting intervals.
130 {
131 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100132 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100133 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100134 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100135 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100136 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100137
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100138 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100139 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100140 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100141 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142 }
143
144 // Test with siblings.
145 {
146 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100147 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
148 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100149 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100150 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100151 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100152 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100153
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100154 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100155 // Sibling of the first interval has no register allocated to it.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100156 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100157 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100158
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100159 intervals[0]->GetNextSibling()->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100160 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100161 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100162 }
163}
164
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700165static void CFG1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100166 /*
167 * Test the following snippet:
168 * return 0;
169 *
170 * Which becomes the following graph:
171 * constant0
172 * goto
173 * |
174 * return
175 * |
176 * exit
177 */
178 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
179 Instruction::CONST_4 | 0 | 0,
180 Instruction::RETURN);
181
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700182 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100183}
184
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700185TEST_ALL_STRATEGIES(CFG1);
186
187static void Loop1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100188 /*
189 * Test the following snippet:
190 * int a = 0;
191 * while (a == a) {
192 * a = 4;
193 * }
194 * return 5;
195 *
196 * Which becomes the following graph:
197 * constant0
198 * constant4
199 * constant5
200 * goto
201 * |
202 * goto
203 * |
204 * phi
205 * equal
206 * if +++++
207 * | \ +
208 * | goto
209 * |
210 * return
211 * |
212 * exit
213 */
214
215 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
216 Instruction::CONST_4 | 0 | 0,
217 Instruction::IF_EQ, 4,
218 Instruction::CONST_4 | 4 << 12 | 0,
219 Instruction::GOTO | 0xFD00,
220 Instruction::CONST_4 | 5 << 12 | 1 << 8,
221 Instruction::RETURN | 1 << 8);
222
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700223 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100224}
225
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700226TEST_ALL_STRATEGIES(Loop1);
227
228static void Loop2(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100229 /*
230 * Test the following snippet:
231 * int a = 0;
232 * while (a == 8) {
233 * a = 4 + 5;
234 * }
235 * return 6 + 7;
236 *
237 * Which becomes the following graph:
238 * constant0
239 * constant4
240 * constant5
241 * constant6
242 * constant7
243 * constant8
244 * goto
245 * |
246 * goto
247 * |
248 * phi
249 * equal
250 * if +++++
251 * | \ +
252 * | 4 + 5
253 * | goto
254 * |
255 * 6 + 7
256 * return
257 * |
258 * exit
259 */
260
261 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
262 Instruction::CONST_4 | 0 | 0,
263 Instruction::CONST_4 | 8 << 12 | 1 << 8,
264 Instruction::IF_EQ | 1 << 8, 7,
265 Instruction::CONST_4 | 4 << 12 | 0 << 8,
266 Instruction::CONST_4 | 5 << 12 | 1 << 8,
267 Instruction::ADD_INT, 1 << 8 | 0,
268 Instruction::GOTO | 0xFA00,
269 Instruction::CONST_4 | 6 << 12 | 1 << 8,
270 Instruction::CONST_4 | 7 << 12 | 1 << 8,
271 Instruction::ADD_INT, 1 << 8 | 0,
272 Instruction::RETURN | 1 << 8);
273
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700274 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100275}
276
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700277TEST_ALL_STRATEGIES(Loop2);
278
279static void Loop3(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100280 /*
281 * Test the following snippet:
282 * int a = 0
283 * do {
284 * b = a;
285 * a++;
286 * } while (a != 5)
287 * return b;
288 *
289 * Which becomes the following graph:
290 * constant0
291 * constant1
292 * constant5
293 * goto
294 * |
295 * goto
296 * |++++++++++++
297 * phi +
298 * a++ +
299 * equals +
300 * if +
301 * |++++++++++++
302 * return
303 * |
304 * exit
305 */
306
307 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
308 Instruction::CONST_4 | 0 | 0,
309 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
310 Instruction::CONST_4 | 5 << 12 | 2 << 8,
311 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
312 Instruction::RETURN | 0 << 8,
313 Instruction::MOVE | 1 << 12 | 0 << 8,
314 Instruction::GOTO | 0xF900);
315
316 ArenaPool pool;
317 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000318 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400319 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
320 X86InstructionSetFeatures::FromCppDefines());
321 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100322 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100323 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700324 RegisterAllocator* register_allocator =
325 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700326 register_allocator->AllocateRegisters();
327 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100328
Vladimir Markoec7802a2015-10-01 20:57:57 +0100329 HBasicBlock* loop_header = graph->GetBlocks()[2];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100330 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
331
332 LiveInterval* phi_interval = phi->GetLiveInterval();
333 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
334 ASSERT_TRUE(phi_interval->HasRegister());
335 ASSERT_TRUE(loop_update->HasRegister());
336 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
337
Vladimir Markoec7802a2015-10-01 20:57:57 +0100338 HBasicBlock* return_block = graph->GetBlocks()[3];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100339 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100340 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
341}
342
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700343TEST_ALL_STRATEGIES(Loop3);
344
David Brazdil4833f5a2015-12-16 10:37:39 +0000345TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100346 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
347 Instruction::CONST_4 | 0 | 0,
Mark Mendell09b84632015-02-13 17:48:38 -0500348 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
349 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
350 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100351 Instruction::RETURN_VOID);
352
353 ArenaPool pool;
354 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000355 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400356 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
357 X86InstructionSetFeatures::FromCppDefines());
358 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100359 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100360 liveness.Analyze();
361
Vladimir Markoec7802a2015-10-01 20:57:57 +0100362 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
363 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
Mark Mendell09b84632015-02-13 17:48:38 -0500364 ASSERT_EQ(last_xor->InputAt(0), first_xor);
365 LiveInterval* interval = first_xor->GetLiveInterval();
366 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100367 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
368
369 // We need a register for the output of the instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500370 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100371
372 // Split at the next instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500373 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100374 // The user of the split is the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500375 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100376
377 // Split before the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500378 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100379 // Ensure the current interval has no register use...
380 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
381 // And the new interval has it for the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500382 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100383}
384
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700385static void DeadPhi(Strategy strategy) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100386 /* Test for a dead loop phi taking as back-edge input a phi that also has
387 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
388 * does not solve the problem because the loop phi will be visited last.
389 *
390 * Test the following snippet:
391 * int a = 0
392 * do {
393 * if (true) {
394 * a = 2;
395 * }
396 * } while (true);
397 */
398
399 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
400 Instruction::CONST_4 | 0 | 0,
401 Instruction::CONST_4 | 1 << 8 | 0,
402 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
403 Instruction::CONST_4 | 2 << 12 | 0 << 8,
404 Instruction::GOTO | 0xFD00,
405 Instruction::RETURN_VOID);
406
407 ArenaPool pool;
408 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000409 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100410 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400411 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
412 X86InstructionSetFeatures::FromCppDefines());
413 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100414 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100415 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700416 RegisterAllocator* register_allocator =
417 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700418 register_allocator->AllocateRegisters();
419 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100420}
421
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700422TEST_ALL_STRATEGIES(DeadPhi);
423
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100424/**
425 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
426 * that share the same register. It should split the interval it is currently
427 * allocating for at the minimum lifetime position between the two inactive intervals.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700428 * This test only applies to the linear scan allocator.
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100429 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000430TEST_F(RegisterAllocatorTest, FreeUntil) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100431 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
432 Instruction::CONST_4 | 0 | 0,
433 Instruction::RETURN);
434
435 ArenaPool pool;
436 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000437 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100438 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400439 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
440 X86InstructionSetFeatures::FromCppDefines());
441 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100442 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100443 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700444 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100445
446 // Add an artifical range to cover the temps that will be put in the unhandled list.
447 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
448 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100449
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100450 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100451 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100452 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100453 graph->GetEntryBlock()->GetFirstInstruction());
454 }
455
Mingyao Yang296bd602014-10-06 16:47:28 -0700456 // For SSA value intervals, only an interval resulted from a split may intersect
457 // with inactive intervals.
458 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100459
460 // Add three temps holding the same register, and starting at different positions.
461 // Put the one that should be picked in the middle of the inactive list to ensure
462 // we do not depend on an order.
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100463 LiveInterval* interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100464 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100465 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100466
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100467 interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100468 interval->AddRange(20, 30);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100469 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100470
David Brazdilf4eb9ae2015-04-17 18:19:30 +0100471 interval = LiveInterval::MakeFixedInterval(&allocator, 0, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100472 interval->AddRange(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100473 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100474
475 register_allocator.number_of_registers_ = 1;
476 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
477 register_allocator.processing_core_registers_ = true;
478 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
479
Mingyao Yang296bd602014-10-06 16:47:28 -0700480 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100481
482 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100483 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100484 // Check that we know need to find a new register where the next interval
485 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100486 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100487}
488
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100489static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
490 HPhi** phi,
491 HInstruction** input1,
492 HInstruction** input2) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100493 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100494 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800495 ScopedNullHandle<mirror::DexCache> dex_cache;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100496 graph->AddBlock(entry);
497 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000498 HInstruction* parameter = new (allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800499 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100500 entry->AddInstruction(parameter);
501
502 HBasicBlock* block = new (allocator) HBasicBlock(graph);
503 graph->AddBlock(block);
504 entry->AddSuccessor(block);
505
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100506 HInstruction* test = new (allocator) HInstanceFieldGet(parameter,
507 Primitive::kPrimBoolean,
508 MemberOffset(22),
509 false,
510 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700511 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700512 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100513 dex_cache,
514 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100515 block->AddInstruction(test);
516 block->AddInstruction(new (allocator) HIf(test));
517 HBasicBlock* then = new (allocator) HBasicBlock(graph);
518 HBasicBlock* else_ = new (allocator) HBasicBlock(graph);
519 HBasicBlock* join = new (allocator) HBasicBlock(graph);
520 graph->AddBlock(then);
521 graph->AddBlock(else_);
522 graph->AddBlock(join);
523
524 block->AddSuccessor(then);
525 block->AddSuccessor(else_);
526 then->AddSuccessor(join);
527 else_->AddSuccessor(join);
528 then->AddInstruction(new (allocator) HGoto());
529 else_->AddInstruction(new (allocator) HGoto());
530
531 *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
532 join->AddPhi(*phi);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100533 *input1 = new (allocator) HInstanceFieldGet(parameter,
534 Primitive::kPrimInt,
535 MemberOffset(42),
536 false,
537 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700538 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700539 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100540 dex_cache,
541 0);
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700542 *input2 = new (allocator) HInstanceFieldGet(parameter,
543 Primitive::kPrimInt,
544 MemberOffset(42),
545 false,
546 kUnknownFieldIndex,
547 kUnknownClassDefIndex,
548 graph->GetDexFile(),
549 dex_cache,
550 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100551 then->AddInstruction(*input1);
552 else_->AddInstruction(*input2);
553 join->AddInstruction(new (allocator) HExit());
554 (*phi)->AddInput(*input1);
555 (*phi)->AddInput(*input2);
556
557 graph->BuildDominatorTree();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000558 graph->AnalyzeLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100559 return graph;
560}
561
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700562static void PhiHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100563 ArenaPool pool;
564 ArenaAllocator allocator(&pool);
565 HPhi *phi;
566 HInstruction *input1, *input2;
567
568 {
569 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400570 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
571 X86InstructionSetFeatures::FromCppDefines());
572 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100573 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100574 liveness.Analyze();
575
576 // Check that the register allocator is deterministic.
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700577 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700578 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700579 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100580
581 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
582 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
583 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
584 }
585
586 {
587 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400588 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
589 X86InstructionSetFeatures::FromCppDefines());
590 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100591 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100592 liveness.Analyze();
593
594 // Set the phi to a specific register, and check that the inputs get allocated
595 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000596 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700597 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700598 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700599 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100600
601 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
602 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
603 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
604 }
605
606 {
607 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400608 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
609 X86InstructionSetFeatures::FromCppDefines());
610 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100611 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100612 liveness.Analyze();
613
614 // Set input1 to a specific register, and check that the phi and other input get allocated
615 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000616 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700617 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700618 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700619 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100620
621 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
622 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
623 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
624 }
625
626 {
627 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400628 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
629 X86InstructionSetFeatures::FromCppDefines());
630 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100631 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100632 liveness.Analyze();
633
634 // Set input2 to a specific register, and check that the phi and other input get allocated
635 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000636 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700637 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700638 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700639 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100640
641 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
642 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
643 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
644 }
645}
646
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700647// TODO: Enable this test for graph coloring register allocation when iterative move
648// coalescing is merged.
649TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) {
650 PhiHint(Strategy::kRegisterAllocatorLinearScan);
651}
652
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100653static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
654 HInstruction** field,
655 HInstruction** ret) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100656 HGraph* graph = CreateGraph(allocator);
Mathieu Chartier9865bde2015-12-21 09:58:16 -0800657 ScopedNullHandle<mirror::DexCache> dex_cache;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100658 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
659 graph->AddBlock(entry);
660 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000661 HInstruction* parameter = new (allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800662 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100663 entry->AddInstruction(parameter);
664
665 HBasicBlock* block = new (allocator) HBasicBlock(graph);
666 graph->AddBlock(block);
667 entry->AddSuccessor(block);
668
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100669 *field = new (allocator) HInstanceFieldGet(parameter,
670 Primitive::kPrimInt,
671 MemberOffset(42),
672 false,
673 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700674 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700675 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100676 dex_cache,
677 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100678 block->AddInstruction(*field);
679 *ret = new (allocator) HReturn(*field);
680 block->AddInstruction(*ret);
681
682 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
683 graph->AddBlock(exit);
684 block->AddSuccessor(exit);
685 exit->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000686
687 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100688 return graph;
689}
690
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700691void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100692 ArenaPool pool;
693 ArenaAllocator allocator(&pool);
694 HInstruction *field, *ret;
695
696 {
697 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400698 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
699 X86InstructionSetFeatures::FromCppDefines());
700 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100701 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100702 liveness.Analyze();
703
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700704 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700705 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700706 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100707
708 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
709 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
710 }
711
712 {
713 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400714 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
715 X86InstructionSetFeatures::FromCppDefines());
716 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100717 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100718 liveness.Analyze();
719
720 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000721 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100722 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100723
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700724 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700725 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700726 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100727
728 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
729 }
730}
731
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700732// TODO: Enable this test for graph coloring register allocation when iterative move
733// coalescing is merged.
734TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
735 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
736}
737
Mark Mendell09b84632015-02-13 17:48:38 -0500738static HGraph* BuildTwoSubs(ArenaAllocator* allocator,
739 HInstruction** first_sub,
740 HInstruction** second_sub) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100741 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100742 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
743 graph->AddBlock(entry);
744 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000745 HInstruction* parameter = new (allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800746 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100747 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000748
749 HInstruction* constant1 = graph->GetIntConstant(1);
750 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100751
752 HBasicBlock* block = new (allocator) HBasicBlock(graph);
753 graph->AddBlock(block);
754 entry->AddSuccessor(block);
755
Mark Mendell09b84632015-02-13 17:48:38 -0500756 *first_sub = new (allocator) HSub(Primitive::kPrimInt, parameter, constant1);
757 block->AddInstruction(*first_sub);
758 *second_sub = new (allocator) HSub(Primitive::kPrimInt, *first_sub, constant2);
759 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100760
761 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000762
763 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100764 return graph;
765}
766
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700767void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100768 ArenaPool pool;
769 ArenaAllocator allocator(&pool);
Mark Mendell09b84632015-02-13 17:48:38 -0500770 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100771
772 {
Mark Mendell09b84632015-02-13 17:48:38 -0500773 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400774 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
775 X86InstructionSetFeatures::FromCppDefines());
776 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100777 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100778 liveness.Analyze();
779
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700780 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700781 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700782 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100783
784 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500785 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
786 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100787 }
788
789 {
Mark Mendell09b84632015-02-13 17:48:38 -0500790 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400791 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
792 X86InstructionSetFeatures::FromCppDefines());
793 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100794 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100795 liveness.Analyze();
796
797 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000798 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500799 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
800 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
801 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100802
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700803 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700804 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700805 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100806
Mark Mendell09b84632015-02-13 17:48:38 -0500807 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
808 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100809 }
810}
811
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700812// TODO: Enable this test for graph coloring register allocation when iterative move
813// coalescing is merged.
814TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
815 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
816}
817
Calin Juravled0d48522014-11-04 16:40:20 +0000818static HGraph* BuildDiv(ArenaAllocator* allocator,
819 HInstruction** div) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100820 HGraph* graph = CreateGraph(allocator);
Calin Juravled0d48522014-11-04 16:40:20 +0000821 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
822 graph->AddBlock(entry);
823 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000824 HInstruction* first = new (allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800825 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000826 HInstruction* second = new (allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800827 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Calin Juravled0d48522014-11-04 16:40:20 +0000828 entry->AddInstruction(first);
829 entry->AddInstruction(second);
830
831 HBasicBlock* block = new (allocator) HBasicBlock(graph);
832 graph->AddBlock(block);
833 entry->AddSuccessor(block);
834
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000835 *div = new (allocator) HDiv(Primitive::kPrimInt, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000836 block->AddInstruction(*div);
837
838 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000839
840 graph->BuildDominatorTree();
Calin Juravled0d48522014-11-04 16:40:20 +0000841 return graph;
842}
843
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700844static void ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
Calin Juravled0d48522014-11-04 16:40:20 +0000845 ArenaPool pool;
846 ArenaAllocator allocator(&pool);
847 HInstruction *div;
848
849 {
850 HGraph* graph = BuildDiv(&allocator, &div);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400851 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
852 X86InstructionSetFeatures::FromCppDefines());
853 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100854 SsaLivenessAnalysis liveness(graph, &codegen);
Calin Juravled0d48522014-11-04 16:40:20 +0000855 liveness.Analyze();
856
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700857 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700858 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700859 register_allocator->AllocateRegisters();
Calin Juravled0d48522014-11-04 16:40:20 +0000860
861 // div on x86 requires its first input in eax and the output be the same as the first input.
862 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
863 }
864}
865
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700866// TODO: Enable this test for graph coloring register allocation when iterative move
867// coalescing is merged.
868TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) {
869 ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan);
870}
871
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000872// Test a bug in the register allocator, where allocating a blocked
873// register would lead to spilling an inactive interval at the wrong
874// position.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700875// This test only applies to the linear scan allocator.
David Brazdil4833f5a2015-12-16 10:37:39 +0000876TEST_F(RegisterAllocatorTest, SpillInactive) {
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000877 ArenaPool pool;
878
879 // Create a synthesized graph to please the register_allocator and
880 // ssa_liveness_analysis code.
881 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100882 HGraph* graph = CreateGraph(&allocator);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000883 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
884 graph->AddBlock(entry);
885 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000886 HInstruction* one = new (&allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800887 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000888 HInstruction* two = new (&allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800889 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000890 HInstruction* three = new (&allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800891 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000892 HInstruction* four = new (&allocator) HParameterValue(
Andreas Gampea5b09a62016-11-17 15:21:22 -0800893 graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000894 entry->AddInstruction(one);
895 entry->AddInstruction(two);
896 entry->AddInstruction(three);
897 entry->AddInstruction(four);
898
899 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
900 graph->AddBlock(block);
901 entry->AddSuccessor(block);
902 block->AddInstruction(new (&allocator) HExit());
903
904 // We create a synthesized user requesting a register, to avoid just spilling the
905 // intervals.
906 HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, Primitive::kPrimInt);
907 user->AddInput(one);
908 user->SetBlock(block);
909 LocationSummary* locations = new (&allocator) LocationSummary(user, LocationSummary::kNoCall);
910 locations->SetInAt(0, Location::RequiresRegister());
911 static constexpr size_t phi_ranges[][2] = {{20, 30}};
912 BuildInterval(phi_ranges, arraysize(phi_ranges), &allocator, -1, user);
913
914 // Create an interval with lifetime holes.
915 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
916 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), &allocator, -1, one);
917 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, first->first_use_);
918 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 7, first->first_use_);
919 first->first_use_ = new(&allocator) UsePosition(user, 0, false, 6, first->first_use_);
920
921 locations = new (&allocator) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
922 locations->SetOut(Location::RequiresRegister());
923 first = first->SplitAt(1);
924
925 // Create an interval that conflicts with the next interval, to force the next
926 // interval to call `AllocateBlockedReg`.
927 static constexpr size_t ranges2[][2] = {{2, 4}};
928 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), &allocator, -1, two);
929 locations = new (&allocator) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
930 locations->SetOut(Location::RequiresRegister());
931
932 // Create an interval that will lead to splitting the first interval. The bug occured
933 // by splitting at a wrong position, in this case at the next intersection between
934 // this interval and the first interval. We would have then put the interval with ranges
935 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
936 // before lifetime position 6 yet.
937 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
938 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), &allocator, -1, three);
939 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 8, third->first_use_);
940 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 4, third->first_use_);
941 third->first_use_ = new(&allocator) UsePosition(user, 0, false, 3, third->first_use_);
942 locations = new (&allocator) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
943 locations->SetOut(Location::RequiresRegister());
944 third = third->SplitAt(3);
945
946 // Because the first part of the split interval was considered handled, this interval
947 // was free to allocate the same register, even though it conflicts with it.
948 static constexpr size_t ranges4[][2] = {{4, 6}};
949 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), &allocator, -1, four);
950 locations = new (&allocator) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
951 locations->SetOut(Location::RequiresRegister());
952
Mark Mendellfb8d2792015-03-31 22:16:59 -0400953 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
954 X86InstructionSetFeatures::FromCppDefines());
955 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100956 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100957 // Populate the instructions in the liveness object, to please the register allocator.
958 for (size_t i = 0; i < 32; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100959 liveness.instructions_from_lifetime_position_.push_back(user);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100960 }
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000961
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700962 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100963 register_allocator.unhandled_core_intervals_.push_back(fourth);
964 register_allocator.unhandled_core_intervals_.push_back(third);
965 register_allocator.unhandled_core_intervals_.push_back(second);
966 register_allocator.unhandled_core_intervals_.push_back(first);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000967
968 // Set just one register available to make all intervals compete for the same.
969 register_allocator.number_of_registers_ = 1;
970 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
971 register_allocator.processing_core_registers_ = true;
972 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
973 register_allocator.LinearScan();
974
975 // Test that there is no conflicts between intervals.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100976 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
977 intervals.push_back(first);
978 intervals.push_back(second);
979 intervals.push_back(third);
980 intervals.push_back(fourth);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000981 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
982 intervals, 0, 0, codegen, &allocator, true, false));
983}
984
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100985} // namespace art