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 
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21 
22 class GraphAndBuilders {
23  public:
GraphAndBuilders(Zone * zone)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 
graph()31   Graph* graph() const { return main_graph_; }
zone()32   Zone* zone() const { return graph()->zone(); }
common()33   CommonOperatorBuilder* common() { return &main_common_; }
machine()34   MachineOperatorBuilder* machine() { return &main_machine_; }
simplified()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 
46 template <typename ReturnType>
47 class 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())
GraphAndBuilders(main_zone ())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   }
~GraphBuilderTester()67   virtual ~GraphBuilderTester() {}
68 
GenerateCode()69   void GenerateCode() { Generate(); }
Parameter(size_t index)70   Node* Parameter(size_t index) {
71     CHECK_LT(index, parameter_count());
72     return parameters_[index];
73   }
74 
isolate()75   Isolate* isolate() { return main_isolate(); }
factory()76   Factory* factory() { return isolate()->factory(); }
77 
78   // Initialize graph and builder.
Begin(int num_parameters)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 
Return(Node * value)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.
End()93   void End() {
94     Node* end = graph()->NewNode(common()->End(1), return_);
95     graph()->SetEnd(end);
96   }
97 
PointerConstant(void * value)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   }
Int32Constant(int32_t value)103   Node* Int32Constant(int32_t value) {
104     return NewNode(common()->Int32Constant(value));
105   }
HeapConstant(Handle<HeapObject> object)106   Node* HeapConstant(Handle<HeapObject> object) {
107     return NewNode(common()->HeapConstant(object));
108   }
109 
BooleanNot(Node * a)110   Node* BooleanNot(Node* a) { return NewNode(simplified()->BooleanNot(), a); }
111 
NumberEqual(Node * a,Node * b)112   Node* NumberEqual(Node* a, Node* b) {
113     return NewNode(simplified()->NumberEqual(), a, b);
114   }
NumberLessThan(Node * a,Node * b)115   Node* NumberLessThan(Node* a, Node* b) {
116     return NewNode(simplified()->NumberLessThan(), a, b);
117   }
NumberLessThanOrEqual(Node * a,Node * b)118   Node* NumberLessThanOrEqual(Node* a, Node* b) {
119     return NewNode(simplified()->NumberLessThanOrEqual(), a, b);
120   }
NumberAdd(Node * a,Node * b)121   Node* NumberAdd(Node* a, Node* b) {
122     return NewNode(simplified()->NumberAdd(), a, b);
123   }
NumberSubtract(Node * a,Node * b)124   Node* NumberSubtract(Node* a, Node* b) {
125     return NewNode(simplified()->NumberSubtract(), a, b);
126   }
NumberMultiply(Node * a,Node * b)127   Node* NumberMultiply(Node* a, Node* b) {
128     return NewNode(simplified()->NumberMultiply(), a, b);
129   }
NumberDivide(Node * a,Node * b)130   Node* NumberDivide(Node* a, Node* b) {
131     return NewNode(simplified()->NumberDivide(), a, b);
132   }
NumberModulus(Node * a,Node * b)133   Node* NumberModulus(Node* a, Node* b) {
134     return NewNode(simplified()->NumberModulus(), a, b);
135   }
NumberToInt32(Node * a)136   Node* NumberToInt32(Node* a) {
137     return NewNode(simplified()->NumberToInt32(), a);
138   }
NumberToUint32(Node * a)139   Node* NumberToUint32(Node* a) {
140     return NewNode(simplified()->NumberToUint32(), a);
141   }
142 
StringEqual(Node * a,Node * b)143   Node* StringEqual(Node* a, Node* b) {
144     return NewNode(simplified()->StringEqual(), a, b);
145   }
StringLessThan(Node * a,Node * b)146   Node* StringLessThan(Node* a, Node* b) {
147     return NewNode(simplified()->StringLessThan(), a, b);
148   }
StringLessThanOrEqual(Node * a,Node * b)149   Node* StringLessThanOrEqual(Node* a, Node* b) {
150     return NewNode(simplified()->StringLessThanOrEqual(), a, b);
151   }
152 
ChangeTaggedToInt32(Node * a)153   Node* ChangeTaggedToInt32(Node* a) {
154     return NewNode(simplified()->ChangeTaggedToInt32(), a);
155   }
ChangeTaggedToUint32(Node * a)156   Node* ChangeTaggedToUint32(Node* a) {
157     return NewNode(simplified()->ChangeTaggedToUint32(), a);
158   }
ChangeTaggedToFloat64(Node * a)159   Node* ChangeTaggedToFloat64(Node* a) {
160     return NewNode(simplified()->ChangeTaggedToFloat64(), a);
161   }
ChangeInt32ToTagged(Node * a)162   Node* ChangeInt32ToTagged(Node* a) {
163     return NewNode(simplified()->ChangeInt32ToTagged(), a);
164   }
ChangeUint32ToTagged(Node * a)165   Node* ChangeUint32ToTagged(Node* a) {
166     return NewNode(simplified()->ChangeUint32ToTagged(), a);
167   }
ChangeFloat64ToTagged(Node * a)168   Node* ChangeFloat64ToTagged(Node* a) {
169     return NewNode(simplified()->ChangeFloat64ToTagged(), a);
170   }
ChangeBoolToBit(Node * a)171   Node* ChangeBoolToBit(Node* a) {
172     return NewNode(simplified()->ChangeBoolToBit(), a);
173   }
ChangeBitToBool(Node * a)174   Node* ChangeBitToBool(Node* a) {
175     return NewNode(simplified()->ChangeBitToBool(), a);
176   }
177 
LoadField(const FieldAccess & access,Node * object)178   Node* LoadField(const FieldAccess& access, Node* object) {
179     return NewNode(simplified()->LoadField(access), object);
180   }
StoreField(const FieldAccess & access,Node * object,Node * value)181   Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
182     return NewNode(simplified()->StoreField(access), object, value);
183   }
LoadElement(const ElementAccess & access,Node * object,Node * index)184   Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
185     return NewNode(simplified()->LoadElement(access), object, index);
186   }
StoreElement(const ElementAccess & access,Node * object,Node * index,Node * value)187   Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
188                      Node* value) {
189     return NewNode(simplified()->StoreElement(access), object, index, value);
190   }
191 
NewNode(const Operator * op)192   Node* NewNode(const Operator* op) {
193     return MakeNode(op, 0, static_cast<Node**>(NULL));
194   }
195 
NewNode(const Operator * op,Node * n1)196   Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1); }
197 
NewNode(const Operator * op,Node * n1,Node * n2)198   Node* NewNode(const Operator* op, Node* n1, Node* n2) {
199     Node* buffer[] = {n1, n2};
200     return MakeNode(op, arraysize(buffer), buffer);
201   }
202 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3)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 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4)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 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4,Node * n5)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 
NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4,Node * n5,Node * n6)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 
NewNode(const Operator * op,int value_input_count,Node ** value_inputs)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 
GetCode()230   Handle<Code> GetCode() {
231     Generate();
232     return code_.ToHandleChecked();
233   }
234 
235  protected:
MakeNode(const Operator * op,int value_input_count,Node ** value_inputs)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 
Generate()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("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 
InitParameters()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 
parameter_count()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