blob: 283d5339740cc5d53a65b2ce62a3d61cff61774f [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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/v8.h"
9
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010#include "src/compiler/instruction-selector.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/compiler/pipeline.h"
12#include "src/compiler/raw-machine-assembler.h"
13#include "src/simulator.h"
14#include "test/cctest/compiler/call-tester.h"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20template <typename MachineAssembler>
21class MachineAssemblerTester : public HandleAndZoneScope,
22 public CallHelper,
23 public MachineAssembler {
24 public:
25 MachineAssemblerTester(MachineType return_type, MachineType p0,
26 MachineType p1, MachineType p2, MachineType p3,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040027 MachineType p4,
28 MachineOperatorBuilder::Flags flags =
29 MachineOperatorBuilder::Flag::kNoFlags)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 : HandleAndZoneScope(),
31 CallHelper(
32 main_isolate(),
33 MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4)),
34 MachineAssembler(
35 new (main_zone()) Graph(main_zone()),
36 MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040037 kMachPtr, flags) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000038
39 Node* LoadFromPointer(void* address, MachineType rep, int32_t offset = 0) {
40 return this->Load(rep, this->PointerConstant(address),
41 this->Int32Constant(offset));
42 }
43
44 void StoreToPointer(void* address, MachineType rep, Node* node) {
45 this->Store(rep, this->PointerConstant(address), node);
46 }
47
48 Node* StringConstant(const char* string) {
49 return this->HeapConstant(
50 this->isolate()->factory()->InternalizeUtf8String(string));
51 }
52
53 void CheckNumber(double expected, Object* number) {
54 CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
55 }
56
57 void CheckString(const char* expected, Object* string) {
58 CHECK(
59 this->isolate()->factory()->InternalizeUtf8String(expected)->SameValue(
60 string));
61 }
62
63 void GenerateCode() { Generate(); }
64
65 protected:
66 virtual byte* Generate() {
67 if (code_.is_null()) {
68 Schedule* schedule = this->Export();
69 CallDescriptor* call_descriptor = this->call_descriptor();
70 Graph* graph = this->graph();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040071 code_ =
72 Pipeline::GenerateCodeForTesting(call_descriptor, graph, schedule);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 }
74 return this->code_.ToHandleChecked()->entry();
75 }
76
77 private:
78 MaybeHandle<Code> code_;
79};
80
81
82template <typename ReturnType>
83class RawMachineAssemblerTester
84 : public MachineAssemblerTester<RawMachineAssembler>,
85 public CallHelper2<ReturnType, RawMachineAssemblerTester<ReturnType> > {
86 public:
87 RawMachineAssemblerTester(MachineType p0 = kMachNone,
88 MachineType p1 = kMachNone,
89 MachineType p2 = kMachNone,
90 MachineType p3 = kMachNone,
91 MachineType p4 = kMachNone)
92 : MachineAssemblerTester<RawMachineAssembler>(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040093 ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, p4,
94 InstructionSelector::SupportedMachineOperatorFlags()) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095
96 template <typename Ci, typename Fn>
97 void Run(const Ci& ci, const Fn& fn) {
98 typename Ci::const_iterator i;
99 for (i = ci.begin(); i != ci.end(); ++i) {
100 CHECK_EQ(fn(*i), this->Call(*i));
101 }
102 }
103
104 template <typename Ci, typename Cj, typename Fn>
105 void Run(const Ci& ci, const Cj& cj, const Fn& fn) {
106 typename Ci::const_iterator i;
107 typename Cj::const_iterator j;
108 for (i = ci.begin(); i != ci.end(); ++i) {
109 for (j = cj.begin(); j != cj.end(); ++j) {
110 CHECK_EQ(fn(*i, *j), this->Call(*i, *j));
111 }
112 }
113 }
114};
115
116
117static const bool USE_RESULT_BUFFER = true;
118static const bool USE_RETURN_REGISTER = false;
119static const int32_t CHECK_VALUE = 0x99BEEDCE;
120
121
122// TODO(titzer): use the C-style calling convention, or any register-based
123// calling convention for binop tests.
124template <typename CType, MachineType rep, bool use_result_buffer>
125class BinopTester {
126 public:
127 explicit BinopTester(RawMachineAssemblerTester<int32_t>* tester)
128 : T(tester),
129 param0(T->LoadFromPointer(&p0, rep)),
130 param1(T->LoadFromPointer(&p1, rep)),
131 p0(static_cast<CType>(0)),
132 p1(static_cast<CType>(0)),
133 result(static_cast<CType>(0)) {}
134
135 RawMachineAssemblerTester<int32_t>* T;
136 Node* param0;
137 Node* param1;
138
139 CType call(CType a0, CType a1) {
140 p0 = a0;
141 p1 = a1;
142 if (use_result_buffer) {
143 CHECK_EQ(CHECK_VALUE, T->Call());
144 return result;
145 } else {
146 return T->Call();
147 }
148 }
149
150 void AddReturn(Node* val) {
151 if (use_result_buffer) {
152 T->Store(rep, T->PointerConstant(&result), T->Int32Constant(0), val);
153 T->Return(T->Int32Constant(CHECK_VALUE));
154 } else {
155 T->Return(val);
156 }
157 }
158
159 template <typename Ci, typename Cj, typename Fn>
160 void Run(const Ci& ci, const Cj& cj, const Fn& fn) {
161 typename Ci::const_iterator i;
162 typename Cj::const_iterator j;
163 for (i = ci.begin(); i != ci.end(); ++i) {
164 for (j = cj.begin(); j != cj.end(); ++j) {
165 CHECK_EQ(fn(*i, *j), this->call(*i, *j));
166 }
167 }
168 }
169
170 protected:
171 CType p0;
172 CType p1;
173 CType result;
174};
175
176
177// A helper class for testing code sequences that take two int parameters and
178// return an int value.
179class Int32BinopTester
180 : public BinopTester<int32_t, kMachInt32, USE_RETURN_REGISTER> {
181 public:
182 explicit Int32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
183 : BinopTester<int32_t, kMachInt32, USE_RETURN_REGISTER>(tester) {}
184};
185
186
187// A helper class for testing code sequences that take two uint parameters and
188// return an uint value.
189class Uint32BinopTester
190 : public BinopTester<uint32_t, kMachUint32, USE_RETURN_REGISTER> {
191 public:
192 explicit Uint32BinopTester(RawMachineAssemblerTester<int32_t>* tester)
193 : BinopTester<uint32_t, kMachUint32, USE_RETURN_REGISTER>(tester) {}
194
195 uint32_t call(uint32_t a0, uint32_t a1) {
196 p0 = a0;
197 p1 = a1;
198 return static_cast<uint32_t>(T->Call());
199 }
200};
201
202
203// A helper class for testing code sequences that take two double parameters and
204// return a double value.
205// TODO(titzer): figure out how to return doubles correctly on ia32.
206class Float64BinopTester
207 : public BinopTester<double, kMachFloat64, USE_RESULT_BUFFER> {
208 public:
209 explicit Float64BinopTester(RawMachineAssemblerTester<int32_t>* tester)
210 : BinopTester<double, kMachFloat64, USE_RESULT_BUFFER>(tester) {}
211};
212
213
214// A helper class for testing code sequences that take two pointer parameters
215// and return a pointer value.
216// TODO(titzer): pick word size of pointers based on V8_TARGET.
217template <typename Type>
218class PointerBinopTester
219 : public BinopTester<Type*, kMachPtr, USE_RETURN_REGISTER> {
220 public:
221 explicit PointerBinopTester(RawMachineAssemblerTester<int32_t>* tester)
222 : BinopTester<Type*, kMachPtr, USE_RETURN_REGISTER>(tester) {}
223};
224
225
226// A helper class for testing code sequences that take two tagged parameters and
227// return a tagged value.
228template <typename Type>
229class TaggedBinopTester
230 : public BinopTester<Type*, kMachAnyTagged, USE_RETURN_REGISTER> {
231 public:
232 explicit TaggedBinopTester(RawMachineAssemblerTester<int32_t>* tester)
233 : BinopTester<Type*, kMachAnyTagged, USE_RETURN_REGISTER>(tester) {}
234};
235
236// A helper class for testing compares. Wraps a machine opcode and provides
237// evaluation routines and the operators.
238class CompareWrapper {
239 public:
240 explicit CompareWrapper(IrOpcode::Value op) : opcode(op) {}
241
242 Node* MakeNode(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
243 return m->NewNode(op(m->machine()), a, b);
244 }
245
246 const Operator* op(MachineOperatorBuilder* machine) {
247 switch (opcode) {
248 case IrOpcode::kWord32Equal:
249 return machine->Word32Equal();
250 case IrOpcode::kInt32LessThan:
251 return machine->Int32LessThan();
252 case IrOpcode::kInt32LessThanOrEqual:
253 return machine->Int32LessThanOrEqual();
254 case IrOpcode::kUint32LessThan:
255 return machine->Uint32LessThan();
256 case IrOpcode::kUint32LessThanOrEqual:
257 return machine->Uint32LessThanOrEqual();
258 case IrOpcode::kFloat64Equal:
259 return machine->Float64Equal();
260 case IrOpcode::kFloat64LessThan:
261 return machine->Float64LessThan();
262 case IrOpcode::kFloat64LessThanOrEqual:
263 return machine->Float64LessThanOrEqual();
264 default:
265 UNREACHABLE();
266 }
267 return NULL;
268 }
269
270 bool Int32Compare(int32_t a, int32_t b) {
271 switch (opcode) {
272 case IrOpcode::kWord32Equal:
273 return a == b;
274 case IrOpcode::kInt32LessThan:
275 return a < b;
276 case IrOpcode::kInt32LessThanOrEqual:
277 return a <= b;
278 case IrOpcode::kUint32LessThan:
279 return static_cast<uint32_t>(a) < static_cast<uint32_t>(b);
280 case IrOpcode::kUint32LessThanOrEqual:
281 return static_cast<uint32_t>(a) <= static_cast<uint32_t>(b);
282 default:
283 UNREACHABLE();
284 }
285 return false;
286 }
287
288 bool Float64Compare(double a, double b) {
289 switch (opcode) {
290 case IrOpcode::kFloat64Equal:
291 return a == b;
292 case IrOpcode::kFloat64LessThan:
293 return a < b;
294 case IrOpcode::kFloat64LessThanOrEqual:
295 return a <= b;
296 default:
297 UNREACHABLE();
298 }
299 return false;
300 }
301
302 IrOpcode::Value opcode;
303};
304
305
306// A small closure class to generate code for a function of two inputs that
307// produces a single output so that it can be used in many different contexts.
308// The {expected()} method should compute the expected output for a given
309// pair of inputs.
310template <typename T>
311class BinopGen {
312 public:
313 virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) = 0;
314 virtual T expected(T a, T b) = 0;
315 virtual ~BinopGen() {}
316};
317
318// A helper class to generate various combination of input shape combinations
319// and run the generated code to ensure it produces the correct results.
320class Int32BinopInputShapeTester {
321 public:
322 explicit Int32BinopInputShapeTester(BinopGen<int32_t>* g) : gen(g) {}
323
324 void TestAllInputShapes();
325
326 private:
327 BinopGen<int32_t>* gen;
328 int32_t input_a;
329 int32_t input_b;
330
331 void Run(RawMachineAssemblerTester<int32_t>* m);
332 void RunLeft(RawMachineAssemblerTester<int32_t>* m);
333 void RunRight(RawMachineAssemblerTester<int32_t>* m);
334};
335} // namespace compiler
336} // namespace internal
337} // namespace v8
338
339#endif // V8_CCTEST_COMPILER_CODEGEN_TESTER_H_