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, SplitBeforeInstruction2) {
305 const int kNumRegs = 6;
306 SetNumRegs(kNumRegs, kNumRegs);
310 // Stack parameters/spilled values.
311 auto p_0 = Define(Slot(-1));
312 auto p_1 = Define(Slot(-2));
315 VReg values[kNumRegs];
316 for (size_t i = 0; i < arraysize(values); ++i) {
317 values[i] = Define(Reg(static_cast<int>(i)));
320 // values[0] and [1] will be split in the second half of this instruction.
321 EmitOOI(Reg(0), Reg(1), Reg(p_0, 0), Reg(p_1, 1));
322 EmitI(Reg(values[0]), Reg(values[1]));
329 TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
332 EndBlock(Branch(Imm(), 1, 5));
336 EndBlock(Branch(Imm(), 1, 2));
339 auto ll = Define(Reg());
343 auto lr = Define(Reg());
347 auto l_phi = Phi(ll, lr);
352 EndBlock(Branch(Imm(), 1, 2));
355 auto rl = Define(Reg());
359 auto rr = Define(Reg());
363 auto r_phi = Phi(rl, rr);
366 // Outer diamond merge.
368 auto phi = Phi(l_phi, r_phi);
376 TEST_F(RegisterAllocatorTest, NestedDiamondPhiMergeDifferent) {
379 EndBlock(Branch(Imm(), 1, 5));
383 EndBlock(Branch(Imm(), 1, 2));
386 auto ll = Define(Reg(0));
390 auto lr = Define(Reg(1));
394 auto l_phi = Phi(ll, lr);
399 EndBlock(Branch(Imm(), 1, 2));
402 auto rl = Define(Reg(2));
406 auto rr = Define(Reg(3));
410 auto r_phi = Phi(rl, rr);
413 // Outer diamond merge.
415 auto phi = Phi(l_phi, r_phi);
423 TEST_F(RegisterAllocatorTest, RegressionSplitBeforeAndMove) {
427 VReg values[kDefaultNRegs];
428 for (size_t i = 0; i < arraysize(values); ++i) {
429 if (i == 0 || i == 1) continue; // Leave a hole for c_1 to take.
430 values[i] = Define(Reg(static_cast<int>(i)));
433 auto c_0 = DefineConstant();
434 auto c_1 = DefineConstant();
436 EmitOI(Reg(1), Reg(c_0, 0), UniqueReg(c_1));
438 // Use previous values to force c_1 to split before the previous instruction.
439 for (size_t i = 0; i < arraysize(values); ++i) {
440 if (i == 0 || i == 1) continue;
441 EmitI(Reg(values[i], static_cast<int>(i)));
450 TEST_F(RegisterAllocatorTest, RegressionSpillTwice) {
452 auto p_0 = Parameter(Reg(1));
453 EmitCall(Slot(-2), Unique(p_0), Reg(p_0, 1));
460 TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) {
463 VReg values[kDefaultNRegs];
464 for (size_t i = arraysize(values); i > 0; --i) {
465 values[i - 1] = Define(Reg(static_cast<int>(i - 1)));
467 auto c = DefineConstant();
468 auto to_spill = Define(Reg());
475 // Create a use for c in second half of prev block's last gap
477 for (size_t i = arraysize(values); i > 0; --i) {
486 // Force c to split within to_spill's definition.
488 EmitI(Reg(to_spill));
497 enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister };
499 const ParameterType kParameterTypes[] = {
500 ParameterType::kFixedSlot, ParameterType::kSlot, ParameterType::kRegister,
501 ParameterType::kFixedRegister};
503 class SlotConstraintTest : public RegisterAllocatorTest,
504 public ::testing::WithParamInterface<
505 ::testing::tuple<ParameterType, int>> {
507 static const int kMaxVariant = 5;
510 ParameterType parameter_type() const {
511 return ::testing::get<0>(B::GetParam());
513 int variant() const { return ::testing::get<1>(B::GetParam()); }
516 typedef ::testing::WithParamInterface<::testing::tuple<ParameterType, int>> B;
521 #if GTEST_HAS_COMBINE
523 TEST_P(SlotConstraintTest, SlotConstraint) {
526 switch (parameter_type()) {
527 case ParameterType::kFixedSlot:
528 p_0 = Parameter(Slot(-1));
530 case ParameterType::kSlot:
531 p_0 = Parameter(Slot(-1));
533 case ParameterType::kRegister:
534 p_0 = Parameter(Reg());
536 case ParameterType::kFixedRegister:
537 p_0 = Parameter(Reg(1));
542 EmitI(Slot(p_0), Reg(p_0));
556 EmitI(Slot(p_0, -1), Slot(p_0), Reg(p_0), Reg(p_0, 1));
568 INSTANTIATE_TEST_CASE_P(
569 RegisterAllocatorTest, SlotConstraintTest,
570 ::testing::Combine(::testing::ValuesIn(kParameterTypes),
571 ::testing::Range(0, SlotConstraintTest::kMaxVariant)));
573 #endif // GTEST_HAS_COMBINE
575 } // namespace compiler
576 } // namespace internal