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