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_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
6#define V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
7
8#include "src/compiler/common-operator.h"
9#include "src/compiler/instruction-selector.h"
10#include "src/compiler/linkage.h"
11#include "src/compiler/machine-operator.h"
12#include "src/compiler/operator-properties.h"
13#include "src/compiler/pipeline.h"
14#include "src/compiler/simplified-operator.h"
15#include "test/cctest/cctest.h"
16#include "test/cctest/compiler/call-tester.h"
17
18namespace v8 {
19namespace internal {
20namespace compiler {
21
22class GraphAndBuilders {
23 public:
24  explicit GraphAndBuilders(Zone* zone)
25      : main_graph_(new (zone) Graph(zone)),
26        main_common_(zone),
27        main_machine_(zone, MachineType::PointerRepresentation(),
28                      InstructionSelector::SupportedMachineOperatorFlags()),
29        main_simplified_(zone) {}
30
31  Graph* graph() const { return main_graph_; }
32  Zone* zone() const { return graph()->zone(); }
33  CommonOperatorBuilder* common() { return &main_common_; }
34  MachineOperatorBuilder* machine() { return &main_machine_; }
35  SimplifiedOperatorBuilder* simplified() { return &main_simplified_; }
36
37 protected:
38  // Prefixed with main_ to avoid naming conflicts.
39  Graph* main_graph_;
40  CommonOperatorBuilder main_common_;
41  MachineOperatorBuilder main_machine_;
42  SimplifiedOperatorBuilder main_simplified_;
43};
44
45
46template <typename ReturnType>
47class GraphBuilderTester : public HandleAndZoneScope,
48                           public GraphAndBuilders,
49                           public CallHelper<ReturnType> {
50 public:
51  explicit GraphBuilderTester(MachineType p0 = MachineType::None(),
52                              MachineType p1 = MachineType::None(),
53                              MachineType p2 = MachineType::None(),
54                              MachineType p3 = MachineType::None(),
55                              MachineType p4 = MachineType::None())
56      : GraphAndBuilders(main_zone()),
57        CallHelper<ReturnType>(
58            main_isolate(),
59            CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p0, p1,
60                            p2, p3, p4)),
61        effect_(NULL),
62        return_(NULL),
63        parameters_(main_zone()->template NewArray<Node*>(parameter_count())) {
64    Begin(static_cast<int>(parameter_count()));
65    InitParameters();
66  }
67  virtual ~GraphBuilderTester() {}
68
69  void GenerateCode() { Generate(); }
70  Node* Parameter(size_t index) {
71    CHECK_LT(index, parameter_count());
72    return parameters_[index];
73  }
74
75  Isolate* isolate() { return main_isolate(); }
76  Factory* factory() { return isolate()->factory(); }
77
78  // Initialize graph and builder.
79  void Begin(int num_parameters) {
80    CHECK_NULL(graph()->start());
81    Node* start = graph()->NewNode(common()->Start(num_parameters + 3));
82    graph()->SetStart(start);
83    effect_ = start;
84  }
85
86  void Return(Node* value) {
87    return_ =
88        graph()->NewNode(common()->Return(), value, effect_, graph()->start());
89    effect_ = NULL;
90  }
91
92  // Close the graph.
93  void End() {
94    Node* end = graph()->NewNode(common()->End(1), return_);
95    graph()->SetEnd(end);
96  }
97
98  Node* PointerConstant(void* value) {
99    intptr_t intptr_value = reinterpret_cast<intptr_t>(value);
100    return kPointerSize == 8 ? NewNode(common()->Int64Constant(intptr_value))
101                             : Int32Constant(static_cast<int>(intptr_value));
102  }
103  Node* Int32Constant(int32_t value) {
104    return NewNode(common()->Int32Constant(value));
105  }
106  Node* HeapConstant(Handle<HeapObject> object) {
107    return NewNode(common()->HeapConstant(object));
108  }
109
110  Node* BooleanNot(Node* a) { return NewNode(simplified()->BooleanNot(), a); }
111
112  Node* NumberEqual(Node* a, Node* b) {
113    return NewNode(simplified()->NumberEqual(), a, b);
114  }
115  Node* NumberLessThan(Node* a, Node* b) {
116    return NewNode(simplified()->NumberLessThan(), a, b);
117  }
118  Node* NumberLessThanOrEqual(Node* a, Node* b) {
119    return NewNode(simplified()->NumberLessThanOrEqual(), a, b);
120  }
121  Node* NumberAdd(Node* a, Node* b) {
122    return NewNode(simplified()->NumberAdd(), a, b);
123  }
124  Node* NumberSubtract(Node* a, Node* b) {
125    return NewNode(simplified()->NumberSubtract(), a, b);
126  }
127  Node* NumberMultiply(Node* a, Node* b) {
128    return NewNode(simplified()->NumberMultiply(), a, b);
129  }
130  Node* NumberDivide(Node* a, Node* b) {
131    return NewNode(simplified()->NumberDivide(), a, b);
132  }
133  Node* NumberModulus(Node* a, Node* b) {
134    return NewNode(simplified()->NumberModulus(), a, b);
135  }
136  Node* NumberToInt32(Node* a) {
137    return NewNode(simplified()->NumberToInt32(), a);
138  }
139  Node* NumberToUint32(Node* a) {
140    return NewNode(simplified()->NumberToUint32(), a);
141  }
142
143  Node* StringEqual(Node* a, Node* b) {
144    return NewNode(simplified()->StringEqual(), a, b);
145  }
146  Node* StringLessThan(Node* a, Node* b) {
147    return NewNode(simplified()->StringLessThan(), a, b);
148  }
149  Node* StringLessThanOrEqual(Node* a, Node* b) {
150    return NewNode(simplified()->StringLessThanOrEqual(), a, b);
151  }
152
153  Node* ChangeTaggedToInt32(Node* a) {
154    return NewNode(simplified()->ChangeTaggedToInt32(), a);
155  }
156  Node* ChangeTaggedToUint32(Node* a) {
157    return NewNode(simplified()->ChangeTaggedToUint32(), a);
158  }
159  Node* ChangeTaggedToFloat64(Node* a) {
160    return NewNode(simplified()->ChangeTaggedToFloat64(), a);
161  }
162  Node* ChangeInt32ToTagged(Node* a) {
163    return NewNode(simplified()->ChangeInt32ToTagged(), a);
164  }
165  Node* ChangeUint32ToTagged(Node* a) {
166    return NewNode(simplified()->ChangeUint32ToTagged(), a);
167  }
168  Node* ChangeFloat64ToTagged(Node* a) {
169    return NewNode(simplified()->ChangeFloat64ToTagged(), a);
170  }
171  Node* ChangeTaggedToBit(Node* a) {
172    return NewNode(simplified()->ChangeTaggedToBit(), a);
173  }
174  Node* ChangeBitToTagged(Node* a) {
175    return NewNode(simplified()->ChangeBitToTagged(), a);
176  }
177
178  Node* LoadField(const FieldAccess& access, Node* object) {
179    return NewNode(simplified()->LoadField(access), object);
180  }
181  Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
182    return NewNode(simplified()->StoreField(access), object, value);
183  }
184  Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
185    return NewNode(simplified()->LoadElement(access), object, index);
186  }
187  Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
188                     Node* value) {
189    return NewNode(simplified()->StoreElement(access), object, index, value);
190  }
191
192  Node* NewNode(const Operator* op) {
193    return MakeNode(op, 0, static_cast<Node**>(NULL));
194  }
195
196  Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); }
197
198  Node* NewNode(const Operator* op, Node* n1, Node* n2) {
199    Node* buffer[] = {n1, n2};
200    return MakeNode(op, arraysize(buffer), buffer);
201  }
202
203  Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) {
204    Node* buffer[] = {n1, n2, n3};
205    return MakeNode(op, arraysize(buffer), buffer);
206  }
207
208  Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) {
209    Node* buffer[] = {n1, n2, n3, n4};
210    return MakeNode(op, arraysize(buffer), buffer);
211  }
212
213  Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
214                Node* n5) {
215    Node* buffer[] = {n1, n2, n3, n4, n5};
216    return MakeNode(op, arraysize(buffer), buffer);
217  }
218
219  Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4,
220                Node* n5, Node* n6) {
221    Node* nodes[] = {n1, n2, n3, n4, n5, n6};
222    return MakeNode(op, arraysize(nodes), nodes);
223  }
224
225  Node* NewNode(const Operator* op, int value_input_count,
226                Node** value_inputs) {
227    return MakeNode(op, value_input_count, value_inputs);
228  }
229
230  Handle<Code> GetCode() {
231    Generate();
232    return code_.ToHandleChecked();
233  }
234
235 protected:
236  Node* MakeNode(const Operator* op, int value_input_count,
237                 Node** value_inputs) {
238    CHECK_EQ(op->ValueInputCount(), value_input_count);
239
240    CHECK(!OperatorProperties::HasContextInput(op));
241    CHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
242    bool has_control = op->ControlInputCount() == 1;
243    bool has_effect = op->EffectInputCount() == 1;
244
245    CHECK_LT(op->ControlInputCount(), 2);
246    CHECK_LT(op->EffectInputCount(), 2);
247
248    Node* result = NULL;
249    if (!has_control && !has_effect) {
250      result = graph()->NewNode(op, value_input_count, value_inputs);
251    } else {
252      int input_count_with_deps = value_input_count;
253      if (has_control) ++input_count_with_deps;
254      if (has_effect) ++input_count_with_deps;
255      Node** buffer = zone()->template NewArray<Node*>(input_count_with_deps);
256      memcpy(buffer, value_inputs, kPointerSize * value_input_count);
257      Node** current_input = buffer + value_input_count;
258      if (has_effect) {
259        *current_input++ = effect_;
260      }
261      if (has_control) {
262        *current_input++ = graph()->start();
263      }
264      result = graph()->NewNode(op, input_count_with_deps, buffer);
265      if (has_effect) {
266        effect_ = result;
267      }
268      // This graph builder does not support control flow.
269      CHECK_EQ(0, op->ControlOutputCount());
270    }
271
272    return result;
273  }
274
275  virtual byte* Generate() {
276    if (code_.is_null()) {
277      Zone* zone = graph()->zone();
278      CallDescriptor* desc =
279          Linkage::GetSimplifiedCDescriptor(zone, this->csig_);
280      CompilationInfo info(ArrayVector("testing"), main_isolate(), main_zone());
281      code_ = Pipeline::GenerateCodeForTesting(&info, desc, graph());
282#ifdef ENABLE_DISASSEMBLER
283      if (!code_.is_null() && FLAG_print_opt_code) {
284        OFStream os(stdout);
285        code_.ToHandleChecked()->Disassemble("test code", os);
286      }
287#endif
288    }
289    return code_.ToHandleChecked()->entry();
290  }
291
292  void InitParameters() {
293    int param_count = static_cast<int>(parameter_count());
294    for (int i = 0; i < param_count; ++i) {
295      parameters_[i] = this->NewNode(common()->Parameter(i), graph()->start());
296    }
297  }
298
299  size_t parameter_count() const { return this->csig_->parameter_count(); }
300
301 private:
302  Node* effect_;
303  Node* return_;
304  Node** parameters_;
305  MaybeHandle<Code> code_;
306};
307
308}  // namespace compiler
309}  // namespace internal
310}  // namespace v8
311
312#endif  // V8_CCTEST_COMPILER_GRAPH_BUILDER_TESTER_H_
313