LCOV - code coverage report
Current view: top level - test/unittests/compiler/backend - instruction-selector-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 362 395 91.6 %
Date: 2019-04-17 Functions: 52 74 70.3 %

          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 "test/unittests/compiler/backend/instruction-selector-unittest.h"
       6             : 
       7             : #include "src/code-factory.h"
       8             : #include "src/compiler/compiler-source-position-table.h"
       9             : #include "src/compiler/graph.h"
      10             : #include "src/compiler/schedule.h"
      11             : #include "src/flags.h"
      12             : #include "src/objects-inl.h"
      13             : #include "test/unittests/compiler/compiler-test-utils.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : namespace compiler {
      18             : 
      19         342 : InstructionSelectorTest::InstructionSelectorTest() : rng_(FLAG_random_seed) {}
      20             : 
      21             : InstructionSelectorTest::~InstructionSelectorTest() = default;
      22             : 
      23         249 : InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
      24             :     InstructionSelector::Features features,
      25             :     InstructionSelectorTest::StreamBuilderMode mode,
      26             :     InstructionSelector::SourcePositionMode source_position_mode) {
      27         249 :   Schedule* schedule = Export();
      28         249 :   if (FLAG_trace_turbo) {
      29           0 :     StdoutStream{} << "=== Schedule before instruction selection ==="
      30             :                    << std::endl
      31           0 :                    << *schedule;
      32             :   }
      33         249 :   size_t const node_count = graph()->NodeCount();
      34         249 :   EXPECT_NE(0u, node_count);
      35             :   Linkage linkage(call_descriptor());
      36             :   InstructionBlocks* instruction_blocks =
      37         498 :       InstructionSequence::InstructionBlocksFor(test_->zone(), schedule);
      38         249 :   InstructionSequence sequence(test_->isolate(), test_->zone(),
      39         498 :                                instruction_blocks);
      40         249 :   SourcePositionTable source_position_table(graph());
      41             :   InstructionSelector selector(
      42         249 :       test_->zone(), node_count, &linkage, &sequence, schedule,
      43             :       &source_position_table, nullptr,
      44             :       InstructionSelector::kEnableSwitchJumpTable, source_position_mode,
      45             :       features, InstructionSelector::kDisableScheduling,
      46             :       InstructionSelector::kEnableRootsRelativeAddressing,
      47         498 :       PoisoningMitigationLevel::kPoisonAll);
      48         249 :   selector.SelectInstructions();
      49         249 :   if (FLAG_trace_turbo) {
      50           0 :     StdoutStream{} << "=== Code sequence after instruction selection ==="
      51             :                    << std::endl
      52           0 :                    << sequence;
      53             :   }
      54         498 :   Stream s;
      55         498 :   s.virtual_registers_ = selector.GetVirtualRegistersForTesting();
      56             :   // Map virtual registers.
      57        1537 :   for (Instruction* const instr : sequence) {
      58        1288 :     if (instr->opcode() < 0) continue;
      59        1288 :     if (mode == kTargetInstructions) {
      60        1015 :       switch (instr->arch_opcode()) {
      61             : #define CASE(Name) \
      62             :   case k##Name:    \
      63             :     break;
      64             :         TARGET_ARCH_OPCODE_LIST(CASE)
      65             : #undef CASE
      66             :         default:
      67             :           continue;
      68             :       }
      69             :     }
      70         528 :     if (mode == kAllExceptNopInstructions && instr->arch_opcode() == kArchNop) {
      71             :       continue;
      72             :     }
      73        1885 :     for (size_t i = 0; i < instr->OutputCount(); ++i) {
      74             :       InstructionOperand* output = instr->OutputAt(i);
      75         301 :       EXPECT_NE(InstructionOperand::IMMEDIATE, output->kind());
      76         301 :       if (output->IsConstant()) {
      77             :         int vreg = ConstantOperand::cast(output)->virtual_register();
      78          24 :         s.constants_.insert(std::make_pair(vreg, sequence.GetConstant(vreg)));
      79             :       }
      80             :     }
      81        3268 :     for (size_t i = 0; i < instr->InputCount(); ++i) {
      82             :       InstructionOperand* input = instr->InputAt(i);
      83         762 :       EXPECT_NE(InstructionOperand::CONSTANT, input->kind());
      84         762 :       if (input->IsImmediate()) {
      85             :         auto imm = ImmediateOperand::cast(input);
      86         319 :         if (imm->type() == ImmediateOperand::INDEXED) {
      87             :           int index = imm->indexed_value();
      88             :           s.immediates_.insert(
      89         410 :               std::make_pair(index, sequence.GetImmediate(imm)));
      90             :         }
      91             :       }
      92             :     }
      93         491 :     s.instructions_.push_back(instr);
      94             :   }
      95         976 :   for (auto i : s.virtual_registers_) {
      96         727 :     int const virtual_register = i.second;
      97         727 :     if (sequence.IsFP(virtual_register)) {
      98         114 :       EXPECT_FALSE(sequence.IsReference(virtual_register));
      99             :       s.doubles_.insert(virtual_register);
     100             :     }
     101        1454 :     if (sequence.IsReference(virtual_register)) {
     102          60 :       EXPECT_FALSE(sequence.IsFP(virtual_register));
     103             :       s.references_.insert(virtual_register);
     104             :     }
     105             :   }
     106         255 :   for (int i = 0; i < sequence.GetDeoptimizationEntryCount(); i++) {
     107           6 :     s.deoptimization_entries_.push_back(
     108           3 :         sequence.GetDeoptimizationEntry(i).descriptor());
     109             :   }
     110         498 :   return s;
     111             : }
     112             : 
     113         363 : int InstructionSelectorTest::Stream::ToVreg(const Node* node) const {
     114             :   VirtualRegisters::const_iterator i = virtual_registers_.find(node->id());
     115         363 :   CHECK(i != virtual_registers_.end());
     116         363 :   return i->second;
     117             : }
     118             : 
     119           4 : bool InstructionSelectorTest::Stream::IsFixed(const InstructionOperand* operand,
     120             :                                               Register reg) const {
     121           4 :   if (!operand->IsUnallocated()) return false;
     122             :   const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
     123           4 :   if (!unallocated->HasFixedRegisterPolicy()) return false;
     124           4 :   return unallocated->fixed_register_index() == reg.code();
     125             : }
     126             : 
     127          68 : bool InstructionSelectorTest::Stream::IsSameAsFirst(
     128             :     const InstructionOperand* operand) const {
     129          68 :   if (!operand->IsUnallocated()) return false;
     130             :   const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
     131          68 :   return unallocated->HasSameAsInputPolicy();
     132             : }
     133             : 
     134           2 : bool InstructionSelectorTest::Stream::IsUsedAtStart(
     135             :     const InstructionOperand* operand) const {
     136           2 :   if (!operand->IsUnallocated()) return false;
     137             :   const UnallocatedOperand* unallocated = UnallocatedOperand::cast(operand);
     138           2 :   return unallocated->IsUsedAtStart();
     139             : }
     140             : 
     141             : const FrameStateFunctionInfo*
     142           0 : InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo(
     143             :     int parameter_count, int local_count) {
     144           4 :   return common()->CreateFrameStateFunctionInfo(
     145             :       FrameStateType::kInterpretedFunction, parameter_count, local_count,
     146           4 :       Handle<SharedFunctionInfo>());
     147             : }
     148             : 
     149             : // -----------------------------------------------------------------------------
     150             : // Return.
     151             : 
     152       15444 : TARGET_TEST_F(InstructionSelectorTest, ReturnFloat32Constant) {
     153             :   const float kValue = 4.2f;
     154           1 :   StreamBuilder m(this, MachineType::Float32());
     155           1 :   m.Return(m.Float32Constant(kValue));
     156           1 :   Stream s = m.Build(kAllInstructions);
     157           2 :   ASSERT_EQ(3U, s.size());
     158           3 :   EXPECT_EQ(kArchNop, s[0]->arch_opcode());
     159           3 :   ASSERT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
     160           2 :   EXPECT_FLOAT_EQ(kValue, s.ToFloat32(s[0]->OutputAt(0)));
     161           3 :   EXPECT_EQ(kArchRet, s[1]->arch_opcode());
     162           3 :   EXPECT_EQ(2U, s[1]->InputCount());
     163             : }
     164             : 
     165       15444 : TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
     166           1 :   StreamBuilder m(this, MachineType::Int32(), MachineType::Int32());
     167           1 :   m.Return(m.Parameter(0));
     168           1 :   Stream s = m.Build(kAllInstructions);
     169           2 :   ASSERT_EQ(3U, s.size());
     170           3 :   EXPECT_EQ(kArchNop, s[0]->arch_opcode());
     171           3 :   ASSERT_EQ(1U, s[0]->OutputCount());
     172           3 :   EXPECT_EQ(kArchRet, s[1]->arch_opcode());
     173           3 :   EXPECT_EQ(2U, s[1]->InputCount());
     174             : }
     175             : 
     176       15444 : TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
     177           1 :   StreamBuilder m(this, MachineType::Int32());
     178           1 :   m.Return(m.Int32Constant(0));
     179           1 :   Stream s = m.Build(kAllInstructions);
     180           2 :   ASSERT_EQ(3U, s.size());
     181           3 :   EXPECT_EQ(kArchNop, s[0]->arch_opcode());
     182           3 :   ASSERT_EQ(1U, s[0]->OutputCount());
     183           3 :   EXPECT_EQ(InstructionOperand::CONSTANT, s[0]->OutputAt(0)->kind());
     184           3 :   EXPECT_EQ(0, s.ToInt32(s[0]->OutputAt(0)));
     185           3 :   EXPECT_EQ(kArchRet, s[1]->arch_opcode());
     186           3 :   EXPECT_EQ(2U, s[1]->InputCount());
     187             : }
     188             : 
     189             : // -----------------------------------------------------------------------------
     190             : // Conversions.
     191             : 
     192       15444 : TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToWord32WithParameter) {
     193           1 :   StreamBuilder m(this, MachineType::Int32(), MachineType::Float64());
     194           1 :   m.Return(m.TruncateFloat64ToWord32(m.Parameter(0)));
     195           1 :   Stream s = m.Build(kAllInstructions);
     196           2 :   ASSERT_EQ(4U, s.size());
     197           3 :   EXPECT_EQ(kArchNop, s[0]->arch_opcode());
     198           3 :   EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
     199           3 :   EXPECT_EQ(1U, s[1]->InputCount());
     200           3 :   EXPECT_EQ(1U, s[1]->OutputCount());
     201           3 :   EXPECT_EQ(kArchRet, s[2]->arch_opcode());
     202             : }
     203             : 
     204             : // -----------------------------------------------------------------------------
     205             : // Parameters.
     206             : 
     207       15444 : TARGET_TEST_F(InstructionSelectorTest, DoubleParameter) {
     208           1 :   StreamBuilder m(this, MachineType::Float64(), MachineType::Float64());
     209           1 :   Node* param = m.Parameter(0);
     210           1 :   m.Return(param);
     211           1 :   Stream s = m.Build(kAllInstructions);
     212           2 :   EXPECT_TRUE(s.IsDouble(param));
     213           1 : }
     214             : 
     215       15444 : TARGET_TEST_F(InstructionSelectorTest, ReferenceParameter) {
     216           1 :   StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged());
     217           1 :   Node* param = m.Parameter(0);
     218           1 :   m.Return(param);
     219           1 :   Stream s = m.Build(kAllInstructions);
     220           2 :   EXPECT_TRUE(s.IsReference(param));
     221           1 : }
     222             : 
     223             : // -----------------------------------------------------------------------------
     224             : // FinishRegion.
     225             : 
     226       15444 : TARGET_TEST_F(InstructionSelectorTest, FinishRegion) {
     227           1 :   StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged());
     228           1 :   Node* param = m.Parameter(0);
     229             :   Node* finish =
     230           1 :       m.AddNode(m.common()->FinishRegion(), param, m.graph()->start());
     231           1 :   m.Return(finish);
     232           1 :   Stream s = m.Build(kAllInstructions);
     233           2 :   ASSERT_EQ(3U, s.size());
     234           3 :   EXPECT_EQ(kArchNop, s[0]->arch_opcode());
     235           3 :   ASSERT_EQ(1U, s[0]->OutputCount());
     236           2 :   ASSERT_TRUE(s[0]->Output()->IsUnallocated());
     237           3 :   EXPECT_EQ(kArchRet, s[1]->arch_opcode());
     238           3 :   EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[0]->Output()));
     239           3 :   EXPECT_EQ(s.ToVreg(param), s.ToVreg(s[1]->InputAt(1)));
     240           2 :   EXPECT_TRUE(s.IsReference(finish));
     241             : }
     242             : 
     243             : // -----------------------------------------------------------------------------
     244             : // Phi.
     245             : 
     246             : typedef InstructionSelectorTestWithParam<MachineType>
     247             :     InstructionSelectorPhiTest;
     248             : 
     249       18572 : TARGET_TEST_P(InstructionSelectorPhiTest, Doubleness) {
     250          11 :   const MachineType type = GetParam();
     251          11 :   StreamBuilder m(this, type, type, type);
     252          11 :   Node* param0 = m.Parameter(0);
     253          11 :   Node* param1 = m.Parameter(1);
     254          11 :   RawMachineLabel a, b, c;
     255          11 :   m.Branch(m.Int32Constant(0), &a, &b);
     256          11 :   m.Bind(&a);
     257          11 :   m.Goto(&c);
     258          11 :   m.Bind(&b);
     259          11 :   m.Goto(&c);
     260          11 :   m.Bind(&c);
     261          11 :   Node* phi = m.Phi(type.representation(), param0, param1);
     262          11 :   m.Return(phi);
     263          11 :   Stream s = m.Build(kAllInstructions);
     264          22 :   EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param0));
     265          22 :   EXPECT_EQ(s.IsDouble(phi), s.IsDouble(param1));
     266          11 : }
     267             : 
     268       18572 : TARGET_TEST_P(InstructionSelectorPhiTest, Referenceness) {
     269          11 :   const MachineType type = GetParam();
     270          11 :   StreamBuilder m(this, type, type, type);
     271          11 :   Node* param0 = m.Parameter(0);
     272          11 :   Node* param1 = m.Parameter(1);
     273          11 :   RawMachineLabel a, b, c;
     274          11 :   m.Branch(m.Int32Constant(1), &a, &b);
     275          11 :   m.Bind(&a);
     276          11 :   m.Goto(&c);
     277          11 :   m.Bind(&b);
     278          11 :   m.Goto(&c);
     279          11 :   m.Bind(&c);
     280          11 :   Node* phi = m.Phi(type.representation(), param0, param1);
     281          11 :   m.Return(phi);
     282          11 :   Stream s = m.Build(kAllInstructions);
     283          22 :   EXPECT_EQ(s.IsReference(phi), s.IsReference(param0));
     284          22 :   EXPECT_EQ(s.IsReference(phi), s.IsReference(param1));
     285          11 : }
     286             : 
     287      163664 : INSTANTIATE_TEST_SUITE_P(
     288             :     InstructionSelectorTest, InstructionSelectorPhiTest,
     289             :     ::testing::Values(MachineType::Float64(), MachineType::Int8(),
     290             :                       MachineType::Uint8(), MachineType::Int16(),
     291             :                       MachineType::Uint16(), MachineType::Int32(),
     292             :                       MachineType::Uint32(), MachineType::Int64(),
     293             :                       MachineType::Uint64(), MachineType::Pointer(),
     294             :                       MachineType::AnyTagged()));
     295             : 
     296             : // -----------------------------------------------------------------------------
     297             : // ValueEffect.
     298             : 
     299       15444 : TARGET_TEST_F(InstructionSelectorTest, ValueEffect) {
     300           1 :   StreamBuilder m1(this, MachineType::Int32(), MachineType::Pointer());
     301           1 :   Node* p1 = m1.Parameter(0);
     302           1 :   m1.Return(m1.Load(MachineType::Int32(), p1, m1.Int32Constant(0)));
     303           1 :   Stream s1 = m1.Build(kAllInstructions);
     304           1 :   StreamBuilder m2(this, MachineType::Int32(), MachineType::Pointer());
     305           1 :   Node* p2 = m2.Parameter(0);
     306           2 :   m2.Return(m2.AddNode(
     307             :       m2.machine()->Load(MachineType::Int32()), p2, m2.Int32Constant(0),
     308             :       m2.AddNode(m2.common()->BeginRegion(RegionObservability::kObservable),
     309           1 :                  m2.graph()->start())));
     310           1 :   Stream s2 = m2.Build(kAllInstructions);
     311           1 :   EXPECT_LE(3U, s1.size());
     312           3 :   ASSERT_EQ(s1.size(), s2.size());
     313          17 :   TRACED_FORRANGE(size_t, i, 0, s1.size() - 1) {
     314           4 :     const Instruction* i1 = s1[i];
     315           4 :     const Instruction* i2 = s2[i];
     316          12 :     EXPECT_EQ(i1->arch_opcode(), i2->arch_opcode());
     317          12 :     EXPECT_EQ(i1->InputCount(), i2->InputCount());
     318          12 :     EXPECT_EQ(i1->OutputCount(), i2->OutputCount());
     319             :   }
     320             : }
     321             : 
     322             : // -----------------------------------------------------------------------------
     323             : // Calls with deoptimization.
     324             : 
     325       15444 : TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) {
     326             :   StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(),
     327           1 :                   MachineType::AnyTagged(), MachineType::AnyTagged());
     328             : 
     329             :   BailoutId bailout_id(42);
     330             : 
     331           1 :   Node* function_node = m.Parameter(0);
     332           1 :   Node* receiver = m.Parameter(1);
     333           1 :   Node* context = m.Parameter(2);
     334             : 
     335             :   ZoneVector<MachineType> int32_type(1, MachineType::Int32(), zone());
     336             :   ZoneVector<MachineType> empty_types(zone());
     337             : 
     338             :   auto call_descriptor = Linkage::GetJSCallDescriptor(
     339             :       zone(), false, 1,
     340           1 :       CallDescriptor::kNeedsFrameState | CallDescriptor::kCanUseRoots);
     341             : 
     342             :   // Build frame state for the state before the call.
     343           1 :   Node* parameters = m.AddNode(
     344             :       m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
     345             :       m.Int32Constant(1));
     346           1 :   Node* locals = m.AddNode(
     347             :       m.common()->TypedStateValues(&empty_types, SparseInputMask::Dense()));
     348           1 :   Node* stack = m.AddNode(
     349             :       m.common()->TypedStateValues(&empty_types, SparseInputMask::Dense()));
     350           1 :   Node* context_sentinel = m.Int32Constant(0);
     351           2 :   Node* state_node = m.AddNode(
     352             :       m.common()->FrameState(bailout_id, OutputFrameStateCombine::PokeAt(0),
     353             :                              m.GetFrameStateFunctionInfo(1, 0)),
     354             :       parameters, locals, stack, context_sentinel, function_node,
     355             :       m.UndefinedConstant());
     356             : 
     357             :   // Build the call.
     358           1 :   Node* nodes[] = {function_node,      receiver, m.UndefinedConstant(),
     359           2 :                    m.Int32Constant(1), context,  state_node};
     360           1 :   Node* call = m.CallNWithFrameState(call_descriptor, arraysize(nodes), nodes);
     361           1 :   m.Return(call);
     362             : 
     363           1 :   Stream s = m.Build(kAllExceptNopInstructions);
     364             : 
     365             :   // Skip until kArchCallJSFunction.
     366             :   size_t index = 0;
     367           4 :   for (; index < s.size() && s[index]->arch_opcode() != kArchCallJSFunction;
     368             :        index++) {
     369             :   }
     370             :   // Now we should have two instructions: call and return.
     371           2 :   ASSERT_EQ(index + 2, s.size());
     372             : 
     373           3 :   EXPECT_EQ(kArchCallJSFunction, s[index++]->arch_opcode());
     374           3 :   EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
     375             : 
     376             :   // TODO(jarin) Check deoptimization table.
     377             : }
     378             : 
     379       15444 : TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeopt) {
     380             :   StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(),
     381           1 :                   MachineType::AnyTagged(), MachineType::AnyTagged());
     382             : 
     383             :   BailoutId bailout_id_before(42);
     384             : 
     385             :   // Some arguments for the call node.
     386           1 :   Node* function_node = m.Parameter(0);
     387           1 :   Node* receiver = m.Parameter(1);
     388           1 :   Node* context = m.Int32Constant(1);  // Context is ignored.
     389             : 
     390             :   ZoneVector<MachineType> int32_type(1, MachineType::Int32(), zone());
     391             :   ZoneVector<MachineType> float64_type(1, MachineType::Float64(), zone());
     392             :   ZoneVector<MachineType> tagged_type(1, MachineType::AnyTagged(), zone());
     393             : 
     394           1 :   Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
     395           1 :   auto call_descriptor = Linkage::GetStubCallDescriptor(
     396           1 :       zone(), callable.descriptor(), 1, CallDescriptor::kNeedsFrameState,
     397           1 :       Operator::kNoProperties);
     398             : 
     399             :   // Build frame state for the state before the call.
     400           1 :   Node* parameters = m.AddNode(
     401             :       m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
     402             :       m.Int32Constant(43));
     403           1 :   Node* locals = m.AddNode(
     404             :       m.common()->TypedStateValues(&float64_type, SparseInputMask::Dense()),
     405             :       m.Float64Constant(0.5));
     406           1 :   Node* stack = m.AddNode(
     407             :       m.common()->TypedStateValues(&tagged_type, SparseInputMask::Dense()),
     408             :       m.UndefinedConstant());
     409           1 :   Node* context_sentinel = m.Int32Constant(0);
     410             :   Node* state_node =
     411           2 :       m.AddNode(m.common()->FrameState(bailout_id_before,
     412             :                                        OutputFrameStateCombine::PokeAt(0),
     413             :                                        m.GetFrameStateFunctionInfo(1, 1)),
     414             :                 parameters, locals, stack, context_sentinel, function_node,
     415             :                 m.UndefinedConstant());
     416             : 
     417             :   // Build the call.
     418           1 :   Node* stub_code = m.HeapConstant(callable.code());
     419           1 :   Node* nodes[] = {stub_code, function_node, receiver, context, state_node};
     420           1 :   Node* call = m.CallNWithFrameState(call_descriptor, arraysize(nodes), nodes);
     421           1 :   m.Return(call);
     422             : 
     423           1 :   Stream s = m.Build(kAllExceptNopInstructions);
     424             : 
     425             :   // Skip until kArchCallJSFunction.
     426           1 :   size_t index = 0;
     427           4 :   for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
     428             :        index++) {
     429             :   }
     430             :   // Now we should have two instructions: call, return.
     431           2 :   ASSERT_EQ(index + 2, s.size());
     432             : 
     433             :   // Check the call instruction
     434           1 :   const Instruction* call_instr = s[index++];
     435           2 :   EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
     436             :   size_t num_operands =
     437             :       1 +  // Code object.
     438             :       1 +  // Poison index
     439             :       6 +  // Frame state deopt id + one input for each value in frame state.
     440             :       1 +  // Function.
     441           1 :       1;   // Context.
     442           2 :   ASSERT_EQ(num_operands, call_instr->InputCount());
     443             : 
     444             :   // Code object.
     445           1 :   EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
     446             : 
     447             :   // Deoptimization id.
     448             :   int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(2));
     449             :   FrameStateDescriptor* desc_before =
     450           1 :       s.GetFrameStateDescriptor(deopt_id_before);
     451           2 :   EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
     452           2 :   EXPECT_EQ(1u, desc_before->parameters_count());
     453           2 :   EXPECT_EQ(1u, desc_before->locals_count());
     454           2 :   EXPECT_EQ(1u, desc_before->stack_count());
     455           2 :   EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(4)));
     456           2 :   EXPECT_EQ(0, s.ToInt32(call_instr->InputAt(5)));  // This should be a context.
     457             :                                                     // We inserted 0 here.
     458           2 :   EXPECT_EQ(0.5, s.ToFloat64(call_instr->InputAt(6)));
     459           1 :   EXPECT_TRUE(s.ToHeapObject(call_instr->InputAt(7))->IsUndefined(isolate()));
     460             : 
     461             :   // Function.
     462           2 :   EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(8)));
     463             :   // Context.
     464           2 :   EXPECT_EQ(s.ToVreg(context), s.ToVreg(call_instr->InputAt(9)));
     465             : 
     466           3 :   EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
     467             : 
     468           2 :   EXPECT_EQ(index, s.size());
     469             : }
     470             : 
     471       15444 : TARGET_TEST_F(InstructionSelectorTest, CallStubWithDeoptRecursiveFrameState) {
     472             :   StreamBuilder m(this, MachineType::AnyTagged(), MachineType::AnyTagged(),
     473           1 :                   MachineType::AnyTagged(), MachineType::AnyTagged());
     474             : 
     475             :   BailoutId bailout_id_before(42);
     476             :   BailoutId bailout_id_parent(62);
     477             : 
     478             :   // Some arguments for the call node.
     479           1 :   Node* function_node = m.Parameter(0);
     480           1 :   Node* receiver = m.Parameter(1);
     481           1 :   Node* context = m.Int32Constant(66);
     482           1 :   Node* context2 = m.Int32Constant(46);
     483             : 
     484             :   ZoneVector<MachineType> int32_type(1, MachineType::Int32(), zone());
     485             :   ZoneVector<MachineType> int32x2_type(2, MachineType::Int32(), zone());
     486             :   ZoneVector<MachineType> float64_type(1, MachineType::Float64(), zone());
     487             : 
     488           1 :   Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
     489           1 :   auto call_descriptor = Linkage::GetStubCallDescriptor(
     490           1 :       zone(), callable.descriptor(), 1, CallDescriptor::kNeedsFrameState,
     491           1 :       Operator::kNoProperties);
     492             : 
     493             :   // Build frame state for the state before the call.
     494           1 :   Node* parameters = m.AddNode(
     495             :       m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
     496             :       m.Int32Constant(63));
     497           1 :   Node* locals = m.AddNode(
     498             :       m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
     499             :       m.Int32Constant(64));
     500           1 :   Node* stack = m.AddNode(
     501             :       m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
     502             :       m.Int32Constant(65));
     503           2 :   Node* frame_state_parent = m.AddNode(
     504             :       m.common()->FrameState(bailout_id_parent,
     505             :                              OutputFrameStateCombine::Ignore(),
     506             :                              m.GetFrameStateFunctionInfo(1, 1)),
     507             :       parameters, locals, stack, context, function_node, m.UndefinedConstant());
     508             : 
     509           1 :   Node* parameters2 = m.AddNode(
     510             :       m.common()->TypedStateValues(&int32_type, SparseInputMask::Dense()),
     511             :       m.Int32Constant(43));
     512           1 :   Node* locals2 = m.AddNode(
     513             :       m.common()->TypedStateValues(&float64_type, SparseInputMask::Dense()),
     514             :       m.Float64Constant(0.25));
     515           1 :   Node* stack2 = m.AddNode(
     516             :       m.common()->TypedStateValues(&int32x2_type, SparseInputMask::Dense()),
     517             :       m.Int32Constant(44), m.Int32Constant(45));
     518             :   Node* state_node =
     519           1 :       m.AddNode(m.common()->FrameState(bailout_id_before,
     520             :                                        OutputFrameStateCombine::PokeAt(0),
     521             :                                        m.GetFrameStateFunctionInfo(1, 1)),
     522             :                 parameters2, locals2, stack2, context2, function_node,
     523             :                 frame_state_parent);
     524             : 
     525             :   // Build the call.
     526           1 :   Node* stub_code = m.HeapConstant(callable.code());
     527           1 :   Node* nodes[] = {stub_code, function_node, receiver, context2, state_node};
     528           1 :   Node* call = m.CallNWithFrameState(call_descriptor, arraysize(nodes), nodes);
     529           1 :   m.Return(call);
     530             : 
     531           1 :   Stream s = m.Build(kAllExceptNopInstructions);
     532             : 
     533             :   // Skip until kArchCallJSFunction.
     534           1 :   size_t index = 0;
     535           4 :   for (; index < s.size() && s[index]->arch_opcode() != kArchCallCodeObject;
     536             :        index++) {
     537             :   }
     538             :   // Now we should have three instructions: call, return.
     539           2 :   EXPECT_EQ(index + 2, s.size());
     540             : 
     541             :   // Check the call instruction
     542           1 :   const Instruction* call_instr = s[index++];
     543           2 :   EXPECT_EQ(kArchCallCodeObject, call_instr->arch_opcode());
     544             :   size_t num_operands =
     545             :       1 +  // Code object.
     546             :       1 +  // Poison index.
     547             :       1 +  // Frame state deopt id
     548             :       6 +  // One input for each value in frame state + context.
     549             :       5 +  // One input for each value in the parent frame state + context.
     550             :       1 +  // Function.
     551           1 :       1;   // Context.
     552           2 :   EXPECT_EQ(num_operands, call_instr->InputCount());
     553             :   // Code object.
     554           1 :   EXPECT_TRUE(call_instr->InputAt(0)->IsImmediate());
     555             : 
     556             :   // Deoptimization id.
     557             :   int32_t deopt_id_before = s.ToInt32(call_instr->InputAt(2));
     558             :   FrameStateDescriptor* desc_before =
     559           1 :       s.GetFrameStateDescriptor(deopt_id_before);
     560             :   FrameStateDescriptor* desc_before_outer = desc_before->outer_state();
     561           2 :   EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
     562           2 :   EXPECT_EQ(1u, desc_before_outer->parameters_count());
     563           2 :   EXPECT_EQ(1u, desc_before_outer->locals_count());
     564           2 :   EXPECT_EQ(1u, desc_before_outer->stack_count());
     565             :   // Values from parent environment.
     566           2 :   EXPECT_EQ(63, s.ToInt32(call_instr->InputAt(4)));
     567             :   // Context:
     568           2 :   EXPECT_EQ(66, s.ToInt32(call_instr->InputAt(5)));
     569           2 :   EXPECT_EQ(64, s.ToInt32(call_instr->InputAt(6)));
     570           2 :   EXPECT_EQ(65, s.ToInt32(call_instr->InputAt(7)));
     571             :   // Values from the nested frame.
     572           2 :   EXPECT_EQ(1u, desc_before->parameters_count());
     573           2 :   EXPECT_EQ(1u, desc_before->locals_count());
     574           2 :   EXPECT_EQ(2u, desc_before->stack_count());
     575           2 :   EXPECT_EQ(43, s.ToInt32(call_instr->InputAt(9)));
     576           2 :   EXPECT_EQ(46, s.ToInt32(call_instr->InputAt(10)));
     577           2 :   EXPECT_EQ(0.25, s.ToFloat64(call_instr->InputAt(11)));
     578           2 :   EXPECT_EQ(44, s.ToInt32(call_instr->InputAt(12)));
     579           2 :   EXPECT_EQ(45, s.ToInt32(call_instr->InputAt(13)));
     580             : 
     581             :   // Function.
     582           2 :   EXPECT_EQ(s.ToVreg(function_node), s.ToVreg(call_instr->InputAt(14)));
     583             :   // Context.
     584           2 :   EXPECT_EQ(s.ToVreg(context2), s.ToVreg(call_instr->InputAt(15)));
     585             :   // Continuation.
     586             : 
     587           3 :   EXPECT_EQ(kArchRet, s[index++]->arch_opcode());
     588           2 :   EXPECT_EQ(index, s.size());
     589           1 : }
     590             : 
     591             : // Helper to make calls to private InstructionSelector shuffle functions.
     592          14 : class InstructionSelectorShuffleTest : public ::testing::Test {
     593             :  public:
     594             :   using Shuffle = std::array<uint8_t, kSimd128Size>;
     595             : 
     596             :   struct TestShuffle {
     597             :     Shuffle non_canonical;
     598             :     Shuffle canonical;
     599             :     bool needs_swap;
     600             :     bool is_swizzle;
     601             :   };
     602             : 
     603             :   // Call testing members in InstructionSelector.
     604             :   static void CanonicalizeShuffle(bool inputs_equal, Shuffle* shuffle,
     605             :                                   bool* needs_swap, bool* is_swizzle) {
     606             :     InstructionSelector::CanonicalizeShuffleForTesting(
     607             :         inputs_equal, &(*shuffle)[0], needs_swap, is_swizzle);
     608             :   }
     609             : 
     610             :   static bool TryMatchIdentity(const Shuffle& shuffle) {
     611             :     return InstructionSelector::TryMatchIdentityForTesting(&shuffle[0]);
     612             :   }
     613             :   template <int LANES>
     614             :   static bool TryMatchDup(const Shuffle& shuffle, int* index) {
     615             :     return InstructionSelector::TryMatchDupForTesting<LANES>(&shuffle[0],
     616             :                                                              index);
     617             :   }
     618             :   static bool TryMatch32x4Shuffle(const Shuffle& shuffle,
     619             :                                   uint8_t* shuffle32x4) {
     620             :     return InstructionSelector::TryMatch32x4ShuffleForTesting(&shuffle[0],
     621             :                                                               shuffle32x4);
     622             :   }
     623             :   static bool TryMatch16x8Shuffle(const Shuffle& shuffle,
     624             :                                   uint8_t* shuffle16x8) {
     625             :     return InstructionSelector::TryMatch16x8ShuffleForTesting(&shuffle[0],
     626             :                                                               shuffle16x8);
     627             :   }
     628             :   static bool TryMatchConcat(const Shuffle& shuffle, uint8_t* offset) {
     629             :     return InstructionSelector::TryMatchConcatForTesting(&shuffle[0], offset);
     630             :   }
     631             :   static bool TryMatchBlend(const Shuffle& shuffle) {
     632             :     return InstructionSelector::TryMatchBlendForTesting(&shuffle[0]);
     633             :   }
     634             : };
     635             : 
     636           0 : bool operator==(const InstructionSelectorShuffleTest::Shuffle& a,
     637             :                 const InstructionSelectorShuffleTest::Shuffle& b) {
     638           0 :   for (int i = 0; i < kSimd128Size; ++i) {
     639           0 :     if (a[i] != b[i]) return false;
     640             :   }
     641             :   return true;
     642             : }
     643             : 
     644       15444 : TEST_F(InstructionSelectorShuffleTest, CanonicalizeShuffle) {
     645             :   const bool kInputsEqual = true;
     646             :   const bool kNeedsSwap = true;
     647             :   const bool kIsSwizzle = true;
     648             : 
     649             :   bool needs_swap;
     650             :   bool is_swizzle;
     651             : 
     652             :   // Test canonicalization driven by input shuffle.
     653             :   TestShuffle test_shuffles[] = {
     654             :       // Identity is canonical.
     655             :       {{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
     656             :        {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
     657             :        !kNeedsSwap,
     658             :        kIsSwizzle},
     659             :       // Non-canonical identity requires a swap.
     660             :       {{{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}},
     661             :        {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
     662             :        kNeedsSwap,
     663             :        kIsSwizzle},
     664             :       // General shuffle, canonical is unchanged.
     665             :       {{{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}},
     666             :        {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}},
     667             :        !kNeedsSwap,
     668             :        !kIsSwizzle},
     669             :       // Non-canonical shuffle requires a swap.
     670             :       {{{16, 0, 17, 1, 18, 2, 19, 3, 20, 4, 21, 5, 22, 6, 23, 7}},
     671             :        {{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}},
     672             :        kNeedsSwap,
     673             :        !kIsSwizzle},
     674           1 :   };
     675           9 :   for (size_t i = 0; i < arraysize(test_shuffles); ++i) {
     676           4 :     Shuffle shuffle = test_shuffles[i].non_canonical;
     677             :     CanonicalizeShuffle(!kInputsEqual, &shuffle, &needs_swap, &is_swizzle);
     678           8 :     EXPECT_EQ(shuffle, test_shuffles[i].canonical);
     679           8 :     EXPECT_EQ(needs_swap, test_shuffles[i].needs_swap);
     680           8 :     EXPECT_EQ(is_swizzle, test_shuffles[i].is_swizzle);
     681             :   }
     682             : 
     683             :   // Test canonicalization when inputs are equal (explicit swizzle).
     684             :   TestShuffle test_swizzles[] = {
     685             :       // Identity is canonical.
     686             :       {{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
     687             :        {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
     688             :        !kNeedsSwap,
     689             :        kIsSwizzle},
     690             :       // Non-canonical identity requires a swap.
     691             :       {{{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}},
     692             :        {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
     693             :        !kNeedsSwap,
     694             :        kIsSwizzle},
     695             :       // Canonicalized to swizzle.
     696             :       {{{0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23}},
     697             :        {{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7}},
     698             :        !kNeedsSwap,
     699             :        kIsSwizzle},
     700             :       // Canonicalized to swizzle.
     701             :       {{{16, 0, 17, 1, 18, 2, 19, 3, 20, 4, 21, 5, 22, 6, 23, 7}},
     702             :        {{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7}},
     703             :        !kNeedsSwap,
     704             :        kIsSwizzle},
     705           1 :   };
     706           9 :   for (size_t i = 0; i < arraysize(test_swizzles); ++i) {
     707           4 :     Shuffle shuffle = test_swizzles[i].non_canonical;
     708             :     CanonicalizeShuffle(kInputsEqual, &shuffle, &needs_swap, &is_swizzle);
     709           8 :     EXPECT_EQ(shuffle, test_swizzles[i].canonical);
     710           8 :     EXPECT_EQ(needs_swap, test_swizzles[i].needs_swap);
     711           8 :     EXPECT_EQ(is_swizzle, test_swizzles[i].is_swizzle);
     712             :   }
     713           1 : }
     714             : 
     715       15444 : TEST_F(InstructionSelectorShuffleTest, TryMatchIdentity) {
     716             :   // Match shuffle that returns first source operand.
     717           2 :   EXPECT_TRUE(TryMatchIdentity(
     718           0 :       {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}));
     719             :   // The non-canonicalized identity shuffle doesn't match.
     720           3 :   EXPECT_FALSE(TryMatchIdentity(
     721           0 :       {{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}}));
     722             :   // Even one lane out of place is not an identity shuffle.
     723           3 :   EXPECT_FALSE(TryMatchIdentity(
     724           0 :       {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 31}}));
     725           1 : }
     726             : 
     727       15444 : TEST_F(InstructionSelectorShuffleTest, TryMatchDup) {
     728             :   int index;
     729             :   // All lanes from the same 32 bit source lane.
     730           2 :   EXPECT_TRUE(TryMatchDup<4>({{4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7}},
     731           0 :                              &index));
     732           2 :   EXPECT_EQ(1, index);
     733             :   // It shouldn't match for other vector shapes.
     734           3 :   EXPECT_FALSE(TryMatchDup<8>(
     735           0 :       {{4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7}}, &index));
     736           3 :   EXPECT_FALSE(TryMatchDup<16>(
     737           0 :       {{4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7, 4, 5, 6, 7}}, &index));
     738             :   // All lanes from the same 16 bit source lane.
     739           2 :   EXPECT_TRUE(TryMatchDup<8>(
     740             :       {{16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17}},
     741           0 :       &index));
     742           2 :   EXPECT_EQ(8, index);
     743             :   // It shouldn't match for other vector shapes.
     744           3 :   EXPECT_FALSE(TryMatchDup<4>(
     745             :       {{16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17}},
     746           0 :       &index));
     747           3 :   EXPECT_FALSE(TryMatchDup<16>(
     748             :       {{16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17, 16, 17}},
     749           0 :       &index));
     750             :   // All lanes from the same 8 bit source lane.
     751           2 :   EXPECT_TRUE(TryMatchDup<16>(
     752           0 :       {{7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}}, &index));
     753           2 :   EXPECT_EQ(7, index);
     754             :   // It shouldn't match for other vector shapes.
     755           3 :   EXPECT_FALSE(TryMatchDup<4>(
     756           0 :       {{7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}}, &index));
     757           3 :   EXPECT_FALSE(TryMatchDup<8>(
     758           0 :       {{7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}}, &index));
     759           1 : }
     760             : 
     761       15444 : TEST_F(InstructionSelectorShuffleTest, TryMatchConcat) {
     762             :   uint8_t offset;
     763             :   // Ascending indices, jump at end to same input (concatenating swizzle).
     764           2 :   EXPECT_TRUE(TryMatchConcat(
     765           0 :       {{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2}}, &offset));
     766           2 :   EXPECT_EQ(3, offset);
     767             :   // Ascending indices, jump at end to other input (concatenating shuffle).
     768           2 :   EXPECT_TRUE(TryMatchConcat(
     769           0 :       {{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}}, &offset));
     770           2 :   EXPECT_EQ(4, offset);
     771             : 
     772             :   // Shuffles that should not match:
     773             :   // Ascending indices, but jump isn't at end/beginning.
     774           3 :   EXPECT_FALSE(TryMatchConcat(
     775           0 :       {{3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6}}, &offset));
     776             :   // Ascending indices, but multiple jumps.
     777           3 :   EXPECT_FALSE(TryMatchConcat(
     778           0 :       {{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}}, &offset));
     779           1 : }
     780             : 
     781       15444 : TEST_F(InstructionSelectorShuffleTest, TryMatch32x4Shuffle) {
     782             :   uint8_t shuffle32x4[4];
     783             :   // Match if each group of 4 bytes is from the same 32 bit lane.
     784           2 :   EXPECT_TRUE(TryMatch32x4Shuffle(
     785             :       {{12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 16, 17, 18, 19}},
     786           0 :       shuffle32x4));
     787           2 :   EXPECT_EQ(3, shuffle32x4[0]);
     788           2 :   EXPECT_EQ(2, shuffle32x4[1]);
     789           2 :   EXPECT_EQ(1, shuffle32x4[2]);
     790           2 :   EXPECT_EQ(4, shuffle32x4[3]);
     791             :   // Bytes must be in order in the 32 bit lane.
     792           3 :   EXPECT_FALSE(TryMatch32x4Shuffle(
     793             :       {{12, 13, 14, 14, 8, 9, 10, 11, 4, 5, 6, 7, 16, 17, 18, 19}},
     794           0 :       shuffle32x4));
     795             :   // Each group must start with the first byte in the 32 bit lane.
     796           3 :   EXPECT_FALSE(TryMatch32x4Shuffle(
     797             :       {{13, 14, 15, 12, 8, 9, 10, 11, 4, 5, 6, 7, 16, 17, 18, 19}},
     798           0 :       shuffle32x4));
     799           1 : }
     800             : 
     801       15444 : TEST_F(InstructionSelectorShuffleTest, TryMatch16x8Shuffle) {
     802             :   uint8_t shuffle16x8[8];
     803             :   // Match if each group of 2 bytes is from the same 16 bit lane.
     804           2 :   EXPECT_TRUE(TryMatch16x8Shuffle(
     805             :       {{12, 13, 30, 31, 8, 9, 26, 27, 4, 5, 22, 23, 16, 17, 2, 3}},
     806           0 :       shuffle16x8));
     807           2 :   EXPECT_EQ(6, shuffle16x8[0]);
     808           2 :   EXPECT_EQ(15, shuffle16x8[1]);
     809           2 :   EXPECT_EQ(4, shuffle16x8[2]);
     810           2 :   EXPECT_EQ(13, shuffle16x8[3]);
     811           2 :   EXPECT_EQ(2, shuffle16x8[4]);
     812           2 :   EXPECT_EQ(11, shuffle16x8[5]);
     813           2 :   EXPECT_EQ(8, shuffle16x8[6]);
     814           2 :   EXPECT_EQ(1, shuffle16x8[7]);
     815             :   // Bytes must be in order in the 16 bit lane.
     816           3 :   EXPECT_FALSE(TryMatch16x8Shuffle(
     817             :       {{12, 13, 30, 30, 8, 9, 26, 27, 4, 5, 22, 23, 16, 17, 2, 3}},
     818           0 :       shuffle16x8));
     819             :   // Each group must start with the first byte in the 16 bit lane.
     820           3 :   EXPECT_FALSE(TryMatch16x8Shuffle(
     821             :       {{12, 13, 31, 30, 8, 9, 26, 27, 4, 5, 22, 23, 16, 17, 2, 3}},
     822           0 :       shuffle16x8));
     823           1 : }
     824             : 
     825       15444 : TEST_F(InstructionSelectorShuffleTest, TryMatchBlend) {
     826             :   // Match if each byte remains in place.
     827           2 :   EXPECT_TRUE(TryMatchBlend(
     828           0 :       {{0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31}}));
     829             :   // Identity is a blend.
     830           2 :   EXPECT_TRUE(
     831           0 :       TryMatchBlend({{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}));
     832             :   // Even one lane out of place is not a blend.
     833           3 :   EXPECT_FALSE(TryMatchBlend(
     834           0 :       {{1, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31}}));
     835           1 : }
     836             : 
     837             : }  // namespace compiler
     838             : }  // namespace internal
     839        9264 : }  // namespace v8

Generated by: LCOV version 1.10