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: 435 482 90.2 %
Date: 2019-04-18 Functions: 59 83 71.1 %

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

Generated by: LCOV version 1.10