1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "register_allocator.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "arch/x86/instruction_set_features_x86.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/arena_allocator.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
22*795d594fSAndroid Build Coastguard Worker #include "builder.h"
23*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
24*795d594fSAndroid Build Coastguard Worker #include "code_generator_x86.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file.h"
26*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
28*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_options.h"
29*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
30*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
31*795d594fSAndroid Build Coastguard Worker #include "register_allocator_linear_scan.h"
32*795d594fSAndroid Build Coastguard Worker #include "ssa_liveness_analysis.h"
33*795d594fSAndroid Build Coastguard Worker #include "ssa_phi_elimination.h"
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard Worker // Note: the register allocator tests rely on the fact that constants have live
38*795d594fSAndroid Build Coastguard Worker // intervals and registers get allocated to them.
39*795d594fSAndroid Build Coastguard Worker
40*795d594fSAndroid Build Coastguard Worker class RegisterAllocatorTest : public CommonCompilerTest, public OptimizingUnitTestHelper {
41*795d594fSAndroid Build Coastguard Worker protected:
SetUp()42*795d594fSAndroid Build Coastguard Worker void SetUp() override {
43*795d594fSAndroid Build Coastguard Worker CommonCompilerTest::SetUp();
44*795d594fSAndroid Build Coastguard Worker // This test is using the x86 ISA.
45*795d594fSAndroid Build Coastguard Worker compiler_options_ = CommonCompilerTest::CreateCompilerOptions(InstructionSet::kX86, "default");
46*795d594fSAndroid Build Coastguard Worker }
47*795d594fSAndroid Build Coastguard Worker
48*795d594fSAndroid Build Coastguard Worker // Helper functions that make use of the OptimizingUnitTest's members.
49*795d594fSAndroid Build Coastguard Worker bool Check(const std::vector<uint16_t>& data);
50*795d594fSAndroid Build Coastguard Worker HGraph* BuildIfElseWithPhi(HPhi** phi, HInstruction** input1, HInstruction** input2);
51*795d594fSAndroid Build Coastguard Worker HGraph* BuildFieldReturn(HInstruction** field, HInstruction** ret);
52*795d594fSAndroid Build Coastguard Worker HGraph* BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub);
53*795d594fSAndroid Build Coastguard Worker HGraph* BuildDiv(HInstruction** div);
54*795d594fSAndroid Build Coastguard Worker
ValidateIntervals(const ScopedArenaVector<LiveInterval * > & intervals,const CodeGenerator & codegen)55*795d594fSAndroid Build Coastguard Worker bool ValidateIntervals(const ScopedArenaVector<LiveInterval*>& intervals,
56*795d594fSAndroid Build Coastguard Worker const CodeGenerator& codegen) {
57*795d594fSAndroid Build Coastguard Worker return RegisterAllocator::ValidateIntervals(ArrayRef<LiveInterval* const>(intervals),
58*795d594fSAndroid Build Coastguard Worker /* number_of_spill_slots= */ 0u,
59*795d594fSAndroid Build Coastguard Worker /* number_of_out_slots= */ 0u,
60*795d594fSAndroid Build Coastguard Worker codegen,
61*795d594fSAndroid Build Coastguard Worker /*liveness=*/ nullptr,
62*795d594fSAndroid Build Coastguard Worker RegisterAllocator::RegisterType::kCoreRegister,
63*795d594fSAndroid Build Coastguard Worker /* log_fatal_on_failure= */ false);
64*795d594fSAndroid Build Coastguard Worker }
65*795d594fSAndroid Build Coastguard Worker
66*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CompilerOptions> compiler_options_;
67*795d594fSAndroid Build Coastguard Worker };
68*795d594fSAndroid Build Coastguard Worker
Check(const std::vector<uint16_t> & data)69*795d594fSAndroid Build Coastguard Worker bool RegisterAllocatorTest::Check(const std::vector<uint16_t>& data) {
70*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
71*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
72*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
73*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
74*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
75*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
76*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
77*795d594fSAndroid Build Coastguard Worker return register_allocator->Validate(false);
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker
80*795d594fSAndroid Build Coastguard Worker /**
81*795d594fSAndroid Build Coastguard Worker * Unit testing of RegisterAllocator::ValidateIntervals. Register allocator
82*795d594fSAndroid Build Coastguard Worker * tests are based on this validation method.
83*795d594fSAndroid Build Coastguard Worker */
TEST_F(RegisterAllocatorTest,ValidateIntervals)84*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, ValidateIntervals) {
85*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph();
86*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
87*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
88*795d594fSAndroid Build Coastguard Worker
89*795d594fSAndroid Build Coastguard Worker // Test with two intervals of the same range.
90*795d594fSAndroid Build Coastguard Worker {
91*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges[][2] = {{0, 42}};
92*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 0));
93*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges, arraysize(ranges), GetScopedAllocator(), 1));
94*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
95*795d594fSAndroid Build Coastguard Worker
96*795d594fSAndroid Build Coastguard Worker intervals[1]->SetRegister(0);
97*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(ValidateIntervals(intervals, codegen));
98*795d594fSAndroid Build Coastguard Worker intervals.clear();
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker // Test with two non-intersecting intervals.
102*795d594fSAndroid Build Coastguard Worker {
103*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges1[][2] = {{0, 42}};
104*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
105*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges2[][2] = {{42, 43}};
106*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
107*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
108*795d594fSAndroid Build Coastguard Worker
109*795d594fSAndroid Build Coastguard Worker intervals[1]->SetRegister(0);
110*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
111*795d594fSAndroid Build Coastguard Worker intervals.clear();
112*795d594fSAndroid Build Coastguard Worker }
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker // Test with two non-intersecting intervals, with one with a lifetime hole.
115*795d594fSAndroid Build Coastguard Worker {
116*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges1[][2] = {{0, 42}, {45, 48}};
117*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
118*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges2[][2] = {{42, 43}};
119*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
120*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker intervals[1]->SetRegister(0);
123*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
124*795d594fSAndroid Build Coastguard Worker intervals.clear();
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker
127*795d594fSAndroid Build Coastguard Worker // Test with intersecting intervals.
128*795d594fSAndroid Build Coastguard Worker {
129*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
130*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
131*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges2[][2] = {{42, 47}};
132*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
133*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker intervals[1]->SetRegister(0);
136*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(ValidateIntervals(intervals, codegen));
137*795d594fSAndroid Build Coastguard Worker intervals.clear();
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker
140*795d594fSAndroid Build Coastguard Worker // Test with siblings.
141*795d594fSAndroid Build Coastguard Worker {
142*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges1[][2] = {{0, 42}, {44, 48}};
143*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), 0));
144*795d594fSAndroid Build Coastguard Worker intervals[0]->SplitAt(43);
145*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges2[][2] = {{42, 47}};
146*795d594fSAndroid Build Coastguard Worker intervals.push_back(BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), 1));
147*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
148*795d594fSAndroid Build Coastguard Worker
149*795d594fSAndroid Build Coastguard Worker intervals[1]->SetRegister(0);
150*795d594fSAndroid Build Coastguard Worker // Sibling of the first interval has no register allocated to it.
151*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
152*795d594fSAndroid Build Coastguard Worker
153*795d594fSAndroid Build Coastguard Worker intervals[0]->GetNextSibling()->SetRegister(0);
154*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(ValidateIntervals(intervals, codegen));
155*795d594fSAndroid Build Coastguard Worker }
156*795d594fSAndroid Build Coastguard Worker }
157*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,CFG1)158*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, CFG1) {
159*795d594fSAndroid Build Coastguard Worker /*
160*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
161*795d594fSAndroid Build Coastguard Worker * return 0;
162*795d594fSAndroid Build Coastguard Worker *
163*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph:
164*795d594fSAndroid Build Coastguard Worker * constant0
165*795d594fSAndroid Build Coastguard Worker * goto
166*795d594fSAndroid Build Coastguard Worker * |
167*795d594fSAndroid Build Coastguard Worker * return
168*795d594fSAndroid Build Coastguard Worker * |
169*795d594fSAndroid Build Coastguard Worker * exit
170*795d594fSAndroid Build Coastguard Worker */
171*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
172*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
173*795d594fSAndroid Build Coastguard Worker Instruction::RETURN);
174*795d594fSAndroid Build Coastguard Worker
175*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(Check(data));
176*795d594fSAndroid Build Coastguard Worker }
177*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,Loop1)178*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, Loop1) {
179*795d594fSAndroid Build Coastguard Worker /*
180*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
181*795d594fSAndroid Build Coastguard Worker * int a = 0;
182*795d594fSAndroid Build Coastguard Worker * while (a == a) {
183*795d594fSAndroid Build Coastguard Worker * a = 4;
184*795d594fSAndroid Build Coastguard Worker * }
185*795d594fSAndroid Build Coastguard Worker * return 5;
186*795d594fSAndroid Build Coastguard Worker *
187*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph:
188*795d594fSAndroid Build Coastguard Worker * constant0
189*795d594fSAndroid Build Coastguard Worker * constant4
190*795d594fSAndroid Build Coastguard Worker * constant5
191*795d594fSAndroid Build Coastguard Worker * goto
192*795d594fSAndroid Build Coastguard Worker * |
193*795d594fSAndroid Build Coastguard Worker * goto
194*795d594fSAndroid Build Coastguard Worker * |
195*795d594fSAndroid Build Coastguard Worker * phi
196*795d594fSAndroid Build Coastguard Worker * equal
197*795d594fSAndroid Build Coastguard Worker * if +++++
198*795d594fSAndroid Build Coastguard Worker * | \ +
199*795d594fSAndroid Build Coastguard Worker * | goto
200*795d594fSAndroid Build Coastguard Worker * |
201*795d594fSAndroid Build Coastguard Worker * return
202*795d594fSAndroid Build Coastguard Worker * |
203*795d594fSAndroid Build Coastguard Worker * exit
204*795d594fSAndroid Build Coastguard Worker */
205*795d594fSAndroid Build Coastguard Worker
206*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
207*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
208*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ, 4,
209*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 0,
210*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFD00,
211*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 5 << 12 | 1 << 8,
212*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 1 << 8);
213*795d594fSAndroid Build Coastguard Worker
214*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(Check(data));
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,Loop2)217*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, Loop2) {
218*795d594fSAndroid Build Coastguard Worker /*
219*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
220*795d594fSAndroid Build Coastguard Worker * int a = 0;
221*795d594fSAndroid Build Coastguard Worker * while (a == 8) {
222*795d594fSAndroid Build Coastguard Worker * a = 4 + 5;
223*795d594fSAndroid Build Coastguard Worker * }
224*795d594fSAndroid Build Coastguard Worker * return 6 + 7;
225*795d594fSAndroid Build Coastguard Worker *
226*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph:
227*795d594fSAndroid Build Coastguard Worker * constant0
228*795d594fSAndroid Build Coastguard Worker * constant4
229*795d594fSAndroid Build Coastguard Worker * constant5
230*795d594fSAndroid Build Coastguard Worker * constant6
231*795d594fSAndroid Build Coastguard Worker * constant7
232*795d594fSAndroid Build Coastguard Worker * constant8
233*795d594fSAndroid Build Coastguard Worker * goto
234*795d594fSAndroid Build Coastguard Worker * |
235*795d594fSAndroid Build Coastguard Worker * goto
236*795d594fSAndroid Build Coastguard Worker * |
237*795d594fSAndroid Build Coastguard Worker * phi
238*795d594fSAndroid Build Coastguard Worker * equal
239*795d594fSAndroid Build Coastguard Worker * if +++++
240*795d594fSAndroid Build Coastguard Worker * | \ +
241*795d594fSAndroid Build Coastguard Worker * | 4 + 5
242*795d594fSAndroid Build Coastguard Worker * | goto
243*795d594fSAndroid Build Coastguard Worker * |
244*795d594fSAndroid Build Coastguard Worker * 6 + 7
245*795d594fSAndroid Build Coastguard Worker * return
246*795d594fSAndroid Build Coastguard Worker * |
247*795d594fSAndroid Build Coastguard Worker * exit
248*795d594fSAndroid Build Coastguard Worker */
249*795d594fSAndroid Build Coastguard Worker
250*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
251*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
252*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 8 << 12 | 1 << 8,
253*795d594fSAndroid Build Coastguard Worker Instruction::IF_EQ | 1 << 8, 7,
254*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 4 << 12 | 0 << 8,
255*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 5 << 12 | 1 << 8,
256*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT, 1 << 8 | 0,
257*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFA00,
258*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 6 << 12 | 1 << 8,
259*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 7 << 12 | 1 << 8,
260*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT, 1 << 8 | 0,
261*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 1 << 8);
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(Check(data));
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,Loop3)266*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, Loop3) {
267*795d594fSAndroid Build Coastguard Worker /*
268*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
269*795d594fSAndroid Build Coastguard Worker * int a = 0
270*795d594fSAndroid Build Coastguard Worker * do {
271*795d594fSAndroid Build Coastguard Worker * b = a;
272*795d594fSAndroid Build Coastguard Worker * a++;
273*795d594fSAndroid Build Coastguard Worker * } while (a != 5)
274*795d594fSAndroid Build Coastguard Worker * return b;
275*795d594fSAndroid Build Coastguard Worker *
276*795d594fSAndroid Build Coastguard Worker * Which becomes the following graph:
277*795d594fSAndroid Build Coastguard Worker * constant0
278*795d594fSAndroid Build Coastguard Worker * constant1
279*795d594fSAndroid Build Coastguard Worker * constant5
280*795d594fSAndroid Build Coastguard Worker * goto
281*795d594fSAndroid Build Coastguard Worker * |
282*795d594fSAndroid Build Coastguard Worker * goto
283*795d594fSAndroid Build Coastguard Worker * |++++++++++++
284*795d594fSAndroid Build Coastguard Worker * phi +
285*795d594fSAndroid Build Coastguard Worker * a++ +
286*795d594fSAndroid Build Coastguard Worker * equals +
287*795d594fSAndroid Build Coastguard Worker * if +
288*795d594fSAndroid Build Coastguard Worker * |++++++++++++
289*795d594fSAndroid Build Coastguard Worker * return
290*795d594fSAndroid Build Coastguard Worker * |
291*795d594fSAndroid Build Coastguard Worker * exit
292*795d594fSAndroid Build Coastguard Worker */
293*795d594fSAndroid Build Coastguard Worker
294*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
295*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
296*795d594fSAndroid Build Coastguard Worker Instruction::ADD_INT_LIT8 | 1 << 8, 1 << 8,
297*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 5 << 12 | 2 << 8,
298*795d594fSAndroid Build Coastguard Worker Instruction::IF_NE | 1 << 8 | 2 << 12, 3,
299*795d594fSAndroid Build Coastguard Worker Instruction::RETURN | 0 << 8,
300*795d594fSAndroid Build Coastguard Worker Instruction::MOVE | 1 << 12 | 0 << 8,
301*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xF900);
302*795d594fSAndroid Build Coastguard Worker
303*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
304*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
305*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
306*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
307*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
308*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
309*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
310*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(register_allocator->Validate(false));
311*795d594fSAndroid Build Coastguard Worker
312*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_header = graph->GetBlocks()[2];
313*795d594fSAndroid Build Coastguard Worker HPhi* phi = loop_header->GetFirstPhi()->AsPhi();
314*795d594fSAndroid Build Coastguard Worker
315*795d594fSAndroid Build Coastguard Worker LiveInterval* phi_interval = phi->GetLiveInterval();
316*795d594fSAndroid Build Coastguard Worker LiveInterval* loop_update = phi->InputAt(1)->GetLiveInterval();
317*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(phi_interval->HasRegister());
318*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(loop_update->HasRegister());
319*795d594fSAndroid Build Coastguard Worker ASSERT_NE(phi_interval->GetRegister(), loop_update->GetRegister());
320*795d594fSAndroid Build Coastguard Worker
321*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = graph->GetBlocks()[3];
322*795d594fSAndroid Build Coastguard Worker HReturn* ret = return_block->GetLastInstruction()->AsReturn();
323*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(phi_interval->GetRegister(), ret->InputAt(0)->GetLiveInterval()->GetRegister());
324*795d594fSAndroid Build Coastguard Worker }
325*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,FirstRegisterUse)326*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, FirstRegisterUse) {
327*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
328*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
329*795d594fSAndroid Build Coastguard Worker Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8,
330*795d594fSAndroid Build Coastguard Worker Instruction::XOR_INT_LIT8 | 0 << 8, 1 << 8,
331*795d594fSAndroid Build Coastguard Worker Instruction::XOR_INT_LIT8 | 1 << 8, 1 << 8 | 1,
332*795d594fSAndroid Build Coastguard Worker Instruction::RETURN_VOID);
333*795d594fSAndroid Build Coastguard Worker
334*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
335*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
336*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
337*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
338*795d594fSAndroid Build Coastguard Worker
339*795d594fSAndroid Build Coastguard Worker HXor* first_xor = graph->GetBlocks()[1]->GetFirstInstruction()->AsXor();
340*795d594fSAndroid Build Coastguard Worker HXor* last_xor = graph->GetBlocks()[1]->GetLastInstruction()->GetPrevious()->AsXor();
341*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(last_xor->InputAt(0), first_xor);
342*795d594fSAndroid Build Coastguard Worker LiveInterval* interval = first_xor->GetLiveInterval();
343*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(interval->GetEnd(), last_xor->GetLifetimePosition());
344*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(interval->GetNextSibling() == nullptr);
345*795d594fSAndroid Build Coastguard Worker
346*795d594fSAndroid Build Coastguard Worker // We need a register for the output of the instruction.
347*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(interval->FirstRegisterUse(), first_xor->GetLifetimePosition());
348*795d594fSAndroid Build Coastguard Worker
349*795d594fSAndroid Build Coastguard Worker // Split at the next instruction.
350*795d594fSAndroid Build Coastguard Worker interval = interval->SplitAt(first_xor->GetLifetimePosition() + 2);
351*795d594fSAndroid Build Coastguard Worker // The user of the split is the last add.
352*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
353*795d594fSAndroid Build Coastguard Worker
354*795d594fSAndroid Build Coastguard Worker // Split before the last add.
355*795d594fSAndroid Build Coastguard Worker LiveInterval* new_interval = interval->SplitAt(last_xor->GetLifetimePosition() - 1);
356*795d594fSAndroid Build Coastguard Worker // Ensure the current interval has no register use...
357*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(interval->FirstRegisterUse(), kNoLifetime);
358*795d594fSAndroid Build Coastguard Worker // And the new interval has it for the last add.
359*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(new_interval->FirstRegisterUse(), last_xor->GetLifetimePosition());
360*795d594fSAndroid Build Coastguard Worker }
361*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,DeadPhi)362*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, DeadPhi) {
363*795d594fSAndroid Build Coastguard Worker /* Test for a dead loop phi taking as back-edge input a phi that also has
364*795d594fSAndroid Build Coastguard Worker * this loop phi as input. Walking backwards in SsaDeadPhiElimination
365*795d594fSAndroid Build Coastguard Worker * does not solve the problem because the loop phi will be visited last.
366*795d594fSAndroid Build Coastguard Worker *
367*795d594fSAndroid Build Coastguard Worker * Test the following snippet:
368*795d594fSAndroid Build Coastguard Worker * int a = 0
369*795d594fSAndroid Build Coastguard Worker * do {
370*795d594fSAndroid Build Coastguard Worker * if (true) {
371*795d594fSAndroid Build Coastguard Worker * a = 2;
372*795d594fSAndroid Build Coastguard Worker * }
373*795d594fSAndroid Build Coastguard Worker * } while (true);
374*795d594fSAndroid Build Coastguard Worker */
375*795d594fSAndroid Build Coastguard Worker
376*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
377*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
378*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 1 << 8 | 0,
379*795d594fSAndroid Build Coastguard Worker Instruction::IF_NE | 1 << 8 | 1 << 12, 3,
380*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 2 << 12 | 0 << 8,
381*795d594fSAndroid Build Coastguard Worker Instruction::GOTO | 0xFD00,
382*795d594fSAndroid Build Coastguard Worker Instruction::RETURN_VOID);
383*795d594fSAndroid Build Coastguard Worker
384*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
385*795d594fSAndroid Build Coastguard Worker SsaDeadPhiElimination(graph).Run();
386*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
387*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
388*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
389*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
390*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
391*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
392*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(register_allocator->Validate(false));
393*795d594fSAndroid Build Coastguard Worker }
394*795d594fSAndroid Build Coastguard Worker
395*795d594fSAndroid Build Coastguard Worker /**
396*795d594fSAndroid Build Coastguard Worker * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
397*795d594fSAndroid Build Coastguard Worker * that share the same register. It should split the interval it is currently
398*795d594fSAndroid Build Coastguard Worker * allocating for at the minimum lifetime position between the two inactive intervals.
399*795d594fSAndroid Build Coastguard Worker * This test only applies to the linear scan allocator.
400*795d594fSAndroid Build Coastguard Worker */
TEST_F(RegisterAllocatorTest,FreeUntil)401*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, FreeUntil) {
402*795d594fSAndroid Build Coastguard Worker const std::vector<uint16_t> data = TWO_REGISTERS_CODE_ITEM(
403*795d594fSAndroid Build Coastguard Worker Instruction::CONST_4 | 0 | 0,
404*795d594fSAndroid Build Coastguard Worker Instruction::RETURN);
405*795d594fSAndroid Build Coastguard Worker
406*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateCFG(data);
407*795d594fSAndroid Build Coastguard Worker SsaDeadPhiElimination(graph).Run();
408*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
409*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
410*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
411*795d594fSAndroid Build Coastguard Worker RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
412*795d594fSAndroid Build Coastguard Worker
413*795d594fSAndroid Build Coastguard Worker // Add an artifical range to cover the temps that will be put in the unhandled list.
414*795d594fSAndroid Build Coastguard Worker LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
415*795d594fSAndroid Build Coastguard Worker unhandled->AddLoopRange(0, 60);
416*795d594fSAndroid Build Coastguard Worker
417*795d594fSAndroid Build Coastguard Worker // Populate the instructions in the liveness object, to please the register allocator.
418*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < 60; ++i) {
419*795d594fSAndroid Build Coastguard Worker liveness.instructions_from_lifetime_position_.push_back(
420*795d594fSAndroid Build Coastguard Worker graph->GetEntryBlock()->GetFirstInstruction());
421*795d594fSAndroid Build Coastguard Worker }
422*795d594fSAndroid Build Coastguard Worker
423*795d594fSAndroid Build Coastguard Worker // For SSA value intervals, only an interval resulted from a split may intersect
424*795d594fSAndroid Build Coastguard Worker // with inactive intervals.
425*795d594fSAndroid Build Coastguard Worker unhandled = register_allocator.Split(unhandled, 5);
426*795d594fSAndroid Build Coastguard Worker
427*795d594fSAndroid Build Coastguard Worker // Add three temps holding the same register, and starting at different positions.
428*795d594fSAndroid Build Coastguard Worker // Put the one that should be picked in the middle of the inactive list to ensure
429*795d594fSAndroid Build Coastguard Worker // we do not depend on an order.
430*795d594fSAndroid Build Coastguard Worker LiveInterval* interval =
431*795d594fSAndroid Build Coastguard Worker LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
432*795d594fSAndroid Build Coastguard Worker interval->AddRange(40, 50);
433*795d594fSAndroid Build Coastguard Worker register_allocator.inactive_.push_back(interval);
434*795d594fSAndroid Build Coastguard Worker
435*795d594fSAndroid Build Coastguard Worker interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
436*795d594fSAndroid Build Coastguard Worker interval->AddRange(20, 30);
437*795d594fSAndroid Build Coastguard Worker register_allocator.inactive_.push_back(interval);
438*795d594fSAndroid Build Coastguard Worker
439*795d594fSAndroid Build Coastguard Worker interval = LiveInterval::MakeFixedInterval(GetScopedAllocator(), 0, DataType::Type::kInt32);
440*795d594fSAndroid Build Coastguard Worker interval->AddRange(60, 70);
441*795d594fSAndroid Build Coastguard Worker register_allocator.inactive_.push_back(interval);
442*795d594fSAndroid Build Coastguard Worker
443*795d594fSAndroid Build Coastguard Worker register_allocator.number_of_registers_ = 1;
444*795d594fSAndroid Build Coastguard Worker register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
445*795d594fSAndroid Build Coastguard Worker register_allocator.current_register_type_ = RegisterAllocator::RegisterType::kCoreRegister;
446*795d594fSAndroid Build Coastguard Worker register_allocator.unhandled_ = ®ister_allocator.unhandled_core_intervals_;
447*795d594fSAndroid Build Coastguard Worker
448*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(register_allocator.TryAllocateFreeReg(unhandled));
449*795d594fSAndroid Build Coastguard Worker
450*795d594fSAndroid Build Coastguard Worker // Check that we have split the interval.
451*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(1u, register_allocator.unhandled_->size());
452*795d594fSAndroid Build Coastguard Worker // Check that we know need to find a new register where the next interval
453*795d594fSAndroid Build Coastguard Worker // that uses the register starts.
454*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(20u, register_allocator.unhandled_->front()->GetStart());
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker
BuildIfElseWithPhi(HPhi ** phi,HInstruction ** input1,HInstruction ** input2)457*795d594fSAndroid Build Coastguard Worker HGraph* RegisterAllocatorTest::BuildIfElseWithPhi(HPhi** phi,
458*795d594fSAndroid Build Coastguard Worker HInstruction** input1,
459*795d594fSAndroid Build Coastguard Worker HInstruction** input2) {
460*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph();
461*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
462*795d594fSAndroid Build Coastguard Worker graph->AddBlock(entry);
463*795d594fSAndroid Build Coastguard Worker graph->SetEntryBlock(entry);
464*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
465*795d594fSAndroid Build Coastguard Worker
466*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
467*795d594fSAndroid Build Coastguard Worker graph->AddBlock(block);
468*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block);
469*795d594fSAndroid Build Coastguard Worker
470*795d594fSAndroid Build Coastguard Worker HInstruction* test = MakeIFieldGet(block, parameter, DataType::Type::kBool, MemberOffset(22));
471*795d594fSAndroid Build Coastguard Worker MakeIf(block, test);
472*795d594fSAndroid Build Coastguard Worker
473*795d594fSAndroid Build Coastguard Worker HBasicBlock* then = new (GetAllocator()) HBasicBlock(graph);
474*795d594fSAndroid Build Coastguard Worker HBasicBlock* else_ = new (GetAllocator()) HBasicBlock(graph);
475*795d594fSAndroid Build Coastguard Worker HBasicBlock* join = new (GetAllocator()) HBasicBlock(graph);
476*795d594fSAndroid Build Coastguard Worker graph->AddBlock(then);
477*795d594fSAndroid Build Coastguard Worker graph->AddBlock(else_);
478*795d594fSAndroid Build Coastguard Worker graph->AddBlock(join);
479*795d594fSAndroid Build Coastguard Worker
480*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(then);
481*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(else_);
482*795d594fSAndroid Build Coastguard Worker then->AddSuccessor(join);
483*795d594fSAndroid Build Coastguard Worker else_->AddSuccessor(join);
484*795d594fSAndroid Build Coastguard Worker MakeGoto(then);
485*795d594fSAndroid Build Coastguard Worker MakeGoto(else_);
486*795d594fSAndroid Build Coastguard Worker
487*795d594fSAndroid Build Coastguard Worker *input1 = MakeIFieldGet(then, parameter, DataType::Type::kInt32, MemberOffset(42));
488*795d594fSAndroid Build Coastguard Worker *input2 = MakeIFieldGet(else_, parameter, DataType::Type::kInt32, MemberOffset(42));
489*795d594fSAndroid Build Coastguard Worker
490*795d594fSAndroid Build Coastguard Worker *phi = MakePhi(join, {*input1, *input2});
491*795d594fSAndroid Build Coastguard Worker MakeExit(join);
492*795d594fSAndroid Build Coastguard Worker
493*795d594fSAndroid Build Coastguard Worker graph->BuildDominatorTree();
494*795d594fSAndroid Build Coastguard Worker graph->AnalyzeLoops();
495*795d594fSAndroid Build Coastguard Worker return graph;
496*795d594fSAndroid Build Coastguard Worker }
497*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,PhiHint)498*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, PhiHint) {
499*795d594fSAndroid Build Coastguard Worker HPhi *phi;
500*795d594fSAndroid Build Coastguard Worker HInstruction *input1, *input2;
501*795d594fSAndroid Build Coastguard Worker
502*795d594fSAndroid Build Coastguard Worker {
503*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
504*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
505*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
506*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
507*795d594fSAndroid Build Coastguard Worker
508*795d594fSAndroid Build Coastguard Worker // Check that the register allocator is deterministic.
509*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
510*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
511*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
512*795d594fSAndroid Build Coastguard Worker
513*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 0);
514*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 0);
515*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 0);
516*795d594fSAndroid Build Coastguard Worker }
517*795d594fSAndroid Build Coastguard Worker
518*795d594fSAndroid Build Coastguard Worker {
519*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
520*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
521*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
522*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
523*795d594fSAndroid Build Coastguard Worker
524*795d594fSAndroid Build Coastguard Worker // Set the phi to a specific register, and check that the inputs get allocated
525*795d594fSAndroid Build Coastguard Worker // the same register.
526*795d594fSAndroid Build Coastguard Worker phi->GetLocations()->UpdateOut(Location::RegisterLocation(2));
527*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
528*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
529*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
530*795d594fSAndroid Build Coastguard Worker
531*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
532*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
533*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
534*795d594fSAndroid Build Coastguard Worker }
535*795d594fSAndroid Build Coastguard Worker
536*795d594fSAndroid Build Coastguard Worker {
537*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
538*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
539*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
540*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
541*795d594fSAndroid Build Coastguard Worker
542*795d594fSAndroid Build Coastguard Worker // Set input1 to a specific register, and check that the phi and other input get allocated
543*795d594fSAndroid Build Coastguard Worker // the same register.
544*795d594fSAndroid Build Coastguard Worker input1->GetLocations()->UpdateOut(Location::RegisterLocation(2));
545*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
546*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
547*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
548*795d594fSAndroid Build Coastguard Worker
549*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
550*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
551*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
552*795d594fSAndroid Build Coastguard Worker }
553*795d594fSAndroid Build Coastguard Worker
554*795d594fSAndroid Build Coastguard Worker {
555*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildIfElseWithPhi(&phi, &input1, &input2);
556*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
557*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
558*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
559*795d594fSAndroid Build Coastguard Worker
560*795d594fSAndroid Build Coastguard Worker // Set input2 to a specific register, and check that the phi and other input get allocated
561*795d594fSAndroid Build Coastguard Worker // the same register.
562*795d594fSAndroid Build Coastguard Worker input2->GetLocations()->UpdateOut(Location::RegisterLocation(2));
563*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
564*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
565*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
566*795d594fSAndroid Build Coastguard Worker
567*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input1->GetLiveInterval()->GetRegister(), 2);
568*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(input2->GetLiveInterval()->GetRegister(), 2);
569*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(phi->GetLiveInterval()->GetRegister(), 2);
570*795d594fSAndroid Build Coastguard Worker }
571*795d594fSAndroid Build Coastguard Worker }
572*795d594fSAndroid Build Coastguard Worker
BuildFieldReturn(HInstruction ** field,HInstruction ** ret)573*795d594fSAndroid Build Coastguard Worker HGraph* RegisterAllocatorTest::BuildFieldReturn(HInstruction** field, HInstruction** ret) {
574*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph();
575*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
576*795d594fSAndroid Build Coastguard Worker graph->AddBlock(entry);
577*795d594fSAndroid Build Coastguard Worker graph->SetEntryBlock(entry);
578*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
579*795d594fSAndroid Build Coastguard Worker
580*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
581*795d594fSAndroid Build Coastguard Worker graph->AddBlock(block);
582*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block);
583*795d594fSAndroid Build Coastguard Worker
584*795d594fSAndroid Build Coastguard Worker *field = MakeIFieldGet(block, parameter, DataType::Type::kInt32, MemberOffset(42));
585*795d594fSAndroid Build Coastguard Worker *ret = MakeReturn(block, *field);
586*795d594fSAndroid Build Coastguard Worker
587*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph);
588*795d594fSAndroid Build Coastguard Worker graph->AddBlock(exit);
589*795d594fSAndroid Build Coastguard Worker block->AddSuccessor(exit);
590*795d594fSAndroid Build Coastguard Worker MakeExit(exit);
591*795d594fSAndroid Build Coastguard Worker
592*795d594fSAndroid Build Coastguard Worker graph->BuildDominatorTree();
593*795d594fSAndroid Build Coastguard Worker return graph;
594*795d594fSAndroid Build Coastguard Worker }
595*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,ExpectedInRegisterHint)596*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, ExpectedInRegisterHint) {
597*795d594fSAndroid Build Coastguard Worker HInstruction *field, *ret;
598*795d594fSAndroid Build Coastguard Worker
599*795d594fSAndroid Build Coastguard Worker {
600*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildFieldReturn(&field, &ret);
601*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
602*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
603*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
604*795d594fSAndroid Build Coastguard Worker
605*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
606*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
607*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker // Check the validity that in normal conditions, the register should be hinted to 0 (EAX).
610*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 0);
611*795d594fSAndroid Build Coastguard Worker }
612*795d594fSAndroid Build Coastguard Worker
613*795d594fSAndroid Build Coastguard Worker {
614*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildFieldReturn(&field, &ret);
615*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
616*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
617*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
618*795d594fSAndroid Build Coastguard Worker
619*795d594fSAndroid Build Coastguard Worker // Check that the field gets put in the register expected by its use.
620*795d594fSAndroid Build Coastguard Worker // Don't use SetInAt because we are overriding an already allocated location.
621*795d594fSAndroid Build Coastguard Worker ret->GetLocations()->inputs_[0] = Location::RegisterLocation(2);
622*795d594fSAndroid Build Coastguard Worker
623*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
624*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
625*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
626*795d594fSAndroid Build Coastguard Worker
627*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(field->GetLiveInterval()->GetRegister(), 2);
628*795d594fSAndroid Build Coastguard Worker }
629*795d594fSAndroid Build Coastguard Worker }
630*795d594fSAndroid Build Coastguard Worker
BuildTwoSubs(HInstruction ** first_sub,HInstruction ** second_sub)631*795d594fSAndroid Build Coastguard Worker HGraph* RegisterAllocatorTest::BuildTwoSubs(HInstruction** first_sub, HInstruction** second_sub) {
632*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph();
633*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
634*795d594fSAndroid Build Coastguard Worker graph->AddBlock(entry);
635*795d594fSAndroid Build Coastguard Worker graph->SetEntryBlock(entry);
636*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kInt32);
637*795d594fSAndroid Build Coastguard Worker
638*795d594fSAndroid Build Coastguard Worker HInstruction* constant1 = graph->GetIntConstant(1);
639*795d594fSAndroid Build Coastguard Worker HInstruction* constant2 = graph->GetIntConstant(2);
640*795d594fSAndroid Build Coastguard Worker
641*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
642*795d594fSAndroid Build Coastguard Worker graph->AddBlock(block);
643*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block);
644*795d594fSAndroid Build Coastguard Worker
645*795d594fSAndroid Build Coastguard Worker *first_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, parameter, constant1);
646*795d594fSAndroid Build Coastguard Worker block->AddInstruction(*first_sub);
647*795d594fSAndroid Build Coastguard Worker *second_sub = new (GetAllocator()) HSub(DataType::Type::kInt32, *first_sub, constant2);
648*795d594fSAndroid Build Coastguard Worker block->AddInstruction(*second_sub);
649*795d594fSAndroid Build Coastguard Worker
650*795d594fSAndroid Build Coastguard Worker MakeExit(block);
651*795d594fSAndroid Build Coastguard Worker
652*795d594fSAndroid Build Coastguard Worker graph->BuildDominatorTree();
653*795d594fSAndroid Build Coastguard Worker return graph;
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,SameAsFirstInputHint)656*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, SameAsFirstInputHint) {
657*795d594fSAndroid Build Coastguard Worker HInstruction *first_sub, *second_sub;
658*795d594fSAndroid Build Coastguard Worker
659*795d594fSAndroid Build Coastguard Worker {
660*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
661*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
662*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
663*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
664*795d594fSAndroid Build Coastguard Worker
665*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
666*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
667*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
668*795d594fSAndroid Build Coastguard Worker
669*795d594fSAndroid Build Coastguard Worker // Check the validity that in normal conditions, the registers are the same.
670*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 1);
671*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 1);
672*795d594fSAndroid Build Coastguard Worker }
673*795d594fSAndroid Build Coastguard Worker
674*795d594fSAndroid Build Coastguard Worker {
675*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildTwoSubs(&first_sub, &second_sub);
676*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
677*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
678*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
679*795d594fSAndroid Build Coastguard Worker
680*795d594fSAndroid Build Coastguard Worker // check that both adds get the same register.
681*795d594fSAndroid Build Coastguard Worker // Don't use UpdateOutput because output is already allocated.
682*795d594fSAndroid Build Coastguard Worker first_sub->InputAt(0)->GetLocations()->output_ = Location::RegisterLocation(2);
683*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(first_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
684*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(second_sub->GetLocations()->Out().GetPolicy(), Location::kSameAsFirstInput);
685*795d594fSAndroid Build Coastguard Worker
686*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
687*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
688*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
689*795d594fSAndroid Build Coastguard Worker
690*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(first_sub->GetLiveInterval()->GetRegister(), 2);
691*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(second_sub->GetLiveInterval()->GetRegister(), 2);
692*795d594fSAndroid Build Coastguard Worker }
693*795d594fSAndroid Build Coastguard Worker }
694*795d594fSAndroid Build Coastguard Worker
BuildDiv(HInstruction ** div)695*795d594fSAndroid Build Coastguard Worker HGraph* RegisterAllocatorTest::BuildDiv(HInstruction** div) {
696*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph();
697*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
698*795d594fSAndroid Build Coastguard Worker graph->AddBlock(entry);
699*795d594fSAndroid Build Coastguard Worker graph->SetEntryBlock(entry);
700*795d594fSAndroid Build Coastguard Worker HInstruction* first = MakeParam(DataType::Type::kInt32);
701*795d594fSAndroid Build Coastguard Worker HInstruction* second = MakeParam(DataType::Type::kInt32);
702*795d594fSAndroid Build Coastguard Worker
703*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
704*795d594fSAndroid Build Coastguard Worker graph->AddBlock(block);
705*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block);
706*795d594fSAndroid Build Coastguard Worker
707*795d594fSAndroid Build Coastguard Worker *div = new (GetAllocator()) HDiv(
708*795d594fSAndroid Build Coastguard Worker DataType::Type::kInt32, first, second, 0); // don't care about dex_pc.
709*795d594fSAndroid Build Coastguard Worker block->AddInstruction(*div);
710*795d594fSAndroid Build Coastguard Worker
711*795d594fSAndroid Build Coastguard Worker MakeExit(block);
712*795d594fSAndroid Build Coastguard Worker
713*795d594fSAndroid Build Coastguard Worker graph->BuildDominatorTree();
714*795d594fSAndroid Build Coastguard Worker return graph;
715*795d594fSAndroid Build Coastguard Worker }
716*795d594fSAndroid Build Coastguard Worker
TEST_F(RegisterAllocatorTest,ExpectedExactInRegisterAndSameOutputHint)717*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, ExpectedExactInRegisterAndSameOutputHint) {
718*795d594fSAndroid Build Coastguard Worker HInstruction *div;
719*795d594fSAndroid Build Coastguard Worker HGraph* graph = BuildDiv(&div);
720*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
721*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
722*795d594fSAndroid Build Coastguard Worker liveness.Analyze();
723*795d594fSAndroid Build Coastguard Worker
724*795d594fSAndroid Build Coastguard Worker std::unique_ptr<RegisterAllocator> register_allocator =
725*795d594fSAndroid Build Coastguard Worker RegisterAllocator::Create(GetScopedAllocator(), &codegen, liveness);
726*795d594fSAndroid Build Coastguard Worker register_allocator->AllocateRegisters();
727*795d594fSAndroid Build Coastguard Worker
728*795d594fSAndroid Build Coastguard Worker // div on x86 requires its first input in eax and the output be the same as the first input.
729*795d594fSAndroid Build Coastguard Worker ASSERT_EQ(div->GetLiveInterval()->GetRegister(), 0);
730*795d594fSAndroid Build Coastguard Worker }
731*795d594fSAndroid Build Coastguard Worker
732*795d594fSAndroid Build Coastguard Worker // Test a bug in the register allocator, where allocating a blocked
733*795d594fSAndroid Build Coastguard Worker // register would lead to spilling an inactive interval at the wrong
734*795d594fSAndroid Build Coastguard Worker // position.
735*795d594fSAndroid Build Coastguard Worker // This test only applies to the linear scan allocator.
TEST_F(RegisterAllocatorTest,SpillInactive)736*795d594fSAndroid Build Coastguard Worker TEST_F(RegisterAllocatorTest, SpillInactive) {
737*795d594fSAndroid Build Coastguard Worker // Create a synthesized graph to please the register_allocator and
738*795d594fSAndroid Build Coastguard Worker // ssa_liveness_analysis code.
739*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph();
740*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
741*795d594fSAndroid Build Coastguard Worker graph->AddBlock(entry);
742*795d594fSAndroid Build Coastguard Worker graph->SetEntryBlock(entry);
743*795d594fSAndroid Build Coastguard Worker HInstruction* one = MakeParam(DataType::Type::kInt32);
744*795d594fSAndroid Build Coastguard Worker HInstruction* two = MakeParam(DataType::Type::kInt32);
745*795d594fSAndroid Build Coastguard Worker HInstruction* three = MakeParam(DataType::Type::kInt32);
746*795d594fSAndroid Build Coastguard Worker HInstruction* four = MakeParam(DataType::Type::kInt32);
747*795d594fSAndroid Build Coastguard Worker
748*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph);
749*795d594fSAndroid Build Coastguard Worker graph->AddBlock(block);
750*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block);
751*795d594fSAndroid Build Coastguard Worker MakeExit(block);
752*795d594fSAndroid Build Coastguard Worker
753*795d594fSAndroid Build Coastguard Worker // We create a synthesized user requesting a register, to avoid just spilling the
754*795d594fSAndroid Build Coastguard Worker // intervals.
755*795d594fSAndroid Build Coastguard Worker HPhi* user = new (GetAllocator()) HPhi(GetAllocator(), 0, 1, DataType::Type::kInt32);
756*795d594fSAndroid Build Coastguard Worker user->SetBlock(block);
757*795d594fSAndroid Build Coastguard Worker user->AddInput(one);
758*795d594fSAndroid Build Coastguard Worker LocationSummary* locations = new (GetAllocator()) LocationSummary(user, LocationSummary::kNoCall);
759*795d594fSAndroid Build Coastguard Worker locations->SetInAt(0, Location::RequiresRegister());
760*795d594fSAndroid Build Coastguard Worker static constexpr size_t phi_ranges[][2] = {{20, 30}};
761*795d594fSAndroid Build Coastguard Worker BuildInterval(phi_ranges, arraysize(phi_ranges), GetScopedAllocator(), -1, user);
762*795d594fSAndroid Build Coastguard Worker
763*795d594fSAndroid Build Coastguard Worker // Create an interval with lifetime holes.
764*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges1[][2] = {{0, 2}, {4, 6}, {8, 10}};
765*795d594fSAndroid Build Coastguard Worker LiveInterval* first = BuildInterval(ranges1, arraysize(ranges1), GetScopedAllocator(), -1, one);
766*795d594fSAndroid Build Coastguard Worker first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 8));
767*795d594fSAndroid Build Coastguard Worker first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 7));
768*795d594fSAndroid Build Coastguard Worker first->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 6));
769*795d594fSAndroid Build Coastguard Worker
770*795d594fSAndroid Build Coastguard Worker locations = new (GetAllocator()) LocationSummary(first->GetDefinedBy(), LocationSummary::kNoCall);
771*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
772*795d594fSAndroid Build Coastguard Worker first = first->SplitAt(1);
773*795d594fSAndroid Build Coastguard Worker
774*795d594fSAndroid Build Coastguard Worker // Create an interval that conflicts with the next interval, to force the next
775*795d594fSAndroid Build Coastguard Worker // interval to call `AllocateBlockedReg`.
776*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges2[][2] = {{2, 4}};
777*795d594fSAndroid Build Coastguard Worker LiveInterval* second = BuildInterval(ranges2, arraysize(ranges2), GetScopedAllocator(), -1, two);
778*795d594fSAndroid Build Coastguard Worker locations =
779*795d594fSAndroid Build Coastguard Worker new (GetAllocator()) LocationSummary(second->GetDefinedBy(), LocationSummary::kNoCall);
780*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
781*795d594fSAndroid Build Coastguard Worker
782*795d594fSAndroid Build Coastguard Worker // Create an interval that will lead to splitting the first interval. The bug occured
783*795d594fSAndroid Build Coastguard Worker // by splitting at a wrong position, in this case at the next intersection between
784*795d594fSAndroid Build Coastguard Worker // this interval and the first interval. We would have then put the interval with ranges
785*795d594fSAndroid Build Coastguard Worker // "[0, 2(, [4, 6(" in the list of handled intervals, even though we haven't processed intervals
786*795d594fSAndroid Build Coastguard Worker // before lifetime position 6 yet.
787*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges3[][2] = {{2, 4}, {8, 10}};
788*795d594fSAndroid Build Coastguard Worker LiveInterval* third = BuildInterval(ranges3, arraysize(ranges3), GetScopedAllocator(), -1, three);
789*795d594fSAndroid Build Coastguard Worker third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 8));
790*795d594fSAndroid Build Coastguard Worker third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 4));
791*795d594fSAndroid Build Coastguard Worker third->uses_.push_front(*new (GetScopedAllocator()) UsePosition(user, 0u, 3));
792*795d594fSAndroid Build Coastguard Worker locations = new (GetAllocator()) LocationSummary(third->GetDefinedBy(), LocationSummary::kNoCall);
793*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
794*795d594fSAndroid Build Coastguard Worker third = third->SplitAt(3);
795*795d594fSAndroid Build Coastguard Worker
796*795d594fSAndroid Build Coastguard Worker // Because the first part of the split interval was considered handled, this interval
797*795d594fSAndroid Build Coastguard Worker // was free to allocate the same register, even though it conflicts with it.
798*795d594fSAndroid Build Coastguard Worker static constexpr size_t ranges4[][2] = {{4, 6}};
799*795d594fSAndroid Build Coastguard Worker LiveInterval* fourth = BuildInterval(ranges4, arraysize(ranges4), GetScopedAllocator(), -1, four);
800*795d594fSAndroid Build Coastguard Worker locations =
801*795d594fSAndroid Build Coastguard Worker new (GetAllocator()) LocationSummary(fourth->GetDefinedBy(), LocationSummary::kNoCall);
802*795d594fSAndroid Build Coastguard Worker locations->SetOut(Location::RequiresRegister());
803*795d594fSAndroid Build Coastguard Worker
804*795d594fSAndroid Build Coastguard Worker x86::CodeGeneratorX86 codegen(graph, *compiler_options_);
805*795d594fSAndroid Build Coastguard Worker SsaLivenessAnalysis liveness(graph, &codegen, GetScopedAllocator());
806*795d594fSAndroid Build Coastguard Worker // Populate the instructions in the liveness object, to please the register allocator.
807*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < 32; ++i) {
808*795d594fSAndroid Build Coastguard Worker liveness.instructions_from_lifetime_position_.push_back(user);
809*795d594fSAndroid Build Coastguard Worker }
810*795d594fSAndroid Build Coastguard Worker
811*795d594fSAndroid Build Coastguard Worker RegisterAllocatorLinearScan register_allocator(GetScopedAllocator(), &codegen, liveness);
812*795d594fSAndroid Build Coastguard Worker register_allocator.unhandled_core_intervals_.push_back(fourth);
813*795d594fSAndroid Build Coastguard Worker register_allocator.unhandled_core_intervals_.push_back(third);
814*795d594fSAndroid Build Coastguard Worker register_allocator.unhandled_core_intervals_.push_back(second);
815*795d594fSAndroid Build Coastguard Worker register_allocator.unhandled_core_intervals_.push_back(first);
816*795d594fSAndroid Build Coastguard Worker
817*795d594fSAndroid Build Coastguard Worker // Set just one register available to make all intervals compete for the same.
818*795d594fSAndroid Build Coastguard Worker register_allocator.number_of_registers_ = 1;
819*795d594fSAndroid Build Coastguard Worker register_allocator.registers_array_ = GetAllocator()->AllocArray<size_t>(1);
820*795d594fSAndroid Build Coastguard Worker register_allocator.current_register_type_ = RegisterAllocator::RegisterType::kCoreRegister;
821*795d594fSAndroid Build Coastguard Worker register_allocator.unhandled_ = ®ister_allocator.unhandled_core_intervals_;
822*795d594fSAndroid Build Coastguard Worker register_allocator.LinearScan();
823*795d594fSAndroid Build Coastguard Worker
824*795d594fSAndroid Build Coastguard Worker // Test that there is no conflicts between intervals.
825*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<LiveInterval*> intervals(GetScopedAllocator()->Adapter());
826*795d594fSAndroid Build Coastguard Worker intervals.push_back(first);
827*795d594fSAndroid Build Coastguard Worker intervals.push_back(second);
828*795d594fSAndroid Build Coastguard Worker intervals.push_back(third);
829*795d594fSAndroid Build Coastguard Worker intervals.push_back(fourth);
830*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(ValidateIntervals(intervals, codegen));
831*795d594fSAndroid Build Coastguard Worker }
832*795d594fSAndroid Build Coastguard Worker
833*795d594fSAndroid Build Coastguard Worker } // namespace art
834