blob: 59987e26b67ae326600aecee7eec3d678fcb38e1 [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
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070017#include "register_allocator.h"
18
Mark Mendellfb8d2792015-03-31 22:16:59 -040019#include "arch/x86/instruction_set_features_x86.h"
Mathieu Chartierb666f482015-02-18 14:33:14 -080020#include "base/arena_allocator.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010021#include "builder.h"
22#include "code_generator.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010023#include "code_generator_x86.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010024#include "dex_file.h"
Andreas Gampea5b09a62016-11-17 15:21:22 -080025#include "dex_file_types.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010026#include "dex_instruction.h"
Calin Juravlecd6dffe2015-01-08 17:35:35 +000027#include "driver/compiler_options.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010028#include "nodes.h"
29#include "optimizing_unit_test.h"
Matthew Gharritye9288852016-07-14 14:08:16 -070030#include "register_allocator_linear_scan.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010031#include "ssa_liveness_analysis.h"
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010032#include "ssa_phi_elimination.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010033
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010034namespace art {
35
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070036using Strategy = RegisterAllocator::Strategy;
37
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010038// Note: the register allocator tests rely on the fact that constants have live
39// intervals and registers get allocated to them.
40
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070041class RegisterAllocatorTest : public CommonCompilerTest {
42 protected:
43 // These functions need to access private variables of LocationSummary, so we declare it
44 // as a member of RegisterAllocatorTest, which we make a friend class.
45 static void SameAsFirstInputHint(Strategy strategy);
46 static void ExpectedInRegisterHint(Strategy strategy);
47};
David Brazdil4833f5a2015-12-16 10:37:39 +000048
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070049// This macro should include all register allocation strategies that should be tested.
50#define TEST_ALL_STRATEGIES(test_name)\
51TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
52 test_name(Strategy::kRegisterAllocatorLinearScan);\
53}\
54TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
55 test_name(Strategy::kRegisterAllocatorGraphColor);\
56}
57
58static bool Check(const uint16_t* data, Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010059 ArenaPool pool;
60 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +000061 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -040062 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
63 X86InstructionSetFeatures::FromCppDefines());
64 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +010065 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010066 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070067 RegisterAllocator* register_allocator =
68 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070069 register_allocator->AllocateRegisters();
70 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010071}
72
73/**
74 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
75 * tests are based on this validation method.
76 */
David Brazdil4833f5a2015-12-16 10:37:39 +000077TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010078 ArenaPool pool;
79 ArenaAllocator allocator(&pool);
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010080 HGraph* graph = CreateGraph(&allocator);
Mark Mendellfb8d2792015-03-31 22:16:59 -040081 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
82 X86InstructionSetFeatures::FromCppDefines());
83 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010084 ArenaVector<LiveInterval*> intervals(allocator.Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010085
86 // Test with two intervals of the same range.
87 {
88 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010089 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 0));
90 intervals.push_back(BuildInterval(ranges, arraysize(ranges), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010091 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010092 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010094 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010095 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010096 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +010097 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010098 }
99
100 // Test with two non-intersecting intervals.
101 {
102 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100103 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100104 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100105 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100106 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100107 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100108
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100109 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100110 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100111 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100112 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100113 }
114
115 // Test with two non-intersecting intervals, with one with a lifetime hole.
116 {
117 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100118 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100119 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100120 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100121 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100122 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100123
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100124 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100125 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100126 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100127 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100128 }
129
130 // Test with intersecting intervals.
131 {
132 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100133 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100134 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100135 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100136 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100137 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100138
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100139 intervals[1]->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100140 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100141 intervals, 0, 0, codegen, &allocator, true, false));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100142 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100143 }
144
145 // Test with siblings.
146 {
147 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100148 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
149 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100150 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100151 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100152 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100153 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100154
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100155 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100156 // Sibling of the first interval has no register allocated to it.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100157 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100158 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100159
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100160 intervals[0]->GetNextSibling()->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100161 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100162 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100163 }
164}
165
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700166static void CFG1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100167 /*
168 * Test the following snippet:
169 * return 0;
170 *
171 * Which becomes the following graph:
172 * constant0
173 * goto
174 * |
175 * return
176 * |
177 * exit
178 */
179 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
180 Instruction::CONST_4 | 0 | 0,
181 Instruction::RETURN);
182
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700183 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100184}
185
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700186TEST_ALL_STRATEGIES(CFG1);
187
188static void Loop1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100189 /*
190 * Test the following snippet:
191 * int a = 0;
192 * while (a == a) {
193 * a = 4;
194 * }
195 * return 5;
196 *
197 * Which becomes the following graph:
198 * constant0
199 * constant4
200 * constant5
201 * goto
202 * |
203 * goto
204 * |
205 * phi
206 * equal
207 * if +++++
208 * | \ +
209 * | goto
210 * |
211 * return
212 * |
213 * exit
214 */
215
216 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
217 Instruction::CONST_4 | 0 | 0,
218 Instruction::IF_EQ, 4,
219 Instruction::CONST_4 | 4 << 12 | 0,
220 Instruction::GOTO | 0xFD00,
221 Instruction::CONST_4 | 5 << 12 | 1 << 8,
222 Instruction::RETURN | 1 << 8);
223
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700224 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100225}
226
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700227TEST_ALL_STRATEGIES(Loop1);
228
229static void Loop2(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100230 /*
231 * Test the following snippet:
232 * int a = 0;
233 * while (a == 8) {
234 * a = 4 + 5;
235 * }
236 * return 6 + 7;
237 *
238 * Which becomes the following graph:
239 * constant0
240 * constant4
241 * constant5
242 * constant6
243 * constant7
244 * constant8
245 * goto
246 * |
247 * goto
248 * |
249 * phi
250 * equal
251 * if +++++
252 * | \ +
253 * | 4 + 5
254 * | goto
255 * |
256 * 6 + 7
257 * return
258 * |
259 * exit
260 */
261
262 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
263 Instruction::CONST_4 | 0 | 0,
264 Instruction::CONST_4 | 8 << 12 | 1 << 8,
265 Instruction::IF_EQ | 1 << 8, 7,
266 Instruction::CONST_4 | 4 << 12 | 0 << 8,
267 Instruction::CONST_4 | 5 << 12 | 1 << 8,
268 Instruction::ADD_INT, 1 << 8 | 0,
269 Instruction::GOTO | 0xFA00,
270 Instruction::CONST_4 | 6 << 12 | 1 << 8,
271 Instruction::CONST_4 | 7 << 12 | 1 << 8,
272 Instruction::ADD_INT, 1 << 8 | 0,
273 Instruction::RETURN | 1 << 8);
274
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700275 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100276}
277
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700278TEST_ALL_STRATEGIES(Loop2);
279
280static void Loop3(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100281 /*
282 * Test the following snippet:
283 * int a = 0
284 * do {
285 * b = a;
286 * a++;
287 * } while (a != 5)
288 * return b;
289 *
290 * Which becomes the following graph:
291 * constant0
292 * constant1
293 * constant5
294 * goto
295 * |
296 * goto
297 * |++++++++++++
298 * phi +
299 * a++ +
300 * equals +
301 * if +
302 * |++++++++++++
303 * return
304 * |
305 * exit
306 */
307
308 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
309 Instruction::CONST_4 | 0 | 0,
310 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
311 Instruction::CONST_4 | 5 << 12 | 2 << 8,
312 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
313 Instruction::RETURN | 0 << 8,
314 Instruction::MOVE | 1 << 12 | 0 << 8,
315 Instruction::GOTO | 0xF900);
316
317 ArenaPool pool;
318 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000319 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400320 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
321 X86InstructionSetFeatures::FromCppDefines());
322 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100323 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100324 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700325 RegisterAllocator* register_allocator =
326 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700327 register_allocator->AllocateRegisters();
328 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100329
Vladimir Markoec7802a2015-10-01 20:57:57 +0100330 HBasicBlock* loop_header = graph->GetBlocks()[2];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100331 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
332
333 LiveInterval* phi_interval = phi->GetLiveInterval();
334 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
335 ASSERT_TRUE(phi_interval->HasRegister());
336 ASSERT_TRUE(loop_update->HasRegister());
337 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
338
Vladimir Markoec7802a2015-10-01 20:57:57 +0100339 HBasicBlock* return_block = graph->GetBlocks()[3];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100340 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100341 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
342}
343
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700344TEST_ALL_STRATEGIES(Loop3);
345
David Brazdil4833f5a2015-12-16 10:37:39 +0000346TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100347 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
348 Instruction::CONST_4 | 0 | 0,
Mark Mendell09b84632015-02-13 17:48:38 -0500349 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
350 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
351 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100352 Instruction::RETURN_VOID);
353
354 ArenaPool pool;
355 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000356 HGraph* graph = CreateCFG(&allocator, data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400357 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
358 X86InstructionSetFeatures::FromCppDefines());
359 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100360 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100361 liveness.Analyze();
362
Vladimir Markoec7802a2015-10-01 20:57:57 +0100363 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
364 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
Mark Mendell09b84632015-02-13 17:48:38 -0500365 ASSERT_EQ(last_xor->InputAt(0), first_xor);
366 LiveInterval* interval = first_xor->GetLiveInterval();
367 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100368 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
369
370 // We need a register for the output of the instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500371 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100372
373 // Split at the next instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500374 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100375 // The user of the split is the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500376 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100377
378 // Split before the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500379 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100380 // Ensure the current interval has no register use...
381 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
382 // And the new interval has it for the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500383 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100384}
385
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700386static void DeadPhi(Strategy strategy) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100387 /* Test for a dead loop phi taking as back-edge input a phi that also has
388 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
389 * does not solve the problem because the loop phi will be visited last.
390 *
391 * Test the following snippet:
392 * int a = 0
393 * do {
394 * if (true) {
395 * a = 2;
396 * }
397 * } while (true);
398 */
399
400 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
401 Instruction::CONST_4 | 0 | 0,
402 Instruction::CONST_4 | 1 << 8 | 0,
403 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
404 Instruction::CONST_4 | 2 << 12 | 0 << 8,
405 Instruction::GOTO | 0xFD00,
406 Instruction::RETURN_VOID);
407
408 ArenaPool pool;
409 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000410 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100411 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400412 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
413 X86InstructionSetFeatures::FromCppDefines());
414 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100415 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100416 liveness.Analyze();
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700417 RegisterAllocator* register_allocator =
418 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700419 register_allocator->AllocateRegisters();
420 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100421}
422
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700423TEST_ALL_STRATEGIES(DeadPhi);
424
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100425/**
426 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
427 * that share the same register. It should split the interval it is currently
428 * allocating for at the minimum lifetime position between the two inactive intervals.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700429 * This test only applies to the linear scan allocator.
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100430 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000431TEST_F(RegisterAllocatorTest, FreeUntil) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100432 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
433 Instruction::CONST_4 | 0 | 0,
434 Instruction::RETURN);
435
436 ArenaPool pool;
437 ArenaAllocator allocator(&pool);
David Brazdilbadd8262016-02-02 16:28:56 +0000438 HGraph* graph = CreateCFG(&allocator, data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100439 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400440 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
441 X86InstructionSetFeatures::FromCppDefines());
442 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100443 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100444 liveness.Analyze();
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700445 RegisterAllocatorLinearScan register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100446
447 // Add an artifical range to cover the temps that will be put in the unhandled list.
448 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
449 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100450
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100451 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100452 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100453 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100454 graph->GetEntryBlock()->GetFirstInstruction());
455 }
456
Mingyao Yang296bd602014-10-06 16:47:28 -0700457 // For SSA value intervals, only an interval resulted from a split may intersect
458 // with inactive intervals.
459 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100460
461 // Add three temps holding the same register, and starting at different positions.
462 // Put the one that should be picked in the middle of the inactive list to ensure
463 // we do not depend on an order.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100464 LiveInterval* interval = LiveInterval::MakeFixedInterval(&allocator, 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100465 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100466 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100467
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100468 interval = LiveInterval::MakeFixedInterval(&allocator, 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100469 interval->AddRange(20, 30);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100470 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100471
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100472 interval = LiveInterval::MakeFixedInterval(&allocator, 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100473 interval->AddRange(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100474 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100475
476 register_allocator.number_of_registers_ = 1;
477 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
478 register_allocator.processing_core_registers_ = true;
479 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
480
Mingyao Yang296bd602014-10-06 16:47:28 -0700481 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100482
483 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100484 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100485 // Check that we know need to find a new register where the next interval
486 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100487 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100488}
489
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100490static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
491 HPhi** phi,
492 HInstruction** input1,
493 HInstruction** input2) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100494 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100495 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
496 graph->AddBlock(entry);
497 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000498 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100499 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
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,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000507 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100508 DataType::Type::kBool,
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100509 MemberOffset(22),
510 false,
511 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700512 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700513 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100514 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
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100531 *phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100532 join->AddPhi(*phi);
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100533 *input1 = new (allocator) HInstanceFieldGet(parameter,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000534 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100535 DataType::Type::kInt32,
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100536 MemberOffset(42),
537 false,
538 kUnknownFieldIndex,
Mingyao Yang8df69d42015-10-22 15:40:58 -0700539 kUnknownClassDefIndex,
Mathieu Chartier736b5602015-09-02 14:54:11 -0700540 graph->GetDexFile(),
Calin Juravle154746b2015-10-06 15:46:54 +0100541 0);
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700542 *input2 = new (allocator) HInstanceFieldGet(parameter,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000543 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100544 DataType::Type::kInt32,
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700545 MemberOffset(42),
546 false,
547 kUnknownFieldIndex,
548 kUnknownClassDefIndex,
549 graph->GetDexFile(),
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700550 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);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100657 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
658 graph->AddBlock(entry);
659 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000660 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100661 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100662 entry->AddInstruction(parameter);
663
664 HBasicBlock* block = new (allocator) HBasicBlock(graph);
665 graph->AddBlock(block);
666 entry->AddSuccessor(block);
667
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100668 *field = new (allocator) HInstanceFieldGet(parameter,
Nicolas Geoffrayc52b26d2016-12-19 09:18:07 +0000669 nullptr,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100670 DataType::Type::kInt32,
Guillaume "Vermeille" Sanchez104fd8a2015-05-20 17:52:13 +0100671 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 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100677 block->AddInstruction(*field);
678 *ret = new (allocator) HReturn(*field);
679 block->AddInstruction(*ret);
680
681 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
682 graph->AddBlock(exit);
683 block->AddSuccessor(exit);
684 exit->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000685
686 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100687 return graph;
688}
689
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700690void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100691 ArenaPool pool;
692 ArenaAllocator allocator(&pool);
693 HInstruction *field, *ret;
694
695 {
696 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400697 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
698 X86InstructionSetFeatures::FromCppDefines());
699 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100700 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100701 liveness.Analyze();
702
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700703 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700704 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700705 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100706
707 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
708 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
709 }
710
711 {
712 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400713 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
714 X86InstructionSetFeatures::FromCppDefines());
715 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100716 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100717 liveness.Analyze();
718
719 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000720 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100721 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100722
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700723 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700724 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700725 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100726
727 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
728 }
729}
730
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700731// TODO: Enable this test for graph coloring register allocation when iterative move
732// coalescing is merged.
733TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
734 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
735}
736
Mark Mendell09b84632015-02-13 17:48:38 -0500737static HGraph* BuildTwoSubs(ArenaAllocator* allocator,
738 HInstruction** first_sub,
739 HInstruction** second_sub) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100740 HGraph* graph = CreateGraph(allocator);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100741 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
742 graph->AddBlock(entry);
743 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000744 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100745 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100746 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000747
748 HInstruction* constant1 = graph->GetIntConstant(1);
749 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100750
751 HBasicBlock* block = new (allocator) HBasicBlock(graph);
752 graph->AddBlock(block);
753 entry->AddSuccessor(block);
754
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100755 *first_sub = new (allocator) HSub(DataType::Type::kInt32, parameter, constant1);
Mark Mendell09b84632015-02-13 17:48:38 -0500756 block->AddInstruction(*first_sub);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100757 *second_sub = new (allocator) HSub(DataType::Type::kInt32, *first_sub, constant2);
Mark Mendell09b84632015-02-13 17:48:38 -0500758 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100759
760 block->AddInstruction(new (allocator) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000761
762 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100763 return graph;
764}
765
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700766void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100767 ArenaPool pool;
768 ArenaAllocator allocator(&pool);
Mark Mendell09b84632015-02-13 17:48:38 -0500769 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100770
771 {
Mark Mendell09b84632015-02-13 17:48:38 -0500772 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400773 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
774 X86InstructionSetFeatures::FromCppDefines());
775 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100776 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100777 liveness.Analyze();
778
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700779 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700780 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700781 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100782
783 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500784 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
785 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100786 }
787
788 {
Mark Mendell09b84632015-02-13 17:48:38 -0500789 HGraph* graph = BuildTwoSubs(&allocator, &first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400790 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
791 X86InstructionSetFeatures::FromCppDefines());
792 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Nicolas Geoffray0d9f17d2015-04-15 14:17:44 +0100793 SsaLivenessAnalysis liveness(graph, &codegen);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100794 liveness.Analyze();
795
796 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000797 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500798 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
799 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
800 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100801
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700802 RegisterAllocator* register_allocator =
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700803 RegisterAllocator::Create(&allocator, &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700804 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100805
Mark Mendell09b84632015-02-13 17:48:38 -0500806 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
807 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100808 }
809}
810
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700811// TODO: Enable this test for graph coloring register allocation when iterative move
812// coalescing is merged.
813TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
814 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
815}
816
Calin Juravled0d48522014-11-04 16:40:20 +0000817static HGraph* BuildDiv(ArenaAllocator* allocator,
818 HInstruction** div) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100819 HGraph* graph = CreateGraph(allocator);
Calin Juravled0d48522014-11-04 16:40:20 +0000820 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
821 graph->AddBlock(entry);
822 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000823 HInstruction* first = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100824 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000825 HInstruction* second = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100826 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravled0d48522014-11-04 16:40:20 +0000827 entry->AddInstruction(first);
828 entry->AddInstruction(second);
829
830 HBasicBlock* block = new (allocator) HBasicBlock(graph);
831 graph->AddBlock(block);
832 entry->AddSuccessor(block);
833
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100834 *div =
835 new (allocator) HDiv(DataType::Type::kInt32, 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(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100887 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000888 HInstruction* two = new (&allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100889 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000890 HInstruction* three = new (&allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100891 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000892 HInstruction* four = new (&allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100893 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
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.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100906 HPhi* user = new (&allocator) HPhi(&allocator, 0, 1, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000907 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);
Vladimir Marko82b07402017-03-01 19:02:04 +0000917 first->uses_.push_front(*new(&allocator) UsePosition(user, false, 8));
918 first->uses_.push_front(*new(&allocator) UsePosition(user, false, 7));
919 first->uses_.push_front(*new(&allocator) UsePosition(user, false, 6));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000920
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);
Vladimir Marko82b07402017-03-01 19:02:04 +0000939 third->uses_.push_front(*new(&allocator) UsePosition(user, false, 8));
940 third->uses_.push_front(*new(&allocator) UsePosition(user, false, 4));
941 third->uses_.push_front(*new(&allocator) UsePosition(user, false, 3));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000942 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