blob: c2ea80ec337dac9804485a561d6663088475f2f9 [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
17#include "builder.h"
18#include "code_generator.h"
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010019#include "code_generator_x86.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010020#include "dex_file.h"
21#include "dex_instruction.h"
22#include "nodes.h"
23#include "optimizing_unit_test.h"
24#include "register_allocator.h"
25#include "ssa_liveness_analysis.h"
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +010026#include "ssa_phi_elimination.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010027#include "utils/arena_allocator.h"
28
29#include "gtest/gtest.h"
30
31namespace art {
32
33// Note: the register allocator tests rely on the fact that constants have live
34// intervals and registers get allocated to them.
35
36static bool Check(const uint16_t* data) {
37 ArenaPool pool;
38 ArenaAllocator allocator(&pool);
39 HGraphBuilder builder(&allocator);
40 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
41 HGraph* graph = builder.BuildGraph(*item);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +000042 graph->TryBuildingSsa();
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010043 x86::CodeGeneratorX86 codegen(graph);
44 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010045 liveness.Analyze();
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010046 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +010047 register_allocator.AllocateRegisters();
48 return register_allocator.Validate(false);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010049}
50
51/**
52 * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
53 * tests are based on this validation method.
54 */
55TEST(RegisterAllocatorTest, ValidateIntervals) {
56 ArenaPool pool;
57 ArenaAllocator allocator(&pool);
58 HGraph* graph = new (&allocator) HGraph(&allocator);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010059 x86::CodeGeneratorX86 codegen(graph);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010060 GrowableArray<LiveInterval*> intervals(&allocator, 0);
61
62 // Test with two intervals of the same range.
63 {
64 static constexpr size_t ranges[][2] = {{0, 42}};
65 intervals.Add(BuildInterval(ranges, arraysize(ranges), &allocator, 0));
66 intervals.Add(BuildInterval(ranges, arraysize(ranges), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010067 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010068 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010069
70 intervals.Get(1)->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010071 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010072 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010073 intervals.Reset();
74 }
75
76 // Test with two non-intersecting intervals.
77 {
78 static constexpr size_t ranges1[][2] = {{0, 42}};
79 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
80 static constexpr size_t ranges2[][2] = {{42, 43}};
81 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010082 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010083 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010084
85 intervals.Get(1)->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010086 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010087 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010088 intervals.Reset();
89 }
90
91 // Test with two non-intersecting intervals, with one with a lifetime hole.
92 {
93 static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
94 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
95 static constexpr size_t ranges2[][2] = {{42, 43}};
96 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +010097 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +010098 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010099
100 intervals.Get(1)->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100101 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100102 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100103 intervals.Reset();
104 }
105
106 // Test with intersecting intervals.
107 {
108 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
109 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
110 static constexpr size_t ranges2[][2] = {{42, 47}};
111 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100112 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100113 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100114
115 intervals.Get(1)->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100116 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100117 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100118 intervals.Reset();
119 }
120
121 // Test with siblings.
122 {
123 static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
124 intervals.Add(BuildInterval(ranges1, arraysize(ranges1), &allocator, 0));
125 intervals.Get(0)->SplitAt(43);
126 static constexpr size_t ranges2[][2] = {{42, 47}};
127 intervals.Add(BuildInterval(ranges2, arraysize(ranges2), &allocator, 1));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100128 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100129 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100130
131 intervals.Get(1)->SetRegister(0);
132 // Sibling of the first interval has no register allocated to it.
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100133 ASSERT_TRUE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100134 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100135
136 intervals.Get(0)->GetNextSibling()->SetRegister(0);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100137 ASSERT_FALSE(RegisterAllocator::ValidateIntervals(
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100138 intervals, 0, 0, codegen, &allocator, true, false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100139 }
140}
141
142TEST(RegisterAllocatorTest, CFG1) {
143 /*
144 * Test the following snippet:
145 * return 0;
146 *
147 * Which becomes the following graph:
148 * constant0
149 * goto
150 * |
151 * return
152 * |
153 * exit
154 */
155 const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
156 Instruction::CONST_4 | 0 | 0,
157 Instruction::RETURN);
158
159 ASSERT_TRUE(Check(data));
160}
161
162TEST(RegisterAllocatorTest, Loop1) {
163 /*
164 * Test the following snippet:
165 * int a = 0;
166 * while (a == a) {
167 * a = 4;
168 * }
169 * return 5;
170 *
171 * Which becomes the following graph:
172 * constant0
173 * constant4
174 * constant5
175 * goto
176 * |
177 * goto
178 * |
179 * phi
180 * equal
181 * if +++++
182 * | \ +
183 * | goto
184 * |
185 * return
186 * |
187 * exit
188 */
189
190 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
191 Instruction::CONST_4 | 0 | 0,
192 Instruction::IF_EQ, 4,
193 Instruction::CONST_4 | 4 << 12 | 0,
194 Instruction::GOTO | 0xFD00,
195 Instruction::CONST_4 | 5 << 12 | 1 << 8,
196 Instruction::RETURN | 1 << 8);
197
198 ASSERT_TRUE(Check(data));
199}
200
201TEST(RegisterAllocatorTest, Loop2) {
202 /*
203 * Test the following snippet:
204 * int a = 0;
205 * while (a == 8) {
206 * a = 4 + 5;
207 * }
208 * return 6 + 7;
209 *
210 * Which becomes the following graph:
211 * constant0
212 * constant4
213 * constant5
214 * constant6
215 * constant7
216 * constant8
217 * goto
218 * |
219 * goto
220 * |
221 * phi
222 * equal
223 * if +++++
224 * | \ +
225 * | 4 + 5
226 * | goto
227 * |
228 * 6 + 7
229 * return
230 * |
231 * exit
232 */
233
234 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
235 Instruction::CONST_4 | 0 | 0,
236 Instruction::CONST_4 | 8 << 12 | 1 << 8,
237 Instruction::IF_EQ | 1 << 8, 7,
238 Instruction::CONST_4 | 4 << 12 | 0 << 8,
239 Instruction::CONST_4 | 5 << 12 | 1 << 8,
240 Instruction::ADD_INT, 1 << 8 | 0,
241 Instruction::GOTO | 0xFA00,
242 Instruction::CONST_4 | 6 << 12 | 1 << 8,
243 Instruction::CONST_4 | 7 << 12 | 1 << 8,
244 Instruction::ADD_INT, 1 << 8 | 0,
245 Instruction::RETURN | 1 << 8);
246
247 ASSERT_TRUE(Check(data));
248}
249
250static HGraph* BuildSSAGraph(const uint16_t* data, ArenaAllocator* allocator) {
251 HGraphBuilder builder(allocator);
252 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
253 HGraph* graph = builder.BuildGraph(*item);
Nicolas Geoffraye53798a2014-12-01 10:31:54 +0000254 graph->TryBuildingSsa();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100255 return graph;
256}
257
258TEST(RegisterAllocatorTest, Loop3) {
259 /*
260 * Test the following snippet:
261 * int a = 0
262 * do {
263 * b = a;
264 * a++;
265 * } while (a != 5)
266 * return b;
267 *
268 * Which becomes the following graph:
269 * constant0
270 * constant1
271 * constant5
272 * goto
273 * |
274 * goto
275 * |++++++++++++
276 * phi +
277 * a++ +
278 * equals +
279 * if +
280 * |++++++++++++
281 * return
282 * |
283 * exit
284 */
285
286 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
287 Instruction::CONST_4 | 0 | 0,
288 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
289 Instruction::CONST_4 | 5 << 12 | 2 << 8,
290 Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
291 Instruction::RETURN | 0 << 8,
292 Instruction::MOVE | 1 << 12 | 0 << 8,
293 Instruction::GOTO | 0xF900);
294
295 ArenaPool pool;
296 ArenaAllocator allocator(&pool);
297 HGraph* graph = BuildSSAGraph(data, &allocator);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100298 x86::CodeGeneratorX86 codegen(graph);
299 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100300 liveness.Analyze();
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100301 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100302 register_allocator.AllocateRegisters();
303 ASSERT_TRUE(register_allocator.Validate(false));
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100304
305 HBasicBlock* loop_header = graph->GetBlocks().Get(2);
306 HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
307
308 LiveInterval* phi_interval = phi->GetLiveInterval();
309 LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
310 ASSERT_TRUE(phi_interval->HasRegister());
311 ASSERT_TRUE(loop_update->HasRegister());
312 ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
313
314 HBasicBlock* return_block = graph->GetBlocks().Get(3);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100315 HReturn* ret = return_block->GetLastInstruction()->AsReturn();
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100316 ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
317}
318
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100319TEST(RegisterAllocatorTest, FirstRegisterUse) {
320 const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
321 Instruction::CONST_4 | 0 | 0,
322 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
323 Instruction::ADD_INT_LIT8 | 0 << 8, 1 << 8,
324 Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8 | 1,
325 Instruction::RETURN_VOID);
326
327 ArenaPool pool;
328 ArenaAllocator allocator(&pool);
329 HGraph* graph = BuildSSAGraph(data, &allocator);
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100330 x86::CodeGeneratorX86 codegen(graph);
331 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100332 liveness.Analyze();
333
334 HAdd* first_add = graph->GetBlocks().Get(1)->GetFirstInstruction()->AsAdd();
335 HAdd* last_add = graph->GetBlocks().Get(1)->GetLastInstruction()->GetPrevious()->AsAdd();
336 ASSERT_EQ(last_add->InputAt(0), first_add);
337 LiveInterval* interval = first_add->GetLiveInterval();
Nicolas Geoffrayfd680d82014-09-29 09:46:03 +0100338 ASSERT_EQ(interval->GetEnd(), last_add->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100339 ASSERT_TRUE(interval->GetNextSibling() == nullptr);
340
341 // We need a register for the output of the instruction.
342 ASSERT_EQ(interval->FirstRegisterUse(), first_add->GetLifetimePosition());
343
344 // Split at the next instruction.
345 interval = interval->SplitAt(first_add->GetLifetimePosition() + 2);
346 // The user of the split is the last add.
Nicolas Geoffray1f897b92014-10-21 17:14:05 +0100347 ASSERT_EQ(interval->FirstRegisterUse(), last_add->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100348
349 // Split before the last add.
350 LiveInterval* new_interval = interval->SplitAt(last_add->GetLifetimePosition() - 1);
351 // Ensure the current interval has no register use...
352 ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
353 // And the new interval has it for the last add.
Nicolas Geoffray1f897b92014-10-21 17:14:05 +0100354 ASSERT_EQ(new_interval->FirstRegisterUse(), last_add->GetLifetimePosition());
Nicolas Geoffrayde025a72014-06-19 17:06:46 +0100355}
356
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100357TEST(RegisterAllocatorTest, DeadPhi) {
358 /* Test for a dead loop phi taking as back-edge input a phi that also has
359 * this loop phi as input. Walking backwards in SsaDeadPhiElimination
360 * does not solve the problem because the loop phi will be visited last.
361 *
362 * Test the following snippet:
363 * int a = 0
364 * do {
365 * if (true) {
366 * a = 2;
367 * }
368 * } while (true);
369 */
370
371 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
372 Instruction::CONST_4 | 0 | 0,
373 Instruction::CONST_4 | 1 << 8 | 0,
374 Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
375 Instruction::CONST_4 | 2 << 12 | 0 << 8,
376 Instruction::GOTO | 0xFD00,
377 Instruction::RETURN_VOID);
378
379 ArenaPool pool;
380 ArenaAllocator allocator(&pool);
381 HGraph* graph = BuildSSAGraph(data, &allocator);
382 SsaDeadPhiElimination(graph).Run();
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100383 x86::CodeGeneratorX86 codegen(graph);
384 SsaLivenessAnalysis liveness(*graph, &codegen);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100385 liveness.Analyze();
Nicolas Geoffray8a16d972014-09-11 10:30:02 +0100386 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
Nicolas Geoffray3ac17fc2014-08-06 23:02:54 +0100387 register_allocator.AllocateRegisters();
388 ASSERT_TRUE(register_allocator.Validate(false));
389}
390
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100391/**
392 * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
393 * that share the same register. It should split the interval it is currently
394 * allocating for at the minimum lifetime position between the two inactive intervals.
395 */
396TEST(RegisterAllocatorTest, FreeUntil) {
397 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
398 Instruction::CONST_4 | 0 | 0,
399 Instruction::RETURN);
400
401 ArenaPool pool;
402 ArenaAllocator allocator(&pool);
403 HGraph* graph = BuildSSAGraph(data, &allocator);
404 SsaDeadPhiElimination(graph).Run();
405 x86::CodeGeneratorX86 codegen(graph);
406 SsaLivenessAnalysis liveness(*graph, &codegen);
407 liveness.Analyze();
408 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
409
410 // Add an artifical range to cover the temps that will be put in the unhandled list.
411 LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
412 unhandled->AddLoopRange(0, 60);
Mingyao Yang296bd602014-10-06 16:47:28 -0700413 // For SSA value intervals, only an interval resulted from a split may intersect
414 // with inactive intervals.
415 unhandled = register_allocator.Split(unhandled, 5);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100416
417 // Add three temps holding the same register, and starting at different positions.
418 // Put the one that should be picked in the middle of the inactive list to ensure
419 // we do not depend on an order.
Mingyao Yang296bd602014-10-06 16:47:28 -0700420 LiveInterval* interval = LiveInterval::MakeInterval(&allocator, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100421 interval->SetRegister(0);
422 interval->AddRange(40, 50);
423 register_allocator.inactive_.Add(interval);
424
Mingyao Yang296bd602014-10-06 16:47:28 -0700425 interval = LiveInterval::MakeInterval(&allocator, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100426 interval->SetRegister(0);
427 interval->AddRange(20, 30);
428 register_allocator.inactive_.Add(interval);
429
Mingyao Yang296bd602014-10-06 16:47:28 -0700430 interval = LiveInterval::MakeInterval(&allocator, Primitive::kPrimInt);
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100431 interval->SetRegister(0);
432 interval->AddRange(60, 70);
433 register_allocator.inactive_.Add(interval);
434
435 register_allocator.number_of_registers_ = 1;
436 register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
437 register_allocator.processing_core_registers_ = true;
438 register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
439
Mingyao Yang296bd602014-10-06 16:47:28 -0700440 ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
Nicolas Geoffrayaac0f392014-09-16 14:11:14 +0100441
442 // Check that we have split the interval.
443 ASSERT_EQ(1u, register_allocator.unhandled_->Size());
444 // Check that we know need to find a new register where the next interval
445 // that uses the register starts.
446 ASSERT_EQ(20u, register_allocator.unhandled_->Get(0)->GetStart());
447}
448
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100449static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator,
450 HPhi** phi,
451 HInstruction** input1,
452 HInstruction** input2) {
453 HGraph* graph = new (allocator) HGraph(allocator);
454 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
455 graph->AddBlock(entry);
456 graph->SetEntryBlock(entry);
457 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
458 entry->AddInstruction(parameter);
459
460 HBasicBlock* block = new (allocator) HBasicBlock(graph);
461 graph->AddBlock(block);
462 entry->AddSuccessor(block);
463
464 HInstruction* test = new (allocator) HInstanceFieldGet(
Calin Juravle52c48962014-12-16 17:02:57 +0000465 parameter, Primitive::kPrimBoolean, MemberOffset(22), false);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100466 block->AddInstruction(test);
467 block->AddInstruction(new (allocator) HIf(test));
468 HBasicBlock* then = new (allocator) HBasicBlock(graph);
469 HBasicBlock* else_ = new (allocator) HBasicBlock(graph);
470 HBasicBlock* join = new (allocator) HBasicBlock(graph);
471 graph->AddBlock(then);
472 graph->AddBlock(else_);
473 graph->AddBlock(join);
474
475 block->AddSuccessor(then);
476 block->AddSuccessor(else_);
477 then->AddSuccessor(join);
478 else_->AddSuccessor(join);
479 then->AddInstruction(new (allocator) HGoto());
480 else_->AddInstruction(new (allocator) HGoto());
481
482 *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
483 join->AddPhi(*phi);
Calin Juravle52c48962014-12-16 17:02:57 +0000484 *input1 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
485 MemberOffset(42), false);
486 *input2 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
487 MemberOffset(42), false);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100488 then->AddInstruction(*input1);
489 else_->AddInstruction(*input2);
490 join->AddInstruction(new (allocator) HExit());
491 (*phi)->AddInput(*input1);
492 (*phi)->AddInput(*input2);
493
494 graph->BuildDominatorTree();
Nicolas Geoffrayf5370122014-12-02 11:51:19 +0000495 graph->AnalyzeNaturalLoops();
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100496 return graph;
497}
498
499TEST(RegisterAllocatorTest, PhiHint) {
500 ArenaPool pool;
501 ArenaAllocator allocator(&pool);
502 HPhi *phi;
503 HInstruction *input1, *input2;
504
505 {
506 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
507 x86::CodeGeneratorX86 codegen(graph);
508 SsaLivenessAnalysis liveness(*graph, &codegen);
509 liveness.Analyze();
510
511 // Check that the register allocator is deterministic.
512 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
513 register_allocator.AllocateRegisters();
514
515 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
516 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
517 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
518 }
519
520 {
521 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
522 x86::CodeGeneratorX86 codegen(graph);
523 SsaLivenessAnalysis liveness(*graph, &codegen);
524 liveness.Analyze();
525
526 // Set the phi to a specific register, and check that the inputs get allocated
527 // the same register.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100528 phi->GetLocations()->SetOut(Location::RegisterLocation(2));
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100529 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
530 register_allocator.AllocateRegisters();
531
532 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
533 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
534 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
535 }
536
537 {
538 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
539 x86::CodeGeneratorX86 codegen(graph);
540 SsaLivenessAnalysis liveness(*graph, &codegen);
541 liveness.Analyze();
542
543 // Set input1 to a specific register, and check that the phi and other input get allocated
544 // the same register.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100545 input1->GetLocations()->SetOut(Location::RegisterLocation(2));
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100546 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
547 register_allocator.AllocateRegisters();
548
549 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
550 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
551 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
552 }
553
554 {
555 HGraph* graph = BuildIfElseWithPhi(&allocator, &phi, &input1, &input2);
556 x86::CodeGeneratorX86 codegen(graph);
557 SsaLivenessAnalysis liveness(*graph, &codegen);
558 liveness.Analyze();
559
560 // Set input2 to a specific register, and check that the phi and other input get allocated
561 // the same register.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100562 input2->GetLocations()->SetOut(Location::RegisterLocation(2));
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100563 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
564 register_allocator.AllocateRegisters();
565
566 ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
567 ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
568 ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
569 }
570}
571
572static HGraph* BuildFieldReturn(ArenaAllocator* allocator,
573 HInstruction** field,
574 HInstruction** ret) {
575 HGraph* graph = new (allocator) HGraph(allocator);
576 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
577 graph->AddBlock(entry);
578 graph->SetEntryBlock(entry);
579 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
580 entry->AddInstruction(parameter);
581
582 HBasicBlock* block = new (allocator) HBasicBlock(graph);
583 graph->AddBlock(block);
584 entry->AddSuccessor(block);
585
Calin Juravle52c48962014-12-16 17:02:57 +0000586 *field = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
587 MemberOffset(42), false);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100588 block->AddInstruction(*field);
589 *ret = new (allocator) HReturn(*field);
590 block->AddInstruction(*ret);
591
592 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
593 graph->AddBlock(exit);
594 block->AddSuccessor(exit);
595 exit->AddInstruction(new (allocator) HExit());
596 return graph;
597}
598
599TEST(RegisterAllocatorTest, ExpectedInRegisterHint) {
600 ArenaPool pool;
601 ArenaAllocator allocator(&pool);
602 HInstruction *field, *ret;
603
604 {
605 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
606 x86::CodeGeneratorX86 codegen(graph);
607 SsaLivenessAnalysis liveness(*graph, &codegen);
608 liveness.Analyze();
609
610 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
611 register_allocator.AllocateRegisters();
612
613 // Sanity check that in normal conditions, the register should be hinted to 0 (EAX).
614 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
615 }
616
617 {
618 HGraph* graph = BuildFieldReturn(&allocator, &field, &ret);
619 x86::CodeGeneratorX86 codegen(graph);
620 SsaLivenessAnalysis liveness(*graph, &codegen);
621 liveness.Analyze();
622
623 // Check that the field gets put in the register expected by its use.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000624 // Don't use SetInAt because we are overriding an already allocated location.
625 ret->GetLocations()->inputs_.Put(0, Location::RegisterLocation(2));
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100626
627 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
628 register_allocator.AllocateRegisters();
629
630 ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
631 }
632}
633
634static HGraph* BuildTwoAdds(ArenaAllocator* allocator,
635 HInstruction** first_add,
636 HInstruction** second_add) {
637 HGraph* graph = new (allocator) HGraph(allocator);
638 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
639 graph->AddBlock(entry);
640 graph->SetEntryBlock(entry);
641 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimInt);
642 HInstruction* constant1 = new (allocator) HIntConstant(0);
643 HInstruction* constant2 = new (allocator) HIntConstant(0);
644 entry->AddInstruction(parameter);
645 entry->AddInstruction(constant1);
646 entry->AddInstruction(constant2);
647
648 HBasicBlock* block = new (allocator) HBasicBlock(graph);
649 graph->AddBlock(block);
650 entry->AddSuccessor(block);
651
652 *first_add = new (allocator) HAdd(Primitive::kPrimInt, parameter, constant1);
653 block->AddInstruction(*first_add);
654 *second_add = new (allocator) HAdd(Primitive::kPrimInt, *first_add, constant2);
655 block->AddInstruction(*second_add);
656
657 block->AddInstruction(new (allocator) HExit());
658 return graph;
659}
660
661TEST(RegisterAllocatorTest, SameAsFirstInputHint) {
662 ArenaPool pool;
663 ArenaAllocator allocator(&pool);
664 HInstruction *first_add, *second_add;
665
666 {
667 HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add);
668 x86::CodeGeneratorX86 codegen(graph);
669 SsaLivenessAnalysis liveness(*graph, &codegen);
670 liveness.Analyze();
671
672 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
673 register_allocator.AllocateRegisters();
674
675 // Sanity check that in normal conditions, the registers are the same.
676 ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 1);
677 ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 1);
678 }
679
680 {
681 HGraph* graph = BuildTwoAdds(&allocator, &first_add, &second_add);
682 x86::CodeGeneratorX86 codegen(graph);
683 SsaLivenessAnalysis liveness(*graph, &codegen);
684 liveness.Analyze();
685
686 // check that both adds get the same register.
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000687 // Don't use SetOutput because output is already allocated.
688 first_add->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100689 ASSERT_EQ(first_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
690 ASSERT_EQ(second_add->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
691
692 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
693 register_allocator.AllocateRegisters();
694
695 ASSERT_EQ(first_add->GetLiveInterval()->GetRegister(), 2);
696 ASSERT_EQ(second_add->GetLiveInterval()->GetRegister(), 2);
697 }
698}
699
Calin Juravled0d48522014-11-04 16:40:20 +0000700static HGraph* BuildDiv(ArenaAllocator* allocator,
701 HInstruction** div) {
702 HGraph* graph = new (allocator) HGraph(allocator);
703 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
704 graph->AddBlock(entry);
705 graph->SetEntryBlock(entry);
706 HInstruction* first = new (allocator) HParameterValue(0, Primitive::kPrimInt);
707 HInstruction* second = new (allocator) HParameterValue(0, Primitive::kPrimInt);
708 entry->AddInstruction(first);
709 entry->AddInstruction(second);
710
711 HBasicBlock* block = new (allocator) HBasicBlock(graph);
712 graph->AddBlock(block);
713 entry->AddSuccessor(block);
714
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000715 *div = new (allocator) HDiv(Primitive::kPrimInt, first, second, 0); // don't care about dex_pc.
Calin Juravled0d48522014-11-04 16:40:20 +0000716 block->AddInstruction(*div);
717
718 block->AddInstruction(new (allocator) HExit());
719 return graph;
720}
721
722TEST(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) {
723 ArenaPool pool;
724 ArenaAllocator allocator(&pool);
725 HInstruction *div;
726
727 {
728 HGraph* graph = BuildDiv(&allocator, &div);
729 x86::CodeGeneratorX86 codegen(graph);
730 SsaLivenessAnalysis liveness(*graph, &codegen);
731 liveness.Analyze();
732
733 RegisterAllocator register_allocator(&allocator, &codegen, liveness);
734 register_allocator.AllocateRegisters();
735
736 // div on x86 requires its first input in eax and the output be the same as the first input.
737 ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
738 }
739}
740
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100741} // namespace art