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/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"
19 ChangeLowering::~ChangeLowering() {}
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);
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);
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));
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);
72 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
73 // The AllocateHeapNumberStub does not use the context, so we can safely pass
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);
91 Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) {
92 return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
96 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) {
97 return ChangeInt32ToFloat64(ChangeSmiToInt32(value));
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);
110 Node* ChangeLowering::ChangeUint32ToFloat64(Node* value) {
111 return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
115 Node* ChangeLowering::ChangeUint32ToSmi(Node* value) {
116 if (machine()->Is64()) {
117 value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
119 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
123 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
124 return graph()->NewNode(machine()->Load(kMachFloat64), value,
125 HeapNumberValueIndexConstant(), graph()->start(),
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));
138 Node* ChangeLowering::Uint32LessThanOrEqual(Node* lhs, Node* rhs) {
139 return graph()->NewNode(machine()->Uint32LessThanOrEqual(), lhs, rhs);
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()));
151 Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
153 graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
157 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
158 return Replace(AllocateHeapNumberWithValue(val, control));
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())) {
170 graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()));
173 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
174 Node* ovf = graph()->NewNode(common()->Projection(1), add);
176 Diamond d(graph(), common(), ovf, BranchHint::kFalse);
179 d.Phi(kMachAnyTagged,
180 AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), d.if_true),
181 graph()->NewNode(common()->Projection(0), add)));
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);
194 d.Phi(type, graph()->NewNode(op, LoadHeapNumberValue(value, d.if_true)),
195 ChangeSmiToInt32(value)));
201 bool CanCover(Node* value, IrOpcode::Value opcode) {
202 if (value->opcode() != opcode) return false;
204 for (Edge const edge : value->use_edges()) {
205 if (NodeProperties::IsEffectEdge(edge)) continue;
206 DCHECK(NodeProperties::IsValueEdge(edge));
207 if (!first) return false;
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);
228 Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse);
232 OperatorProperties::HasFrameStateInput(value->op())
233 ? graph()->NewNode(value->op(), object, context,
234 NodeProperties::GetFrameStateInput(value),
236 : graph()->NewNode(value->op(), object, context, effect,
238 Diamond d2(graph(), common(), TestNotSmi(number));
240 Node* phi2 = d2.Phi(kMachFloat64, LoadHeapNumberValue(number, d2.if_true),
241 ChangeSmiToFloat64(number));
243 Node* phi1 = d1.Phi(kMachFloat64, phi2, ChangeSmiToFloat64(object));
244 Node* ephi1 = d1.EffectPhi(number, effect);
246 for (Edge edge : value->use_edges()) {
247 if (NodeProperties::IsEffectEdge(edge)) {
248 edge.UpdateTo(ephi1);
251 return Replace(phi1);
254 Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse);
256 Node* load = LoadHeapNumberValue(value, d.if_true);
257 Node* number = ChangeSmiToFloat64(value);
258 return Replace(d.Phi(kMachFloat64, load, number));
262 Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) {
263 Diamond d(graph(), common(),
264 Uint32LessThanOrEqual(value, SmiMaxValueConstant()),
267 return Replace(d.Phi(
268 kMachAnyTagged, ChangeUint32ToSmi(value),
269 AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), d.if_false)));
273 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
276 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
279 CommonOperatorBuilder* ChangeLowering::common() const {
280 return jsgraph()->common();
284 MachineOperatorBuilder* ChangeLowering::machine() const {
285 return jsgraph()->machine();
288 } // namespace compiler
289 } // namespace internal