blob: 69ed8c7fcc5c5ce70bad315c9ecf93f9d61b2523 [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
Vladimir Markoca6fff82017-10-03 14:49:14 +010041class RegisterAllocatorTest : public OptimizingUnitTest {
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070042 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.
Vladimir Markoca6fff82017-10-03 14:49:14 +010045 void SameAsFirstInputHint(Strategy strategy);
46 void ExpectedInRegisterHint(Strategy strategy);
47
48 // Helper functions that make use of the OptimizingUnitTest's members.
49 bool Check(const uint16_t* data, Strategy strategy);
50 void CFG1(Strategy strategy);
51 void Loop1(Strategy strategy);
52 void Loop2(Strategy strategy);
53 void Loop3(Strategy strategy);
54 void DeadPhi(Strategy strategy);
55 HGraph* BuildIfElseWithPhi(HPhi** phi, HInstruction** input1, HInstruction** input2);
56 void PhiHint(Strategy strategy);
57 HGraph* BuildFieldReturn(HInstruction** field, HInstruction** ret);
58 HGraph* BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub);
59 HGraph* BuildDiv(HInstruction** div);
60 void ExpectedExactInRegisterAndSameOutputHint(Strategy strategy);
Vladimir Markoe764d2e2017-10-05 14:35:55 +010061
62 bool ValidateIntervals(const ScopedArenaVector<LiveInterval*>& intervals,
63 const CodeGenerator& codegen) {
64 return RegisterAllocator::ValidateIntervals(ArrayRef<LiveInterval* const>(intervals),
65 /* number_of_spill_slots */ 0u,
66 /* number_of_out_slots */ 0u,
67 codegen,
68 /* processing_core_registers */ true,
69 /* log_fatal_on_failure */ false);
70 }
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070071};
David Brazdil4833f5a2015-12-16 10:37:39 +000072
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070073// This macro should include all register allocation strategies that should be tested.
74#define TEST_ALL_STRATEGIES(test_name)\
75TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
76 test_name(Strategy::kRegisterAllocatorLinearScan);\
77}\
78TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
79 test_name(Strategy::kRegisterAllocatorGraphColor);\
80}
81
Vladimir Markoca6fff82017-10-03 14:49:14 +010082bool RegisterAllocatorTest::Check(const uint16_t* data, Strategy strategy) {
83 HGraph* graph = CreateCFG(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -040084 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
85 X86InstructionSetFeatures::FromCppDefines());
86 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +010087 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010088 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +010089 std::unique_ptr<RegisterAllocator> register_allocator =
90 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070091 register_allocator->AllocateRegisters();
92 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010093}
94
95/**
96 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
97 * tests are based on this validation method.
98 */
David Brazdil4833f5a2015-12-16 10:37:39 +000099TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100100 HGraph* graph = CreateGraph();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400101 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
102 X86InstructionSetFeatures::FromCppDefines());
103 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100104 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100105
106 // Test with two intervals of the same range.
107 {
108 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100109 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 0));
110 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 1));
111 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100112
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100113 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100114 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100115 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100116 }
117
118 // Test with two non-intersecting intervals.
119 {
120 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100121 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100122 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100123 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
124 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100125
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100126 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100127 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100128 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100129 }
130
131 // Test with two non-intersecting intervals, with one with a lifetime hole.
132 {
133 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100134 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100135 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100136 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
137 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100138
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100139 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100140 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100141 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142 }
143
144 // Test with intersecting intervals.
145 {
146 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100147 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100148 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100149 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
150 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100151
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100152 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100153 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100154 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100155 }
156
157 // Test with siblings.
158 {
159 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100160 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100161 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100162 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100163 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
164 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100165
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100166 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100167 // Sibling of the first interval has no register allocated to it.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100168 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100169
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100170 intervals[0]->GetNextSibling()->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100171 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100172 }
173}
174
Vladimir Markoca6fff82017-10-03 14:49:14 +0100175void RegisterAllocatorTest::CFG1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100176 /*
177 * Test the following snippet:
178 * return 0;
179 *
180 * Which becomes the following graph:
181 * constant0
182 * goto
183 * |
184 * return
185 * |
186 * exit
187 */
188 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
189 Instruction::CONST_4 | 0 | 0,
190 Instruction::RETURN);
191
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700192 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100193}
194
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700195TEST_ALL_STRATEGIES(CFG1);
196
Vladimir Markoca6fff82017-10-03 14:49:14 +0100197void RegisterAllocatorTest::Loop1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100198 /*
199 * Test the following snippet:
200 * int a = 0;
201 * while (a == a) {
202 * a = 4;
203 * }
204 * return 5;
205 *
206 * Which becomes the following graph:
207 * constant0
208 * constant4
209 * constant5
210 * goto
211 * |
212 * goto
213 * |
214 * phi
215 * equal
216 * if +++++
217 * | \ +
218 * | goto
219 * |
220 * return
221 * |
222 * exit
223 */
224
225 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
226 Instruction::CONST_4 | 0 | 0,
227 Instruction::IF_EQ, 4,
228 Instruction::CONST_4 | 4 << 12 | 0,
229 Instruction::GOTO | 0xFD00,
230 Instruction::CONST_4 | 5 << 12 | 1 << 8,
231 Instruction::RETURN | 1 << 8);
232
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700233 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100234}
235
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700236TEST_ALL_STRATEGIES(Loop1);
237
Vladimir Markoca6fff82017-10-03 14:49:14 +0100238void RegisterAllocatorTest::Loop2(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100239 /*
240 * Test the following snippet:
241 * int a = 0;
242 * while (a == 8) {
243 * a = 4 + 5;
244 * }
245 * return 6 + 7;
246 *
247 * Which becomes the following graph:
248 * constant0
249 * constant4
250 * constant5
251 * constant6
252 * constant7
253 * constant8
254 * goto
255 * |
256 * goto
257 * |
258 * phi
259 * equal
260 * if +++++
261 * | \ +
262 * | 4 + 5
263 * | goto
264 * |
265 * 6 + 7
266 * return
267 * |
268 * exit
269 */
270
271 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
272 Instruction::CONST_4 | 0 | 0,
273 Instruction::CONST_4 | 8 << 12 | 1 << 8,
274 Instruction::IF_EQ | 1 << 8, 7,
275 Instruction::CONST_4 | 4 << 12 | 0 << 8,
276 Instruction::CONST_4 | 5 << 12 | 1 << 8,
277 Instruction::ADD_INT, 1 << 8 | 0,
278 Instruction::GOTO | 0xFA00,
279 Instruction::CONST_4 | 6 << 12 | 1 << 8,
280 Instruction::CONST_4 | 7 << 12 | 1 << 8,
281 Instruction::ADD_INT, 1 << 8 | 0,
282 Instruction::RETURN | 1 << 8);
283
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700284 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100285}
286
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700287TEST_ALL_STRATEGIES(Loop2);
288
Vladimir Markoca6fff82017-10-03 14:49:14 +0100289void RegisterAllocatorTest::Loop3(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100290 /*
291 * Test the following snippet:
292 * int a = 0
293 * do {
294 * b = a;
295 * a++;
296 * } while (a != 5)
297 * return b;
298 *
299 * Which becomes the following graph:
300 * constant0
301 * constant1
302 * constant5
303 * goto
304 * |
305 * goto
306 * |++++++++++++
307 * phi +
308 * a++ +
309 * equals +
310 * if +
311 * |++++++++++++
312 * return
313 * |
314 * exit
315 */
316
317 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
318 Instruction::CONST_4 | 0 | 0,
319 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
320 Instruction::CONST_4 | 5 << 12 | 2 << 8,
321 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
322 Instruction::RETURN | 0 << 8,
323 Instruction::MOVE | 1 << 12 | 0 << 8,
324 Instruction::GOTO | 0xF900);
325
Vladimir Markoca6fff82017-10-03 14:49:14 +0100326 HGraph* graph = CreateCFG(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400327 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
328 X86InstructionSetFeatures::FromCppDefines());
329 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100330 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100331 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100332 std::unique_ptr<RegisterAllocator> register_allocator =
333 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700334 register_allocator->AllocateRegisters();
335 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100336
Vladimir Markoec7802a2015-10-01 20:57:57 +0100337 HBasicBlock* loop_header = graph->GetBlocks()[2];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100338 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
339
340 LiveInterval* phi_interval = phi->GetLiveInterval();
341 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
342 ASSERT_TRUE(phi_interval->HasRegister());
343 ASSERT_TRUE(loop_update->HasRegister());
344 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
345
Vladimir Markoec7802a2015-10-01 20:57:57 +0100346 HBasicBlock* return_block = graph->GetBlocks()[3];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100347 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100348 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
349}
350
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700351TEST_ALL_STRATEGIES(Loop3);
352
David Brazdil4833f5a2015-12-16 10:37:39 +0000353TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100354 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
355 Instruction::CONST_4 | 0 | 0,
Mark Mendell09b84632015-02-13 17:48:38 -0500356 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
357 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
358 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100359 Instruction::RETURN_VOID);
360
Vladimir Markoca6fff82017-10-03 14:49:14 +0100361 HGraph* graph = CreateCFG(data);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400362 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
363 X86InstructionSetFeatures::FromCppDefines());
364 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100365 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100366 liveness.Analyze();
367
Vladimir Markoec7802a2015-10-01 20:57:57 +0100368 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
369 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
Mark Mendell09b84632015-02-13 17:48:38 -0500370 ASSERT_EQ(last_xor->InputAt(0), first_xor);
371 LiveInterval* interval = first_xor->GetLiveInterval();
372 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100373 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
374
375 // We need a register for the output of the instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500376 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100377
378 // Split at the next instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500379 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100380 // The user of the split is the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500381 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100382
383 // Split before the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500384 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100385 // Ensure the current interval has no register use...
386 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
387 // And the new interval has it for the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500388 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100389}
390
Vladimir Markoca6fff82017-10-03 14:49:14 +0100391void RegisterAllocatorTest::DeadPhi(Strategy strategy) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100392 /* Test for a dead loop phi taking as back-edge input a phi that also has
393 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
394 * does not solve the problem because the loop phi will be visited last.
395 *
396 * Test the following snippet:
397 * int a = 0
398 * do {
399 * if (true) {
400 * a = 2;
401 * }
402 * } while (true);
403 */
404
405 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
406 Instruction::CONST_4 | 0 | 0,
407 Instruction::CONST_4 | 1 << 8 | 0,
408 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
409 Instruction::CONST_4 | 2 << 12 | 0 << 8,
410 Instruction::GOTO | 0xFD00,
411 Instruction::RETURN_VOID);
412
Vladimir Markoca6fff82017-10-03 14:49:14 +0100413 HGraph* graph = CreateCFG(data);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100414 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400415 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
416 X86InstructionSetFeatures::FromCppDefines());
417 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100418 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100419 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100420 std::unique_ptr<RegisterAllocator> register_allocator =
421 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700422 register_allocator->AllocateRegisters();
423 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100424}
425
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700426TEST_ALL_STRATEGIES(DeadPhi);
427
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100428/**
429 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
430 * that share the same register. It should split the interval it is currently
431 * allocating for at the minimum lifetime position between the two inactive intervals.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700432 * This test only applies to the linear scan allocator.
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100433 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000434TEST_F(RegisterAllocatorTest, FreeUntil) {
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100435 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
436 Instruction::CONST_4 | 0 | 0,
437 Instruction::RETURN);
438
Vladimir Markoca6fff82017-10-03 14:49:14 +0100439 HGraph* graph = CreateCFG(data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100440 SsaDeadPhiElimination(graph).Run();
Mark Mendellfb8d2792015-03-31 22:16:59 -0400441 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
442 X86InstructionSetFeatures::FromCppDefines());
443 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100444 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100445 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100446 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100447
448 // Add an artifical range to cover the temps that will be put in the unhandled list.
449 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
450 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100451
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100452 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100453 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100454 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100455 graph->GetEntryBlock()->GetFirstInstruction());
456 }
457
Mingyao Yang296bd602014-10-06 16:47:28 -0700458 // For SSA value intervals, only an interval resulted from a split may intersect
459 // with inactive intervals.
460 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100461
462 // Add three temps holding the same register, and starting at different positions.
463 // Put the one that should be picked in the middle of the inactive list to ensure
464 // we do not depend on an order.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100465 LiveInterval* interval =
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100466 LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100467 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100468 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100469
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100470 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100471 interval->AddRange(20, 30);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100472 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100473
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100474 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100475 interval->AddRange(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100476 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100477
478 register_allocator.number_of_registers_ = 1;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100479 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100480 register_allocator.processing_core_registers_ = true;
481 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
482
Mingyao Yang296bd602014-10-06 16:47:28 -0700483 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100484
485 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100486 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100487 // Check that we know need to find a new register where the next interval
488 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100489 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100490}
491
Vladimir Markoca6fff82017-10-03 14:49:14 +0100492HGraph* RegisterAllocatorTest::BuildIfElseWithPhi(HPhi** phi,
493 HInstruction** input1,
494 HInstruction** input2) {
495 HGraph* graph = CreateGraph();
496 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100497 graph->AddBlock(entry);
498 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100499 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100500 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100501 entry->AddInstruction(parameter);
502
Vladimir Markoca6fff82017-10-03 14:49:14 +0100503 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100504 graph->AddBlock(block);
505 entry->AddSuccessor(block);
506
Vladimir Markoca6fff82017-10-03 14:49:14 +0100507 HInstruction* test = new (GetAllocator()) HInstanceFieldGet(parameter,
508 nullptr,
509 DataType::Type::kBool,
510 MemberOffset(22),
511 false,
512 kUnknownFieldIndex,
513 kUnknownClassDefIndex,
514 graph->GetDexFile(),
515 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100516 block->AddInstruction(test);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100517 block->AddInstruction(new (GetAllocator()) HIf(test));
518 HBasicBlock* then = new (GetAllocator()) HBasicBlock(graph);
519 HBasicBlock* else_ = new (GetAllocator()) HBasicBlock(graph);
520 HBasicBlock* join = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100521 graph->AddBlock(then);
522 graph->AddBlock(else_);
523 graph->AddBlock(join);
524
525 block->AddSuccessor(then);
526 block->AddSuccessor(else_);
527 then->AddSuccessor(join);
528 else_->AddSuccessor(join);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100529 then->AddInstruction(new (GetAllocator()) HGoto());
530 else_->AddInstruction(new (GetAllocator()) HGoto());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100531
Vladimir Markoca6fff82017-10-03 14:49:14 +0100532 *phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100533 join->AddPhi(*phi);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100534 *input1 = new (GetAllocator()) HInstanceFieldGet(parameter,
535 nullptr,
536 DataType::Type::kInt32,
537 MemberOffset(42),
538 false,
539 kUnknownFieldIndex,
540 kUnknownClassDefIndex,
541 graph->GetDexFile(),
542 0);
543 *input2 = new (GetAllocator()) HInstanceFieldGet(parameter,
544 nullptr,
545 DataType::Type::kInt32,
546 MemberOffset(42),
547 false,
548 kUnknownFieldIndex,
549 kUnknownClassDefIndex,
550 graph->GetDexFile(),
551 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100552 then->AddInstruction(*input1);
553 else_->AddInstruction(*input2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100554 join->AddInstruction(new (GetAllocator()) HExit());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100555 (*phi)->AddInput(*input1);
556 (*phi)->AddInput(*input2);
557
558 graph->BuildDominatorTree();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000559 graph->AnalyzeLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100560 return graph;
561}
562
Vladimir Markoca6fff82017-10-03 14:49:14 +0100563void RegisterAllocatorTest::PhiHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100564 HPhi *phi;
565 HInstruction *input1, *input2;
566
567 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100568 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400569 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
570 X86InstructionSetFeatures::FromCppDefines());
571 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100572 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100573 liveness.Analyze();
574
575 // Check that the register allocator is deterministic.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100576 std::unique_ptr<RegisterAllocator> register_allocator =
577 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700578 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100579
580 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
581 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
582 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
583 }
584
585 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100586 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400587 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
588 X86InstructionSetFeatures::FromCppDefines());
589 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100590 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100591 liveness.Analyze();
592
593 // Set the phi to a specific register, and check that the inputs get allocated
594 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000595 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100596 std::unique_ptr<RegisterAllocator> register_allocator =
597 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700598 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100599
600 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
601 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
602 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
603 }
604
605 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100606 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400607 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
608 X86InstructionSetFeatures::FromCppDefines());
609 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100610 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100611 liveness.Analyze();
612
613 // Set input1 to a specific register, and check that the phi and other input get allocated
614 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000615 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100616 std::unique_ptr<RegisterAllocator> register_allocator =
617 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700618 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100619
620 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
621 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
622 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
623 }
624
625 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100626 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400627 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
628 X86InstructionSetFeatures::FromCppDefines());
629 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100630 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100631 liveness.Analyze();
632
633 // Set input2 to a specific register, and check that the phi and other input get allocated
634 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000635 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100636 std::unique_ptr<RegisterAllocator> register_allocator =
637 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700638 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100639
640 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
641 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
642 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
643 }
644}
645
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700646// TODO: Enable this test for graph coloring register allocation when iterative move
647// coalescing is merged.
648TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) {
649 PhiHint(Strategy::kRegisterAllocatorLinearScan);
650}
651
Vladimir Markoca6fff82017-10-03 14:49:14 +0100652HGraph* RegisterAllocatorTest::BuildFieldReturn(HInstruction** field, HInstruction** ret) {
653 HGraph* graph = CreateGraph();
654 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100655 graph->AddBlock(entry);
656 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100657 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100658 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100659 entry->AddInstruction(parameter);
660
Vladimir Markoca6fff82017-10-03 14:49:14 +0100661 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100662 graph->AddBlock(block);
663 entry->AddSuccessor(block);
664
Vladimir Markoca6fff82017-10-03 14:49:14 +0100665 *field = new (GetAllocator()) HInstanceFieldGet(parameter,
666 nullptr,
667 DataType::Type::kInt32,
668 MemberOffset(42),
669 false,
670 kUnknownFieldIndex,
671 kUnknownClassDefIndex,
672 graph->GetDexFile(),
673 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100674 block->AddInstruction(*field);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100675 *ret = new (GetAllocator()) HReturn(*field);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100676 block->AddInstruction(*ret);
677
Vladimir Markoca6fff82017-10-03 14:49:14 +0100678 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100679 graph->AddBlock(exit);
680 block->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100681 exit->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000682
683 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100684 return graph;
685}
686
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700687void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100688 HInstruction *field, *ret;
689
690 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100691 HGraph* graph = BuildFieldReturn(&field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400692 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
693 X86InstructionSetFeatures::FromCppDefines());
694 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100695 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100696 liveness.Analyze();
697
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100698 std::unique_ptr<RegisterAllocator> register_allocator =
699 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700700 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100701
702 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
703 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
704 }
705
706 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100707 HGraph* graph = BuildFieldReturn(&field, &ret);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400708 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
709 X86InstructionSetFeatures::FromCppDefines());
710 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100711 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100712 liveness.Analyze();
713
714 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000715 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100716 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100717
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100718 std::unique_ptr<RegisterAllocator> register_allocator =
719 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700720 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100721
722 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
723 }
724}
725
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700726// TODO: Enable this test for graph coloring register allocation when iterative move
727// coalescing is merged.
728TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
729 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
730}
731
Vladimir Markoca6fff82017-10-03 14:49:14 +0100732HGraph* RegisterAllocatorTest::BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub) {
733 HGraph* graph = CreateGraph();
734 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100735 graph->AddBlock(entry);
736 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100737 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100738 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100739 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000740
741 HInstruction* constant1 = graph->GetIntConstant(1);
742 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100743
Vladimir Markoca6fff82017-10-03 14:49:14 +0100744 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100745 graph->AddBlock(block);
746 entry->AddSuccessor(block);
747
Vladimir Markoca6fff82017-10-03 14:49:14 +0100748 *first_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, parameter, constant1);
Mark Mendell09b84632015-02-13 17:48:38 -0500749 block->AddInstruction(*first_sub);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100750 *second_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, *first_sub, constant2);
Mark Mendell09b84632015-02-13 17:48:38 -0500751 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100752
Vladimir Markoca6fff82017-10-03 14:49:14 +0100753 block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000754
755 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100756 return graph;
757}
758
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700759void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
Mark Mendell09b84632015-02-13 17:48:38 -0500760 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100761
762 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100763 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400764 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
765 X86InstructionSetFeatures::FromCppDefines());
766 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100767 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100768 liveness.Analyze();
769
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100770 std::unique_ptr<RegisterAllocator> register_allocator =
771 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700772 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100773
774 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500775 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
776 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100777 }
778
779 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100780 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
Mark Mendellfb8d2792015-03-31 22:16:59 -0400781 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
782 X86InstructionSetFeatures::FromCppDefines());
783 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100784 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100785 liveness.Analyze();
786
787 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000788 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500789 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
790 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
791 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100792
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100793 std::unique_ptr<RegisterAllocator> register_allocator =
794 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700795 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100796
Mark Mendell09b84632015-02-13 17:48:38 -0500797 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
798 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100799 }
800}
801
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700802// TODO: Enable this test for graph coloring register allocation when iterative move
803// coalescing is merged.
804TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
805 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
806}
807
Vladimir Markoca6fff82017-10-03 14:49:14 +0100808HGraph* RegisterAllocatorTest::BuildDiv(HInstruction** div) {
809 HGraph* graph = CreateGraph();
810 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Calin Juravled0d48522014-11-04 16:40:20 +0000811 graph->AddBlock(entry);
812 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100813 HInstruction* first = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100814 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100815 HInstruction* second = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100816 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravled0d48522014-11-04 16:40:20 +0000817 entry->AddInstruction(first);
818 entry->AddInstruction(second);
819
Vladimir Markoca6fff82017-10-03 14:49:14 +0100820 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Calin Juravled0d48522014-11-04 16:40:20 +0000821 graph->AddBlock(block);
822 entry->AddSuccessor(block);
823
Vladimir Markoca6fff82017-10-03 14:49:14 +0100824 *div = new (GetAllocator()) HDiv(
825 DataType::Type::kInt32, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000826 block->AddInstruction(*div);
827
Vladimir Markoca6fff82017-10-03 14:49:14 +0100828 block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000829
830 graph->BuildDominatorTree();
Calin Juravled0d48522014-11-04 16:40:20 +0000831 return graph;
832}
833
Vladimir Markoca6fff82017-10-03 14:49:14 +0100834void RegisterAllocatorTest::ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
Calin Juravled0d48522014-11-04 16:40:20 +0000835 HInstruction *div;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100836 HGraph* graph = BuildDiv(&div);
837 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
838 X86InstructionSetFeatures::FromCppDefines());
839 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100840 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100841 liveness.Analyze();
Calin Juravled0d48522014-11-04 16:40:20 +0000842
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100843 std::unique_ptr<RegisterAllocator> register_allocator =
844 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100845 register_allocator->AllocateRegisters();
Calin Juravled0d48522014-11-04 16:40:20 +0000846
Vladimir Markoca6fff82017-10-03 14:49:14 +0100847 // div on x86 requires its first input in eax and the output be the same as the first input.
848 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
Calin Juravled0d48522014-11-04 16:40:20 +0000849}
850
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700851// TODO: Enable this test for graph coloring register allocation when iterative move
852// coalescing is merged.
853TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) {
854 ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan);
855}
856
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000857// Test a bug in the register allocator, where allocating a blocked
858// register would lead to spilling an inactive interval at the wrong
859// position.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700860// This test only applies to the linear scan allocator.
David Brazdil4833f5a2015-12-16 10:37:39 +0000861TEST_F(RegisterAllocatorTest, SpillInactive) {
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000862 // Create a synthesized graph to please the register_allocator and
863 // ssa_liveness_analysis code.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100864 HGraph* graph = CreateGraph();
865 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000866 graph->AddBlock(entry);
867 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100868 HInstruction* one = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100869 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100870 HInstruction* two = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100871 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100872 HInstruction* three = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100873 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100874 HInstruction* four = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100875 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000876 entry->AddInstruction(one);
877 entry->AddInstruction(two);
878 entry->AddInstruction(three);
879 entry->AddInstruction(four);
880
Vladimir Markoca6fff82017-10-03 14:49:14 +0100881 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000882 graph->AddBlock(block);
883 entry->AddSuccessor(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100884 block->AddInstruction(new (GetAllocator()) HExit());
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000885
886 // We create a synthesized user requesting a register, to avoid just spilling the
887 // intervals.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100888 HPhi* user = new (GetAllocator()) HPhi(GetAllocator(), 0, 1, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000889 user->AddInput(one);
890 user->SetBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100891 LocationSummary* locations = new (GetAllocator()) LocationSummary(user, LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000892 locations->SetInAt(0, Location::RequiresRegister());
893 static constexpr size_t phi_ranges[][2] = {{20, 30}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100894 BuildInterval(phi_ranges, arraysize(phi_ranges), GetScopedAllocator(), -1, user);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000895
896 // Create an interval with lifetime holes.
897 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100898 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), -1, one);
899 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8));
900 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 7));
901 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 6));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000902
Vladimir Markoca6fff82017-10-03 14:49:14 +0100903 locations = new (GetAllocator()) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000904 locations->SetOut(Location::RequiresRegister());
905 first = first->SplitAt(1);
906
907 // Create an interval that conflicts with the next interval, to force the next
908 // interval to call `AllocateBlockedReg`.
909 static constexpr size_t ranges2[][2] = {{2, 4}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100910 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), -1, two);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100911 locations =
912 new (GetAllocator()) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000913 locations->SetOut(Location::RequiresRegister());
914
915 // Create an interval that will lead to splitting the first interval. The bug occured
916 // by splitting at a wrong position, in this case at the next intersection between
917 // this interval and the first interval. We would have then put the interval with ranges
918 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
919 // before lifetime position 6 yet.
920 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100921 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), GetScopedAllocator(), -1, three);
922 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8));
923 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 4));
924 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 3));
Vladimir Markoca6fff82017-10-03 14:49:14 +0100925 locations = new (GetAllocator()) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000926 locations->SetOut(Location::RequiresRegister());
927 third = third->SplitAt(3);
928
929 // Because the first part of the split interval was considered handled, this interval
930 // was free to allocate the same register, even though it conflicts with it.
931 static constexpr size_t ranges4[][2] = {{4, 6}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100932 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), GetScopedAllocator(), -1, four);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100933 locations =
934 new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000935 locations->SetOut(Location::RequiresRegister());
936
Mark Mendellfb8d2792015-03-31 22:16:59 -0400937 std::unique_ptr<const X86InstructionSetFeatures> features_x86(
938 X86InstructionSetFeatures::FromCppDefines());
939 x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100940 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100941 // Populate the instructions in the liveness object, to please the register allocator.
942 for (size_t i = 0; i < 32; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100943 liveness.instructions_from_lifetime_position_.push_back(user);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100944 }
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000945
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100946 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100947 register_allocator.unhandled_core_intervals_.push_back(fourth);
948 register_allocator.unhandled_core_intervals_.push_back(third);
949 register_allocator.unhandled_core_intervals_.push_back(second);
950 register_allocator.unhandled_core_intervals_.push_back(first);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000951
952 // Set just one register available to make all intervals compete for the same.
953 register_allocator.number_of_registers_ = 1;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100954 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000955 register_allocator.processing_core_registers_ = true;
956 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
957 register_allocator.LinearScan();
958
959 // Test that there is no conflicts between intervals.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100960 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100961 intervals.push_back(first);
962 intervals.push_back(second);
963 intervals.push_back(third);
964 intervals.push_back(fourth);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100965 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000966}
967
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100968} // namespace art