1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "src/compiler/pipeline.h"
6 #include "test/unittests/compiler/instruction-sequence-unittest.h"
12 class RegisterAllocatorTest : public InstructionSequenceTest {
16 Pipeline::AllocateRegistersForTesting(config(), sequence(), true);
21 TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
24 auto a_reg = Parameter();
25 auto b_reg = Parameter();
26 auto c_reg = EmitOI(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
34 TEST_F(RegisterAllocatorTest, SimpleLoop) {
36 // while(true) { i++ }
38 auto i_reg = DefineConstant();
45 auto phi = Phi(i_reg, 2);
46 auto ipp = EmitOI(Same(), Reg(phi), Use(DefineConstant()));
47 SetInput(phi, 1, ipp);
57 TEST_F(RegisterAllocatorTest, SimpleBranch) {
60 auto i = DefineConstant();
61 EndBlock(Branch(Reg(i), 1, 2));
64 Return(DefineConstant());
68 Return(DefineConstant());
75 TEST_F(RegisterAllocatorTest, SimpleDiamond) {
76 // return p0 ? p0 : p0
78 auto param = Parameter();
79 EndBlock(Branch(Reg(param), 1, 2));
95 TEST_F(RegisterAllocatorTest, SimpleDiamondPhi) {
98 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
101 auto t_val = DefineConstant();
105 auto f_val = DefineConstant();
109 Return(Reg(Phi(t_val, f_val)));
116 TEST_F(RegisterAllocatorTest, DiamondManyPhis) {
117 const int kPhis = kDefaultNRegs * 2;
120 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
124 for (int i = 0; i < kPhis; ++i) {
125 t_vals[i] = DefineConstant();
131 for (int i = 0; i < kPhis; ++i) {
132 f_vals[i] = DefineConstant();
137 TestOperand merged[kPhis];
138 for (int i = 0; i < kPhis; ++i) {
139 merged[i] = Use(Phi(t_vals[i], f_vals[i]));
141 Return(EmitCall(Slot(-1), kPhis, merged));
148 TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
149 const int kPhis = kDefaultNRegs * 2;
154 for (int i = 0; i < kPhis; ++i) {
155 vals[i] = Parameter(Slot(-1 - i));
157 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
167 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
176 TestOperand merged[kPhis];
177 for (int i = 0; i < kPhis; ++i) {
178 merged[i] = Use(Phi(vals[i], vals[i]));
180 Return(EmitCall(Reg(0), kPhis, merged));
187 TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
188 const size_t kNumRegs = 3;
189 const size_t kParams = kNumRegs + 1;
190 // Override number of registers.
191 SetNumRegs(kNumRegs, kNumRegs);
194 auto constant = DefineConstant();
195 VReg parameters[kParams];
196 for (size_t i = 0; i < arraysize(parameters); ++i) {
197 parameters[i] = DefineConstant();
201 PhiInstruction* phis[kParams];
208 for (size_t i = 0; i < arraysize(parameters); ++i) {
209 phis[i] = Phi(parameters[i], 2);
212 // Perform some computations.
213 // something like phi[i] += const
214 for (size_t i = 0; i < arraysize(parameters); ++i) {
215 auto result = EmitOI(Same(), Reg(phis[i]), Use(constant));
216 SetInput(phis[i], 1, result);
219 EndBlock(Branch(Reg(DefineConstant()), 1, 2));
221 // Jump back to loop header.
229 Return(DefineConstant());
236 TEST_F(RegisterAllocatorTest, SpillPhi) {
238 EndBlock(Branch(Imm(), 1, 2));
241 auto left = Define(Reg(0));
245 auto right = Define(Reg(0));
249 auto phi = Phi(left, right);
258 TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) {
260 VReg constants[kDefaultNRegs];
261 for (size_t i = 0; i < arraysize(constants); ++i) {
262 constants[i] = DefineConstant();
264 TestOperand call_ops[kDefaultNRegs * 2];
265 for (int i = 0; i < kDefaultNRegs; ++i) {
266 call_ops[i] = Reg(constants[i], i);
268 for (int i = 0; i < kDefaultNRegs; ++i) {
269 call_ops[i + kDefaultNRegs] = Slot(constants[i], i);
271 EmitCall(Slot(-1), arraysize(call_ops), call_ops);
278 TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
279 const int kNumRegs = 6;
280 SetNumRegs(kNumRegs, kNumRegs);
284 // Stack parameters/spilled values.
285 auto p_0 = Define(Slot(-1));
286 auto p_1 = Define(Slot(-2));
289 VReg values[kNumRegs];
290 for (size_t i = 0; i < arraysize(values); ++i) {
291 values[i] = Define(Reg(static_cast<int>(i)));
294 // values[0] will be split in the second half of this instruction.
295 // Models Intel mod instructions.
296 EmitOI(Reg(0), Reg(p_0, 1), UniqueReg(p_1));
297 EmitI(Reg(values[0], 0));
304 TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
307 EndBlock(Branch(Imm(), 1, 5));
311 EndBlock(Branch(Imm(), 1, 2));
314 auto ll = Define(Reg());
318 auto lr = Define(Reg());
322 auto l_phi = Phi(ll, lr);
327 EndBlock(Branch(Imm(), 1, 2));
330 auto rl = Define(Reg());
334 auto rr = Define(Reg());
338 auto r_phi = Phi(rl, rr);
341 // Outer diamond merge.
343 auto phi = Phi(l_phi, r_phi);
351 TEST_F(RegisterAllocatorTest, NestedDiamondPhiMergeDifferent) {
354 EndBlock(Branch(Imm(), 1, 5));
358 EndBlock(Branch(Imm(), 1, 2));
361 auto ll = Define(Reg(0));
365 auto lr = Define(Reg(1));
369 auto l_phi = Phi(ll, lr);
374 EndBlock(Branch(Imm(), 1, 2));
377 auto rl = Define(Reg(2));
381 auto rr = Define(Reg(3));
385 auto r_phi = Phi(rl, rr);
388 // Outer diamond merge.
390 auto phi = Phi(l_phi, r_phi);
398 TEST_F(RegisterAllocatorTest, RegressionSplitBeforeAndMove) {
402 VReg values[kDefaultNRegs];
403 for (size_t i = 0; i < arraysize(values); ++i) {
404 if (i == 0 || i == 1) continue; // Leave a hole for c_1 to take.
405 values[i] = Define(Reg(static_cast<int>(i)));
408 auto c_0 = DefineConstant();
409 auto c_1 = DefineConstant();
411 EmitOI(Reg(1), Reg(c_0, 0), UniqueReg(c_1));
413 // Use previous values to force c_1 to split before the previous instruction.
414 for (size_t i = 0; i < arraysize(values); ++i) {
415 if (i == 0 || i == 1) continue;
416 EmitI(Reg(values[i], static_cast<int>(i)));
425 TEST_F(RegisterAllocatorTest, RegressionSpillTwice) {
427 auto p_0 = Parameter(Reg(1));
428 EmitCall(Slot(-2), Unique(p_0), Reg(p_0, 1));
435 TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) {
438 VReg values[kDefaultNRegs];
439 for (size_t i = arraysize(values); i > 0; --i) {
440 values[i - 1] = Define(Reg(static_cast<int>(i - 1)));
442 auto c = DefineConstant();
443 auto to_spill = Define(Reg());
450 // Create a use for c in second half of prev block's last gap
452 for (size_t i = arraysize(values); i > 0; --i) {
461 // Force c to split within to_spill's definition.
463 EmitI(Reg(to_spill));
469 } // namespace compiler
470 } // namespace internal