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.
5 #include "src/compiler/change-lowering.h"
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"
18 ChangeLowering::~ChangeLowering() {}
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);
48 Node* ChangeLowering::HeapNumberValueIndexConstant() {
49 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
53 Node* ChangeLowering::SmiMaxValueConstant() {
54 return jsgraph()->Int32Constant(Smi::kMaxValue);
58 Node* ChangeLowering::SmiShiftBitsConstant() {
59 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
63 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
64 // The AllocateHeapNumberStub does not use the context, so we can safely pass
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));
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);
85 Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) {
86 return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
90 Node* ChangeLowering::ChangeInt32ToSmi(Node* value) {
91 if (machine()->Is64()) {
92 value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value);
94 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
98 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) {
99 return ChangeInt32ToFloat64(ChangeSmiToInt32(value));
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);
112 Node* ChangeLowering::ChangeUint32ToFloat64(Node* value) {
113 return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
117 Node* ChangeLowering::ChangeUint32ToSmi(Node* value) {
118 if (machine()->Is64()) {
119 value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
121 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
125 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
126 return graph()->NewNode(machine()->Load(kMachFloat64), value,
127 HeapNumberValueIndexConstant(), graph()->start(),
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));
140 Reduction ChangeLowering::ChangeBitToBool(Node* value, Node* control) {
141 return Replace(graph()->NewNode(common()->Select(kMachAnyTagged), value,
142 jsgraph()->TrueConstant(),
143 jsgraph()->FalseConstant()));
147 Reduction ChangeLowering::ChangeBoolToBit(Node* value) {
148 return Replace(graph()->NewNode(machine()->WordEqual(), value,
149 jsgraph()->TrueConstant()));
153 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* value, Node* control) {
154 return Replace(AllocateHeapNumberWithValue(value, control));
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));
164 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
166 Node* ovf = graph()->NewNode(common()->Projection(1), add);
168 graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control);
170 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
172 AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), if_true);
174 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
175 Node* vfalse = graph()->NewNode(common()->Projection(0), add);
177 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
179 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge);
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));
191 const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32;
192 const Operator* op = (signedness == kSigned)
193 ? machine()->ChangeFloat64ToInt32()
194 : machine()->ChangeFloat64ToUint32();
196 if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedPointer())) {
197 return Replace(graph()->NewNode(op, LoadHeapNumberValue(value, control)));
200 Node* check = TestNotSmi(value);
202 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
204 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
205 Node* vtrue = graph()->NewNode(op, LoadHeapNumberValue(value, if_true));
207 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
208 Node* vfalse = ChangeSmiToInt32(value);
210 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
211 Node* phi = graph()->NewNode(common()->Phi(type, 2), vtrue, vfalse, merge);
219 bool CanCover(Node* value, IrOpcode::Value opcode) {
220 if (value->opcode() != opcode) return false;
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;
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);
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);
251 Node* check1 = TestNotSmi(object);
253 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
255 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
257 FLAG_turbo_deoptimization
258 ? graph()->NewNode(value->op(), object, context,
259 NodeProperties::GetFrameStateInput(value, 0),
261 : graph()->NewNode(value->op(), object, context, effect, if_true1);
262 Node* etrue1 = vtrue1;
264 Node* check2 = TestNotSmi(vtrue1);
265 Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_true1);
267 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
268 Node* vtrue2 = LoadHeapNumberValue(vtrue1, if_true2);
270 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
271 Node* vfalse2 = ChangeSmiToFloat64(vtrue1);
273 if_true1 = graph()->NewNode(merge_op, if_true2, if_false2);
274 vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1);
277 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
278 Node* vfalse1 = ChangeSmiToFloat64(object);
279 Node* efalse1 = effect;
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);
285 NodeProperties::ReplaceWithValue(value, phi1, ephi1, merge1);
286 return Replace(phi1);
289 Node* check = TestNotSmi(value);
291 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
293 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
294 Node* vtrue = LoadHeapNumberValue(value, if_true);
296 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
297 Node* vfalse = ChangeSmiToFloat64(value);
299 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
301 graph()->NewNode(common()->Phi(kMachFloat64, 2), vtrue, vfalse, merge);
307 Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) {
308 if (NodeProperties::GetBounds(value).upper->Is(Type::UnsignedSmall())) {
309 return Replace(ChangeUint32ToSmi(value));
312 Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value,
313 SmiMaxValueConstant());
315 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
317 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
318 Node* vtrue = ChangeUint32ToSmi(value);
320 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
322 AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), if_false);
324 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
326 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge);
332 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
335 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
338 CommonOperatorBuilder* ChangeLowering::common() const {
339 return jsgraph()->common();
343 MachineOperatorBuilder* ChangeLowering::machine() const {
344 return jsgraph()->machine();
347 } // namespace compiler
348 } // namespace internal