instruction-selector-unittest.h 11.1 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
#define V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
7 8

#include <deque>
9
#include <set>
10

11
#include "src/base/utils/random-number-generator.h"
12
#include "src/compiler/instruction-selector.h"
13
#include "src/compiler/raw-machine-assembler.h"
14
#include "src/macro-assembler.h"
15
#include "test/unittests/test-utils.h"
16 17 18 19 20

namespace v8 {
namespace internal {
namespace compiler {

21 22
class InstructionSelectorTest : public TestWithContext,
                                public TestWithIsolateAndZone {
23
 public:
24
  InstructionSelectorTest();
25
  ~InstructionSelectorTest() override;
26

27 28
  base::RandomNumberGenerator* rng() { return &rng_; }

29 30
  class Stream;

31 32 33 34 35
  enum StreamBuilderMode {
    kAllInstructions,
    kTargetInstructions,
    kAllExceptNopInstructions
  };
36

37
  class StreamBuilder final : public RawMachineAssembler {
38
   public:
39
    StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
40 41 42 43 44
        : RawMachineAssembler(test->isolate(),
                              new (test->zone()) Graph(test->zone()),
                              MakeCallDescriptor(test->zone(), return_type),
                              MachineType::PointerRepresentation(),
                              MachineOperatorBuilder::kAllOptionalOps),
45
          test_(test) {}
46 47
    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
                  MachineType parameter0_type)
48
        : RawMachineAssembler(
49
              test->isolate(), new (test->zone()) Graph(test->zone()),
50
              MakeCallDescriptor(test->zone(), return_type, parameter0_type),
51 52
              MachineType::PointerRepresentation(),
              MachineOperatorBuilder::kAllOptionalOps),
53
          test_(test) {}
54 55
    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
                  MachineType parameter0_type, MachineType parameter1_type)
56
        : RawMachineAssembler(
57
              test->isolate(), new (test->zone()) Graph(test->zone()),
58 59
              MakeCallDescriptor(test->zone(), return_type, parameter0_type,
                                 parameter1_type),
60 61
              MachineType::PointerRepresentation(),
              MachineOperatorBuilder::kAllOptionalOps),
62
          test_(test) {}
63 64 65 66
    StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
                  MachineType parameter0_type, MachineType parameter1_type,
                  MachineType parameter2_type)
        : RawMachineAssembler(
67
              test->isolate(), new (test->zone()) Graph(test->zone()),
68 69
              MakeCallDescriptor(test->zone(), return_type, parameter0_type,
                                 parameter1_type, parameter2_type),
70 71
              MachineType::PointerRepresentation(),
              MachineOperatorBuilder::kAllOptionalOps),
72
          test_(test) {}
73 74 75 76 77 78 79 80 81 82 83

    Stream Build(CpuFeature feature) {
      return Build(InstructionSelector::Features(feature));
    }
    Stream Build(CpuFeature feature1, CpuFeature feature2) {
      return Build(InstructionSelector::Features(feature1, feature2));
    }
    Stream Build(StreamBuilderMode mode = kTargetInstructions) {
      return Build(InstructionSelector::Features(), mode);
    }
    Stream Build(InstructionSelector::Features features,
84 85 86
                 StreamBuilderMode mode = kTargetInstructions,
                 InstructionSelector::SourcePositionMode source_position_mode =
                     InstructionSelector::kAllSourcePositions);
87

88 89 90
    const FrameStateFunctionInfo* GetFrameStateFunctionInfo(int parameter_count,
                                                            int local_count);

91
   private:
92
    CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) {
93 94
      MachineSignature::Builder builder(zone, 1, 0);
      builder.AddReturn(return_type);
95
      return MakeSimpleCallDescriptor(zone, builder.Build());
96 97
    }

98 99
    CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
                                       MachineType parameter0_type) {
100 101 102
      MachineSignature::Builder builder(zone, 1, 1);
      builder.AddReturn(return_type);
      builder.AddParam(parameter0_type);
103
      return MakeSimpleCallDescriptor(zone, builder.Build());
104 105
    }

106 107 108
    CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
                                       MachineType parameter0_type,
                                       MachineType parameter1_type) {
109 110 111 112
      MachineSignature::Builder builder(zone, 1, 2);
      builder.AddReturn(return_type);
      builder.AddParam(parameter0_type);
      builder.AddParam(parameter1_type);
113
      return MakeSimpleCallDescriptor(zone, builder.Build());
114 115
    }

116 117 118 119
    CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
                                       MachineType parameter0_type,
                                       MachineType parameter1_type,
                                       MachineType parameter2_type) {
120 121 122 123 124
      MachineSignature::Builder builder(zone, 1, 3);
      builder.AddReturn(return_type);
      builder.AddParam(parameter0_type);
      builder.AddParam(parameter1_type);
      builder.AddParam(parameter2_type);
125
      return MakeSimpleCallDescriptor(zone, builder.Build());
126 127
    }

