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_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
6 : #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/backend/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 : namespace v8 {
18 : namespace internal {
19 : namespace compiler {
20 :
21 172 : class InstructionSelectorTest : public TestWithNativeContextAndZone {
22 : public:
23 : InstructionSelectorTest();
24 : ~InstructionSelectorTest() override;
25 :
26 : base::RandomNumberGenerator* rng() { return &rng_; }
27 :
28 : class Stream;
29 :
30 : enum StreamBuilderMode {
31 : kAllInstructions,
32 : kTargetInstructions,
33 : kAllExceptNopInstructions
34 : };
35 :
36 : class StreamBuilder final : public RawMachineAssembler {
37 : public:
38 5 : StreamBuilder(InstructionSelectorTest* test, MachineType return_type)
39 : : RawMachineAssembler(test->isolate(),
40 5 : new (test->zone()) Graph(test->zone()),
41 : MakeCallDescriptor(test->zone(), return_type),
42 : MachineType::PointerRepresentation(),
43 : MachineOperatorBuilder::kAllOptionalOps),
44 10 : test_(test) {}
45 103 : StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
46 : MachineType parameter0_type)
47 : : RawMachineAssembler(
48 103 : test->isolate(), new (test->zone()) Graph(test->zone()),
49 : MakeCallDescriptor(test->zone(), return_type, parameter0_type),
50 : MachineType::PointerRepresentation(),
51 : MachineOperatorBuilder::kAllOptionalOps,
52 : InstructionSelector::AlignmentRequirements()),
53 309 : test_(test) {}
54 128 : StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
55 : MachineType parameter0_type, MachineType parameter1_type)
56 : : RawMachineAssembler(
57 128 : test->isolate(), new (test->zone()) Graph(test->zone()),
58 : MakeCallDescriptor(test->zone(), return_type, parameter0_type,
59 : parameter1_type),
60 : MachineType::PointerRepresentation(),
61 : MachineOperatorBuilder::kAllOptionalOps),
62 256 : test_(test) {}
63 14 : StreamBuilder(InstructionSelectorTest* test, MachineType return_type,
64 : MachineType parameter0_type, MachineType parameter1_type,
65 : MachineType parameter2_type)
66 : : RawMachineAssembler(
67 14 : test->isolate(), new (test->zone()) Graph(test->zone()),
68 : MakeCallDescriptor(test->zone(), return_type, parameter0_type,
69 : parameter1_type, parameter2_type),
70 : MachineType::PointerRepresentation(),
71 : MachineOperatorBuilder::kAllOptionalOps),
72 28 : test_(test) {}
73 :
74 : Stream Build(CpuFeature feature) {
75 3 : return Build(InstructionSelector::Features(feature));
76 : }
77 : Stream Build(CpuFeature feature1, CpuFeature feature2) {
78 : return Build(InstructionSelector::Features(feature1, feature2));
79 : }
80 : Stream Build(StreamBuilderMode mode = kTargetInstructions) {
81 247 : return Build(InstructionSelector::Features(), mode);
82 : }
83 : Stream Build(InstructionSelector::Features features,
84 : StreamBuilderMode mode = kTargetInstructions,
85 : InstructionSelector::SourcePositionMode source_position_mode =
86 : InstructionSelector::kAllSourcePositions);
87 :
88 : const FrameStateFunctionInfo* GetFrameStateFunctionInfo(int parameter_count,
89 : int local_count);
90 :
91 : private:
92 5 : CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) {
93 : MachineSignature::Builder builder(zone, 1, 0);
94 : builder.AddReturn(return_type);
95 5 : return MakeSimpleCallDescriptor(zone, builder.Build());
96 : }
97 :
98 103 : CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
99 : MachineType parameter0_type) {
100 : MachineSignature::Builder builder(zone, 1, 1);
101 : builder.AddReturn(return_type);
102 : builder.AddParam(parameter0_type);
103 103 : return MakeSimpleCallDescriptor(zone, builder.Build());
104 : }
105 :
106 128 : CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
107 : MachineType parameter0_type,
108 : MachineType parameter1_type) {
109 : MachineSignature::Builder builder(zone, 1, 2);
110 : builder.AddReturn(return_type);
111 : builder.AddParam(parameter0_type);
112 : builder.AddParam(parameter1_type);
113 128 : return MakeSimpleCallDescriptor(zone, builder.Build());
114 : }
115 :
116 14 : CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type,
117 : MachineType parameter0_type,
118 : MachineType parameter1_type,
119 : MachineType parameter2_type) {
120 : MachineSignature::Builder builder(zone, 1, 3);
121 : builder.AddReturn(return_type);
122 : builder.AddParam(parameter0_type);
123 : builder.AddParam(parameter1_type);
124 : builder.AddParam(parameter2_type);
125 14 : return MakeSimpleCallDescriptor(zone, builder.Build());
126 : }
127 :
128 : private:
129 : InstructionSelectorTest* test_;
130 :
131 : // Create a simple call descriptor for testing.
132 250 : CallDescriptor* MakeSimpleCallDescriptor(Zone* zone,
133 1401 : MachineSignature* msig) {
134 : LocationSignature::Builder locations(zone, msig->return_count(),
135 : msig->parameter_count());
136 :
137 : // Add return location(s).
138 250 : const int return_count = static_cast<int>(msig->return_count());
139 500 : for (int i = 0; i < return_count; i++) {
140 : locations.AddReturn(
141 750 : LinkageLocation::ForCallerFrameSlot(-1 - i, msig->GetReturn(i)));
142 : }
143 :
144 : // Just put all parameters on the stack.
145 250 : const int parameter_count = static_cast<int>(msig->parameter_count());
146 651 : for (int i = 0; i < parameter_count; i++) {
147 : locations.AddParam(
148 802 : LinkageLocation::ForCallerFrameSlot(-1 - i, msig->GetParam(i)));
149 : }
150 :
151 : const RegList kCalleeSaveRegisters = 0;
152 : const RegList kCalleeSaveFPRegisters = 0;
153 :
154 : MachineType target_type = MachineType::Pointer();
155 : LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
156 : return new (zone) CallDescriptor( // --
157 : CallDescriptor::kCallAddress, // kind
158 : target_type, // target MachineType
159 : target_loc, // target location
160 : locations.Build(), // location_sig
161 : 0, // stack_parameter_count
162 : Operator::kNoProperties, // properties
163 : kCalleeSaveRegisters, // callee-saved registers
164 : kCalleeSaveFPRegisters, // callee-saved fp regs
165 : CallDescriptor::kCanUseRoots, // flags
166 500 : "iselect-test-call");
167 : }
168 : };
169 :
170 2000 : class Stream final {
171 : public:
172 : size_t size() const { return instructions_.size(); }
173 1050 : const Instruction* operator[](size_t index) const {
174 1050 : EXPECT_LT(index, size());
175 2100 : return instructions_[index];
176 : }
177 :
178 : bool IsDouble(const InstructionOperand* operand) const {
179 : return IsDouble(ToVreg(operand));
180 : }
181 :
182 90 : bool IsDouble(const Node* node) const { return IsDouble(ToVreg(node)); }
183 :
184 : bool IsInteger(const InstructionOperand* operand) const {
185 : return IsInteger(ToVreg(operand));
186 : }
187 :
188 : bool IsInteger(const Node* node) const { return IsInteger(ToVreg(node)); }
189 :
190 : bool IsReference(const InstructionOperand* operand) const {
191 : return IsReference(ToVreg(operand));
192 : }
193 :
194 46 : bool IsReference(const Node* node) const {
195 92 : return IsReference(ToVreg(node));
196 : }
197 :
198 : float ToFloat32(const InstructionOperand* operand) const {
199 2 : return ToConstant(operand).ToFloat32();
200 : }
201 :
202 : double ToFloat64(const InstructionOperand* operand) const {
203 4 : return ToConstant(operand).ToFloat64().value();
204 : }
205 :
206 : int32_t ToInt32(const InstructionOperand* operand) const {
207 164 : return ToConstant(operand).ToInt32();
208 : }
209 :
210 : int64_t ToInt64(const InstructionOperand* operand) const {
211 : return ToConstant(operand).ToInt64();
212 : }
213 :
214 1 : Handle<HeapObject> ToHeapObject(const InstructionOperand* operand) const {
215 1 : return ToConstant(operand).ToHeapObject();
216 : }
217 :
218 272 : int ToVreg(const InstructionOperand* operand) const {
219 272 : if (operand->IsConstant()) {
220 0 : return ConstantOperand::cast(operand)->virtual_register();
221 : }
222 544 : EXPECT_EQ(InstructionOperand::UNALLOCATED, operand->kind());
223 272 : return UnallocatedOperand::cast(operand)->virtual_register();
224 : }
225 :
226 : int ToVreg(const Node* node) const;
227 :
228 : bool IsFixed(const InstructionOperand* operand, Register reg) const;
229 : bool IsSameAsFirst(const InstructionOperand* operand) const;
230 : bool IsUsedAtStart(const InstructionOperand* operand) const;
231 :
232 2 : FrameStateDescriptor* GetFrameStateDescriptor(int deoptimization_id) {
233 2 : EXPECT_LT(deoptimization_id, GetFrameStateDescriptorCount());
234 4 : return deoptimization_entries_[deoptimization_id];
235 : }
236 :
237 : int GetFrameStateDescriptorCount() {
238 2 : return static_cast<int>(deoptimization_entries_.size());
239 : }
240 :
241 : private:
242 : bool IsDouble(int virtual_register) const {
243 : return doubles_.find(virtual_register) != doubles_.end();
244 : }
245 :
246 : bool IsInteger(int virtual_register) const {
247 : return !IsDouble(virtual_register) && !IsReference(virtual_register);
248 : }
249 :
250 : bool IsReference(int virtual_register) const {
251 : return references_.find(virtual_register) != references_.end();
252 : }
253 :
254 86 : Constant ToConstant(const InstructionOperand* operand) const {
255 : ConstantMap::const_iterator i;
256 86 : if (operand->IsConstant()) {
257 4 : i = constants_.find(ConstantOperand::cast(operand)->virtual_register());
258 6 : EXPECT_EQ(ConstantOperand::cast(operand)->virtual_register(), i->first);
259 4 : EXPECT_FALSE(constants_.end() == i);
260 : } else {
261 168 : EXPECT_EQ(InstructionOperand::IMMEDIATE, operand->kind());
262 : auto imm = ImmediateOperand::cast(operand);
263 84 : if (imm->type() == ImmediateOperand::INLINE) {
264 17 : return Constant(imm->inline_value());
265 : }
266 134 : i = immediates_.find(imm->indexed_value());
267 201 : EXPECT_EQ(imm->indexed_value(), i->first);
268 134 : EXPECT_FALSE(immediates_.end() == i);
269 : }
270 69 : return i->second;
271 : }
272 :
273 : friend class StreamBuilder;
274 :
275 : typedef std::map<int, Constant> ConstantMap;
276 : typedef std::map<NodeId, int> VirtualRegisters;
277 :
278 : ConstantMap constants_;
279 : ConstantMap immediates_;
280 : std::deque<Instruction*> instructions_;
281 : std::set<int> doubles_;
282 : std::set<int> references_;
283 : VirtualRegisters virtual_registers_;
284 : std::deque<FrameStateDescriptor*> deoptimization_entries_;
285 : };
286 :
287 : base::RandomNumberGenerator rng_;
288 : };
289 :
290 : template <typename T>
291 326 : class InstructionSelectorTestWithParam
292 : : public InstructionSelectorTest,
293 : public ::testing::WithParamInterface<T> {};
294 :
295 : } // namespace compiler
296 : } // namespace internal
297 : } // namespace v8
298 :
299 : #endif // V8_UNITTESTS_COMPILER_INSTRUCTION_SELECTOR_UNITTEST_H_
|