a015c501adba42e780e52721888e9fa2ffa18a66
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / compiler / test-changes-lowering.cc
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 #include <limits>
6
7 #include "src/compiler/change-lowering.h"
8 #include "src/compiler/control-builders.h"
9 #include "src/compiler/generic-node-inl.h"
10 #include "src/compiler/js-graph.h"
11 #include "src/compiler/node-properties-inl.h"
12 #include "src/compiler/pipeline.h"
13 #include "src/compiler/simplified-lowering.h"
14 #include "src/compiler/verifier.h"
15 #include "src/execution.h"
16 #include "src/globals.h"
17 #include "src/parser.h"
18 #include "src/rewriter.h"
19 #include "src/scopes.h"
20 #include "test/cctest/cctest.h"
21 #include "test/cctest/compiler/codegen-tester.h"
22 #include "test/cctest/compiler/function-tester.h"
23 #include "test/cctest/compiler/graph-builder-tester.h"
24 #include "test/cctest/compiler/value-helper.h"
25
26 using namespace v8::internal;
27 using namespace v8::internal::compiler;
28
29 template <typename ReturnType>
30 class ChangesLoweringTester : public GraphBuilderTester<ReturnType> {
31  public:
32   explicit ChangesLoweringTester(MachineType p0 = kMachNone)
33       : GraphBuilderTester<ReturnType>(p0),
34         javascript(this->zone()),
35         jsgraph(this->graph(), this->common(), &javascript, this->machine()),
36         function(Handle<JSFunction>::null()) {}
37
38   JSOperatorBuilder javascript;
39   JSGraph jsgraph;
40   Handle<JSFunction> function;
41
42   Node* start() { return this->graph()->start(); }
43
44   template <typename T>
45   T* CallWithPotentialGC() {
46     // TODO(titzer): we wrap the code in a JSFunction here to reuse the
47     // JSEntryStub; that could be done with a special prologue or other stub.
48     if (function.is_null()) {
49       function = FunctionTester::ForMachineGraph(this->graph());
50     }
51     Handle<Object>* args = NULL;
52     MaybeHandle<Object> result =
53         Execution::Call(this->isolate(), function, factory()->undefined_value(),
54                         0, args, false);
55     return T::cast(*result.ToHandleChecked());
56   }
57
58   void StoreFloat64(Node* node, double* ptr) {
59     Node* ptr_node = this->PointerConstant(ptr);
60     this->Store(kMachFloat64, ptr_node, node);
61   }
62
63   Node* LoadInt32(int32_t* ptr) {
64     Node* ptr_node = this->PointerConstant(ptr);
65     return this->Load(kMachInt32, ptr_node);
66   }
67
68   Node* LoadUint32(uint32_t* ptr) {
69     Node* ptr_node = this->PointerConstant(ptr);
70     return this->Load(kMachUint32, ptr_node);
71   }
72
73   Node* LoadFloat64(double* ptr) {
74     Node* ptr_node = this->PointerConstant(ptr);
75     return this->Load(kMachFloat64, ptr_node);
76   }
77
78   void CheckNumber(double expected, Object* number) {
79     CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
80   }
81
82   void BuildAndLower(const Operator* op) {
83     // We build a graph by hand here, because the raw machine assembler
84     // does not add the correct control and effect nodes.
85     Node* p0 = this->Parameter(0);
86     Node* change = this->graph()->NewNode(op, p0);
87     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
88                                        this->start(), this->start());
89     Node* end = this->graph()->NewNode(this->common()->End(), ret);
90     this->graph()->SetEnd(end);
91     LowerChange(change);
92   }
93
94   void BuildStoreAndLower(const Operator* op, const Operator* store_op,
95                           void* location) {
96     // We build a graph by hand here, because the raw machine assembler
97     // does not add the correct control and effect nodes.
98     Node* p0 = this->Parameter(0);
99     Node* change = this->graph()->NewNode(op, p0);
100     Node* store = this->graph()->NewNode(
101         store_op, this->PointerConstant(location), this->Int32Constant(0),
102         change, this->start(), this->start());
103     Node* ret = this->graph()->NewNode(
104         this->common()->Return(), this->Int32Constant(0), store, this->start());
105     Node* end = this->graph()->NewNode(this->common()->End(), ret);
106     this->graph()->SetEnd(end);
107     LowerChange(change);
108   }
109
110   void BuildLoadAndLower(const Operator* op, const Operator* load_op,
111                          void* location) {
112     // We build a graph by hand here, because the raw machine assembler
113     // does not add the correct control and effect nodes.
114     Node* load = this->graph()->NewNode(
115         load_op, this->PointerConstant(location), this->Int32Constant(0),
116         this->start(), this->start());
117     Node* change = this->graph()->NewNode(op, load);
118     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
119                                        this->start(), this->start());
120     Node* end = this->graph()->NewNode(this->common()->End(), ret);
121     this->graph()->SetEnd(end);
122     LowerChange(change);
123   }
124
125   void LowerChange(Node* change) {
126     // Run the graph reducer with changes lowering on a single node.
127     CompilationInfo info(this->isolate(), this->zone());
128     Linkage linkage(this->zone(), &info);
129     ChangeLowering lowering(&jsgraph, &linkage);
130     GraphReducer reducer(this->graph());
131     reducer.AddReducer(&lowering);
132     reducer.ReduceNode(change);
133     Verifier::Run(this->graph(), Verifier::UNTYPED);
134   }
135
136   Factory* factory() { return this->isolate()->factory(); }
137   Heap* heap() { return this->isolate()->heap(); }
138 };
139
140
141 TEST(RunChangeTaggedToInt32) {
142   // Build and lower a graph by hand.
143   ChangesLoweringTester<int32_t> t(kMachAnyTagged);
144   t.BuildAndLower(t.simplified()->ChangeTaggedToInt32());
145
146   if (Pipeline::SupportedTarget()) {
147     FOR_INT32_INPUTS(i) {
148       int32_t input = *i;
149
150       if (Smi::IsValid(input)) {
151         int32_t result = t.Call(Smi::FromInt(input));
152         CHECK_EQ(input, result);
153       }
154
155       {
156         Handle<Object> number = t.factory()->NewNumber(input);
157         int32_t result = t.Call(*number);
158         CHECK_EQ(input, result);
159       }
160
161       {
162         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
163         int32_t result = t.Call(*number);
164         CHECK_EQ(input, result);
165       }
166     }
167   }
168 }
169
170
171 TEST(RunChangeTaggedToUint32) {
172   // Build and lower a graph by hand.
173   ChangesLoweringTester<uint32_t> t(kMachAnyTagged);
174   t.BuildAndLower(t.simplified()->ChangeTaggedToUint32());
175
176   if (Pipeline::SupportedTarget()) {
177     FOR_UINT32_INPUTS(i) {
178       uint32_t input = *i;
179
180       if (Smi::IsValid(input)) {
181         uint32_t result = t.Call(Smi::FromInt(input));
182         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
183       }
184
185       {
186         Handle<Object> number = t.factory()->NewNumber(input);
187         uint32_t result = t.Call(*number);
188         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
189       }
190
191       {
192         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
193         uint32_t result = t.Call(*number);
194         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
195       }
196     }
197   }
198 }
199
200
201 TEST(RunChangeTaggedToFloat64) {
202   ChangesLoweringTester<int32_t> t(kMachAnyTagged);
203   double result;
204
205   t.BuildStoreAndLower(
206       t.simplified()->ChangeTaggedToFloat64(),
207       t.machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
208       &result);
209
210   if (Pipeline::SupportedTarget()) {
211     FOR_INT32_INPUTS(i) {
212       int32_t input = *i;
213
214       if (Smi::IsValid(input)) {
215         t.Call(Smi::FromInt(input));
216         CHECK_EQ(input, static_cast<int32_t>(result));
217       }
218
219       {
220         Handle<Object> number = t.factory()->NewNumber(input);
221         t.Call(*number);
222         CHECK_EQ(input, static_cast<int32_t>(result));
223       }
224
225       {
226         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
227         t.Call(*number);
228         CHECK_EQ(input, static_cast<int32_t>(result));
229       }
230     }
231   }
232
233   if (Pipeline::SupportedTarget()) {
234     FOR_FLOAT64_INPUTS(i) {
235       double input = *i;
236       {
237         Handle<Object> number = t.factory()->NewNumber(input);
238         t.Call(*number);
239         CHECK_EQ(input, result);
240       }
241
242       {
243         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
244         t.Call(*number);
245         CHECK_EQ(input, result);
246       }
247     }
248   }
249 }
250
251
252 TEST(RunChangeBoolToBit) {
253   ChangesLoweringTester<int32_t> t(kMachAnyTagged);
254   t.BuildAndLower(t.simplified()->ChangeBoolToBit());
255
256   if (Pipeline::SupportedTarget()) {
257     Object* true_obj = t.heap()->true_value();
258     int32_t result = t.Call(true_obj);
259     CHECK_EQ(1, result);
260   }
261
262   if (Pipeline::SupportedTarget()) {
263     Object* false_obj = t.heap()->false_value();
264     int32_t result = t.Call(false_obj);
265     CHECK_EQ(0, result);
266   }
267 }
268
269
270 TEST(RunChangeBitToBool) {
271   ChangesLoweringTester<Object*> t(kMachInt32);
272   t.BuildAndLower(t.simplified()->ChangeBitToBool());
273
274   if (Pipeline::SupportedTarget()) {
275     Object* result = t.Call(1);
276     Object* true_obj = t.heap()->true_value();
277     CHECK_EQ(true_obj, result);
278   }
279
280   if (Pipeline::SupportedTarget()) {
281     Object* result = t.Call(0);
282     Object* false_obj = t.heap()->false_value();
283     CHECK_EQ(false_obj, result);
284   }
285 }
286
287
288 #if V8_TURBOFAN_BACKEND
289 // TODO(titzer): disabled on ARM
290
291 TEST(RunChangeInt32ToTaggedSmi) {
292   ChangesLoweringTester<Object*> t;
293   int32_t input;
294   t.BuildLoadAndLower(t.simplified()->ChangeInt32ToTagged(),
295                       t.machine()->Load(kMachInt32), &input);
296
297   if (Pipeline::SupportedTarget()) {
298     FOR_INT32_INPUTS(i) {
299       input = *i;
300       if (!Smi::IsValid(input)) continue;
301       Object* result = t.Call();
302       t.CheckNumber(static_cast<double>(input), result);
303     }
304   }
305 }
306
307
308 TEST(RunChangeUint32ToTaggedSmi) {
309   ChangesLoweringTester<Object*> t;
310   uint32_t input;
311   t.BuildLoadAndLower(t.simplified()->ChangeUint32ToTagged(),
312                       t.machine()->Load(kMachUint32), &input);
313
314   if (Pipeline::SupportedTarget()) {
315     FOR_UINT32_INPUTS(i) {
316       input = *i;
317       if (input > static_cast<uint32_t>(Smi::kMaxValue)) continue;
318       Object* result = t.Call();
319       double expected = static_cast<double>(input);
320       t.CheckNumber(expected, result);
321     }
322   }
323 }
324
325
326 TEST(RunChangeInt32ToTagged) {
327   ChangesLoweringTester<Object*> t;
328   int32_t input;
329   t.BuildLoadAndLower(t.simplified()->ChangeInt32ToTagged(),
330                       t.machine()->Load(kMachInt32), &input);
331
332   if (Pipeline::SupportedTarget()) {
333     for (int m = 0; m < 3; m++) {  // Try 3 GC modes.
334       FOR_INT32_INPUTS(i) {
335         if (m == 0) CcTest::heap()->EnableInlineAllocation();
336         if (m == 1) CcTest::heap()->DisableInlineAllocation();
337         if (m == 2) SimulateFullSpace(CcTest::heap()->new_space());
338
339         input = *i;
340         Object* result = t.CallWithPotentialGC<Object>();
341         t.CheckNumber(static_cast<double>(input), result);
342       }
343     }
344   }
345 }
346
347
348 TEST(RunChangeUint32ToTagged) {
349   ChangesLoweringTester<Object*> t;
350   uint32_t input;
351   t.BuildLoadAndLower(t.simplified()->ChangeUint32ToTagged(),
352                       t.machine()->Load(kMachUint32), &input);
353
354   if (Pipeline::SupportedTarget()) {
355     for (int m = 0; m < 3; m++) {  // Try 3 GC modes.
356       FOR_UINT32_INPUTS(i) {
357         if (m == 0) CcTest::heap()->EnableInlineAllocation();
358         if (m == 1) CcTest::heap()->DisableInlineAllocation();
359         if (m == 2) SimulateFullSpace(CcTest::heap()->new_space());
360
361         input = *i;
362         Object* result = t.CallWithPotentialGC<Object>();
363         double expected = static_cast<double>(input);
364         t.CheckNumber(expected, result);
365       }
366     }
367   }
368 }
369
370
371 TEST(RunChangeFloat64ToTagged) {
372   ChangesLoweringTester<Object*> t;
373   double input;
374   t.BuildLoadAndLower(t.simplified()->ChangeFloat64ToTagged(),
375                       t.machine()->Load(kMachFloat64), &input);
376
377   if (Pipeline::SupportedTarget()) {
378     for (int m = 0; m < 3; m++) {  // Try 3 GC modes.
379       FOR_FLOAT64_INPUTS(i) {
380         if (m == 0) CcTest::heap()->EnableInlineAllocation();
381         if (m == 1) CcTest::heap()->DisableInlineAllocation();
382         if (m == 2) SimulateFullSpace(CcTest::heap()->new_space());
383
384         input = *i;
385         Object* result = t.CallWithPotentialGC<Object>();
386         t.CheckNumber(input, result);
387       }
388     }
389   }
390 }
391
392 #endif  // V8_TURBOFAN_BACKEND