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/ast/scopes.h"
8 #include "src/compiler/change-lowering.h"
9 #include "src/compiler/control-builders.h"
10 #include "src/compiler/js-graph.h"
11 #include "src/compiler/node-properties.h"
12 #include "src/compiler/pipeline.h"
13 #include "src/compiler/select-lowering.h"
14 #include "src/compiler/simplified-lowering.h"
15 #include "src/compiler/typer.h"
16 #include "src/compiler/verifier.h"
17 #include "src/execution.h"
18 #include "src/globals.h"
19 #include "src/parsing/parser.h"
20 #include "src/parsing/rewriter.h"
21 #include "test/cctest/cctest.h"
22 #include "test/cctest/compiler/codegen-tester.h"
23 #include "test/cctest/compiler/function-tester.h"
24 #include "test/cctest/compiler/graph-builder-tester.h"
25 #include "test/cctest/compiler/value-helper.h"
26 
27 namespace v8 {
28 namespace internal {
29 namespace compiler {
30 
31 template <typename ReturnType>
32 class ChangesLoweringTester : public GraphBuilderTester<ReturnType> {
33  public:
ChangesLoweringTester(MachineType p0=MachineType::None ())34   explicit ChangesLoweringTester(MachineType p0 = MachineType::None())
35       : GraphBuilderTester<ReturnType>(p0),
36         javascript(this->zone()),
37         jsgraph(this->isolate(), this->graph(), this->common(), &javascript,
38                 nullptr, this->machine()),
39         function(Handle<JSFunction>::null()) {}
40 
41   JSOperatorBuilder javascript;
42   JSGraph jsgraph;
43   Handle<JSFunction> function;
44 
start()45   Node* start() { return this->graph()->start(); }
46 
47   template <typename T>
CallWithPotentialGC()48   T* CallWithPotentialGC() {
49     // TODO(titzer): we wrap the code in a JSFunction here to reuse the
50     // JSEntryStub; that could be done with a special prologue or other stub.
51     if (function.is_null()) {
52       function = FunctionTester::ForMachineGraph(this->graph());
53     }
54     Handle<Object>* args = NULL;
55     MaybeHandle<Object> result =
56         Execution::Call(this->isolate(), function, factory()->undefined_value(),
57                         0, args, false);
58     return T::cast(*result.ToHandleChecked());
59   }
60 
StoreFloat64(Node * node,double * ptr)61   void StoreFloat64(Node* node, double* ptr) {
62     Node* ptr_node = this->PointerConstant(ptr);
63     this->Store(MachineType::Float64(), ptr_node, node);
64   }
65 
LoadInt32(int32_t * ptr)66   Node* LoadInt32(int32_t* ptr) {
67     Node* ptr_node = this->PointerConstant(ptr);
68     return this->Load(MachineType::Int32(), ptr_node);
69   }
70 
LoadUint32(uint32_t * ptr)71   Node* LoadUint32(uint32_t* ptr) {
72     Node* ptr_node = this->PointerConstant(ptr);
73     return this->Load(MachineType::Uint32(), ptr_node);
74   }
75 
LoadFloat64(double * ptr)76   Node* LoadFloat64(double* ptr) {
77     Node* ptr_node = this->PointerConstant(ptr);
78     return this->Load(MachineType::Float64(), ptr_node);
79   }
80 
CheckNumber(double expected,Object * number)81   void CheckNumber(double expected, Object* number) {
82     CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number));
83   }
84 
BuildAndLower(const Operator * op)85   void BuildAndLower(const Operator* op) {
86     // We build a graph by hand here, because the raw machine assembler
87     // does not add the correct control and effect nodes.
88     Node* p0 = this->Parameter(0);
89     Node* change = this->graph()->NewNode(op, p0);
90     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
91                                        this->start(), this->start());
92     Node* end = this->graph()->NewNode(this->common()->End(1), ret);
93     this->graph()->SetEnd(end);
94     LowerChange(change);
95   }
96 
BuildStoreAndLower(const Operator * op,const Operator * store_op,void * location)97   void BuildStoreAndLower(const Operator* op, const Operator* store_op,
98                           void* location) {
99     // We build a graph by hand here, because the raw machine assembler
100     // does not add the correct control and effect nodes.
101     Node* p0 = this->Parameter(0);
102     Node* change = this->graph()->NewNode(op, p0);
103     Node* store = this->graph()->NewNode(
104         store_op, this->PointerConstant(location), this->Int32Constant(0),
105         change, this->start(), this->start());
106     Node* ret = this->graph()->NewNode(
107         this->common()->Return(), this->Int32Constant(0), store, this->start());
108     Node* end = this->graph()->NewNode(this->common()->End(1), ret);
109     this->graph()->SetEnd(end);
110     LowerChange(change);
111   }
112 
BuildLoadAndLower(const Operator * op,const Operator * load_op,void * location)113   void BuildLoadAndLower(const Operator* op, const Operator* load_op,
114                          void* location) {
115     // We build a graph by hand here, because the raw machine assembler
116     // does not add the correct control and effect nodes.
117     Node* load = this->graph()->NewNode(
118         load_op, this->PointerConstant(location), this->Int32Constant(0),
119         this->start(), this->start());
120     Node* change = this->graph()->NewNode(op, load);
121     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
122                                        this->start(), this->start());
123     Node* end = this->graph()->NewNode(this->common()->End(1), ret);
124     this->graph()->SetEnd(end);
125     LowerChange(change);
126   }
127 
LowerChange(Node * change)128   void LowerChange(Node* change) {
129     // Run the graph reducer with changes lowering on a single node.
130     Typer typer(this->isolate(), this->graph());
131     typer.Run();
132     ChangeLowering change_lowering(&jsgraph);
133     SelectLowering select_lowering(this->graph(), this->common());
134     GraphReducer reducer(this->zone(), this->graph());
135     reducer.AddReducer(&change_lowering);
136     reducer.AddReducer(&select_lowering);
137     reducer.ReduceNode(change);
138     Verifier::Run(this->graph(), Verifier::UNTYPED);
139   }
140 
factory()141   Factory* factory() { return this->isolate()->factory(); }
heap()142   Heap* heap() { return this->isolate()->heap(); }
143 };
144 
145 
TEST(RunChangeTaggedToInt32)146 TEST(RunChangeTaggedToInt32) {
147   // Build and lower a graph by hand.
148   ChangesLoweringTester<int32_t> t(MachineType::AnyTagged());
149   t.BuildAndLower(t.simplified()->ChangeTaggedToInt32());
150 
151     FOR_INT32_INPUTS(i) {
152       int32_t input = *i;
153 
154       if (Smi::IsValid(input)) {
155         int32_t result = t.Call(Smi::FromInt(input));
156         CHECK_EQ(input, result);
157       }
158 
159       {
160         Handle<Object> number = t.factory()->NewNumber(input);
161         int32_t result = t.Call(*number);
162         CHECK_EQ(input, result);
163       }
164 
165       {
166         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
167         int32_t result = t.Call(*number);
168         CHECK_EQ(input, result);
169       }
170   }
171 }
172 
173 
TEST(RunChangeTaggedToUint32)174 TEST(RunChangeTaggedToUint32) {
175   // Build and lower a graph by hand.
176   ChangesLoweringTester<uint32_t> t(MachineType::AnyTagged());
177   t.BuildAndLower(t.simplified()->ChangeTaggedToUint32());
178 
179     FOR_UINT32_INPUTS(i) {
180       uint32_t input = *i;
181 
182       if (Smi::IsValid(input)) {
183         uint32_t result = t.Call(Smi::FromInt(input));
184         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
185       }
186 
187       {
188         Handle<Object> number = t.factory()->NewNumber(input);
189         uint32_t result = t.Call(*number);
190         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
191       }
192 
193       {
194         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
195         uint32_t result = t.Call(*number);
196         CHECK_EQ(static_cast<int32_t>(input), static_cast<int32_t>(result));
197       }
198     }
199 }
200 
201 
TEST(RunChangeTaggedToFloat64)202 TEST(RunChangeTaggedToFloat64) {
203   ChangesLoweringTester<int32_t> t(MachineType::AnyTagged());
204   double result;
205 
206   t.BuildStoreAndLower(t.simplified()->ChangeTaggedToFloat64(),
207                        t.machine()->Store(StoreRepresentation(
208                            MachineRepresentation::kFloat64, kNoWriteBarrier)),
209                        &result);
210 
211   {
212     FOR_INT32_INPUTS(i) {
213       int32_t input = *i;
214 
215       if (Smi::IsValid(input)) {
216         t.Call(Smi::FromInt(input));
217         CHECK_EQ(input, static_cast<int32_t>(result));
218       }
219 
220       {
221         Handle<Object> number = t.factory()->NewNumber(input);
222         t.Call(*number);
223         CHECK_EQ(input, static_cast<int32_t>(result));
224       }
225 
226       {
227         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
228         t.Call(*number);
229         CHECK_EQ(input, static_cast<int32_t>(result));
230       }
231     }
232   }
233 
234   {
235     FOR_FLOAT64_INPUTS(i) {
236       double input = *i;
237       {
238         Handle<Object> number = t.factory()->NewNumber(input);
239         t.Call(*number);
240         CheckDoubleEq(input, result);
241       }
242 
243       {
244         Handle<HeapNumber> number = t.factory()->NewHeapNumber(input);
245         t.Call(*number);
246         CheckDoubleEq(input, result);
247       }
248     }
249   }
250 }
251 
252 
TEST(RunChangeBoolToBit)253 TEST(RunChangeBoolToBit) {
254   ChangesLoweringTester<int32_t> t(MachineType::AnyTagged());
255   t.BuildAndLower(t.simplified()->ChangeBoolToBit());
256 
257   {
258     Object* true_obj = t.heap()->true_value();
259     int32_t result = t.Call(true_obj);
260     CHECK_EQ(1, result);
261   }
262 
263   {
264     Object* false_obj = t.heap()->false_value();
265     int32_t result = t.Call(false_obj);
266     CHECK_EQ(0, result);
267   }
268 }
269 
270 
TEST(RunChangeBitToBool)271 TEST(RunChangeBitToBool) {
272   ChangesLoweringTester<Object*> t(MachineType::Int32());
273   t.BuildAndLower(t.simplified()->ChangeBitToBool());
274 
275   {
276     Object* result = t.Call(1);
277     Object* true_obj = t.heap()->true_value();
278     CHECK_EQ(true_obj, result);
279   }
280 
281   {
282     Object* result = t.Call(0);
283     Object* false_obj = t.heap()->false_value();
284     CHECK_EQ(false_obj, result);
285   }
286 }
287 
288 }  // namespace compiler
289 }  // namespace internal
290 }  // namespace v8
291