blob: 7144775c2b300153749c2cc4d3511799074abccf [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"
David Sehr9e734c72018-01-04 17:56:19 -080024#include "dex/dex_file.h"
25#include "dex/dex_file_types.h"
26#include "dex/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:
Vladimir Markoa0431112018-06-25 09:32:54 +010043 void SetUp() OVERRIDE {
44 // This test is using the x86 ISA.
45 OverrideInstructionSetFeatures(InstructionSet::kX86, "default");
46 OptimizingUnitTest::SetUp();
47 }
48
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070049 // These functions need to access private variables of LocationSummary, so we declare it
50 // as a member of RegisterAllocatorTest, which we make a friend class.
Vladimir Markoca6fff82017-10-03 14:49:14 +010051 void SameAsFirstInputHint(Strategy strategy);
52 void ExpectedInRegisterHint(Strategy strategy);
53
54 // Helper functions that make use of the OptimizingUnitTest's members.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080055 bool Check(const std::vector<uint16_t>& data, Strategy strategy);
Vladimir Markoca6fff82017-10-03 14:49:14 +010056 void CFG1(Strategy strategy);
57 void Loop1(Strategy strategy);
58 void Loop2(Strategy strategy);
59 void Loop3(Strategy strategy);
60 void DeadPhi(Strategy strategy);
61 HGraph* BuildIfElseWithPhi(HPhi** phi, HInstruction** input1, HInstruction** input2);
62 void PhiHint(Strategy strategy);
63 HGraph* BuildFieldReturn(HInstruction** field, HInstruction** ret);
64 HGraph* BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub);
65 HGraph* BuildDiv(HInstruction** div);
66 void ExpectedExactInRegisterAndSameOutputHint(Strategy strategy);
Vladimir Markoe764d2e2017-10-05 14:35:55 +010067
68 bool ValidateIntervals(const ScopedArenaVector<LiveInterval*>& intervals,
69 const CodeGenerator& codegen) {
70 return RegisterAllocator::ValidateIntervals(ArrayRef<LiveInterval* const>(intervals),
71 /* number_of_spill_slots */ 0u,
72 /* number_of_out_slots */ 0u,
73 codegen,
74 /* processing_core_registers */ true,
75 /* log_fatal_on_failure */ false);
76 }
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070077};
David Brazdil4833f5a2015-12-16 10:37:39 +000078
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070079// This macro should include all register allocation strategies that should be tested.
80#define TEST_ALL_STRATEGIES(test_name)\
81TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
82 test_name(Strategy::kRegisterAllocatorLinearScan);\
83}\
84TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
85 test_name(Strategy::kRegisterAllocatorGraphColor);\
86}
87
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080088bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010089 HGraph* graph = CreateCFG(data);
Vladimir Markoa0431112018-06-25 09:32:54 +010090 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +010091 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010092 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +010093 std::unique_ptr<RegisterAllocator> register_allocator =
94 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070095 register_allocator->AllocateRegisters();
96 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010097}
98
99/**
100 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
101 * tests are based on this validation method.
102 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000103TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100104 HGraph* graph = CreateGraph();
Vladimir Markoa0431112018-06-25 09:32:54 +0100105 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100106 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100107
108 // Test with two intervals of the same range.
109 {
110 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100111 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 0));
112 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 1));
113 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100114
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100115 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100116 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100117 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118 }
119
120 // Test with two non-intersecting intervals.
121 {
122 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100123 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100124 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100125 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
126 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100127
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100128 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100129 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100130 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100131 }
132
133 // Test with two non-intersecting intervals, with one with a lifetime hole.
134 {
135 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100136 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100137 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100138 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
139 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100140
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100141 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100142 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100143 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100144 }
145
146 // Test with intersecting intervals.
147 {
148 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100149 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100150 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100151 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
152 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100153
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100154 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100155 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100156 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100157 }
158
159 // Test with siblings.
160 {
161 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100162 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100163 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100164 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100165 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
166 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100167
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100168 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100169 // Sibling of the first interval has no register allocated to it.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100170 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100171
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100172 intervals[0]->GetNextSibling()->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100173 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100174 }
175}
176
Vladimir Markoca6fff82017-10-03 14:49:14 +0100177void RegisterAllocatorTest::CFG1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100178 /*
179 * Test the following snippet:
180 * return 0;
181 *
182 * Which becomes the following graph:
183 * constant0
184 * goto
185 * |
186 * return
187 * |
188 * exit
189 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800190 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100191 Instruction::CONST_4 | 0 | 0,
192 Instruction::RETURN);
193
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700194 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100195}
196
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700197TEST_ALL_STRATEGIES(CFG1);
198
Vladimir Markoca6fff82017-10-03 14:49:14 +0100199void RegisterAllocatorTest::Loop1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100200 /*
201 * Test the following snippet:
202 * int a = 0;
203 * while (a == a) {
204 * a = 4;
205 * }
206 * return 5;
207 *
208 * Which becomes the following graph:
209 * constant0
210 * constant4
211 * constant5
212 * goto
213 * |
214 * goto
215 * |
216 * phi
217 * equal
218 * if +++++
219 * | \ +
220 * | goto
221 * |
222 * return
223 * |
224 * exit
225 */
226
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800227 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100228 Instruction::CONST_4 | 0 | 0,
229 Instruction::IF_EQ, 4,
230 Instruction::CONST_4 | 4 << 12 | 0,
231 Instruction::GOTO | 0xFD00,
232 Instruction::CONST_4 | 5 << 12 | 1 << 8,
233 Instruction::RETURN | 1 << 8);
234
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700235 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100236}
237
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700238TEST_ALL_STRATEGIES(Loop1);
239
Vladimir Markoca6fff82017-10-03 14:49:14 +0100240void RegisterAllocatorTest::Loop2(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100241 /*
242 * Test the following snippet:
243 * int a = 0;
244 * while (a == 8) {
245 * a = 4 + 5;
246 * }
247 * return 6 + 7;
248 *
249 * Which becomes the following graph:
250 * constant0
251 * constant4
252 * constant5
253 * constant6
254 * constant7
255 * constant8
256 * goto
257 * |
258 * goto
259 * |
260 * phi
261 * equal
262 * if +++++
263 * | \ +
264 * | 4 + 5
265 * | goto
266 * |
267 * 6 + 7
268 * return
269 * |
270 * exit
271 */
272
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800273 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100274 Instruction::CONST_4 | 0 | 0,
275 Instruction::CONST_4 | 8 << 12 | 1 << 8,
276 Instruction::IF_EQ | 1 << 8, 7,
277 Instruction::CONST_4 | 4 << 12 | 0 << 8,
278 Instruction::CONST_4 | 5 << 12 | 1 << 8,
279 Instruction::ADD_INT, 1 << 8 | 0,
280 Instruction::GOTO | 0xFA00,
281 Instruction::CONST_4 | 6 << 12 | 1 << 8,
282 Instruction::CONST_4 | 7 << 12 | 1 << 8,
283 Instruction::ADD_INT, 1 << 8 | 0,
284 Instruction::RETURN | 1 << 8);
285
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700286 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100287}
288
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700289TEST_ALL_STRATEGIES(Loop2);
290
Vladimir Markoca6fff82017-10-03 14:49:14 +0100291void RegisterAllocatorTest::Loop3(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100292 /*
293 * Test the following snippet:
294 * int a = 0
295 * do {
296 * b = a;
297 * a++;
298 * } while (a != 5)
299 * return b;
300 *
301 * Which becomes the following graph:
302 * constant0
303 * constant1
304 * constant5
305 * goto
306 * |
307 * goto
308 * |++++++++++++
309 * phi +
310 * a++ +
311 * equals +
312 * if +
313 * |++++++++++++
314 * return
315 * |
316 * exit
317 */
318
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800319 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100320 Instruction::CONST_4 | 0 | 0,
321 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
322 Instruction::CONST_4 | 5 << 12 | 2 << 8,
323 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
324 Instruction::RETURN | 0 << 8,
325 Instruction::MOVE | 1 << 12 | 0 << 8,
326 Instruction::GOTO | 0xF900);
327
Vladimir Markoca6fff82017-10-03 14:49:14 +0100328 HGraph* graph = CreateCFG(data);
Vladimir Markoa0431112018-06-25 09:32:54 +0100329 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
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) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800354 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100355 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);
Vladimir Markoa0431112018-06-25 09:32:54 +0100362 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100363 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100364 liveness.Analyze();
365
Vladimir Markoec7802a2015-10-01 20:57:57 +0100366 HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
367 HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
Mark Mendell09b84632015-02-13 17:48:38 -0500368 ASSERT_EQ(last_xor->InputAt(0), first_xor);
369 LiveInterval* interval = first_xor->GetLiveInterval();
370 ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100371 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
372
373 // We need a register for the output of the instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500374 ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100375
376 // Split at the next instruction.
Mark Mendell09b84632015-02-13 17:48:38 -0500377 interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100378 // The user of the split is the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500379 ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100380
381 // Split before the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500382 LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100383 // Ensure the current interval has no register use...
384 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
385 // And the new interval has it for the last add.
Mark Mendell09b84632015-02-13 17:48:38 -0500386 ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100387}
388
Vladimir Markoca6fff82017-10-03 14:49:14 +0100389void RegisterAllocatorTest::DeadPhi(Strategy strategy) {
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100390 /* Test for a dead loop phi taking as back-edge input a phi that also has
391 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
392 * does not solve the problem because the loop phi will be visited last.
393 *
394 * Test the following snippet:
395 * int a = 0
396 * do {
397 * if (true) {
398 * a = 2;
399 * }
400 * } while (true);
401 */
402
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800403 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100404 Instruction::CONST_4 | 0 | 0,
405 Instruction::CONST_4 | 1 << 8 | 0,
406 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
407 Instruction::CONST_4 | 2 << 12 | 0 << 8,
408 Instruction::GOTO | 0xFD00,
409 Instruction::RETURN_VOID);
410
Vladimir Markoca6fff82017-10-03 14:49:14 +0100411 HGraph* graph = CreateCFG(data);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100412 SsaDeadPhiElimination(graph).Run();
Vladimir Markoa0431112018-06-25 09:32:54 +0100413 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100414 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100415 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100416 std::unique_ptr<RegisterAllocator> register_allocator =
417 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700418 register_allocator->AllocateRegisters();
419 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100420}
421
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700422TEST_ALL_STRATEGIES(DeadPhi);
423
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100424/**
425 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
426 * that share the same register. It should split the interval it is currently
427 * allocating for at the minimum lifetime position between the two inactive intervals.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700428 * This test only applies to the linear scan allocator.
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100429 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000430TEST_F(RegisterAllocatorTest, FreeUntil) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800431 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100432 Instruction::CONST_4 | 0 | 0,
433 Instruction::RETURN);
434
Vladimir Markoca6fff82017-10-03 14:49:14 +0100435 HGraph* graph = CreateCFG(data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100436 SsaDeadPhiElimination(graph).Run();
Vladimir Markoa0431112018-06-25 09:32:54 +0100437 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100438 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100439 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100440 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100441
442 // Add an artifical range to cover the temps that will be put in the unhandled list.
443 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
444 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100445
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100446 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100447 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100448 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100449 graph->GetEntryBlock()->GetFirstInstruction());
450 }
451
Mingyao Yang296bd602014-10-06 16:47:28 -0700452 // For SSA value intervals, only an interval resulted from a split may intersect
453 // with inactive intervals.
454 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100455
456 // Add three temps holding the same register, and starting at different positions.
457 // Put the one that should be picked in the middle of the inactive list to ensure
458 // we do not depend on an order.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100459 LiveInterval* interval =
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100460 LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100461 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100462 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100463
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100464 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100465 interval->AddRange(20, 30);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100466 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100467
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100468 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100469 interval->AddRange(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100470 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100471
472 register_allocator.number_of_registers_ = 1;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100473 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100474 register_allocator.processing_core_registers_ = true;
475 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
476
Mingyao Yang296bd602014-10-06 16:47:28 -0700477 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100478
479 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100480 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100481 // Check that we know need to find a new register where the next interval
482 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100483 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100484}
485
Vladimir Markoca6fff82017-10-03 14:49:14 +0100486HGraph* RegisterAllocatorTest::BuildIfElseWithPhi(HPhi** phi,
487 HInstruction** input1,
488 HInstruction** input2) {
489 HGraph* graph = CreateGraph();
490 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100491 graph->AddBlock(entry);
492 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100493 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100494 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100495 entry->AddInstruction(parameter);
496
Vladimir Markoca6fff82017-10-03 14:49:14 +0100497 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100498 graph->AddBlock(block);
499 entry->AddSuccessor(block);
500
Vladimir Markoca6fff82017-10-03 14:49:14 +0100501 HInstruction* test = new (GetAllocator()) HInstanceFieldGet(parameter,
502 nullptr,
503 DataType::Type::kBool,
504 MemberOffset(22),
505 false,
506 kUnknownFieldIndex,
507 kUnknownClassDefIndex,
508 graph->GetDexFile(),
509 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100510 block->AddInstruction(test);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100511 block->AddInstruction(new (GetAllocator()) HIf(test));
512 HBasicBlock* then = new (GetAllocator()) HBasicBlock(graph);
513 HBasicBlock* else_ = new (GetAllocator()) HBasicBlock(graph);
514 HBasicBlock* join = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100515 graph->AddBlock(then);
516 graph->AddBlock(else_);
517 graph->AddBlock(join);
518
519 block->AddSuccessor(then);
520 block->AddSuccessor(else_);
521 then->AddSuccessor(join);
522 else_->AddSuccessor(join);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100523 then->AddInstruction(new (GetAllocator()) HGoto());
524 else_->AddInstruction(new (GetAllocator()) HGoto());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100525
Vladimir Markoca6fff82017-10-03 14:49:14 +0100526 *phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100527 join->AddPhi(*phi);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100528 *input1 = new (GetAllocator()) HInstanceFieldGet(parameter,
529 nullptr,
530 DataType::Type::kInt32,
531 MemberOffset(42),
532 false,
533 kUnknownFieldIndex,
534 kUnknownClassDefIndex,
535 graph->GetDexFile(),
536 0);
537 *input2 = new (GetAllocator()) HInstanceFieldGet(parameter,
538 nullptr,
539 DataType::Type::kInt32,
540 MemberOffset(42),
541 false,
542 kUnknownFieldIndex,
543 kUnknownClassDefIndex,
544 graph->GetDexFile(),
545 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100546 then->AddInstruction(*input1);
547 else_->AddInstruction(*input2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100548 join->AddInstruction(new (GetAllocator()) HExit());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100549 (*phi)->AddInput(*input1);
550 (*phi)->AddInput(*input2);
551
552 graph->BuildDominatorTree();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000553 graph->AnalyzeLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100554 return graph;
555}
556
Vladimir Markoca6fff82017-10-03 14:49:14 +0100557void RegisterAllocatorTest::PhiHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100558 HPhi *phi;
559 HInstruction *input1, *input2;
560
561 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100562 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100563 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100564 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100565 liveness.Analyze();
566
567 // Check that the register allocator is deterministic.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100568 std::unique_ptr<RegisterAllocator> register_allocator =
569 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700570 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100571
572 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
573 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
574 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
575 }
576
577 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100578 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100579 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100580 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100581 liveness.Analyze();
582
583 // Set the phi to a specific register, and check that the inputs get allocated
584 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000585 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100586 std::unique_ptr<RegisterAllocator> register_allocator =
587 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700588 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100589
590 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
591 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
592 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
593 }
594
595 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100596 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100597 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100598 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100599 liveness.Analyze();
600
601 // Set input1 to a specific register, and check that the phi and other input get allocated
602 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000603 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100604 std::unique_ptr<RegisterAllocator> register_allocator =
605 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700606 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100607
608 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
609 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
610 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
611 }
612
613 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100614 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100615 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100616 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100617 liveness.Analyze();
618
619 // Set input2 to a specific register, and check that the phi and other input get allocated
620 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000621 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100622 std::unique_ptr<RegisterAllocator> register_allocator =
623 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700624 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100625
626 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
627 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
628 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
629 }
630}
631
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700632// TODO: Enable this test for graph coloring register allocation when iterative move
633// coalescing is merged.
634TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) {
635 PhiHint(Strategy::kRegisterAllocatorLinearScan);
636}
637
Vladimir Markoca6fff82017-10-03 14:49:14 +0100638HGraph* RegisterAllocatorTest::BuildFieldReturn(HInstruction** field, HInstruction** ret) {
639 HGraph* graph = CreateGraph();
640 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100641 graph->AddBlock(entry);
642 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100643 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100644 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100645 entry->AddInstruction(parameter);
646
Vladimir Markoca6fff82017-10-03 14:49:14 +0100647 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100648 graph->AddBlock(block);
649 entry->AddSuccessor(block);
650
Vladimir Markoca6fff82017-10-03 14:49:14 +0100651 *field = new (GetAllocator()) HInstanceFieldGet(parameter,
652 nullptr,
653 DataType::Type::kInt32,
654 MemberOffset(42),
655 false,
656 kUnknownFieldIndex,
657 kUnknownClassDefIndex,
658 graph->GetDexFile(),
659 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100660 block->AddInstruction(*field);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100661 *ret = new (GetAllocator()) HReturn(*field);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100662 block->AddInstruction(*ret);
663
Vladimir Markoca6fff82017-10-03 14:49:14 +0100664 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100665 graph->AddBlock(exit);
666 block->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100667 exit->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000668
669 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100670 return graph;
671}
672
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700673void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100674 HInstruction *field, *ret;
675
676 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100677 HGraph* graph = BuildFieldReturn(&field, &ret);
Vladimir Markoa0431112018-06-25 09:32:54 +0100678 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100679 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100680 liveness.Analyze();
681
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100682 std::unique_ptr<RegisterAllocator> register_allocator =
683 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700684 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100685
686 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
687 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
688 }
689
690 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100691 HGraph* graph = BuildFieldReturn(&field, &ret);
Vladimir Markoa0431112018-06-25 09:32:54 +0100692 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100693 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100694 liveness.Analyze();
695
696 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000697 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100698 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100699
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100700 std::unique_ptr<RegisterAllocator> register_allocator =
701 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700702 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100703
704 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
705 }
706}
707
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700708// TODO: Enable this test for graph coloring register allocation when iterative move
709// coalescing is merged.
710TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
711 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
712}
713
Vladimir Markoca6fff82017-10-03 14:49:14 +0100714HGraph* RegisterAllocatorTest::BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub) {
715 HGraph* graph = CreateGraph();
716 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100717 graph->AddBlock(entry);
718 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100719 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100720 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100721 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000722
723 HInstruction* constant1 = graph->GetIntConstant(1);
724 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100725
Vladimir Markoca6fff82017-10-03 14:49:14 +0100726 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100727 graph->AddBlock(block);
728 entry->AddSuccessor(block);
729
Vladimir Markoca6fff82017-10-03 14:49:14 +0100730 *first_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, parameter, constant1);
Mark Mendell09b84632015-02-13 17:48:38 -0500731 block->AddInstruction(*first_sub);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100732 *second_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, *first_sub, constant2);
Mark Mendell09b84632015-02-13 17:48:38 -0500733 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100734
Vladimir Markoca6fff82017-10-03 14:49:14 +0100735 block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000736
737 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100738 return graph;
739}
740
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700741void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
Mark Mendell09b84632015-02-13 17:48:38 -0500742 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100743
744 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100745 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
Vladimir Markoa0431112018-06-25 09:32:54 +0100746 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100747 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100748 liveness.Analyze();
749
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100750 std::unique_ptr<RegisterAllocator> register_allocator =
751 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700752 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100753
754 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500755 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
756 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100757 }
758
759 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100760 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
Vladimir Markoa0431112018-06-25 09:32:54 +0100761 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100762 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100763 liveness.Analyze();
764
765 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000766 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500767 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
768 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
769 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100770
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100771 std::unique_ptr<RegisterAllocator> register_allocator =
772 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700773 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100774
Mark Mendell09b84632015-02-13 17:48:38 -0500775 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
776 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100777 }
778}
779
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700780// TODO: Enable this test for graph coloring register allocation when iterative move
781// coalescing is merged.
782TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
783 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
784}
785
Vladimir Markoca6fff82017-10-03 14:49:14 +0100786HGraph* RegisterAllocatorTest::BuildDiv(HInstruction** div) {
787 HGraph* graph = CreateGraph();
788 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Calin Juravled0d48522014-11-04 16:40:20 +0000789 graph->AddBlock(entry);
790 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100791 HInstruction* first = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100792 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100793 HInstruction* second = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100794 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravled0d48522014-11-04 16:40:20 +0000795 entry->AddInstruction(first);
796 entry->AddInstruction(second);
797
Vladimir Markoca6fff82017-10-03 14:49:14 +0100798 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Calin Juravled0d48522014-11-04 16:40:20 +0000799 graph->AddBlock(block);
800 entry->AddSuccessor(block);
801
Vladimir Markoca6fff82017-10-03 14:49:14 +0100802 *div = new (GetAllocator()) HDiv(
803 DataType::Type::kInt32, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000804 block->AddInstruction(*div);
805
Vladimir Markoca6fff82017-10-03 14:49:14 +0100806 block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000807
808 graph->BuildDominatorTree();
Calin Juravled0d48522014-11-04 16:40:20 +0000809 return graph;
810}
811
Vladimir Markoca6fff82017-10-03 14:49:14 +0100812void RegisterAllocatorTest::ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
Calin Juravled0d48522014-11-04 16:40:20 +0000813 HInstruction *div;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100814 HGraph* graph = BuildDiv(&div);
Vladimir Markoa0431112018-06-25 09:32:54 +0100815 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100816 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100817 liveness.Analyze();
Calin Juravled0d48522014-11-04 16:40:20 +0000818
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100819 std::unique_ptr<RegisterAllocator> register_allocator =
820 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100821 register_allocator->AllocateRegisters();
Calin Juravled0d48522014-11-04 16:40:20 +0000822
Vladimir Markoca6fff82017-10-03 14:49:14 +0100823 // div on x86 requires its first input in eax and the output be the same as the first input.
824 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
Calin Juravled0d48522014-11-04 16:40:20 +0000825}
826
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700827// TODO: Enable this test for graph coloring register allocation when iterative move
828// coalescing is merged.
829TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) {
830 ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan);
831}
832
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000833// Test a bug in the register allocator, where allocating a blocked
834// register would lead to spilling an inactive interval at the wrong
835// position.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700836// This test only applies to the linear scan allocator.
David Brazdil4833f5a2015-12-16 10:37:39 +0000837TEST_F(RegisterAllocatorTest, SpillInactive) {
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000838 // Create a synthesized graph to please the register_allocator and
839 // ssa_liveness_analysis code.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100840 HGraph* graph = CreateGraph();
841 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000842 graph->AddBlock(entry);
843 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100844 HInstruction* one = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100845 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100846 HInstruction* two = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100847 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100848 HInstruction* three = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100849 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100850 HInstruction* four = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100851 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000852 entry->AddInstruction(one);
853 entry->AddInstruction(two);
854 entry->AddInstruction(three);
855 entry->AddInstruction(four);
856
Vladimir Markoca6fff82017-10-03 14:49:14 +0100857 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000858 graph->AddBlock(block);
859 entry->AddSuccessor(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100860 block->AddInstruction(new (GetAllocator()) HExit());
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000861
862 // We create a synthesized user requesting a register, to avoid just spilling the
863 // intervals.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100864 HPhi* user = new (GetAllocator()) HPhi(GetAllocator(), 0, 1, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000865 user->AddInput(one);
866 user->SetBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100867 LocationSummary* locations = new (GetAllocator()) LocationSummary(user, LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000868 locations->SetInAt(0, Location::RequiresRegister());
869 static constexpr size_t phi_ranges[][2] = {{20, 30}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100870 BuildInterval(phi_ranges, arraysize(phi_ranges), GetScopedAllocator(), -1, user);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000871
872 // Create an interval with lifetime holes.
873 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100874 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), -1, one);
875 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8));
876 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 7));
877 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 6));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000878
Vladimir Markoca6fff82017-10-03 14:49:14 +0100879 locations = new (GetAllocator()) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000880 locations->SetOut(Location::RequiresRegister());
881 first = first->SplitAt(1);
882
883 // Create an interval that conflicts with the next interval, to force the next
884 // interval to call `AllocateBlockedReg`.
885 static constexpr size_t ranges2[][2] = {{2, 4}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100886 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), -1, two);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100887 locations =
888 new (GetAllocator()) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000889 locations->SetOut(Location::RequiresRegister());
890
891 // Create an interval that will lead to splitting the first interval. The bug occured
892 // by splitting at a wrong position, in this case at the next intersection between
893 // this interval and the first interval. We would have then put the interval with ranges
894 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
895 // before lifetime position 6 yet.
896 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100897 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), GetScopedAllocator(), -1, three);
898 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 8));
899 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 4));
900 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, false, 3));
Vladimir Markoca6fff82017-10-03 14:49:14 +0100901 locations = new (GetAllocator()) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000902 locations->SetOut(Location::RequiresRegister());
903 third = third->SplitAt(3);
904
905 // Because the first part of the split interval was considered handled, this interval
906 // was free to allocate the same register, even though it conflicts with it.
907 static constexpr size_t ranges4[][2] = {{4, 6}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100908 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), GetScopedAllocator(), -1, four);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100909 locations =
910 new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000911 locations->SetOut(Location::RequiresRegister());
912
Vladimir Markoa0431112018-06-25 09:32:54 +0100913 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100914 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100915 // Populate the instructions in the liveness object, to please the register allocator.
916 for (size_t i = 0; i < 32; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100917 liveness.instructions_from_lifetime_position_.push_back(user);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100918 }
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000919
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100920 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100921 register_allocator.unhandled_core_intervals_.push_back(fourth);
922 register_allocator.unhandled_core_intervals_.push_back(third);
923 register_allocator.unhandled_core_intervals_.push_back(second);
924 register_allocator.unhandled_core_intervals_.push_back(first);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000925
926 // Set just one register available to make all intervals compete for the same.
927 register_allocator.number_of_registers_ = 1;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100928 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000929 register_allocator.processing_core_registers_ = true;
930 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
931 register_allocator.LinearScan();
932
933 // Test that there is no conflicts between intervals.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100934 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100935 intervals.push_back(first);
936 intervals.push_back(second);
937 intervals.push_back(third);
938 intervals.push_back(fourth);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100939 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000940}
941
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100942} // namespace art