LCOV - code coverage report
Current view: top level - test/cctest/compiler - codegen-tester.h (source / functions) Hit Total Coverage
Test: app.info Lines: 103 106 97.2 %
Date: 2019-02-19 Functions: 141 191 73.8 %

          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             : #ifndef V8_CCTEST_COMPILER_CODEGEN_TESTER_H_
       6             : #define V8_CCTEST_COMPILER_CODEGEN_TESTER_H_
       7             : 
       8             : #include "src/compiler/backend/instruction-selector.h"
       9             : #include "src/compiler/pipeline.h"
      10             : #include "src/compiler/raw-machine-assembler.h"
      11             : #include "src/optimized-compilation-info.h"
      12             : #include "src/simulator.h"
      13             : #include "test/cctest/cctest.h"
      14             : #include "test/cctest/compiler/call-tester.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace compiler {
      19             : 
      20             : template <typename ReturnType>
      21             : class RawMachineAssemblerTester : public HandleAndZoneScope,
      22             :                                   public CallHelper<ReturnType>,
      23             :                                   public RawMachineAssembler {
      24             :  public:
      25             :   template <typename... ParamMachTypes>
      26      163868 :   explicit RawMachineAssemblerTester(ParamMachTypes... p)
      27             :       : HandleAndZoneScope(),
      28             :         CallHelper<ReturnType>(
      29             :             main_isolate(),
      30      163868 :             CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p...)),
      31             :         RawMachineAssembler(
      32             :             main_isolate(), new (main_zone()) Graph(main_zone()),
      33             :             Linkage::GetSimplifiedCDescriptor(
      34             :                 main_zone(),
      35             :                 CSignature::New(main_zone(), MachineTypeForC<ReturnType>(),
      36      163868 :                                 p...),
      37             :                 true),
      38             :             MachineType::PointerRepresentation(),
      39             :             InstructionSelector::SupportedMachineOperatorFlags(),
      40      819340 :             InstructionSelector::AlignmentRequirements()) {}
      41             : 
      42             :   template <typename... ParamMachTypes>
      43         640 :   RawMachineAssemblerTester(Code::Kind kind, ParamMachTypes... p)
      44             :       : HandleAndZoneScope(),
      45             :         CallHelper<ReturnType>(
      46             :             main_isolate(),
      47         640 :             CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p...)),
      48             :         RawMachineAssembler(
      49             :             main_isolate(), new (main_zone()) Graph(main_zone()),
      50             :             Linkage::GetSimplifiedCDescriptor(
      51             :                 main_zone(),
      52             :                 CSignature::New(main_zone(), MachineTypeForC<ReturnType>(),
      53         640 :                                 p...),
      54             :                 true),
      55             :             MachineType::PointerRepresentation(),
      56             :             InstructionSelector::SupportedMachineOperatorFlags(),
      57             :             InstructionSelector::AlignmentRequirements()),
      58        3200 :         kind_(kind) {}
      59             : 
      60      328188 :   ~RawMachineAssemblerTester() override = default;
      61             : 
      62         168 :   void CheckNumber(double expected, Object number) {
      63         336 :     CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
      64         168 :   }
      65             : 
      66          16 :   void CheckString(const char* expected, Object string) {
      67          32 :     CHECK(
      68             :         this->isolate()->factory()->InternalizeUtf8String(expected)->SameValue(
      69             :             string));
      70          16 :   }
      71             : 
      72        9740 :   void GenerateCode() { Generate(); }
      73             : 
      74             :   Handle<Code> GetCode() {
      75             :     Generate();
      76             :     return code_.ToHandleChecked();
      77             :   }
      78             : 
      79             :  protected:
      80    35282852 :   Address Generate() override {
      81    35282852 :     if (code_.is_null()) {
      82      163612 :       Schedule* schedule = this->Export();
      83             :       auto call_descriptor = this->call_descriptor();
      84             :       Graph* graph = this->graph();
      85      327224 :       OptimizedCompilationInfo info(ArrayVector("testing"), main_zone(), kind_);
      86      163612 :       code_ = Pipeline::GenerateCodeForTesting(
      87             :           &info, main_isolate(), call_descriptor, graph,
      88      327224 :           AssemblerOptions::Default(main_isolate()), schedule);
      89             :     }
      90    35282852 :     return this->code_.ToHandleChecked()->entry();
      91             :   }
      92             : 
      93             :  private:
      94             :   Code::Kind kind_ = Code::Kind::STUB;
      95             :   MaybeHandle<Code> code_;
      96             : };
      97             : 
      98             : template <typename ReturnType>
      99       16512 : class BufferedRawMachineAssemblerTester
     100             :     : public RawMachineAssemblerTester<int32_t> {
     101             :  public:
     102             :   template <typename... ParamMachTypes>
     103       16512 :   explicit BufferedRawMachineAssemblerTester(ParamMachTypes... p)
     104             :       : RawMachineAssemblerTester<int32_t>(
     105             :             MachineType::Pointer(), ((void)p, MachineType::Pointer())...),
     106             :         test_graph_signature_(
     107       16512 :             CSignature::New(this->main_zone(), MachineType::Int32(), p...)),
     108       33024 :         return_parameter_index_(sizeof...(p)) {
     109             :     static_assert(sizeof...(p) <= arraysize(parameter_nodes_),
     110             :                   "increase parameter_nodes_ array");
     111        2088 :     std::array<MachineType, sizeof...(p)> p_arr{{p...}};
     112        4280 :     for (size_t i = 0; i < p_arr.size(); ++i) {
     113        2192 :       parameter_nodes_[i] = Load(p_arr[i], RawMachineAssembler::Parameter(i));
     114             :     }
     115       16512 :   }
     116             : 
     117     2707520 :   Address Generate() override { return RawMachineAssemblerTester::Generate(); }
     118             : 
     119             :   // The BufferedRawMachineAssemblerTester does not pass parameters directly
     120             :   // to the constructed IR graph. Instead it passes a pointer to the parameter
     121             :   // to the IR graph, and adds Load nodes to the IR graph to load the
     122             :   // parameters from memory. Thereby it is possible to pass 64 bit parameters
     123             :   // to the IR graph.
     124             :   Node* Parameter(size_t index) {
     125             :     CHECK_GT(arraysize(parameter_nodes_), index);
     126        2096 :     return parameter_nodes_[index];
     127             :   }
     128             : 
     129             :   // The BufferedRawMachineAssemblerTester adds a Store node to the IR graph
     130             :   // to store the graph's return value in memory. The memory address for the
     131             :   // Store node is provided as a parameter. By storing the return value in
     132             :   // memory it is possible to return 64 bit values.
     133       16504 :   void Return(Node* input) {
     134       16504 :     Store(MachineTypeForC<ReturnType>().representation(),
     135             :           RawMachineAssembler::Parameter(return_parameter_index_), input,
     136             :           kNoWriteBarrier);
     137       16504 :     RawMachineAssembler::Return(Int32Constant(1234));
     138       16504 :   }
     139             : 
     140             :   template <typename... Params>
     141     2572272 :   ReturnType Call(Params... p) {
     142             :     uintptr_t zap_data[] = {kZapValue, kZapValue};
     143        3456 :     ReturnType return_value;
     144             :     STATIC_ASSERT(sizeof(return_value) <= sizeof(zap_data));
     145             :     MemCopy(&return_value, &zap_data, sizeof(return_value));
     146     2572272 :     CSignature::VerifyParams<Params...>(test_graph_signature_);
     147     2707520 :     CallHelper<int32_t>::Call(reinterpret_cast<void*>(&p)...,
     148     2693196 :                               reinterpret_cast<void*>(&return_value));
     149     2707520 :     return return_value;
     150             :   }
     151             : 
     152             :  private:
     153             :   CSignature* test_graph_signature_;
     154             :   Node* parameter_nodes_[4];
     155             :   uint32_t return_parameter_index_;
     156             : };
     157             : 
     158             : template <>
     159          20 : class BufferedRawMachineAssemblerTester<void>
     160             :     : public RawMachineAssemblerTester<void> {
     161             :  public:
     162             :   template <typename... ParamMachTypes>
     163          20 :   explicit BufferedRawMachineAssemblerTester(ParamMachTypes... p)
     164             :       : RawMachineAssemblerTester<void>(((void)p, MachineType::Pointer())...),
     165             :         test_graph_signature_(
     166             :             CSignature::New(RawMachineAssemblerTester<void>::main_zone(),
     167          40 :                             MachineType::None(), p...)) {
     168             :     static_assert(sizeof...(p) <= arraysize(parameter_nodes_),
     169             :                   "increase parameter_nodes_ array");
     170          16 :     std::array<MachineType, sizeof...(p)> p_arr{{p...}};
     171          56 :     for (size_t i = 0; i < p_arr.size(); ++i) {
     172          40 :       parameter_nodes_[i] = Load(p_arr[i], RawMachineAssembler::Parameter(i));
     173             :     }
     174          20 :   }
     175             : 
     176      236396 :   Address Generate() override { return RawMachineAssemblerTester::Generate(); }
     177             : 
     178             :   // The BufferedRawMachineAssemblerTester does not pass parameters directly
     179             :   // to the constructed IR graph. Instead it passes a pointer to the parameter
     180             :   // to the IR graph, and adds Load nodes to the IR graph to load the
     181             :   // parameters from memory. Thereby it is possible to pass 64 bit parameters
     182             :   // to the IR graph.
     183             :   Node* Parameter(size_t index) {
     184             :     CHECK_GT(arraysize(parameter_nodes_), index);
     185          16 :     return parameter_nodes_[index];
     186             :   }
     187             : 
     188             :   template <typename... Params>
     189             :   void Call(Params... p) {
     190      236392 :     CSignature::VerifyParams<Params...>(test_graph_signature_);
     191      236392 :     CallHelper<void>::Call(reinterpret_cast<void*>(&p)...);
     192             :   }
     193             : 
     194             :  private:
     195             :   CSignature* test_graph_signature_;
     196             :   Node* parameter_nodes_[4];
     197             : };
     198             : 
     199             : static const bool USE_RESULT_BUFFER = true;
     200             : static const bool USE_RETURN_REGISTER = false;
     201             : static const int32_t CHECK_VALUE = 0x99BEEDCE;
     202             : 
     203             : 
     204             : // TODO(titzer): use the C-style calling convention, or any register-based
     205             : // calling convention for binop tests.
     206             : template <typename CType, bool use_result_buffer>
     207             : class BinopTester {
     208             :  public:
     209         832 :   explicit BinopTester(RawMachineAssemblerTester<int32_t>* tester,
     210             :                        MachineType rep)
     211             :       : T(tester),
     212             :         param0(T->LoadFromPointer(&p0, rep)),
     213             :         param1(T->LoadFromPointer(&p1, rep)),
     214             :         rep(rep),
     215             :         p0(static_cast<CType>(0)),
     216             :         p1(static_cast<CType>(0)),
     217         832 :         result(static_cast<CType>(0)) {}
     218             : 
     219             :   RawMachineAssemblerTester<int32_t>* T;
     220             :   Node* param0;
     221             :   Node* param1;
     222             : 
     223      404228 :   CType call(CType a0, CType a1) {
     224     2535536 :     p0 = a0;
     225     2535536 :     p1 = a1;
     226             :     if (use_result_buffer) {
     227      808456 :       CHECK_EQ(CHECK_VALUE, T->Call());
     228      404228 :       return result;
     229             :     } else {
     230     2210040 :       return static_cast<CType>(T->Call());
     231             :     }
     232             :   }
     233             : 
     234          68 :   void AddReturn(Node* val) {
     235             :     if (use_result_buffer) {
     236         136 :       T->Store(rep.representation(), T->PointerConstant(&result),
     237             :                T->Int32Constant(0), val, kNoWriteBarrier);
     238          68 :       T->Return(T->Int32Constant(CHECK_VALUE));
     239             :     } else {
     240         820 :       T->Return(val);
     241             :     }
     242          68 :   }
     243             : 
     244             :   template <typename Ci, typename Cj, typename Fn>
     245             :   void Run(const Ci& ci, const Cj& cj, const Fn& fn) {
     246             :     typename Ci::const_iterator i;
     247             :     typename Cj::const_iterator j;
     248             :     for (i = ci.begin(); i != ci.end(); ++i) {
     249             :       for (j = cj.begin(); j != cj.end(); ++j) {
     250             :         CHECK_EQ(fn(*i, *j), this->call(*i, *j));
     251             :       }
     252             :     }
     253             :   }
     254             : 
     255             :  protected:
     256             :   MachineType rep;
     257             :   CType p0;
     258             :   CType p1;
     259             :   CType result;
     260             : };
     261             : 
     262             : 
     263             : // A helper class for testing code sequences that take two int parameters and
     264             : // return an int value.
     265             : class Int32BinopTester : public BinopTester<int32_t, USE_RETURN_REGISTER> {
     266             :  public:
     267             :   explicit Int32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
     268             :       : BinopTester<int32_t, USE_RETURN_REGISTER>(tester,
     269         632 :                                                   MachineType::Int32()) {}
     270             : };
     271             : 
     272             : 
     273             : // A helper class for testing code sequences that take two int parameters and
     274             : // return an int value.
     275             : class Int64BinopTester : public BinopTester<int64_t, USE_RETURN_REGISTER> {
     276             :  public:
     277             :   explicit Int64BinopTester(RawMachineAssemblerTester<int32_t>* tester)
     278             :       : BinopTester<int64_t, USE_RETURN_REGISTER>(tester,
     279          16 :                                                   MachineType::Int64()) {}
     280             : };
     281             : 
     282             : 
     283             : // A helper class for testing code sequences that take two uint parameters and
     284             : // return an uint value.
     285             : class Uint32BinopTester : public BinopTester<uint32_t, USE_RETURN_REGISTER> {
     286             :  public:
     287             :   explicit Uint32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
     288             :       : BinopTester<uint32_t, USE_RETURN_REGISTER>(tester,
     289         116 :                                                    MachineType::Uint32()) {}
     290             : 
     291             :   uint32_t call(uint32_t a0, uint32_t a1) {
     292      335476 :     p0 = a0;
     293      335476 :     p1 = a1;
     294      670948 :     return static_cast<uint32_t>(T->Call());
     295             :   }
     296             : };
     297             : 
     298             : 
     299             : // A helper class for testing code sequences that take two float parameters and
     300             : // return a float value.
     301             : class Float32BinopTester : public BinopTester<float, USE_RESULT_BUFFER> {
     302             :  public:
     303             :   explicit Float32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
     304          24 :       : BinopTester<float, USE_RESULT_BUFFER>(tester, MachineType::Float32()) {}
     305             : };
     306             : 
     307             : 
     308             : // A helper class for testing code sequences that take two double parameters and
     309             : // return a double value.
     310             : class Float64BinopTester : public BinopTester<double, USE_RESULT_BUFFER> {
     311             :  public:
     312             :   explicit Float64BinopTester(RawMachineAssemblerTester<int32_t>* tester)
     313          44 :       : BinopTester<double, USE_RESULT_BUFFER>(tester, MachineType::Float64()) {
     314             :   }
     315             : };
     316             : 
     317             : 
     318             : // A helper class for testing code sequences that take two pointer parameters
     319             : // and return a pointer value.
     320             : // TODO(titzer): pick word size of pointers based on V8_TARGET.
     321             : template <typename Type>
     322             : class PointerBinopTester : public BinopTester<Type, USE_RETURN_REGISTER> {
     323             :  public:
     324             :   explicit PointerBinopTester(RawMachineAssemblerTester<int32_t>* tester)
     325             :       : BinopTester<Type, USE_RETURN_REGISTER>(tester, MachineType::Pointer()) {
     326             :   }
     327             : };
     328             : 
     329             : 
     330             : // A helper class for testing code sequences that take two tagged parameters and
     331             : // return a tagged value.
     332             : template <typename Type>
     333             : class TaggedBinopTester : public BinopTester<Type, USE_RETURN_REGISTER> {
     334             :  public:
     335             :   explicit TaggedBinopTester(RawMachineAssemblerTester<int32_t>* tester)
     336             :       : BinopTester<Type, USE_RETURN_REGISTER>(tester,
     337             :                                                MachineType::AnyTagged()) {}
     338             : };
     339             : 
     340             : // A helper class for testing compares. Wraps a machine opcode and provides
     341             : // evaluation routines and the operators.
     342             : class CompareWrapper {
     343             :  public:
     344         140 :   explicit CompareWrapper(IrOpcode::Value op) : opcode(op) {}
     345             : 
     346        8184 :   Node* MakeNode(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
     347       16368 :     return m->AddNode(op(m->machine()), a, b);
     348             :   }
     349             : 
     350        8184 :   const Operator* op(MachineOperatorBuilder* machine) {
     351        8184 :     switch (opcode) {
     352             :       case IrOpcode::kWord32Equal:
     353        1632 :         return machine->Word32Equal();
     354             :       case IrOpcode::kInt32LessThan:
     355        1632 :         return machine->Int32LessThan();
     356             :       case IrOpcode::kInt32LessThanOrEqual:
     357        1632 :         return machine->Int32LessThanOrEqual();
     358             :       case IrOpcode::kUint32LessThan:
     359        1632 :         return machine->Uint32LessThan();
     360             :       case IrOpcode::kUint32LessThanOrEqual:
     361        1632 :         return machine->Uint32LessThanOrEqual();
     362             :       case IrOpcode::kFloat64Equal:
     363           8 :         return machine->Float64Equal();
     364             :       case IrOpcode::kFloat64LessThan:
     365           8 :         return machine->Float64LessThan();
     366             :       case IrOpcode::kFloat64LessThanOrEqual:
     367           8 :         return machine->Float64LessThanOrEqual();
     368             :       default:
     369           0 :         UNREACHABLE();
     370             :     }
     371             :     return nullptr;
     372             :   }
     373             : 
     374     2141164 :   bool Int32Compare(int32_t a, int32_t b) {
     375     2141164 :     switch (opcode) {
     376             :       case IrOpcode::kWord32Equal:
     377      438976 :         return a == b;
     378             :       case IrOpcode::kInt32LessThan:
     379      425536 :         return a < b;
     380             :       case IrOpcode::kInt32LessThanOrEqual:
     381      425536 :         return a <= b;
     382             :       case IrOpcode::kUint32LessThan:
     383      425560 :         return static_cast<uint32_t>(a) < static_cast<uint32_t>(b);
     384             :       case IrOpcode::kUint32LessThanOrEqual:
     385      425556 :         return static_cast<uint32_t>(a) <= static_cast<uint32_t>(b);
     386             :       default:
     387           0 :         UNREACHABLE();
     388             :     }
     389             :     return false;
     390             :   }
     391             : 
     392       20452 :   bool Float64Compare(double a, double b) {
     393       20452 :     switch (opcode) {
     394             :       case IrOpcode::kFloat64Equal:
     395       10008 :         return a == b;
     396             :       case IrOpcode::kFloat64LessThan:
     397       10024 :         return a < b;
     398             :       case IrOpcode::kFloat64LessThanOrEqual:
     399         420 :         return a <= b;
     400             :       default:
     401           0 :         UNREACHABLE();
     402             :     }
     403             :     return false;
     404             :   }
     405             : 
     406             :   IrOpcode::Value opcode;
     407             : };
     408             : 
     409             : 
     410             : // A small closure class to generate code for a function of two inputs that
     411             : // produces a single output so that it can be used in many different contexts.
     412             : // The {expected()} method should compute the expected output for a given
     413             : // pair of inputs.
     414             : template <typename T>
     415         120 : class BinopGen {
     416             :  public:
     417             :   virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) = 0;
     418             :   virtual T expected(T a, T b) = 0;
     419         120 :   virtual ~BinopGen() = default;
     420             : };
     421             : 
     422             : // A helper class to generate various combination of input shape combinations
     423             : // and run the generated code to ensure it produces the correct results.
     424             : class Int32BinopInputShapeTester {
     425             :  public:
     426             :   explicit Int32BinopInputShapeTester(BinopGen<int32_t>* g)
     427         120 :       : gen(g), input_a(0), input_b(0) {}
     428             : 
     429             :   void TestAllInputShapes();
     430             : 
     431             :  private:
     432             :   BinopGen<int32_t>* gen;
     433             :   int32_t input_a;
     434             :   int32_t input_b;
     435             : 
     436             :   void Run(RawMachineAssemblerTester<int32_t>* m);
     437             :   void RunLeft(RawMachineAssemblerTester<int32_t>* m);
     438             :   void RunRight(RawMachineAssemblerTester<int32_t>* m);
     439             : };
     440             : }  // namespace compiler
     441             : }  // namespace internal
     442             : }  // namespace v8
     443             : 
     444             : #endif  // V8_CCTEST_COMPILER_CODEGEN_TESTER_H_

Generated by: LCOV version 1.10