deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / compiler / change-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 "src/compiler/change-lowering.h"
6
7 #include "src/code-factory.h"
8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/linkage.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node-properties.h"
12 #include "src/compiler/operator-properties.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 ChangeLowering::~ChangeLowering() {}
19
20
21 Reduction ChangeLowering::Reduce(Node* node) {
22   Node* control = graph()->start();
23   switch (node->opcode()) {
24     case IrOpcode::kChangeBitToBool:
25       return ChangeBitToBool(node->InputAt(0), control);
26     case IrOpcode::kChangeBoolToBit:
27       return ChangeBoolToBit(node->InputAt(0));
28     case IrOpcode::kChangeFloat64ToTagged:
29       return ChangeFloat64ToTagged(node->InputAt(0), control);
30     case IrOpcode::kChangeInt32ToTagged:
31       return ChangeInt32ToTagged(node->InputAt(0), control);
32     case IrOpcode::kChangeTaggedToFloat64:
33       return ChangeTaggedToFloat64(node->InputAt(0), control);
34     case IrOpcode::kChangeTaggedToInt32:
35       return ChangeTaggedToUI32(node->InputAt(0), control, kSigned);
36     case IrOpcode::kChangeTaggedToUint32:
37       return ChangeTaggedToUI32(node->InputAt(0), control, kUnsigned);
38     case IrOpcode::kChangeUint32ToTagged:
39       return ChangeUint32ToTagged(node->InputAt(0), control);
40     default:
41       return NoChange();
42   }
43   UNREACHABLE();
44   return NoChange();
45 }
46
47
48 Node* ChangeLowering::HeapNumberValueIndexConstant() {
49   return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
50 }
51
52
53 Node* ChangeLowering::SmiMaxValueConstant() {
54   return jsgraph()->Int32Constant(Smi::kMaxValue);
55 }
56
57
58 Node* ChangeLowering::SmiShiftBitsConstant() {
59   return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
60 }
61
62
63 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
64   // The AllocateHeapNumberStub does not use the context, so we can safely pass
65   // in Smi zero here.
66   Callable callable = CodeFactory::AllocateHeapNumber(isolate());
67   Node* target = jsgraph()->HeapConstant(callable.code());
68   Node* context = jsgraph()->NoContextConstant();
69   Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
70   if (!allocate_heap_number_operator_.is_set()) {
71     CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
72         isolate(), jsgraph()->zone(), callable.descriptor(), 0,
73         CallDescriptor::kNoFlags, Operator::kNoThrow);
74     allocate_heap_number_operator_.set(common()->Call(descriptor));
75   }
76   Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
77                                        target, context, effect, control);
78   Node* store = graph()->NewNode(
79       machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
80       heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
81   return graph()->NewNode(common()->Finish(1), heap_number, store);
82 }
83
84
85 Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) {
86   return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
87 }
88
89
90 Node* ChangeLowering::ChangeInt32ToSmi(Node* value) {
91   if (machine()->Is64()) {
92     value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value);
93   }
94   return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
95 }
96
97
98 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) {
99   return ChangeInt32ToFloat64(ChangeSmiToInt32(value));
100 }
101
102
103 Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
104   value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
105   if (machine()->Is64()) {
106     value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
107   }
108   return value;
109 }
110
111
112 Node* ChangeLowering::ChangeUint32ToFloat64(Node* value) {
113   return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
114 }
115
116
117 Node* ChangeLowering::ChangeUint32ToSmi(Node* value) {
118   if (machine()->Is64()) {
119     value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
120   }
121   return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
122 }
123
124
125 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
126   return graph()->NewNode(machine()->Load(kMachFloat64), value,
127                           HeapNumberValueIndexConstant(), graph()->start(),
128                           control);
129 }
130
131
132 Node* ChangeLowering::TestNotSmi(Node* value) {
133   STATIC_ASSERT(kSmiTag == 0);
134   STATIC_ASSERT(kSmiTagMask == 1);
135   return graph()->NewNode(machine()->WordAnd(), value,
136                           jsgraph()->IntPtrConstant(kSmiTagMask));
137 }
138
139
140 Reduction ChangeLowering::ChangeBitToBool(Node* value, Node* control) {
141   return Replace(graph()->NewNode(common()->Select(kMachAnyTagged), value,
142                                   jsgraph()->TrueConstant(),
143                                   jsgraph()->FalseConstant()));
144 }
145
146
147 Reduction ChangeLowering::ChangeBoolToBit(Node* value) {
148   return Replace(graph()->NewNode(machine()->WordEqual(), value,
149                                   jsgraph()->TrueConstant()));
150 }
151
152
153 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* value, Node* control) {
154   return Replace(AllocateHeapNumberWithValue(value, control));
155 }
156
157
158 Reduction ChangeLowering::ChangeInt32ToTagged(Node* value, Node* control) {
159   if (machine()->Is64() ||
160       NodeProperties::GetBounds(value).upper->Is(Type::SignedSmall())) {
161     return Replace(ChangeInt32ToSmi(value));
162   }
163
164   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
165
166   Node* ovf = graph()->NewNode(common()->Projection(1), add);
167   Node* branch =
168       graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control);
169
170   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
171   Node* vtrue =
172       AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), if_true);
173
174   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
175   Node* vfalse = graph()->NewNode(common()->Projection(0), add);
176
177   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
178   Node* phi =
179       graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge);
180
181   return Replace(phi);
182 }
183
184
185 Reduction ChangeLowering::ChangeTaggedToUI32(Node* value, Node* control,
186                                              Signedness signedness) {
187   if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedSigned())) {
188     return Replace(ChangeSmiToInt32(value));
189   }
190
191   const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32;
192   const Operator* op = (signedness == kSigned)
193                            ? machine()->ChangeFloat64ToInt32()
194                            : machine()->ChangeFloat64ToUint32();
195
196   if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedPointer())) {
197     return Replace(graph()->NewNode(op, LoadHeapNumberValue(value, control)));
198   }
199
200   Node* check = TestNotSmi(value);
201   Node* branch =
202       graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
203
204   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
205   Node* vtrue = graph()->NewNode(op, LoadHeapNumberValue(value, if_true));
206
207   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
208   Node* vfalse = ChangeSmiToInt32(value);
209
210   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
211   Node* phi = graph()->NewNode(common()->Phi(type, 2), vtrue, vfalse, merge);
212
213   return Replace(phi);
214 }
215
216
217 namespace {
218
219 bool CanCover(Node* value, IrOpcode::Value opcode) {
220   if (value->opcode() != opcode) return false;
221   bool first = true;
222   for (Edge const edge : value->use_edges()) {
223     if (NodeProperties::IsControlEdge(edge)) continue;
224     if (NodeProperties::IsEffectEdge(edge)) continue;
225     DCHECK(NodeProperties::IsValueEdge(edge));
226     if (!first) return false;
227     first = false;
228   }
229   return true;
230 }
231
232 }  // namespace
233
234
235 Reduction ChangeLowering::ChangeTaggedToFloat64(Node* value, Node* control) {
236   if (CanCover(value, IrOpcode::kJSToNumber)) {
237     // ChangeTaggedToFloat64(JSToNumber(x)) =>
238     //   if IsSmi(x) then ChangeSmiToFloat64(x)
239     //   else let y = JSToNumber(x) in
240     //     if IsSmi(y) then ChangeSmiToFloat64(y)
241     //     else LoadHeapNumberValue(y)
242     Node* const object = NodeProperties::GetValueInput(value, 0);
243     Node* const context = NodeProperties::GetContextInput(value);
244     Node* const effect = NodeProperties::GetEffectInput(value);
245     Node* const control = NodeProperties::GetControlInput(value);
246
247     const Operator* merge_op = common()->Merge(2);
248     const Operator* ephi_op = common()->EffectPhi(2);
249     const Operator* phi_op = common()->Phi(kMachFloat64, 2);
250
251     Node* check1 = TestNotSmi(object);
252     Node* branch1 =
253         graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
254
255     Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
256     Node* vtrue1 =
257         FLAG_turbo_deoptimization
258             ? graph()->NewNode(value->op(), object, context,
259                                NodeProperties::GetFrameStateInput(value, 0),
260                                effect, if_true1)
261             : graph()->NewNode(value->op(), object, context, effect, if_true1);
262     Node* etrue1 = vtrue1;
263     {
264       Node* check2 = TestNotSmi(vtrue1);
265       Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_true1);
266
267       Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
268       Node* vtrue2 = LoadHeapNumberValue(vtrue1, if_true2);
269
270       Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
271       Node* vfalse2 = ChangeSmiToFloat64(vtrue1);
272
273       if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
274       vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
275     }
276
277     Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
278     Node* vfalse1 = ChangeSmiToFloat64(object);
279     Node* efalse1 = effect;
280
281     Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1);
282     Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1);
283     Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1);
284
285     NodeProperties::ReplaceWithValue(value, phi1, ephi1, merge1);
286     return Replace(phi1);
287   }
288
289   Node* check = TestNotSmi(value);
290   Node* branch =
291       graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
292
293   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
294   Node* vtrue = LoadHeapNumberValue(value, if_true);
295
296   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
297   Node* vfalse = ChangeSmiToFloat64(value);
298
299   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
300   Node* phi =
301       graph()->NewNode(common()->Phi(kMachFloat64, 2), vtrue, vfalse, merge);
302
303   return Replace(phi);
304 }
305
306
307 Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) {
308   if (NodeProperties::GetBounds(value).upper->Is(Type::UnsignedSmall())) {
309     return Replace(ChangeUint32ToSmi(value));
310   }
311
312   Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value,
313                                  SmiMaxValueConstant());
314   Node* branch =
315       graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
316
317   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
318   Node* vtrue = ChangeUint32ToSmi(value);
319
320   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
321   Node* vfalse =
322       AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), if_false);
323
324   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
325   Node* phi =
326       graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge);
327
328   return Replace(phi);
329 }
330
331
332 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
333
334
335 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
336
337
338 CommonOperatorBuilder* ChangeLowering::common() const {
339   return jsgraph()->common();
340 }
341
342
343 MachineOperatorBuilder* ChangeLowering::machine() const {
344   return jsgraph()->machine();
345 }
346
347 }  // namespace compiler
348 }  // namespace internal
349 }  // namespace v8