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

Generated by: LCOV version 1.10