128 129
   private:
    InstructionSelectorTest* test_;
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

    // Create a simple call descriptor for testing.
    CallDescriptor* MakeSimpleCallDescriptor(Zone* zone,
                                             MachineSignature* msig) {
      LocationSignature::Builder locations(zone, msig->return_count(),
                                           msig->parameter_count());

      // Add return location(s).
      const int return_count = static_cast<int>(msig->return_count());
      for (int i = 0; i < return_count; i++) {
        locations.AddReturn(LinkageLocation::ForCallerFrameSlot(-1 - i));
      }

      // Just put all parameters on the stack.
      const int parameter_count = static_cast<int>(msig->parameter_count());
      for (int i = 0; i < parameter_count; i++) {
        locations.AddParam(LinkageLocation::ForCallerFrameSlot(-1 - i));
      }

      const RegList kCalleeSaveRegisters = 0;
      const RegList kCalleeSaveFPRegisters = 0;

      MachineType target_type = MachineType::Pointer();
      LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
      return new (zone) CallDescriptor(  // --
          CallDescriptor::kCallAddress,  // kind
          target_type,                   // target MachineType
          target_loc,                    // target location
          msig,                          // machine_sig
          locations.Build(),             // location_sig
          0,                             // stack_parameter_count
          Operator::kNoProperties,       // properties
          kCalleeSaveRegisters,          // callee-saved registers
          kCalleeSaveFPRegisters,        // callee-saved fp regs
          CallDescriptor::kNoFlags,      // flags
          "iselect-test-call");
    }
167 168
  };

169
  class Stream final {
170 171 172 173 174 175 176
   public:
    size_t size() const { return instructions_.size(); }
    const Instruction* operator[](size_t index) const {
      EXPECT_LT(index, size());
      return instructions_[index];
    }

177 178 179
    bool IsDouble(const InstructionOperand* operand) const {
      return IsDouble(ToVreg(operand));
    }
180 181

    bool IsDouble(const Node* node) const { return IsDouble(ToVreg(node)); }
182

183 184 185
    bool IsInteger(const InstructionOperand* operand) const {
      return IsInteger(ToVreg(operand));
    }
186 187

    bool IsInteger(const Node* node) const { return IsInteger(ToVreg(node)); }
188 189 190 191

    bool IsReference(const InstructionOperand* operand) const {
      return IsReference(ToVreg(operand));
    }
192 193 194

    bool IsReference(const Node* node) const {
      return IsReference(ToVreg(node));
195 196
    }

197 198 199 200
    float ToFloat32(const InstructionOperand* operand) const {
      return ToConstant(operand).ToFloat32();
    }

201 202 203 204
    double ToFloat64(const InstructionOperand* operand) const {
      return ToConstant(operand).ToFloat64();
    }

205 206 207 208
    int32_t ToInt32(const InstructionOperand* operand) const {
      return ToConstant(operand).ToInt32();
    }

209 210 211 212
    int64_t ToInt64(const InstructionOperand* operand) const {
      return ToConstant(operand).ToInt64();
    }

213 214 215 216
    Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const {
      return ToConstant(operand).ToHeapObject();
    }

217
    int ToVreg(const InstructionOperand* operand) const {
218 219 220
      if (operand->IsConstant()) {
        return ConstantOperand::cast(operand)->virtual_register();
      }
221 222 223 224
      EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
      return UnallocatedOperand::cast(operand)->virtual_register();
    }

225 226
    int ToVreg(const Node* node) const;

227
    bool IsFixed(const InstructionOperand* operand, Register reg) const;
228
    bool IsSameAsFirst(const InstructionOperand* operand) const;
229 230
    bool IsUsedAtStart(const InstructionOperand* operand) const;

231 232
    FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) {
      EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount());
233 234 235
      return deoptimization_entries_[deoptimization_id];
    }

236
    int GetFrameStateDescriptorCount() {
237 238 239
      return static_cast<int>(deoptimization_entries_.size());
    }

240
   private:
241 242 243 244 245 246 247 248 249 250 251 252
    bool IsDouble(int virtual_register) const {
      return doubles_.find(virtual_register) != doubles_.end();
    }

    bool IsInteger(int virtual_register) const {
      return !IsDouble(virtual_register) && !IsReference(virtual_register);
    }

    bool IsReference(int virtual_register) const {
      return references_.find(virtual_register) != references_.end();
    }

253 254 255
    Constant ToConstant(const InstructionOperand* operand) const {
      ConstantMap::const_iterator i;
      if (operand->IsConstant()) {
256 257
        i = constants_.find(ConstantOperand::cast(operand)->virtual_register());
        EXPECT_EQ(ConstantOperand::cast(operand)->virtual_register(), i->first);
ulan@chromium.org's avatar
ulan@chromium.org committed
258
        EXPECT_FALSE(constants_.end() == i);
259 260
      } else {
        EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
261 262 263 264 265 266
        auto imm = ImmediateOperand::cast(operand);
        if (imm->type() == ImmediateOperand::INLINE) {
          return Constant(imm->inline_value());
        }
        i = immediates_.find(imm->indexed_value());
        EXPECT_EQ(imm->indexed_value(), i->first);
ulan@chromium.org's avatar
ulan@chromium.org committed
267
        EXPECT_FALSE(immediates_.end() == i);
268 269 270 271 272 273 274
      }
      return i->second;
    }

    friend class StreamBuilder;

    typedef std::map<int, Constant> ConstantMap;
275
    typedef std::map<NodeId, int> VirtualRegisters;
276 277 278 279

    ConstantMap constants_;
    ConstantMap immediates_;
    std::deque<Instruction*> instructions_;
280 281
    std::set<int> doubles_;
    std::set<int> references_;
282
    VirtualRegisters virtual_registers_;
283
    std::deque<FrameStateDescriptor*> deoptimization_entries_;
284
  };
285 286

  base::RandomNumberGenerator rng_;
287 288
};

289 290 291 292 293 294

template <typename T>
class InstructionSelectorTestWithParam
    : public InstructionSelectorTest,
      public ::testing::WithParamInterface<T> {};

295 296 297 298
}  // namespace compiler
}  // namespace internal
}  // namespace v8

299
#endif  // V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_