LCOV - code coverage report
Current view: top level - test/unittests/compiler/regalloc - register-allocator-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 432 443 97.5 %
Date: 2019-02-19 Functions: 57 84 67.9 %

          Line data    Source code
       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.
       4             : 
       5             : #include "src/assembler-inl.h"
       6             : #include "src/compiler/pipeline.h"
       7             : #include "test/unittests/compiler/backend/instruction-sequence-unittest.h"
       8             : 
       9             : namespace v8 {
      10             : namespace internal {
      11             : namespace compiler {
      12             : 
      13             : namespace {
      14             : 
      15             : // We can't just use the size of the moves collection, because of
      16             : // redundant moves which need to be discounted.
      17           1 : int GetMoveCount(const ParallelMove& moves) {
      18             :   int move_count = 0;
      19           2 :   for (auto move : moves) {
      20           0 :     if (move->IsEliminated() || move->IsRedundant()) continue;
      21           0 :     ++move_count;
      22             :   }
      23           1 :   return move_count;
      24             : }
      25             : 
      26          13 : bool AreOperandsOfSameType(
      27             :     const AllocatedOperand& op,
      28             :     const InstructionSequenceTest::TestOperand& test_op) {
      29             :   bool test_op_is_reg =
      30             :       (test_op.type_ ==
      31          13 :            InstructionSequenceTest::TestOperandType::kFixedRegister ||
      32          13 :        test_op.type_ == InstructionSequenceTest::TestOperandType::kRegister);
      33             : 
      34          18 :   return (op.IsRegister() && test_op_is_reg) ||
      35           5 :          (op.IsStackSlot() && !test_op_is_reg);
      36             : }
      37             : 
      38          13 : bool AllocatedOperandMatches(
      39             :     const AllocatedOperand& op,
      40          13 :     const InstructionSequenceTest::TestOperand& test_op) {
      41          26 :   return AreOperandsOfSameType(op, test_op) &&
      42          26 :          ((op.IsRegister() ? op.GetRegister().code() : op.index()) ==
      43           5 :               test_op.value_ ||
      44          13 :           test_op.value_ == InstructionSequenceTest::kNoValue);
      45             : }
      46             : 
      47           2 : int GetParallelMoveCount(int instr_index, Instruction::GapPosition gap_pos,
      48             :                          const InstructionSequence* sequence) {
      49             :   const ParallelMove* moves =
      50             :       sequence->InstructionAt(instr_index)->GetParallelMove(gap_pos);
      51           2 :   if (moves == nullptr) return 0;
      52           1 :   return GetMoveCount(*moves);
      53             : }
      54             : 
      55           6 : bool IsParallelMovePresent(int instr_index, Instruction::GapPosition gap_pos,
      56             :                            const InstructionSequence* sequence,
      57             :                            const InstructionSequenceTest::TestOperand& src,
      58             :                            const InstructionSequenceTest::TestOperand& dest) {
      59             :   const ParallelMove* moves =
      60           6 :       sequence->InstructionAt(instr_index)->GetParallelMove(gap_pos);
      61           6 :   EXPECT_NE(nullptr, moves);
      62             : 
      63             :   bool found_match = false;
      64          16 :   for (auto move : *moves) {
      65           9 :     if (move->IsEliminated() || move->IsRedundant()) continue;
      66          21 :     if (AllocatedOperandMatches(AllocatedOperand::cast(move->source()), src) &&
      67             :         AllocatedOperandMatches(AllocatedOperand::cast(move->destination()),
      68          13 :                                 dest)) {
      69             :       found_match = true;
      70             :       break;
      71             :     }
      72             :   }
      73           6 :   return found_match;
      74             : }
      75             : 
      76             : }  // namespace
      77             : 
      78          84 : class RegisterAllocatorTest : public InstructionSequenceTest {
      79             :  public:
      80          42 :   void Allocate() {
      81          42 :     WireBlocks();
      82          42 :     Pipeline::AllocateRegistersForTesting(config(), sequence(), true);
      83          42 :   }
      84             : };
      85             : 
      86       15189 : TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
      87             :   // return p0 + p1;
      88           1 :   StartBlock();
      89             :   auto a_reg = Parameter();
      90             :   auto b_reg = Parameter();
      91           1 :   auto c_reg = EmitOI(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
      92           1 :   Return(c_reg);
      93           1 :   EndBlock(Last());
      94             : 
      95           1 :   Allocate();
      96           1 : }
      97             : 
      98       15189 : TEST_F(RegisterAllocatorTest, CanAllocateFPRegisters) {
      99           1 :   StartBlock();
     100             :   TestOperand inputs[] = {
     101           2 :       Reg(FPParameter(kFloat64)), Reg(FPParameter(kFloat64)),
     102           2 :       Reg(FPParameter(kFloat32)), Reg(FPParameter(kFloat32)),
     103           2 :       Reg(FPParameter(kSimd128)), Reg(FPParameter(kSimd128))};
     104           1 :   VReg out1 = EmitOI(FPReg(1, kFloat64), arraysize(inputs), inputs);
     105           1 :   Return(out1);
     106           1 :   EndBlock(Last());
     107             : 
     108           1 :   Allocate();
     109           1 : }
     110             : 
     111       15189 : TEST_F(RegisterAllocatorTest, SimpleLoop) {
     112             :   // i = K;
     113             :   // while(true) { i++ }
     114           1 :   StartBlock();
     115           1 :   auto i_reg = DefineConstant();
     116           1 :   EndBlock();
     117             : 
     118             :   {
     119           1 :     StartLoop(1);
     120             : 
     121           1 :     StartBlock();
     122           1 :     auto phi = Phi(i_reg, 2);
     123           2 :     auto ipp = EmitOI(Same(), Reg(phi), Use(DefineConstant()));
     124           1 :     SetInput(phi, 1, ipp);
     125           1 :     EndBlock(Jump(0));
     126             : 
     127           1 :     EndLoop();
     128             :   }
     129             : 
     130           1 :   Allocate();
     131           1 : }
     132             : 
     133       15189 : TEST_F(RegisterAllocatorTest, SimpleBranch) {
     134             :   // return i ? K1 : K2
     135           1 :   StartBlock();
     136           1 :   auto i = DefineConstant();
     137           1 :   EndBlock(Branch(Reg(i), 1, 2));
     138             : 
     139           1 :   StartBlock();
     140           1 :   Return(DefineConstant());
     141           1 :   EndBlock(Last());
     142             : 
     143           1 :   StartBlock();
     144           1 :   Return(DefineConstant());
     145           1 :   EndBlock(Last());
     146             : 
     147           1 :   Allocate();
     148           1 : }
     149             : 
     150       15189 : TEST_F(RegisterAllocatorTest, SimpleDiamond) {
     151             :   // return p0 ? p0 : p0
     152           1 :   StartBlock();
     153             :   auto param = Parameter();
     154           1 :   EndBlock(Branch(Reg(param), 1, 2));
     155             : 
     156           1 :   StartBlock();
     157           1 :   EndBlock(Jump(2));
     158             : 
     159           1 :   StartBlock();
     160           1 :   EndBlock(Jump(1));
     161             : 
     162           1 :   StartBlock();
     163           1 :   Return(param);
     164           1 :   EndBlock();
     165             : 
     166           1 :   Allocate();
     167           1 : }
     168             : 
     169       15189 : TEST_F(RegisterAllocatorTest, SimpleDiamondPhi) {
     170             :   // return i ? K1 : K2
     171           1 :   StartBlock();
     172           2 :   EndBlock(Branch(Reg(DefineConstant()), 1, 2));
     173             : 
     174           1 :   StartBlock();
     175           1 :   auto t_val = DefineConstant();
     176           1 :   EndBlock(Jump(2));
     177             : 
     178           1 :   StartBlock();
     179           1 :   auto f_val = DefineConstant();
     180           1 :   EndBlock(Jump(1));
     181             : 
     182           1 :   StartBlock();
     183           2 :   Return(Reg(Phi(t_val, f_val)));
     184           1 :   EndBlock();
     185             : 
     186           1 :   Allocate();
     187           1 : }
     188             : 
     189       15189 : TEST_F(RegisterAllocatorTest, DiamondManyPhis) {
     190             :   constexpr int kPhis = Register::kNumRegisters * 2;
     191             : 
     192           1 :   StartBlock();
     193           2 :   EndBlock(Branch(Reg(DefineConstant()), 1, 2));
     194             : 
     195           1 :   StartBlock();
     196          33 :   VReg t_vals[kPhis];
     197          32 :   for (int i = 0; i < kPhis; ++i) {
     198          32 :     t_vals[i] = DefineConstant();
     199             :   }
     200           1 :   EndBlock(Jump(2));
     201             : 
     202           1 :   StartBlock();
     203          33 :   VReg f_vals[kPhis];
     204          32 :   for (int i = 0; i < kPhis; ++i) {
     205          32 :     f_vals[i] = DefineConstant();
     206             :   }
     207           1 :   EndBlock(Jump(1));
     208             : 
     209           1 :   StartBlock();
     210          33 :   TestOperand merged[kPhis];
     211          32 :   for (int i = 0; i < kPhis; ++i) {
     212          96 :     merged[i] = Use(Phi(t_vals[i], f_vals[i]));
     213             :   }
     214           1 :   Return(EmitCall(Slot(-1), kPhis, merged));
     215           1 :   EndBlock();
     216             : 
     217           1 :   Allocate();
     218           1 : }
     219             : 
     220       15189 : TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
     221             :   constexpr int kPhis = Register::kNumRegisters * 2;
     222             : 
     223             :   // First diamond.
     224           1 :   StartBlock();
     225          33 :   VReg vals[kPhis];
     226          32 :   for (int i = 0; i < kPhis; ++i) {
     227          64 :     vals[i] = Parameter(Slot(-1 - i));
     228             :   }
     229           2 :   EndBlock(Branch(Reg(DefineConstant()), 1, 2));
     230             : 
     231           1 :   StartBlock();
     232           1 :   EndBlock(Jump(2));
     233             : 
     234           1 :   StartBlock();
     235           1 :   EndBlock(Jump(1));
     236             : 
     237             :   // Second diamond.
     238           1 :   StartBlock();
     239           2 :   EndBlock(Branch(Reg(DefineConstant()), 1, 2));
     240             : 
     241           1 :   StartBlock();
     242           1 :   EndBlock(Jump(2));
     243             : 
     244           1 :   StartBlock();
     245           1 :   EndBlock(Jump(1));
     246             : 
     247           1 :   StartBlock();
     248          33 :   TestOperand merged[kPhis];
     249          32 :   for (int i = 0; i < kPhis; ++i) {
     250          96 :     merged[i] = Use(Phi(vals[i], vals[i]));
     251             :   }
     252           1 :   Return(EmitCall(Reg(0), kPhis, merged));
     253           1 :   EndBlock();
     254             : 
     255           1 :   Allocate();
     256           1 : }
     257             : 
     258       15189 : TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
     259             :   const size_t kNumRegs = 3;
     260             :   const size_t kParams = kNumRegs + 1;
     261             :   // Override number of registers.
     262           1 :   SetNumRegs(kNumRegs, kNumRegs);
     263             : 
     264           1 :   StartBlock();
     265           5 :   auto constant = DefineConstant();
     266           5 :   VReg parameters[kParams];
     267           4 :   for (size_t i = 0; i < arraysize(parameters); ++i) {
     268           4 :     parameters[i] = DefineConstant();
     269             :   }
     270           1 :   EndBlock();
     271             : 
     272             :   PhiInstruction* phis[kParams];
     273             :   {
     274           1 :     StartLoop(2);
     275             : 
     276             :     // Loop header.
     277           1 :     StartBlock();
     278             : 
     279           5 :     for (size_t i = 0; i < arraysize(parameters); ++i) {
     280           4 :       phis[i] = Phi(parameters[i], 2);
     281             :     }
     282             : 
     283             :     // Perform some computations.
     284             :     // something like phi[i] += const
     285           4 :     for (size_t i = 0; i < arraysize(parameters); ++i) {
     286           8 :       auto result = EmitOI(Same(), Reg(phis[i]), Use(constant));
     287           4 :       SetInput(phis[i], 1, result);
     288             :     }
     289             : 
     290           2 :     EndBlock(Branch(Reg(DefineConstant()), 1, 2));
     291             : 
     292             :     // Jump back to loop header.
     293           1 :     StartBlock();
     294           1 :     EndBlock(Jump(-1));
     295             : 
     296           1 :     EndLoop();
     297             :   }
     298             : 
     299           1 :   StartBlock();
     300           1 :   Return(DefineConstant());
     301           1 :   EndBlock();
     302             : 
     303           1 :   Allocate();
     304           1 : }
     305             : 
     306       15189 : TEST_F(RegisterAllocatorTest, SpillPhi) {
     307           1 :   StartBlock();
     308           2 :   EndBlock(Branch(Imm(), 1, 2));
     309             : 
     310           1 :   StartBlock();
     311           1 :   auto left = Define(Reg(0));
     312           1 :   EndBlock(Jump(2));
     313             : 
     314           1 :   StartBlock();
     315           1 :   auto right = Define(Reg(0));
     316           1 :   EndBlock();
     317             : 
     318           1 :   StartBlock();
     319           1 :   auto phi = Phi(left, right);
     320           1 :   EmitCall(Slot(-1));
     321           1 :   Return(Reg(phi));
     322           1 :   EndBlock();
     323             : 
     324           1 :   Allocate();
     325           1 : }
     326             : 
     327       15189 : TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) {
     328           1 :   StartBlock();
     329          17 :   VReg constants[Register::kNumRegisters];
     330          16 :   for (size_t i = 0; i < arraysize(constants); ++i) {
     331          16 :     constants[i] = DefineConstant();
     332             :   }
     333          32 :   TestOperand call_ops[Register::kNumRegisters * 2];
     334          16 :   for (int i = 0; i < Register::kNumRegisters; ++i) {
     335          32 :     call_ops[i] = Reg(constants[i], i);
     336             :   }
     337          16 :   for (int i = 0; i < Register::kNumRegisters; ++i) {
     338          32 :     call_ops[i + Register::kNumRegisters] = Slot(constants[i], i);
     339             :   }
     340           1 :   EmitCall(Slot(-1), arraysize(call_ops), call_ops);
     341           1 :   EndBlock(Last());
     342             : 
     343           1 :   Allocate();
     344           1 : }
     345             : 
     346       15189 : TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
     347             :   const int kNumRegs = 6;
     348           1 :   SetNumRegs(kNumRegs, kNumRegs);
     349             : 
     350           1 :   StartBlock();
     351             : 
     352             :   // Stack parameters/spilled values.
     353           2 :   auto p_0 = Define(Slot(-1));
     354           2 :   auto p_1 = Define(Slot(-2));
     355             : 
     356             :   // Fill registers.
     357           7 :   VReg values[kNumRegs];
     358           6 :   for (size_t i = 0; i < arraysize(values); ++i) {
     359          12 :     values[i] = Define(Reg(static_cast<int>(i)));
     360             :   }
     361             : 
     362             :   // values[0] will be split in the second half of this instruction.
     363             :   // Models Intel mod instructions.
     364           1 :   EmitOI(Reg(0), Reg(p_0, 1), UniqueReg(p_1));
     365           2 :   EmitI(Reg(values[0], 0));
     366           1 :   EndBlock(Last());
     367             : 
     368           1 :   Allocate();
     369           1 : }
     370             : 
     371       15189 : TEST_F(RegisterAllocatorTest, SplitBeforeInstruction2) {
     372             :   const int kNumRegs = 6;
     373           1 :   SetNumRegs(kNumRegs, kNumRegs);
     374             : 
     375           1 :   StartBlock();
     376             : 
     377             :   // Stack parameters/spilled values.
     378           2 :   auto p_0 = Define(Slot(-1));
     379           2 :   auto p_1 = Define(Slot(-2));
     380             : 
     381             :   // Fill registers.
     382           7 :   VReg values[kNumRegs];
     383           6 :   for (size_t i = 0; i < arraysize(values); ++i) {
     384          12 :     values[i] = Define(Reg(static_cast<int>(i)));
     385             :   }
     386             : 
     387             :   // values[0] and [1] will be split in the second half of this instruction.
     388           1 :   EmitOOI(Reg(0), Reg(1), Reg(p_0, 0), Reg(p_1, 1));
     389           3 :   EmitI(Reg(values[0]), Reg(values[1]));
     390           1 :   EndBlock(Last());
     391             : 
     392           1 :   Allocate();
     393           1 : }
     394             : 
     395       15189 : TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) {
     396             :   // Outer diamond.
     397           1 :   StartBlock();
     398           2 :   EndBlock(Branch(Imm(), 1, 5));
     399             : 
     400             :   // Diamond 1
     401           1 :   StartBlock();
     402           2 :   EndBlock(Branch(Imm(), 1, 2));
     403             : 
     404           1 :   StartBlock();
     405           1 :   auto ll = Define(Reg());
     406           1 :   EndBlock(Jump(2));
     407             : 
     408           1 :   StartBlock();
     409           1 :   auto lr = Define(Reg());
     410           1 :   EndBlock();
     411             : 
     412           1 :   StartBlock();
     413           1 :   auto l_phi = Phi(ll, lr);
     414           1 :   EndBlock(Jump(5));
     415             : 
     416             :   // Diamond 2
     417           1 :   StartBlock();
     418           2 :   EndBlock(Branch(Imm(), 1, 2));
     419             : 
     420           1 :   StartBlock();
     421           1 :   auto rl = Define(Reg());
     422           1 :   EndBlock(Jump(2));
     423             : 
     424           1 :   StartBlock();
     425           1 :   auto rr = Define(Reg());
     426           1 :   EndBlock();
     427             : 
     428           1 :   StartBlock();
     429           1 :   auto r_phi = Phi(rl, rr);
     430           1 :   EndBlock();
     431             : 
     432             :   // Outer diamond merge.
     433           1 :   StartBlock();
     434           1 :   auto phi = Phi(l_phi, r_phi);
     435           1 :   Return(Reg(phi));
     436           1 :   EndBlock();
     437             : 
     438           1 :   Allocate();
     439           1 : }
     440             : 
     441       15189 : TEST_F(RegisterAllocatorTest, NestedDiamondPhiMergeDifferent) {
     442             :   // Outer diamond.
     443           1 :   StartBlock();
     444           2 :   EndBlock(Branch(Imm(), 1, 5));
     445             : 
     446             :   // Diamond 1
     447           1 :   StartBlock();
     448           2 :   EndBlock(Branch(Imm(), 1, 2));
     449             : 
     450           1 :   StartBlock();
     451           1 :   auto ll = Define(Reg(0));
     452           1 :   EndBlock(Jump(2));
     453             : 
     454           1 :   StartBlock();
     455           1 :   auto lr = Define(Reg(1));
     456           1 :   EndBlock();
     457             : 
     458           1 :   StartBlock();
     459           1 :   auto l_phi = Phi(ll, lr);
     460           1 :   EndBlock(Jump(5));
     461             : 
     462             :   // Diamond 2
     463           1 :   StartBlock();
     464           2 :   EndBlock(Branch(Imm(), 1, 2));
     465             : 
     466           1 :   StartBlock();
     467           1 :   auto rl = Define(Reg(2));
     468           1 :   EndBlock(Jump(2));
     469             : 
     470           1 :   StartBlock();
     471           1 :   auto rr = Define(Reg(3));
     472           1 :   EndBlock();
     473             : 
     474           1 :   StartBlock();
     475           1 :   auto r_phi = Phi(rl, rr);
     476           1 :   EndBlock();
     477             : 
     478             :   // Outer diamond merge.
     479           1 :   StartBlock();
     480           1 :   auto phi = Phi(l_phi, r_phi);
     481           1 :   Return(Reg(phi));
     482           1 :   EndBlock();
     483             : 
     484           1 :   Allocate();
     485           1 : }
     486             : 
     487       15189 : TEST_F(RegisterAllocatorTest, RegressionSplitBeforeAndMove) {
     488           1 :   StartBlock();
     489             : 
     490             :   // Fill registers.
     491          17 :   VReg values[Register::kNumRegisters];
     492          16 :   for (size_t i = 0; i < arraysize(values); ++i) {
     493          16 :     if (i == 0 || i == 1) continue;  // Leave a hole for c_1 to take.
     494          28 :     values[i] = Define(Reg(static_cast<int>(i)));
     495             :   }
     496             : 
     497           2 :   auto c_0 = DefineConstant();
     498           2 :   auto c_1 = DefineConstant();
     499             : 
     500           1 :   EmitOI(Reg(1), Reg(c_0, 0), UniqueReg(c_1));
     501             : 
     502             :   // Use previous values to force c_1 to split before the previous instruction.
     503          17 :   for (size_t i = 0; i < arraysize(values); ++i) {
     504          16 :     if (i == 0 || i == 1) continue;
     505          28 :     EmitI(Reg(values[i], static_cast<int>(i)));
     506             :   }
     507             : 
     508           1 :   EndBlock(Last());
     509             : 
     510           1 :   Allocate();
     511           1 : }
     512             : 
     513       15189 : TEST_F(RegisterAllocatorTest, RegressionSpillTwice) {
     514           1 :   StartBlock();
     515             :   auto p_0 = Parameter(Reg(1));
     516           1 :   EmitCall(Slot(-2), Unique(p_0), Reg(p_0, 1));
     517           1 :   EndBlock(Last());
     518             : 
     519           1 :   Allocate();
     520           1 : }
     521             : 
     522       15189 : TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) {
     523           1 :   StartBlock();
     524             :   // Fill registers.
     525          17 :   VReg values[Register::kNumRegisters];
     526          17 :   for (size_t i = arraysize(values); i > 0; --i) {
     527          32 :     values[i - 1] = Define(Reg(static_cast<int>(i - 1)));
     528             :   }
     529           2 :   auto c = DefineConstant();
     530           2 :   auto to_spill = Define(Reg());
     531           1 :   EndBlock(Jump(1));
     532             : 
     533             :   {
     534           1 :     StartLoop(1);
     535             : 
     536           1 :     StartBlock();
     537             :     // Create a use for c in second half of prev block's last gap
     538           1 :     Phi(c);
     539          18 :     for (size_t i = arraysize(values); i > 0; --i) {
     540          16 :       Phi(values[i - 1]);
     541             :     }
     542           1 :     EndBlock(Jump(1));
     543             : 
     544           1 :     EndLoop();
     545             :   }
     546             : 
     547           1 :   StartBlock();
     548             :   // Force c to split within to_spill's definition.
     549           1 :   EmitI(Reg(c));
     550           1 :   EmitI(Reg(to_spill));
     551           1 :   EndBlock(Last());
     552             : 
     553           1 :   Allocate();
     554           1 : }
     555             : 
     556       15189 : TEST_F(RegisterAllocatorTest, DiamondWithCallFirstBlock) {
     557           1 :   StartBlock();
     558           1 :   auto x = EmitOI(Reg(0));
     559           1 :   EndBlock(Branch(Reg(x), 1, 2));
     560             : 
     561           1 :   StartBlock();
     562           1 :   EmitCall(Slot(-1));
     563           1 :   auto occupy = EmitOI(Reg(0));
     564           1 :   EndBlock(Jump(2));
     565             : 
     566           1 :   StartBlock();
     567           1 :   EndBlock(FallThrough());
     568             : 
     569           1 :   StartBlock();
     570             :   Use(occupy);
     571           1 :   Return(Reg(x));
     572           1 :   EndBlock();
     573           1 :   Allocate();
     574           1 : }
     575             : 
     576       15189 : TEST_F(RegisterAllocatorTest, DiamondWithCallSecondBlock) {
     577           1 :   StartBlock();
     578           1 :   auto x = EmitOI(Reg(0));
     579           1 :   EndBlock(Branch(Reg(x), 1, 2));
     580             : 
     581           1 :   StartBlock();
     582           1 :   EndBlock(Jump(2));
     583             : 
     584           1 :   StartBlock();
     585           1 :   EmitCall(Slot(-1));
     586           1 :   auto occupy = EmitOI(Reg(0));
     587           1 :   EndBlock(FallThrough());
     588             : 
     589           1 :   StartBlock();
     590             :   Use(occupy);
     591           1 :   Return(Reg(x));
     592           1 :   EndBlock();
     593           1 :   Allocate();
     594           1 : }
     595             : 
     596       15189 : TEST_F(RegisterAllocatorTest, SingleDeferredBlockSpill) {
     597           1 :   StartBlock();  // B0
     598           1 :   auto var = EmitOI(Reg(0));
     599           1 :   EndBlock(Branch(Reg(var), 1, 2));
     600             : 
     601           1 :   StartBlock();  // B1
     602           1 :   EndBlock(Jump(2));
     603             : 
     604           1 :   StartBlock(true);  // B2
     605           1 :   EmitCall(Slot(-1), Slot(var));
     606           1 :   EndBlock();
     607             : 
     608           1 :   StartBlock();  // B3
     609           1 :   EmitNop();
     610           1 :   EndBlock();
     611             : 
     612           1 :   StartBlock();  // B4
     613           1 :   Return(Reg(var, 0));
     614           1 :   EndBlock();
     615             : 
     616           1 :   Allocate();
     617             : 
     618             :   const int var_def_index = 1;
     619             :   const int call_index = 3;
     620             :   int expect_no_moves =
     621           1 :       FLAG_turbo_preprocess_ranges ? var_def_index : call_index;
     622             :   int expect_spill_move =
     623           1 :       FLAG_turbo_preprocess_ranges ? call_index : var_def_index;
     624             : 
     625             :   // We should have no parallel moves at the "expect_no_moves" position.
     626           2 :   EXPECT_EQ(
     627           0 :       0, GetParallelMoveCount(expect_no_moves, Instruction::START, sequence()));
     628             : 
     629             :   // The spill should be performed at the position expect_spill_move.
     630           2 :   EXPECT_TRUE(IsParallelMovePresent(expect_spill_move, Instruction::START,
     631           0 :                                     sequence(), Reg(0), Slot(0)));
     632           1 : }
     633             : 
     634       15189 : TEST_F(RegisterAllocatorTest, MultipleDeferredBlockSpills) {
     635           1 :   if (!FLAG_turbo_preprocess_ranges) return;
     636             : 
     637           1 :   StartBlock();  // B0
     638           1 :   auto var1 = EmitOI(Reg(0));
     639           2 :   auto var2 = EmitOI(Reg(1));
     640           2 :   auto var3 = EmitOI(Reg(2));
     641           1 :   EndBlock(Branch(Reg(var1, 0), 1, 2));
     642             : 
     643           1 :   StartBlock(true);  // B1
     644           1 :   EmitCall(Slot(-2), Slot(var1));
     645           1 :   EndBlock(Jump(2));
     646             : 
     647           1 :   StartBlock(true);  // B2
     648           1 :   EmitCall(Slot(-1), Slot(var2));
     649           1 :   EndBlock();
     650             : 
     651           1 :   StartBlock();  // B3
     652           1 :   EmitNop();
     653           1 :   EndBlock();
     654             : 
     655           1 :   StartBlock();  // B4
     656           1 :   Return(Reg(var3, 2));
     657           1 :   EndBlock();
     658             : 
     659             :   const int def_of_v2 = 3;
     660             :   const int call_in_b1 = 4;
     661             :   const int call_in_b2 = 6;
     662             :   const int end_of_b1 = 5;
     663             :   const int end_of_b2 = 7;
     664             :   const int start_of_b3 = 8;
     665             : 
     666           1 :   Allocate();
     667             :   // TODO(mtrofin): at the moment, the linear allocator spills var1 and var2,
     668             :   // so only var3 is spilled in deferred blocks.
     669             :   const int var3_reg = 2;
     670             :   const int var3_slot = 2;
     671             : 
     672           2 :   EXPECT_FALSE(IsParallelMovePresent(def_of_v2, Instruction::START, sequence(),
     673           0 :                                      Reg(var3_reg), Slot()));
     674           2 :   EXPECT_TRUE(IsParallelMovePresent(call_in_b1, Instruction::START, sequence(),
     675           0 :                                     Reg(var3_reg), Slot(var3_slot)));
     676           2 :   EXPECT_TRUE(IsParallelMovePresent(end_of_b1, Instruction::START, sequence(),
     677           0 :                                     Slot(var3_slot), Reg()));
     678             : 
     679           2 :   EXPECT_TRUE(IsParallelMovePresent(call_in_b2, Instruction::START, sequence(),
     680           0 :                                     Reg(var3_reg), Slot(var3_slot)));
     681           2 :   EXPECT_TRUE(IsParallelMovePresent(end_of_b2, Instruction::START, sequence(),
     682           0 :                                     Slot(var3_slot), Reg()));
     683             : 
     684           2 :   EXPECT_EQ(0,
     685           0 :             GetParallelMoveCount(start_of_b3, Instruction::START, sequence()));
     686             : }
     687             : 
     688             : namespace {
     689             : 
     690             : enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister };
     691             : 
     692             : const ParameterType kParameterTypes[] = {
     693             :     ParameterType::kFixedSlot, ParameterType::kSlot, ParameterType::kRegister,
     694             :     ParameterType::kFixedRegister};
     695             : 
     696          40 : class SlotConstraintTest : public RegisterAllocatorTest,
     697             :                            public ::testing::WithParamInterface<
     698             :                                ::testing::tuple<ParameterType, int>> {
     699             :  public:
     700             :   static const int kMaxVariant = 5;
     701             : 
     702             :  protected:
     703             :   ParameterType parameter_type() const {
     704          20 :     return ::testing::get<0>(B::GetParam());
     705             :   }
     706          20 :   int variant() const { return ::testing::get<1>(B::GetParam()); }
     707             : 
     708             :  private:
     709             :   typedef ::testing::WithParamInterface<::testing::tuple<ParameterType, int>> B;
     710             : };
     711             : 
     712             : }  // namespace
     713             : 
     714       18302 : TEST_P(SlotConstraintTest, SlotConstraint) {
     715          20 :   StartBlock();
     716             :   VReg p_0;
     717          20 :   switch (parameter_type()) {
     718             :     case ParameterType::kFixedSlot:
     719             :       p_0 = Parameter(Slot(-1));
     720           5 :       break;
     721             :     case ParameterType::kSlot:
     722             :       p_0 = Parameter(Slot(-1));
     723           5 :       break;
     724             :     case ParameterType::kRegister:
     725             :       p_0 = Parameter(Reg());
     726           5 :       break;
     727             :     case ParameterType::kFixedRegister:
     728             :       p_0 = Parameter(Reg(1));
     729           5 :       break;
     730             :   }
     731          20 :   switch (variant()) {
     732             :     case 0:
     733           4 :       EmitI(Slot(p_0), Reg(p_0));
     734           4 :       break;
     735             :     case 1:
     736           4 :       EmitI(Slot(p_0));
     737           4 :       break;
     738             :     case 2:
     739           4 :       EmitI(Reg(p_0));
     740           4 :       EmitI(Slot(p_0));
     741           4 :       break;
     742             :     case 3:
     743           4 :       EmitI(Slot(p_0));
     744           4 :       EmitI(Reg(p_0));
     745           4 :       break;
     746             :     case 4:
     747           4 :       EmitI(Slot(p_0, -1), Slot(p_0), Reg(p_0), Reg(p_0, 1));
     748           4 :       break;
     749             :     default:
     750           0 :       UNREACHABLE();
     751             :       break;
     752             :   }
     753          20 :   EndBlock(Last());
     754             : 
     755          20 :   Allocate();
     756          20 : }
     757             : 
     758       88073 : INSTANTIATE_TEST_SUITE_P(
     759             :     RegisterAllocatorTest, SlotConstraintTest,
     760             :     ::testing::Combine(::testing::ValuesIn(kParameterTypes),
     761             :                        ::testing::Range(0, SlotConstraintTest::kMaxVariant)));
     762             : 
     763             : }  // namespace compiler
     764             : }  // namespace internal
     765        9111 : }  // namespace v8

Generated by: LCOV version 1.10