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_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
6 #define V8_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/test/test-utils.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19 
20 class InstructionSelectorTest : public TestWithContext, public TestWithZone {
21  public:
22   InstructionSelectorTest();
23   virtual ~InstructionSelectorTest();
24 
rng()25   base::RandomNumberGenerator* rng() { return &rng_; }
26 
27   class Stream;
28 
29   enum StreamBuilderMode {
30     kAllInstructions,
31     kTargetInstructions,
32     kAllExceptNopInstructions
33   };
34 
35   class StreamBuilder FINAL : public RawMachineAssembler {
36    public:
StreamBuilder(InstructionSelectorTest * test,MachineType return_type)37     StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
38         : RawMachineAssembler(new (test->zone()) Graph(test->zone()),
39                               MakeMachineSignature(test->zone(), return_type)),
40           test_(test) {}
StreamBuilder(InstructionSelectorTest * test,MachineType return_type,MachineType parameter0_type)41     StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
42                   MachineType parameter0_type)
43         : RawMachineAssembler(
44               new (test->zone()) Graph(test->zone()),
45               MakeMachineSignature(test->zone(), return_type, parameter0_type)),
46           test_(test) {}
StreamBuilder(InstructionSelectorTest * test,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type)47     StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
48                   MachineType parameter0_type, MachineType parameter1_type)
49         : RawMachineAssembler(
50               new (test->zone()) Graph(test->zone()),
51               MakeMachineSignature(test->zone(), return_type, parameter0_type,
52                                    parameter1_type)),
53           test_(test) {}
StreamBuilder(InstructionSelectorTest * test,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type,MachineType parameter2_type)54     StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
55                   MachineType parameter0_type, MachineType parameter1_type,
56                   MachineType parameter2_type)
57         : RawMachineAssembler(
58               new (test->zone()) Graph(test->zone()),
59               MakeMachineSignature(test->zone(), return_type, parameter0_type,
60                                    parameter1_type, parameter2_type)),
61           test_(test) {}
62 
Build(CpuFeature feature)63     Stream Build(CpuFeature feature) {
64       return Build(InstructionSelector::Features(feature));
65     }
Build(CpuFeature feature1,CpuFeature feature2)66     Stream Build(CpuFeature feature1, CpuFeature feature2) {
67       return Build(InstructionSelector::Features(feature1, feature2));
68     }
69     Stream Build(StreamBuilderMode mode = kTargetInstructions) {
70       return Build(InstructionSelector::Features(), mode);
71     }
72     Stream Build(InstructionSelector::Features features,
73                  StreamBuilderMode mode = kTargetInstructions);
74 
75    private:
MakeMachineSignature(Zone * zone,MachineType return_type)76     MachineSignature* MakeMachineSignature(Zone* zone,
77                                            MachineType return_type) {
78       MachineSignature::Builder builder(zone, 1, 0);
79       builder.AddReturn(return_type);
80       return builder.Build();
81     }
82 
MakeMachineSignature(Zone * zone,MachineType return_type,MachineType parameter0_type)83     MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
84                                            MachineType parameter0_type) {
85       MachineSignature::Builder builder(zone, 1, 1);
86       builder.AddReturn(return_type);
87       builder.AddParam(parameter0_type);
88       return builder.Build();
89     }
90 
MakeMachineSignature(Zone * zone,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type)91     MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
92                                            MachineType parameter0_type,
93                                            MachineType parameter1_type) {
94       MachineSignature::Builder builder(zone, 1, 2);
95       builder.AddReturn(return_type);
96       builder.AddParam(parameter0_type);
97       builder.AddParam(parameter1_type);
98       return builder.Build();
99     }
100 
MakeMachineSignature(Zone * zone,MachineType return_type,MachineType parameter0_type,MachineType parameter1_type,MachineType parameter2_type)101     MachineSignature* MakeMachineSignature(Zone* zone, MachineType return_type,
102                                            MachineType parameter0_type,
103                                            MachineType parameter1_type,
104                                            MachineType parameter2_type) {
105       MachineSignature::Builder builder(zone, 1, 3);
106       builder.AddReturn(return_type);
107       builder.AddParam(parameter0_type);
108       builder.AddParam(parameter1_type);
109       builder.AddParam(parameter2_type);
110       return builder.Build();
111     }
112 
113    private:
114     InstructionSelectorTest* test_;
115   };
116 
117   class Stream FINAL {
118    public:
size()119     size_t size() const { return instructions_.size(); }
120     const Instruction* operator[](size_t index) const {
121       EXPECT_LT(index, size());
122       return instructions_[index];
123     }
124 
IsDouble(const InstructionOperand * operand)125     bool IsDouble(const InstructionOperand* operand) const {
126       return IsDouble(ToVreg(operand));
127     }
IsDouble(int virtual_register)128     bool IsDouble(int virtual_register) const {
129       return doubles_.find(virtual_register) != doubles_.end();
130     }
131 
IsInteger(const InstructionOperand * operand)132     bool IsInteger(const InstructionOperand* operand) const {
133       return IsInteger(ToVreg(operand));
134     }
IsInteger(int virtual_register)135     bool IsInteger(int virtual_register) const {
136       return !IsDouble(virtual_register) && !IsReference(virtual_register);
137     }
138 
IsReference(const InstructionOperand * operand)139     bool IsReference(const InstructionOperand* operand) const {
140       return IsReference(ToVreg(operand));
141     }
IsReference(int virtual_register)142     bool IsReference(int virtual_register) const {
143       return references_.find(virtual_register) != references_.end();
144     }
145 
ToInt32(const InstructionOperand * operand)146     int32_t ToInt32(const InstructionOperand* operand) const {
147       return ToConstant(operand).ToInt32();
148     }
149 
ToInt64(const InstructionOperand * operand)150     int64_t ToInt64(const InstructionOperand* operand) const {
151       return ToConstant(operand).ToInt64();
152     }
153 
ToVreg(const InstructionOperand * operand)154     int ToVreg(const InstructionOperand* operand) const {
155       if (operand->IsConstant()) return operand->index();
156       EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
157       return UnallocatedOperand::cast(operand)->virtual_register();
158     }
159 
GetFrameStateDescriptor(int deoptimization_id)160     FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) {
161       EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount());
162       return deoptimization_entries_[deoptimization_id];
163     }
164 
GetFrameStateDescriptorCount()165     int GetFrameStateDescriptorCount() {
166       return static_cast<int>(deoptimization_entries_.size());
167     }
168 
169    private:
ToConstant(const InstructionOperand * operand)170     Constant ToConstant(const InstructionOperand* operand) const {
171       ConstantMap::const_iterator i;
172       if (operand->IsConstant()) {
173         i = constants_.find(operand->index());
174         EXPECT_FALSE(constants_.end() == i);
175       } else {
176         EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
177         i = immediates_.find(operand->index());
178         EXPECT_FALSE(immediates_.end() == i);
179       }
180       EXPECT_EQ(operand->index(), i->first);
181       return i->second;
182     }
183 
184     friend class StreamBuilder;
185 
186     typedef std::map<int, Constant> ConstantMap;
187 
188     ConstantMap constants_;
189     ConstantMap immediates_;
190     std::deque<Instruction*> instructions_;
191     std::set<int> doubles_;
192     std::set<int> references_;
193     std::deque<FrameStateDescriptor*> deoptimization_entries_;
194   };
195 
196   base::RandomNumberGenerator rng_;
197 };
198 
199 
200 template <typename T>
201 class InstructionSelectorTestWithParam
202     : public InstructionSelectorTest,
203       public ::testing::WithParamInterface<T> {};
204 
205 }  // namespace compiler
206 }  // namespace internal
207 }  // namespace v8
208 
209 #endif  // V8_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
210