blob: d1db40be8254cd51d60630e9c9652ecb43a33c2b [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
Vladimir Marko0a516052019-10-14 13:00:44 +000034namespace art {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010035
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:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010043 void SetUp() override {
Vladimir Markoa0431112018-06-25 09:32:54 +010044 OptimizingUnitTest::SetUp();
Vladimir Markof91fc122020-05-13 09:21:00 +010045 // This test is using the x86 ISA.
46 compiler_options_ = CommonCompilerTest::CreateCompilerOptions(InstructionSet::kX86, "default");
Vladimir Markoa0431112018-06-25 09:32:54 +010047 }
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),
Andreas Gampe3db70682018-12-26 15:12:03 -080071 /* number_of_spill_slots= */ 0u,
72 /* number_of_out_slots= */ 0u,
Vladimir Markoe764d2e2017-10-05 14:35:55 +010073 codegen,
Andreas Gampe3db70682018-12-26 15:12:03 -080074 /* processing_core_registers= */ true,
75 /* log_fatal_on_failure= */ false);
Vladimir Markoe764d2e2017-10-05 14:35:55 +010076 }
Vladimir Markof91fc122020-05-13 09:21:00 +010077
78 std::unique_ptr<CompilerOptions> compiler_options_;
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070079};
David Brazdil4833f5a2015-12-16 10:37:39 +000080
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -070081// This macro should include all register allocation strategies that should be tested.
82#define TEST_ALL_STRATEGIES(test_name)\
83TEST_F(RegisterAllocatorTest, test_name##_LinearScan) {\
84 test_name(Strategy::kRegisterAllocatorLinearScan);\
85}\
86TEST_F(RegisterAllocatorTest, test_name##_GraphColor) {\
87 test_name(Strategy::kRegisterAllocatorGraphColor);\
88}
89
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080090bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data, Strategy strategy) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010091 HGraph* graph = CreateCFG(data);
Vladimir Markoa0431112018-06-25 09:32:54 +010092 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +010093 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010094 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +010095 std::unique_ptr<RegisterAllocator> register_allocator =
96 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -070097 register_allocator->AllocateRegisters();
98 return register_allocator->Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010099}
100
101/**
102 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
103 * tests are based on this validation method.
104 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000105TEST_F(RegisterAllocatorTest, ValidateIntervals) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100106 HGraph* graph = CreateGraph();
Vladimir Markoa0431112018-06-25 09:32:54 +0100107 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100108 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100109
110 // Test with two intervals of the same range.
111 {
112 static constexpr size_t ranges[][2] = {{0, 42}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100113 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 0));
114 intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 1));
115 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100116
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100117 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100118 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100119 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100120 }
121
122 // Test with two non-intersecting intervals.
123 {
124 static constexpr size_t ranges1[][2] = {{0, 42}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100125 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100126 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100127 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
128 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100129
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100130 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100131 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100132 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100133 }
134
135 // Test with two non-intersecting intervals, with one with a lifetime hole.
136 {
137 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100138 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100139 static constexpr size_t ranges2[][2] = {{42, 43}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100140 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
141 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100142
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100143 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100144 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100145 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100146 }
147
148 // Test with intersecting intervals.
149 {
150 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100151 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100152 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100153 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
154 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100155
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100156 intervals[1]->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100157 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100158 intervals.clear();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100159 }
160
161 // Test with siblings.
162 {
163 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100164 intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100165 intervals[0]->SplitAt(43);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100166 static constexpr size_t ranges2[][2] = {{42, 47}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100167 intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
168 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100169
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100170 intervals[1]->SetRegister(0);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100171 // Sibling of the first interval has no register allocated to it.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100172 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100173
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100174 intervals[0]->GetNextSibling()->SetRegister(0);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100175 ASSERT_FALSE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100176 }
177}
178
Vladimir Markoca6fff82017-10-03 14:49:14 +0100179void RegisterAllocatorTest::CFG1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100180 /*
181 * Test the following snippet:
182 * return 0;
183 *
184 * Which becomes the following graph:
185 * constant0
186 * goto
187 * |
188 * return
189 * |
190 * exit
191 */
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800192 const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100193 Instruction::CONST_4 | 0 | 0,
194 Instruction::RETURN);
195
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700196 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100197}
198
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700199TEST_ALL_STRATEGIES(CFG1);
200
Vladimir Markoca6fff82017-10-03 14:49:14 +0100201void RegisterAllocatorTest::Loop1(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100202 /*
203 * Test the following snippet:
204 * int a = 0;
205 * while (a == a) {
206 * a = 4;
207 * }
208 * return 5;
209 *
210 * Which becomes the following graph:
211 * constant0
212 * constant4
213 * constant5
214 * goto
215 * |
216 * goto
217 * |
218 * phi
219 * equal
220 * if +++++
221 * | \ +
222 * | goto
223 * |
224 * return
225 * |
226 * exit
227 */
228
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800229 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100230 Instruction::CONST_4 | 0 | 0,
231 Instruction::IF_EQ, 4,
232 Instruction::CONST_4 | 4 << 12 | 0,
233 Instruction::GOTO | 0xFD00,
234 Instruction::CONST_4 | 5 << 12 | 1 << 8,
235 Instruction::RETURN | 1 << 8);
236
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700237 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100238}
239
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700240TEST_ALL_STRATEGIES(Loop1);
241
Vladimir Markoca6fff82017-10-03 14:49:14 +0100242void RegisterAllocatorTest::Loop2(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100243 /*
244 * Test the following snippet:
245 * int a = 0;
246 * while (a == 8) {
247 * a = 4 + 5;
248 * }
249 * return 6 + 7;
250 *
251 * Which becomes the following graph:
252 * constant0
253 * constant4
254 * constant5
255 * constant6
256 * constant7
257 * constant8
258 * goto
259 * |
260 * goto
261 * |
262 * phi
263 * equal
264 * if +++++
265 * | \ +
266 * | 4 + 5
267 * | goto
268 * |
269 * 6 + 7
270 * return
271 * |
272 * exit
273 */
274
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800275 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100276 Instruction::CONST_4 | 0 | 0,
277 Instruction::CONST_4 | 8 << 12 | 1 << 8,
278 Instruction::IF_EQ | 1 << 8, 7,
279 Instruction::CONST_4 | 4 << 12 | 0 << 8,
280 Instruction::CONST_4 | 5 << 12 | 1 << 8,
281 Instruction::ADD_INT, 1 << 8 | 0,
282 Instruction::GOTO | 0xFA00,
283 Instruction::CONST_4 | 6 << 12 | 1 << 8,
284 Instruction::CONST_4 | 7 << 12 | 1 << 8,
285 Instruction::ADD_INT, 1 << 8 | 0,
286 Instruction::RETURN | 1 << 8);
287
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700288 ASSERT_TRUE(Check(data, strategy));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100289}
290
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700291TEST_ALL_STRATEGIES(Loop2);
292
Vladimir Markoca6fff82017-10-03 14:49:14 +0100293void RegisterAllocatorTest::Loop3(Strategy strategy) {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100294 /*
295 * Test the following snippet:
296 * int a = 0
297 * do {
298 * b = a;
299 * a++;
300 * } while (a != 5)
301 * return b;
302 *
303 * Which becomes the following graph:
304 * constant0
305 * constant1
306 * constant5
307 * goto
308 * |
309 * goto
310 * |++++++++++++
311 * phi +
312 * a++ +
313 * equals +
314 * if +
315 * |++++++++++++
316 * return
317 * |
318 * exit
319 */
320
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800321 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100322 Instruction::CONST_4 | 0 | 0,
323 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
324 Instruction::CONST_4 | 5 << 12 | 2 << 8,
325 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
326 Instruction::RETURN | 0 << 8,
327 Instruction::MOVE | 1 << 12 | 0 << 8,
328 Instruction::GOTO | 0xF900);
329
Vladimir Markoca6fff82017-10-03 14:49:14 +0100330 HGraph* graph = CreateCFG(data);
Vladimir Markoa0431112018-06-25 09:32:54 +0100331 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100332 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100333 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100334 std::unique_ptr<RegisterAllocator> register_allocator =
335 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700336 register_allocator->AllocateRegisters();
337 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100338
Vladimir Markoec7802a2015-10-01 20:57:57 +0100339 HBasicBlock* loop_header = graph->GetBlocks()[2];
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100340 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
341
342 LiveInterval* phi_interval = phi->GetLiveInterval();
343 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
344 ASSERT_TRUE(phi_interval->HasRegister());
345 ASSERT_TRUE(loop_update->HasRegister());
346 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
347
Vladimir Markoec7802a2015-10-01 20:57:57 +0100348 HBasicBlock* return_block = graph->GetBlocks()[3];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100349 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100350 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
351}
352
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700353TEST_ALL_STRATEGIES(Loop3);
354
David Brazdil4833f5a2015-12-16 10:37:39 +0000355TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800356 const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100357 Instruction::CONST_4 | 0 | 0,
Mark Mendell09b84632015-02-13 17:48:38 -0500358 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
359 Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
360 Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100361 Instruction::RETURN_VOID);
362
Vladimir Markoca6fff82017-10-03 14:49:14 +0100363 HGraph* graph = CreateCFG(data);
Vladimir Markoa0431112018-06-25 09:32:54 +0100364 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
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
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800405 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100406 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();
Vladimir Markoa0431112018-06-25 09:32:54 +0100415 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100416 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100417 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100418 std::unique_ptr<RegisterAllocator> register_allocator =
419 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700420 register_allocator->AllocateRegisters();
421 ASSERT_TRUE(register_allocator->Validate(false));
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100422}
423
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700424TEST_ALL_STRATEGIES(DeadPhi);
425
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100426/**
427 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
428 * that share the same register. It should split the interval it is currently
429 * allocating for at the minimum lifetime position between the two inactive intervals.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700430 * This test only applies to the linear scan allocator.
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100431 */
David Brazdil4833f5a2015-12-16 10:37:39 +0000432TEST_F(RegisterAllocatorTest, FreeUntil) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800433 const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100434 Instruction::CONST_4 | 0 | 0,
435 Instruction::RETURN);
436
Vladimir Markoca6fff82017-10-03 14:49:14 +0100437 HGraph* graph = CreateCFG(data);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100438 SsaDeadPhiElimination(graph).Run();
Vladimir Markoa0431112018-06-25 09:32:54 +0100439 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100440 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100441 liveness.Analyze();
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100442 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100443
444 // Add an artifical range to cover the temps that will be put in the unhandled list.
445 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
446 unhandled->AddLoopRange(0, 60);
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100447
Nicolas Geoffray30971d62015-06-01 18:37:24 +0100448 // Populate the instructions in the liveness object, to please the register allocator.
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100449 for (size_t i = 0; i < 60; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100450 liveness.instructions_from_lifetime_position_.push_back(
Nicolas Geoffray23a81882015-06-01 18:12:38 +0100451 graph->GetEntryBlock()->GetFirstInstruction());
452 }
453
Mingyao Yang296bd602014-10-06 16:47:28 -0700454 // For SSA value intervals, only an interval resulted from a split may intersect
455 // with inactive intervals.
456 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100457
458 // Add three temps holding the same register, and starting at different positions.
459 // Put the one that should be picked in the middle of the inactive list to ensure
460 // we do not depend on an order.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100461 LiveInterval* interval =
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100462 LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100463 interval->AddRange(40, 50);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100464 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100465
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100466 interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100467 interval->AddRange(20, 30);
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(60, 70);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100472 register_allocator.inactive_.push_back(interval);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100473
474 register_allocator.number_of_registers_ = 1;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100475 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100476 register_allocator.processing_core_registers_ = true;
477 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
478
Mingyao Yang296bd602014-10-06 16:47:28 -0700479 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100480
481 // Check that we have split the interval.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100482 ASSERT_EQ(1u, register_allocator.unhandled_->size());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100483 // Check that we know need to find a new register where the next interval
484 // that uses the register starts.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100485 ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100486}
487
Vladimir Markoca6fff82017-10-03 14:49:14 +0100488HGraph* RegisterAllocatorTest::BuildIfElseWithPhi(HPhi** phi,
489 HInstruction** input1,
490 HInstruction** input2) {
491 HGraph* graph = CreateGraph();
492 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100493 graph->AddBlock(entry);
494 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100495 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100496 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100497 entry->AddInstruction(parameter);
498
Vladimir Markoca6fff82017-10-03 14:49:14 +0100499 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100500 graph->AddBlock(block);
501 entry->AddSuccessor(block);
502
Vladimir Markoca6fff82017-10-03 14:49:14 +0100503 HInstruction* test = new (GetAllocator()) HInstanceFieldGet(parameter,
504 nullptr,
505 DataType::Type::kBool,
506 MemberOffset(22),
507 false,
508 kUnknownFieldIndex,
509 kUnknownClassDefIndex,
510 graph->GetDexFile(),
511 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100512 block->AddInstruction(test);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100513 block->AddInstruction(new (GetAllocator()) HIf(test));
514 HBasicBlock* then = new (GetAllocator()) HBasicBlock(graph);
515 HBasicBlock* else_ = new (GetAllocator()) HBasicBlock(graph);
516 HBasicBlock* join = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100517 graph->AddBlock(then);
518 graph->AddBlock(else_);
519 graph->AddBlock(join);
520
521 block->AddSuccessor(then);
522 block->AddSuccessor(else_);
523 then->AddSuccessor(join);
524 else_->AddSuccessor(join);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100525 then->AddInstruction(new (GetAllocator()) HGoto());
526 else_->AddInstruction(new (GetAllocator()) HGoto());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100527
Vladimir Markoca6fff82017-10-03 14:49:14 +0100528 *phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100529 join->AddPhi(*phi);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100530 *input1 = new (GetAllocator()) HInstanceFieldGet(parameter,
531 nullptr,
532 DataType::Type::kInt32,
533 MemberOffset(42),
534 false,
535 kUnknownFieldIndex,
536 kUnknownClassDefIndex,
537 graph->GetDexFile(),
538 0);
539 *input2 = new (GetAllocator()) HInstanceFieldGet(parameter,
540 nullptr,
541 DataType::Type::kInt32,
542 MemberOffset(42),
543 false,
544 kUnknownFieldIndex,
545 kUnknownClassDefIndex,
546 graph->GetDexFile(),
547 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100548 then->AddInstruction(*input1);
549 else_->AddInstruction(*input2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100550 join->AddInstruction(new (GetAllocator()) HExit());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100551 (*phi)->AddInput(*input1);
552 (*phi)->AddInput(*input2);
553
554 graph->BuildDominatorTree();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000555 graph->AnalyzeLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100556 return graph;
557}
558
Vladimir Markoca6fff82017-10-03 14:49:14 +0100559void RegisterAllocatorTest::PhiHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100560 HPhi *phi;
561 HInstruction *input1, *input2;
562
563 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100564 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100565 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100566 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100567 liveness.Analyze();
568
569 // Check that the register allocator is deterministic.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100570 std::unique_ptr<RegisterAllocator> register_allocator =
571 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700572 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100573
574 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
575 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
576 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
577 }
578
579 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100580 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100581 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100582 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100583 liveness.Analyze();
584
585 // Set the phi to a specific register, and check that the inputs get allocated
586 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000587 phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100588 std::unique_ptr<RegisterAllocator> register_allocator =
589 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700590 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100591
592 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
593 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
594 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
595 }
596
597 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100598 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100599 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100600 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100601 liveness.Analyze();
602
603 // Set input1 to a specific register, and check that the phi and other input get allocated
604 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000605 input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100606 std::unique_ptr<RegisterAllocator> register_allocator =
607 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700608 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100609
610 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
611 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
612 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
613 }
614
615 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100616 HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
Vladimir Markoa0431112018-06-25 09:32:54 +0100617 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100618 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100619 liveness.Analyze();
620
621 // Set input2 to a specific register, and check that the phi and other input get allocated
622 // the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000623 input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100624 std::unique_ptr<RegisterAllocator> register_allocator =
625 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700626 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100627
628 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
629 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
630 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
631 }
632}
633
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700634// TODO: Enable this test for graph coloring register allocation when iterative move
635// coalescing is merged.
636TEST_F(RegisterAllocatorTest, PhiHint_LinearScan) {
637 PhiHint(Strategy::kRegisterAllocatorLinearScan);
638}
639
Vladimir Markoca6fff82017-10-03 14:49:14 +0100640HGraph* RegisterAllocatorTest::BuildFieldReturn(HInstruction** field, HInstruction** ret) {
641 HGraph* graph = CreateGraph();
642 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100643 graph->AddBlock(entry);
644 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100645 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100646 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100647 entry->AddInstruction(parameter);
648
Vladimir Markoca6fff82017-10-03 14:49:14 +0100649 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100650 graph->AddBlock(block);
651 entry->AddSuccessor(block);
652
Vladimir Markoca6fff82017-10-03 14:49:14 +0100653 *field = new (GetAllocator()) HInstanceFieldGet(parameter,
654 nullptr,
655 DataType::Type::kInt32,
656 MemberOffset(42),
657 false,
658 kUnknownFieldIndex,
659 kUnknownClassDefIndex,
660 graph->GetDexFile(),
661 0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100662 block->AddInstruction(*field);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100663 *ret = new (GetAllocator()) HReturn(*field);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100664 block->AddInstruction(*ret);
665
Vladimir Markoca6fff82017-10-03 14:49:14 +0100666 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100667 graph->AddBlock(exit);
668 block->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100669 exit->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000670
671 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100672 return graph;
673}
674
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700675void RegisterAllocatorTest::ExpectedInRegisterHint(Strategy strategy) {
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100676 HInstruction *field, *ret;
677
678 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100679 HGraph* graph = BuildFieldReturn(&field, &ret);
Vladimir Markoa0431112018-06-25 09:32:54 +0100680 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100681 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100682 liveness.Analyze();
683
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100684 std::unique_ptr<RegisterAllocator> register_allocator =
685 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700686 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100687
688 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
689 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
690 }
691
692 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100693 HGraph* graph = BuildFieldReturn(&field, &ret);
Vladimir Markoa0431112018-06-25 09:32:54 +0100694 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100695 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100696 liveness.Analyze();
697
698 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000699 // Don't use SetInAt because we are overriding an already allocated location.
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100700 ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100701
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100702 std::unique_ptr<RegisterAllocator> register_allocator =
703 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700704 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100705
706 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
707 }
708}
709
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700710// TODO: Enable this test for graph coloring register allocation when iterative move
711// coalescing is merged.
712TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint_LinearScan) {
713 ExpectedInRegisterHint(Strategy::kRegisterAllocatorLinearScan);
714}
715
Vladimir Markoca6fff82017-10-03 14:49:14 +0100716HGraph* RegisterAllocatorTest::BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub) {
717 HGraph* graph = CreateGraph();
718 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100719 graph->AddBlock(entry);
720 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100721 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100722 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100723 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000724
725 HInstruction* constant1 = graph->GetIntConstant(1);
726 HInstruction* constant2 = graph->GetIntConstant(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100727
Vladimir Markoca6fff82017-10-03 14:49:14 +0100728 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100729 graph->AddBlock(block);
730 entry->AddSuccessor(block);
731
Vladimir Markoca6fff82017-10-03 14:49:14 +0100732 *first_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, parameter, constant1);
Mark Mendell09b84632015-02-13 17:48:38 -0500733 block->AddInstruction(*first_sub);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100734 *second_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, *first_sub, constant2);
Mark Mendell09b84632015-02-13 17:48:38 -0500735 block->AddInstruction(*second_sub);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100736
Vladimir Markoca6fff82017-10-03 14:49:14 +0100737 block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000738
739 graph->BuildDominatorTree();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100740 return graph;
741}
742
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700743void RegisterAllocatorTest::SameAsFirstInputHint(Strategy strategy) {
Mark Mendell09b84632015-02-13 17:48:38 -0500744 HInstruction *first_sub, *second_sub;
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100745
746 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100747 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
Vladimir Markoa0431112018-06-25 09:32:54 +0100748 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100749 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100750 liveness.Analyze();
751
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100752 std::unique_ptr<RegisterAllocator> register_allocator =
753 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700754 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100755
756 // Sanity check that in normal conditions, the registers are the same.
Mark Mendell09b84632015-02-13 17:48:38 -0500757 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
758 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100759 }
760
761 {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100762 HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
Vladimir Markoa0431112018-06-25 09:32:54 +0100763 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100764 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100765 liveness.Analyze();
766
767 // check that both adds get the same register.
Nicolas Geoffray18c219b2015-02-04 09:38:49 +0000768 // Don't use UpdateOutput because output is already allocated.
Mark Mendell09b84632015-02-13 17:48:38 -0500769 first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
770 ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
771 ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100772
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100773 std::unique_ptr<RegisterAllocator> register_allocator =
774 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Matthew Gharrity8f49d4b2016-07-14 13:24:00 -0700775 register_allocator->AllocateRegisters();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100776
Mark Mendell09b84632015-02-13 17:48:38 -0500777 ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
778 ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100779 }
780}
781
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700782// TODO: Enable this test for graph coloring register allocation when iterative move
783// coalescing is merged.
784TEST_F(RegisterAllocatorTest, SameAsFirstInputHint_LinearScan) {
785 SameAsFirstInputHint(Strategy::kRegisterAllocatorLinearScan);
786}
787
Vladimir Markoca6fff82017-10-03 14:49:14 +0100788HGraph* RegisterAllocatorTest::BuildDiv(HInstruction** div) {
789 HGraph* graph = CreateGraph();
790 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Calin Juravled0d48522014-11-04 16:40:20 +0000791 graph->AddBlock(entry);
792 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100793 HInstruction* first = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100794 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100795 HInstruction* second = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100796 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Calin Juravled0d48522014-11-04 16:40:20 +0000797 entry->AddInstruction(first);
798 entry->AddInstruction(second);
799
Vladimir Markoca6fff82017-10-03 14:49:14 +0100800 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Calin Juravled0d48522014-11-04 16:40:20 +0000801 graph->AddBlock(block);
802 entry->AddSuccessor(block);
803
Vladimir Markoca6fff82017-10-03 14:49:14 +0100804 *div = new (GetAllocator()) HDiv(
805 DataType::Type::kInt32, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000806 block->AddInstruction(*div);
807
Vladimir Markoca6fff82017-10-03 14:49:14 +0100808 block->AddInstruction(new (GetAllocator()) HExit());
David Brazdil10f56cb2015-03-24 18:49:14 +0000809
810 graph->BuildDominatorTree();
Calin Juravled0d48522014-11-04 16:40:20 +0000811 return graph;
812}
813
Vladimir Markoca6fff82017-10-03 14:49:14 +0100814void RegisterAllocatorTest::ExpectedExactInRegisterAndSameOutputHint(Strategy strategy) {
Calin Juravled0d48522014-11-04 16:40:20 +0000815 HInstruction *div;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100816 HGraph* graph = BuildDiv(&div);
Vladimir Markoa0431112018-06-25 09:32:54 +0100817 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100818 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Vladimir Markoca6fff82017-10-03 14:49:14 +0100819 liveness.Analyze();
Calin Juravled0d48522014-11-04 16:40:20 +0000820
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100821 std::unique_ptr<RegisterAllocator> register_allocator =
822 RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness, strategy);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100823 register_allocator->AllocateRegisters();
Calin Juravled0d48522014-11-04 16:40:20 +0000824
Vladimir Markoca6fff82017-10-03 14:49:14 +0100825 // div on x86 requires its first input in eax and the output be the same as the first input.
826 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
Calin Juravled0d48522014-11-04 16:40:20 +0000827}
828
Matthew Gharrity2ac06bc2016-08-05 09:34:52 -0700829// TODO: Enable this test for graph coloring register allocation when iterative move
830// coalescing is merged.
831TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint_LinearScan) {
832 ExpectedExactInRegisterAndSameOutputHint(Strategy::kRegisterAllocatorLinearScan);
833}
834
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000835// Test a bug in the register allocator, where allocating a blocked
836// register would lead to spilling an inactive interval at the wrong
837// position.
Matthew Gharrityd9ffd0d2016-06-22 10:27:55 -0700838// This test only applies to the linear scan allocator.
David Brazdil4833f5a2015-12-16 10:37:39 +0000839TEST_F(RegisterAllocatorTest, SpillInactive) {
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000840 // Create a synthesized graph to please the register_allocator and
841 // ssa_liveness_analysis code.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100842 HGraph* graph = CreateGraph();
843 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000844 graph->AddBlock(entry);
845 graph->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100846 HInstruction* one = 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* two = 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* three = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100851 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100852 HInstruction* four = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100853 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000854 entry->AddInstruction(one);
855 entry->AddInstruction(two);
856 entry->AddInstruction(three);
857 entry->AddInstruction(four);
858
Vladimir Markoca6fff82017-10-03 14:49:14 +0100859 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000860 graph->AddBlock(block);
861 entry->AddSuccessor(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100862 block->AddInstruction(new (GetAllocator()) HExit());
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000863
864 // We create a synthesized user requesting a register, to avoid just spilling the
865 // intervals.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100866 HPhi* user = new (GetAllocator()) HPhi(GetAllocator(), 0, 1, DataType::Type::kInt32);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000867 user->AddInput(one);
868 user->SetBlock(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100869 LocationSummary* locations = new (GetAllocator()) LocationSummary(user, LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000870 locations->SetInAt(0, Location::RequiresRegister());
871 static constexpr size_t phi_ranges[][2] = {{20, 30}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100872 BuildInterval(phi_ranges, arraysize(phi_ranges), GetScopedAllocator(), -1, user);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000873
874 // Create an interval with lifetime holes.
875 static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100876 LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), -1, one);
Andreas Gampe654698d2018-09-20 13:34:35 -0700877 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 8));
878 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 7));
879 first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 6));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000880
Vladimir Markoca6fff82017-10-03 14:49:14 +0100881 locations = new (GetAllocator()) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000882 locations->SetOut(Location::RequiresRegister());
883 first = first->SplitAt(1);
884
885 // Create an interval that conflicts with the next interval, to force the next
886 // interval to call `AllocateBlockedReg`.
887 static constexpr size_t ranges2[][2] = {{2, 4}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100888 LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), -1, two);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100889 locations =
890 new (GetAllocator()) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000891 locations->SetOut(Location::RequiresRegister());
892
893 // Create an interval that will lead to splitting the first interval. The bug occured
894 // by splitting at a wrong position, in this case at the next intersection between
895 // this interval and the first interval. We would have then put the interval with ranges
896 // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
897 // before lifetime position 6 yet.
898 static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100899 LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), GetScopedAllocator(), -1, three);
Andreas Gampe654698d2018-09-20 13:34:35 -0700900 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 8));
901 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 4));
902 third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 3));
Vladimir Markoca6fff82017-10-03 14:49:14 +0100903 locations = new (GetAllocator()) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000904 locations->SetOut(Location::RequiresRegister());
905 third = third->SplitAt(3);
906
907 // Because the first part of the split interval was considered handled, this interval
908 // was free to allocate the same register, even though it conflicts with it.
909 static constexpr size_t ranges4[][2] = {{4, 6}};
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100910 LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), GetScopedAllocator(), -1, four);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100911 locations =
912 new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000913 locations->SetOut(Location::RequiresRegister());
914
Vladimir Markoa0431112018-06-25 09:32:54 +0100915 x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100916 SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100917 // Populate the instructions in the liveness object, to please the register allocator.
918 for (size_t i = 0; i < 32; ++i) {
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100919 liveness.instructions_from_lifetime_position_.push_back(user);
Nicolas Geoffray8cbab3c2015-04-23 15:14:36 +0100920 }
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000921
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100922 RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100923 register_allocator.unhandled_core_intervals_.push_back(fourth);
924 register_allocator.unhandled_core_intervals_.push_back(third);
925 register_allocator.unhandled_core_intervals_.push_back(second);
926 register_allocator.unhandled_core_intervals_.push_back(first);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000927
928 // Set just one register available to make all intervals compete for the same.
929 register_allocator.number_of_registers_ = 1;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100930 register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000931 register_allocator.processing_core_registers_ = true;
932 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
933 register_allocator.LinearScan();
934
935 // Test that there is no conflicts between intervals.
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100936 ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
Vladimir Marko2aaa4b52015-09-17 17:03:26 +0100937 intervals.push_back(first);
938 intervals.push_back(second);
939 intervals.push_back(third);
940 intervals.push_back(fourth);
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100941 ASSERT_TRUE(ValidateIntervals(intervals, codegen));
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +0000942}
943
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100944} // namespace art