0057b10f819aa986ce6767301d51f59ac78ca083
[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/diamond.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/linkage.h"
11 #include "src/compiler/machine-operator.h"
12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/operator-properties.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18
19 ChangeLowering::~ChangeLowering() {}
20
21
22 Reduction ChangeLowering::Reduce(Node* node) {
23   Node* control = graph()->start();
24   switch (node->opcode()) {
25     case IrOpcode::kChangeBitToBool:
26       return ChangeBitToBool(node->InputAt(0), control);
27     case IrOpcode::kChangeBoolToBit:
28       return ChangeBoolToBit(node->InputAt(0));
29     case IrOpcode::kChangeFloat64ToTagged:
30       return ChangeFloat64ToTagged(node->InputAt(0), control);
31     case IrOpcode::kChangeInt32ToTagged:
32       return ChangeInt32ToTagged(node->InputAt(0), control);
33     case IrOpcode::kChangeTaggedToFloat64:
34       return ChangeTaggedToFloat64(node->InputAt(0), control);
35     case IrOpcode::kChangeTaggedToInt32:
36       return ChangeTaggedToUI32(node->InputAt(0), control, kSigned);
37     case IrOpcode::kChangeTaggedToUint32:
38       return ChangeTaggedToUI32(node->InputAt(0), control, kUnsigned);
39     case IrOpcode::kChangeUint32ToTagged:
40       return ChangeUint32ToTagged(node->InputAt(0), control);
41     default:
42       return NoChange();
43   }
44   UNREACHABLE();
45   return NoChange();
46 }
47
48
49 Node* ChangeLowering::HeapNumberValueIndexConstant() {
50   STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0);
51   const int heap_number_value_offset =
52       ((HeapNumber::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4));
53   return jsgraph()->IntPtrConstant(heap_number_value_offset - kHeapObjectTag);
54 }
55
56
57 Node* ChangeLowering::SmiMaxValueConstant() {
58   const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize()
59                                                : SmiTagging<8>::SmiValueSize();
60   return jsgraph()->Int32Constant(
61       -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
62 }
63
64
65 Node* ChangeLowering::SmiShiftBitsConstant() {
66   const int smi_shift_size = machine()->Is32() ? SmiTagging<4>::SmiShiftSize()
67                                                : SmiTagging<8>::SmiShiftSize();
68   return jsgraph()->IntPtrConstant(smi_shift_size + kSmiTagSize);
69 }
70
71
72 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
73   // The AllocateHeapNumberStub does not use the context, so we can safely pass
74   // in Smi zero here.
75   Callable callable = CodeFactory::AllocateHeapNumber(isolate());
76   CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
77       isolate(), jsgraph()->zone(), callable.descriptor(), 0,
78       CallDescriptor::kNoFlags);
79   Node* target = jsgraph()->HeapConstant(callable.code());
80   Node* context = jsgraph()->NoContextConstant();
81   Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
82   Node* heap_number = graph()->NewNode(common()->Call(descriptor), target,
83                                        context, effect, control);
84   Node* store = graph()->NewNode(
85       machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
86       heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
87   return graph()->NewNode(common()->Finish(1), heap_number, store);
88 }
89
90
91 Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) {
92   return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
93 }
94
95
96 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) {
97   return ChangeInt32ToFloat64(ChangeSmiToInt32(value));
98 }
99
100
101 Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
102   value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
103   if (machine()->Is64()) {
104     value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
105   }
106   return value;
107 }
108
109
110 Node* ChangeLowering::ChangeUint32ToFloat64(Node* value) {
111   return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
112 }
113
114
115 Node* ChangeLowering::ChangeUint32ToSmi(Node* value) {
116   if (machine()->Is64()) {
117     value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
118   }
119   return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
120 }
121
122
123 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
124   return graph()->NewNode(machine()->Load(kMachFloat64), value,
125                           HeapNumberValueIndexConstant(), graph()->start(),
126                           control);
127 }
128
129
130 Node* ChangeLowering::TestNotSmi(Node* value) {
131   STATIC_ASSERT(kSmiTag == 0);
132   STATIC_ASSERT(kSmiTagMask == 1);
133   return graph()->NewNode(machine()->WordAnd(), value,
134                           jsgraph()->IntPtrConstant(kSmiTagMask));
135 }
136
137
138 Node* ChangeLowering::Uint32LessThanOrEqual(Node* lhs, Node* rhs) {
139   return graph()->NewNode(machine()->Uint32LessThanOrEqual(), lhs, rhs);
140 }
141
142
143 Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
144   MachineType const type = static_cast<MachineType>(kTypeBool | kRepTagged);
145   return Replace(graph()->NewNode(common()->Select(type), val,
146                                   jsgraph()->TrueConstant(),
147                                   jsgraph()->FalseConstant()));
148 }
149
150
151 Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
152   return Replace(
153       graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
154 }
155
156
157 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
158   return Replace(AllocateHeapNumberWithValue(val, control));
159 }
160
161
162 Reduction ChangeLowering::ChangeInt32ToTagged(Node* value, Node* control) {
163   if (machine()->Is64()) {
164     return Replace(graph()->NewNode(
165         machine()->Word64Shl(),
166         graph()->NewNode(machine()->ChangeInt32ToInt64(), value),
167         SmiShiftBitsConstant()));
168   } else if (NodeProperties::GetBounds(value).upper->Is(Type::Signed31())) {
169     return Replace(
170         graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()));
171   }
172
173   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
174   Node* ovf = graph()->NewNode(common()->Projection(1), add);
175
176   Diamond d(graph(), common(), ovf, BranchHint::kFalse);
177   d.Chain(control);
178   return Replace(
179       d.Phi(kMachAnyTagged,
180             AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), d.if_true),
181             graph()->NewNode(common()->Projection(0), add)));
182 }
183
184
185 Reduction ChangeLowering::ChangeTaggedToUI32(Node* value, Node* control,
186                                              Signedness signedness) {
187   const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32;
188   const Operator* op = (signedness == kSigned)
189                            ? machine()->ChangeFloat64ToInt32()
190                            : machine()->ChangeFloat64ToUint32();
191   Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse);
192   d.Chain(control);
193   return Replace(
194       d.Phi(type, graph()->NewNode(op, LoadHeapNumberValue(value, d.if_true)),
195             ChangeSmiToInt32(value)));
196 }
197
198
199 namespace {
200
201 bool CanCover(Node* value, IrOpcode::Value opcode) {
202   if (value->opcode() != opcode) return false;
203   bool first = true;
204   for (Edge const edge : value->use_edges()) {
205     if (NodeProperties::IsEffectEdge(edge)) continue;
206     DCHECK(NodeProperties::IsValueEdge(edge));
207     if (!first) return false;
208     first = false;
209   }
210   return true;
211 }
212
213 }  // namespace
214
215
216 Reduction ChangeLowering::ChangeTaggedToFloat64(Node* value, Node* control) {
217   if (CanCover(value, IrOpcode::kJSToNumber)) {
218     // ChangeTaggedToFloat64(JSToNumber(x)) =>
219     //   if IsSmi(x) then ChangeSmiToFloat64(x)
220     //   else let y = JSToNumber(x) in
221     //     if IsSmi(y) then ChangeSmiToFloat64(y)
222     //     else LoadHeapNumberValue(y)
223     Node* const object = NodeProperties::GetValueInput(value, 0);
224     Node* const context = NodeProperties::GetContextInput(value);
225     Node* const effect = NodeProperties::GetEffectInput(value);
226     Node* const control = NodeProperties::GetControlInput(value);
227
228     Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse);
229     d1.Chain(control);
230
231     Node* number =
232         OperatorProperties::HasFrameStateInput(value->op())
233             ? graph()->NewNode(value->op(), object, context,
234                                NodeProperties::GetFrameStateInput(value),
235                                effect, d1.if_true)
236             : graph()->NewNode(value->op(), object, context, effect,
237                                d1.if_true);
238     Diamond d2(graph(), common(), TestNotSmi(number));
239     d2.Nest(d1, true);
240     Node* phi2 = d2.Phi(kMachFloat64, LoadHeapNumberValue(number, d2.if_true),
241                         ChangeSmiToFloat64(number));
242
243     Node* phi1 = d1.Phi(kMachFloat64, phi2, ChangeSmiToFloat64(object));
244     Node* ephi1 = d1.EffectPhi(number, effect);
245
246     for (Edge edge : value->use_edges()) {
247       if (NodeProperties::IsEffectEdge(edge)) {
248         edge.UpdateTo(ephi1);
249       }
250     }
251     return Replace(phi1);
252   }
253
254   Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse);
255   d.Chain(control);
256   Node* load = LoadHeapNumberValue(value, d.if_true);
257   Node* number = ChangeSmiToFloat64(value);
258   return Replace(d.Phi(kMachFloat64, load, number));
259 }
260
261
262 Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) {
263   Diamond d(graph(), common(),
264             Uint32LessThanOrEqual(value, SmiMaxValueConstant()),
265             BranchHint::kTrue);
266   d.Chain(control);
267   return Replace(d.Phi(
268       kMachAnyTagged, ChangeUint32ToSmi(value),
269       AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), d.if_false)));
270 }
271
272
273 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
274
275
276 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
277
278
279 CommonOperatorBuilder* ChangeLowering::common() const {
280   return jsgraph()->common();
281 }
282
283
284 MachineOperatorBuilder* ChangeLowering::machine() const {
285   return jsgraph()->machine();
286 }
287
288 }  // namespace compiler
289 }  // namespace internal
290 }  // namespace v8