1// Copyright 2015 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/interpreter/interpreter-assembler-unittest.h"
6
7#include "src/code-factory.h"
8#include "src/compiler/graph.h"
9#include "src/compiler/node.h"
10#include "src/interface-descriptors.h"
11#include "src/isolate.h"
12#include "test/unittests/compiler/compiler-test-utils.h"
13#include "test/unittests/compiler/node-test-utils.h"
14
15using ::testing::_;
16
17namespace v8 {
18namespace internal {
19
20using namespace compiler;
21
22namespace interpreter {
23
24const interpreter::Bytecode kBytecodes[] = {
25#define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name,
26    BYTECODE_LIST(DEFINE_BYTECODE)
27#undef DEFINE_BYTECODE
28};
29
30Matcher<Node*> IsIntPtrConstant(const intptr_t value) {
31  return kPointerSize == 8 ? IsInt64Constant(static_cast<int64_t>(value))
32                           : IsInt32Constant(static_cast<int32_t>(value));
33}
34
35Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher,
36                           const Matcher<Node*>& rhs_matcher) {
37  return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher)
38                           : IsInt32Add(lhs_matcher, rhs_matcher);
39}
40
41Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher,
42                           const Matcher<Node*>& rhs_matcher) {
43  return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher)
44                           : IsInt32Sub(lhs_matcher, rhs_matcher);
45}
46
47Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher,
48                         const Matcher<Node*>& rhs_matcher) {
49  return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher)
50                           : IsWord32Shl(lhs_matcher, rhs_matcher);
51}
52
53Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher,
54                         const Matcher<Node*>& rhs_matcher) {
55  return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher)
56                           : IsWord32Sar(lhs_matcher, rhs_matcher);
57}
58
59Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher,
60                        const Matcher<Node*>& rhs_matcher) {
61  return kPointerSize == 8 ? IsWord64Or(lhs_matcher, rhs_matcher)
62                           : IsWord32Or(lhs_matcher, rhs_matcher);
63}
64
65InterpreterAssemblerTest::InterpreterAssemblerForTest::
66    ~InterpreterAssemblerForTest() {
67  // Tests don't necessarily read and write accumulator but
68  // InterpreterAssembler checks accumulator uses.
69  if (Bytecodes::ReadsAccumulator(bytecode())) {
70    GetAccumulator();
71  }
72  if (Bytecodes::WritesAccumulator(bytecode())) {
73    SetAccumulator(nullptr);
74  }
75}
76
77Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad(
78    const Matcher<LoadRepresentation>& rep_matcher,
79    const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) {
80  return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher, _, _);
81}
82
83Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore(
84    const Matcher<StoreRepresentation>& rep_matcher,
85    const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher,
86    const Matcher<Node*>& value_matcher) {
87  return ::i::compiler::IsStore(rep_matcher, base_matcher, index_matcher,
88                                value_matcher, _, _);
89}
90
91Matcher<Node*>
92InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedByteOperand(
93    int offset) {
94  return IsLoad(
95      MachineType::Uint8(),
96      IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
97      IsIntPtrAdd(
98          IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
99          IsIntPtrConstant(offset)));
100}
101
102Matcher<Node*>
103InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedByteOperand(
104    int offset) {
105  Matcher<Node*> load_matcher = IsLoad(
106      MachineType::Int8(),
107      IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
108      IsIntPtrAdd(
109          IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
110          IsIntPtrConstant(offset)));
111  if (kPointerSize == 8) {
112    load_matcher = IsChangeInt32ToInt64(load_matcher);
113  }
114  return load_matcher;
115}
116
117Matcher<Node*>
118InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedShortOperand(
119    int offset) {
120  if (TargetSupportsUnalignedAccess()) {
121    return IsLoad(
122        MachineType::Uint16(),
123        IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
124        IsIntPtrAdd(
125            IsParameter(
126                InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
127            IsIntPtrConstant(offset)));
128  } else {
129#if V8_TARGET_LITTLE_ENDIAN
130    const int kStep = -1;
131    const int kMsbOffset = 1;
132#elif V8_TARGET_BIG_ENDIAN
133    const int kStep = 1;
134    const int kMsbOffset = 0;
135#else
136#error "Unknown Architecture"
137#endif
138    Matcher<Node*> bytes[2];
139    for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
140      bytes[i] = IsLoad(
141          MachineType::Uint8(),
142          IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
143          IsIntPtrAdd(
144              IsParameter(
145                  InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
146              IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
147    }
148    return IsWord32Or(IsWord32Shl(bytes[0], IsInt32Constant(kBitsPerByte)),
149                      bytes[1]);
150  }
151}
152
153Matcher<Node*>
154InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedShortOperand(
155    int offset) {
156  Matcher<Node*> load_matcher;
157  if (TargetSupportsUnalignedAccess()) {
158    load_matcher = IsLoad(
159        MachineType::Int16(),
160        IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
161        IsIntPtrAdd(
162            IsParameter(
163                InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
164            IsIntPtrConstant(offset)));
165  } else {
166#if V8_TARGET_LITTLE_ENDIAN
167    const int kStep = -1;
168    const int kMsbOffset = 1;
169#elif V8_TARGET_BIG_ENDIAN
170    const int kStep = 1;
171    const int kMsbOffset = 0;
172#else
173#error "Unknown Architecture"
174#endif
175    Matcher<Node*> bytes[2];
176    for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
177      bytes[i] = IsLoad(
178          (i == 0) ? MachineType::Int8() : MachineType::Uint8(),
179          IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
180          IsIntPtrAdd(
181              IsParameter(
182                  InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
183              IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
184    }
185    load_matcher = IsWord32Or(
186        IsWord32Shl(bytes[0], IsInt32Constant(kBitsPerByte)), bytes[1]);
187  }
188
189  if (kPointerSize == 8) {
190    load_matcher = IsChangeInt32ToInt64(load_matcher);
191  }
192  return load_matcher;
193}
194
195Matcher<Node*>
196InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedQuadOperand(
197    int offset) {
198  if (TargetSupportsUnalignedAccess()) {
199    return IsLoad(
200        MachineType::Uint32(),
201        IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
202        IsIntPtrAdd(
203            IsParameter(
204                InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
205            IsIntPtrConstant(offset)));
206  } else {
207#if V8_TARGET_LITTLE_ENDIAN
208    const int kStep = -1;
209    const int kMsbOffset = 3;
210#elif V8_TARGET_BIG_ENDIAN
211    const int kStep = 1;
212    const int kMsbOffset = 0;
213#else
214#error "Unknown Architecture"
215#endif
216    Matcher<Node*> bytes[4];
217    for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
218      bytes[i] = IsLoad(
219          MachineType::Uint8(),
220          IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
221          IsIntPtrAdd(
222              IsParameter(
223                  InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
224              IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
225    }
226    return IsWord32Or(
227        IsWord32Shl(bytes[0], IsInt32Constant(3 * kBitsPerByte)),
228        IsWord32Or(
229            IsWord32Shl(bytes[1], IsInt32Constant(2 * kBitsPerByte)),
230            IsWord32Or(IsWord32Shl(bytes[2], IsInt32Constant(1 * kBitsPerByte)),
231                       bytes[3])));
232  }
233}
234
235Matcher<Node*>
236InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedQuadOperand(
237    int offset) {
238  Matcher<Node*> load_matcher;
239  if (TargetSupportsUnalignedAccess()) {
240    load_matcher = IsLoad(
241        MachineType::Int32(),
242        IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
243        IsIntPtrAdd(
244            IsParameter(
245                InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
246            IsIntPtrConstant(offset)));
247  } else {
248#if V8_TARGET_LITTLE_ENDIAN
249    const int kStep = -1;
250    int kMsbOffset = 3;
251#elif V8_TARGET_BIG_ENDIAN
252    const int kStep = 1;
253    int kMsbOffset = 0;
254#else
255#error "Unknown Architecture"
256#endif
257    Matcher<Node*> bytes[4];
258    for (int i = 0; i < static_cast<int>(arraysize(bytes)); i++) {
259      bytes[i] = IsLoad(
260          (i == 0) ? MachineType::Int8() : MachineType::Uint8(),
261          IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
262          IsIntPtrAdd(
263              IsParameter(
264                  InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
265              IsIntPtrConstant(offset + kMsbOffset + kStep * i)));
266    }
267    load_matcher = IsWord32Or(
268        IsWord32Shl(bytes[0], IsInt32Constant(3 * kBitsPerByte)),
269        IsWord32Or(
270            IsWord32Shl(bytes[1], IsInt32Constant(2 * kBitsPerByte)),
271            IsWord32Or(IsWord32Shl(bytes[2], IsInt32Constant(1 * kBitsPerByte)),
272                       bytes[3])));
273  }
274
275  if (kPointerSize == 8) {
276    load_matcher = IsChangeInt32ToInt64(load_matcher);
277  }
278  return load_matcher;
279}
280
281Matcher<Node*>
282InterpreterAssemblerTest::InterpreterAssemblerForTest::IsSignedOperand(
283    int offset, OperandSize operand_size) {
284  switch (operand_size) {
285    case OperandSize::kByte:
286      return IsSignedByteOperand(offset);
287    case OperandSize::kShort:
288      return IsSignedShortOperand(offset);
289    case OperandSize::kQuad:
290      return IsSignedQuadOperand(offset);
291    case OperandSize::kNone:
292      UNREACHABLE();
293  }
294  return nullptr;
295}
296
297Matcher<Node*>
298InterpreterAssemblerTest::InterpreterAssemblerForTest::IsUnsignedOperand(
299    int offset, OperandSize operand_size) {
300  switch (operand_size) {
301    case OperandSize::kByte:
302      return IsUnsignedByteOperand(offset);
303    case OperandSize::kShort:
304      return IsUnsignedShortOperand(offset);
305    case OperandSize::kQuad:
306      return IsUnsignedQuadOperand(offset);
307    case OperandSize::kNone:
308      UNREACHABLE();
309  }
310  return nullptr;
311}
312
313TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
314  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
315    InterpreterAssemblerForTest m(this, bytecode);
316    Node* tail_call_node = m.Dispatch();
317
318    OperandScale operand_scale = OperandScale::kSingle;
319    Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd(
320        IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
321        IsIntPtrConstant(
322            interpreter::Bytecodes::Size(bytecode, operand_scale)));
323    Matcher<Node*> target_bytecode_matcher = m.IsLoad(
324        MachineType::Uint8(),
325        IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
326        next_bytecode_offset_matcher);
327    if (kPointerSize == 8) {
328      target_bytecode_matcher = IsChangeUint32ToUint64(target_bytecode_matcher);
329    }
330    Matcher<Node*> code_target_matcher = m.IsLoad(
331        MachineType::Pointer(),
332        IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter),
333        IsWordShl(target_bytecode_matcher, IsIntPtrConstant(kPointerSizeLog2)));
334
335    EXPECT_THAT(
336        tail_call_node,
337        IsTailCall(
338            _, code_target_matcher,
339            IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter),
340            next_bytecode_offset_matcher,
341            IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
342            IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter),
343            _, _));
344  }
345}
346
347TARGET_TEST_F(InterpreterAssemblerTest, Jump) {
348  // If debug code is enabled we emit extra code in Jump.
349  if (FLAG_debug_code) return;
350
351  int jump_offsets[] = {-9710, -77, 0, +3, +97109};
352  TRACED_FOREACH(int, jump_offset, jump_offsets) {
353    TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
354      InterpreterAssemblerForTest m(this, bytecode);
355      Node* tail_call_node = m.Jump(m.IntPtrConstant(jump_offset));
356
357      Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd(
358          IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
359          IsIntPtrConstant(jump_offset));
360      Matcher<Node*> target_bytecode_matcher =
361          m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher);
362      if (kPointerSize == 8) {
363        target_bytecode_matcher =
364            IsChangeUint32ToUint64(target_bytecode_matcher);
365      }
366      Matcher<Node*> code_target_matcher = m.IsLoad(
367          MachineType::Pointer(),
368          IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter),
369          IsWordShl(target_bytecode_matcher,
370                    IsIntPtrConstant(kPointerSizeLog2)));
371
372      EXPECT_THAT(
373          tail_call_node,
374          IsTailCall(
375              _, code_target_matcher,
376              IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter),
377              next_bytecode_offset_matcher, _,
378              IsParameter(
379                  InterpreterDispatchDescriptor::kDispatchTableParameter),
380              _, _));
381    }
382  }
383}
384
385TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
386  static const OperandScale kOperandScales[] = {
387      OperandScale::kSingle, OperandScale::kDouble, OperandScale::kQuadruple};
388  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
389    TRACED_FOREACH(interpreter::OperandScale, operand_scale, kOperandScales) {
390      InterpreterAssemblerForTest m(this, bytecode, operand_scale);
391      int number_of_operands =
392          interpreter::Bytecodes::NumberOfOperands(bytecode);
393      for (int i = 0; i < number_of_operands; i++) {
394        int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i,
395                                                              operand_scale);
396        OperandType operand_type =
397            interpreter::Bytecodes::GetOperandType(bytecode, i);
398        OperandSize operand_size =
399            Bytecodes::SizeOfOperand(operand_type, operand_scale);
400        switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
401          case interpreter::OperandType::kRegCount:
402            EXPECT_THAT(m.BytecodeOperandCount(i),
403                        m.IsUnsignedOperand(offset, operand_size));
404            break;
405          case interpreter::OperandType::kFlag8:
406            EXPECT_THAT(m.BytecodeOperandFlag(i),
407                        m.IsUnsignedOperand(offset, operand_size));
408            break;
409          case interpreter::OperandType::kIdx:
410            EXPECT_THAT(m.BytecodeOperandIdx(i),
411                        m.IsUnsignedOperand(offset, operand_size));
412            break;
413          case interpreter::OperandType::kImm: {
414            EXPECT_THAT(m.BytecodeOperandImm(i),
415                        m.IsSignedOperand(offset, operand_size));
416            break;
417          }
418          case interpreter::OperandType::kMaybeReg:
419          case interpreter::OperandType::kReg:
420          case interpreter::OperandType::kRegOut:
421          case interpreter::OperandType::kRegOutPair:
422          case interpreter::OperandType::kRegOutTriple:
423          case interpreter::OperandType::kRegPair:
424            EXPECT_THAT(m.BytecodeOperandReg(i),
425                        m.IsSignedOperand(offset, operand_size));
426            break;
427          case interpreter::OperandType::kRuntimeId:
428            EXPECT_THAT(m.BytecodeOperandRuntimeId(i),
429                        m.IsUnsignedOperand(offset, operand_size));
430            break;
431          case interpreter::OperandType::kIntrinsicId:
432            EXPECT_THAT(m.BytecodeOperandIntrinsicId(i),
433                        m.IsUnsignedOperand(offset, operand_size));
434            break;
435          case interpreter::OperandType::kNone:
436            UNREACHABLE();
437            break;
438        }
439      }
440    }
441  }
442}
443
444TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) {
445  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
446    if (!interpreter::Bytecodes::ReadsAccumulator(bytecode) ||
447        !interpreter::Bytecodes::WritesAccumulator(bytecode)) {
448      continue;
449    }
450
451    InterpreterAssemblerForTest m(this, bytecode);
452    // Should be incoming accumulator if not set.
453    EXPECT_THAT(
454        m.GetAccumulator(),
455        IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter));
456    // Should be set by SetAccumulator.
457    Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef);
458    m.SetAccumulator(accumulator_value_1);
459    EXPECT_THAT(m.GetAccumulator(), accumulator_value_1);
460    Node* accumulator_value_2 = m.Int32Constant(42);
461    m.SetAccumulator(accumulator_value_2);
462    EXPECT_THAT(m.GetAccumulator(), accumulator_value_2);
463
464    // Should be passed to next bytecode handler on dispatch.
465    Node* tail_call_node = m.Dispatch();
466
467    EXPECT_THAT(tail_call_node,
468                IsTailCall(_, _, accumulator_value_2, _, _, _, _));
469  }
470}
471
472TARGET_TEST_F(InterpreterAssemblerTest, GetContext) {
473  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
474    InterpreterAssemblerForTest m(this, bytecode);
475    EXPECT_THAT(
476        m.GetContext(),
477        m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(),
478                 IsIntPtrConstant(Register::current_context().ToOperand()
479                                  << kPointerSizeLog2)));
480  }
481}
482
483TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) {
484  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
485    InterpreterAssemblerForTest m(this, bytecode);
486    Node* reg_index_node = m.IntPtrConstant(44);
487    Node* reg_location_node = m.RegisterLocation(reg_index_node);
488    EXPECT_THAT(reg_location_node,
489                IsIntPtrAdd(IsLoadParentFramePointer(),
490                            IsWordShl(reg_index_node,
491                                      IsIntPtrConstant(kPointerSizeLog2))));
492  }
493}
494
495TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) {
496  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
497    InterpreterAssemblerForTest m(this, bytecode);
498    Node* reg_index_node = m.IntPtrConstant(44);
499    Node* load_reg_node = m.LoadRegister(reg_index_node);
500    EXPECT_THAT(load_reg_node,
501                m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(),
502                         IsWordShl(reg_index_node,
503                                   IsIntPtrConstant(kPointerSizeLog2))));
504  }
505}
506
507TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) {
508  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
509    InterpreterAssemblerForTest m(this, bytecode);
510    Node* store_value = m.Int32Constant(0xdeadbeef);
511    Node* reg_index_node = m.IntPtrConstant(44);
512    Node* store_reg_node = m.StoreRegister(store_value, reg_index_node);
513    EXPECT_THAT(
514        store_reg_node,
515        m.IsStore(StoreRepresentation(MachineRepresentation::kTagged,
516                                      kNoWriteBarrier),
517                  IsLoadParentFramePointer(),
518                  IsWordShl(reg_index_node, IsIntPtrConstant(kPointerSizeLog2)),
519                  store_value));
520  }
521}
522
523TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) {
524  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
525    InterpreterAssemblerForTest m(this, bytecode);
526    Node* value = m.Int32Constant(44);
527    EXPECT_THAT(m.SmiTag(value),
528                IsIntPtrConstant(static_cast<intptr_t>(44)
529                                 << (kSmiShiftSize + kSmiTagSize)));
530    EXPECT_THAT(
531        m.SmiUntag(value),
532        IsWordSar(value, IsIntPtrConstant(kSmiShiftSize + kSmiTagSize)));
533  }
534}
535
536TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) {
537  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
538    InterpreterAssemblerForTest m(this, bytecode);
539    Node* a = m.Int32Constant(0);
540    Node* b = m.Int32Constant(1);
541    Node* add = m.IntPtrAdd(a, b);
542    EXPECT_THAT(add, IsIntPtrAdd(a, b));
543  }
544}
545
546TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) {
547  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
548    InterpreterAssemblerForTest m(this, bytecode);
549    Node* a = m.Int32Constant(0);
550    Node* b = m.Int32Constant(1);
551    Node* add = m.IntPtrSub(a, b);
552    EXPECT_THAT(add, IsIntPtrSub(a, b));
553  }
554}
555
556TARGET_TEST_F(InterpreterAssemblerTest, WordShl) {
557  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
558    InterpreterAssemblerForTest m(this, bytecode);
559    Node* a = m.IntPtrConstant(0);
560    Node* add = m.WordShl(a, 10);
561    EXPECT_THAT(add, IsWordShl(a, IsIntPtrConstant(10)));
562  }
563}
564
565TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) {
566  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
567    InterpreterAssemblerForTest m(this, bytecode);
568    Node* index = m.IntPtrConstant(2);
569    Node* load_constant = m.LoadConstantPoolEntry(index);
570    Matcher<Node*> constant_pool_matcher = m.IsLoad(
571        MachineType::AnyTagged(),
572        IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
573        IsIntPtrConstant(BytecodeArray::kConstantPoolOffset - kHeapObjectTag));
574    EXPECT_THAT(
575        load_constant,
576        m.IsLoad(MachineType::AnyTagged(), constant_pool_matcher,
577                 IsIntPtrAdd(
578                     IsIntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag),
579                     IsWordShl(index, IsIntPtrConstant(kPointerSizeLog2)))));
580  }
581}
582
583TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
584  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
585    InterpreterAssemblerForTest m(this, bytecode);
586    Node* object = m.IntPtrConstant(0xdeadbeef);
587    int offset = 16;
588    Node* load_field = m.LoadObjectField(object, offset);
589    EXPECT_THAT(load_field,
590                m.IsLoad(MachineType::AnyTagged(), object,
591                         IsIntPtrConstant(offset - kHeapObjectTag)));
592  }
593}
594
595TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
596  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
597    InterpreterAssemblerForTest m(this, bytecode);
598    Node* context = m.IntPtrConstant(1);
599    Node* slot_index = m.IntPtrConstant(22);
600    Node* load_context_slot = m.LoadContextSlot(context, slot_index);
601
602    Matcher<Node*> offset =
603        IsIntPtrAdd(IsWordShl(slot_index, IsIntPtrConstant(kPointerSizeLog2)),
604                    IsIntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
605    EXPECT_THAT(load_context_slot,
606                m.IsLoad(MachineType::AnyTagged(), context, offset));
607  }
608}
609
610TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) {
611  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
612    InterpreterAssemblerForTest m(this, bytecode);
613    Node* context = m.IntPtrConstant(1);
614    Node* slot_index = m.IntPtrConstant(22);
615    Node* value = m.SmiConstant(Smi::FromInt(100));
616    Node* store_context_slot = m.StoreContextSlot(context, slot_index, value);
617
618    Matcher<Node*> offset =
619        IsIntPtrAdd(IsWordShl(slot_index, IsIntPtrConstant(kPointerSizeLog2)),
620                    IsIntPtrConstant(Context::kHeaderSize - kHeapObjectTag));
621    EXPECT_THAT(store_context_slot,
622                m.IsStore(StoreRepresentation(MachineRepresentation::kTagged,
623                                              kFullWriteBarrier),
624                          context, offset, value));
625  }
626}
627
628TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) {
629  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
630    InterpreterAssemblerForTest m(this, bytecode);
631    Node* arg1 = m.Int32Constant(2);
632    Node* arg2 = m.Int32Constant(3);
633    Node* context = m.Int32Constant(4);
634    Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2);
635    EXPECT_THAT(call_runtime,
636                IsCall(_, _, arg1, arg2, _, IsInt32Constant(2), context, _, _));
637  }
638}
639
640TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) {
641  const int kResultSizes[] = {1, 2};
642  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
643    TRACED_FOREACH(int, result_size, kResultSizes) {
644      InterpreterAssemblerForTest m(this, bytecode);
645      Callable builtin = CodeFactory::InterpreterCEntry(isolate(), result_size);
646
647      Node* function_id = m.Int32Constant(0);
648      Node* first_arg = m.Int32Constant(1);
649      Node* arg_count = m.Int32Constant(2);
650      Node* context = m.Int32Constant(4);
651
652      Matcher<Node*> function_table = IsExternalConstant(
653          ExternalReference::runtime_function_table_address(isolate()));
654      Matcher<Node*> function = IsIntPtrAdd(
655          function_table,
656          IsInt32Mul(function_id, IsInt32Constant(sizeof(Runtime::Function))));
657      Matcher<Node*> function_entry =
658          m.IsLoad(MachineType::Pointer(), function,
659                   IsIntPtrConstant(offsetof(Runtime::Function, entry)));
660
661      Node* call_runtime = m.CallRuntimeN(function_id, context, first_arg,
662                                          arg_count, result_size);
663      EXPECT_THAT(call_runtime,
664                  IsCall(_, IsHeapConstant(builtin.code()), arg_count,
665                         first_arg, function_entry, context, _, _));
666    }
667  }
668}
669
670TARGET_TEST_F(InterpreterAssemblerTest, CallJS) {
671  TailCallMode tail_call_modes[] = {TailCallMode::kDisallow,
672                                    TailCallMode::kAllow};
673  TRACED_FOREACH(TailCallMode, tail_call_mode, tail_call_modes) {
674    TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
675      InterpreterAssemblerForTest m(this, bytecode);
676      Callable builtin =
677          CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode);
678      Node* function = m.Int32Constant(0);
679      Node* first_arg = m.Int32Constant(1);
680      Node* arg_count = m.Int32Constant(2);
681      Node* context = m.Int32Constant(3);
682      Node* call_js =
683          m.CallJS(function, context, first_arg, arg_count, tail_call_mode);
684      EXPECT_THAT(call_js, IsCall(_, IsHeapConstant(builtin.code()), arg_count,
685                                  first_arg, function, context, _, _));
686    }
687  }
688}
689
690TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) {
691  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
692    InterpreterAssemblerForTest m(this, bytecode);
693    Node* feedback_vector = m.LoadTypeFeedbackVector();
694
695    Matcher<Node*> load_function_matcher =
696        m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(),
697                 IsIntPtrConstant(Register::function_closure().ToOperand()
698                                  << kPointerSizeLog2));
699    Matcher<Node*> load_literals_matcher = m.IsLoad(
700        MachineType::AnyTagged(), load_function_matcher,
701        IsIntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag));
702
703    EXPECT_THAT(feedback_vector,
704                m.IsLoad(MachineType::AnyTagged(), load_literals_matcher,
705                         IsIntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
706                                          kHeapObjectTag)));
707  }
708}
709
710}  // namespace interpreter
711}  // namespace internal
712}  // namespace v8
713