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"
6 #include "src/compiler/machine-operator.h"
8 #include "src/compiler/js-graph.h"
14 ChangeLowering::~ChangeLowering() {}
17 Reduction ChangeLowering::Reduce(Node* node) {
18 Node* control = graph()->start();
19 switch (node->opcode()) {
20 case IrOpcode::kChangeBitToBool:
21 return ChangeBitToBool(node->InputAt(0), control);
22 case IrOpcode::kChangeBoolToBit:
23 return ChangeBoolToBit(node->InputAt(0));
24 case IrOpcode::kChangeFloat64ToTagged:
25 return ChangeFloat64ToTagged(node->InputAt(0), control);
26 case IrOpcode::kChangeInt32ToTagged:
27 return ChangeInt32ToTagged(node->InputAt(0), control);
28 case IrOpcode::kChangeTaggedToFloat64:
29 return ChangeTaggedToFloat64(node->InputAt(0), control);
30 case IrOpcode::kChangeTaggedToInt32:
31 return ChangeTaggedToUI32(node->InputAt(0), control, kSigned);
32 case IrOpcode::kChangeTaggedToUint32:
33 return ChangeTaggedToUI32(node->InputAt(0), control, kUnsigned);
34 case IrOpcode::kChangeUint32ToTagged:
35 return ChangeUint32ToTagged(node->InputAt(0), control);
44 Node* ChangeLowering::HeapNumberValueIndexConstant() {
45 STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0);
46 const int heap_number_value_offset =
47 ((HeapNumber::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4));
48 return jsgraph()->Int32Constant(heap_number_value_offset - kHeapObjectTag);
52 Node* ChangeLowering::SmiMaxValueConstant() {
53 const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize()
54 : SmiTagging<8>::SmiValueSize();
55 return jsgraph()->Int32Constant(
56 -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
60 Node* ChangeLowering::SmiShiftBitsConstant() {
61 const int smi_shift_size = machine()->Is32() ? SmiTagging<4>::SmiShiftSize()
62 : SmiTagging<8>::SmiShiftSize();
63 return jsgraph()->Int32Constant(smi_shift_size + kSmiTagSize);
67 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
68 // The AllocateHeapNumber() runtime function does not use the context, so we
69 // can safely pass in Smi zero here.
70 Node* context = jsgraph()->ZeroConstant();
71 Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
72 const Runtime::Function* function =
73 Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
74 DCHECK_EQ(0, function->nargs);
75 CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
76 function->function_id, 0, Operator::kNoProperties);
77 Node* heap_number = graph()->NewNode(
78 common()->Call(desc), jsgraph()->CEntryStubConstant(),
79 jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
80 jsgraph()->Int32Constant(function->nargs), context, effect, control);
81 Node* store = graph()->NewNode(
82 machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
83 heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
84 return graph()->NewNode(common()->Finish(1), heap_number, store);
88 Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
89 value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
90 if (machine()->Is64()) {
91 value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
97 Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
98 return graph()->NewNode(machine()->Load(kMachFloat64), value,
99 HeapNumberValueIndexConstant(),
100 graph()->NewNode(common()->ControlEffect(), control));
104 Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
105 Node* branch = graph()->NewNode(common()->Branch(), val, control);
107 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
108 Node* true_value = jsgraph()->TrueConstant();
110 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
111 Node* false_value = jsgraph()->FalseConstant();
113 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
114 Node* phi = graph()->NewNode(
115 common()->Phi(static_cast<MachineType>(kTypeBool | kRepTagged), 2),
116 true_value, false_value, merge);
122 Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
124 graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
128 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
129 return Replace(AllocateHeapNumberWithValue(val, control));
133 Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
134 if (machine()->Is64()) {
136 graph()->NewNode(machine()->Word64Shl(),
137 graph()->NewNode(machine()->ChangeInt32ToInt64(), val),
138 SmiShiftBitsConstant()));
141 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
142 Node* ovf = graph()->NewNode(common()->Projection(1), add);
144 Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
146 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
147 Node* heap_number = AllocateHeapNumberWithValue(
148 graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
150 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
151 Node* smi = graph()->NewNode(common()->Projection(0), add);
153 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
154 Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), heap_number,
161 Reduction ChangeLowering::ChangeTaggedToUI32(Node* val, Node* control,
162 Signedness signedness) {
163 STATIC_ASSERT(kSmiTag == 0);
164 STATIC_ASSERT(kSmiTagMask == 1);
166 Node* tag = graph()->NewNode(machine()->WordAnd(), val,
167 jsgraph()->Int32Constant(kSmiTagMask));
168 Node* branch = graph()->NewNode(common()->Branch(), tag, control);
170 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
171 const Operator* op = (signedness == kSigned)
172 ? machine()->ChangeFloat64ToInt32()
173 : machine()->ChangeFloat64ToUint32();
174 Node* change = graph()->NewNode(op, LoadHeapNumberValue(val, if_true));
176 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
177 Node* number = ChangeSmiToInt32(val);
179 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
180 Node* phi = graph()->NewNode(
181 common()->Phi((signedness == kSigned) ? kMachInt32 : kMachUint32, 2),
182 change, number, merge);
188 Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
189 STATIC_ASSERT(kSmiTag == 0);
190 STATIC_ASSERT(kSmiTagMask == 1);
192 Node* tag = graph()->NewNode(machine()->WordAnd(), val,
193 jsgraph()->Int32Constant(kSmiTagMask));
194 Node* branch = graph()->NewNode(common()->Branch(), tag, control);
196 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
197 Node* load = LoadHeapNumberValue(val, if_true);
199 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
200 Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(),
201 ChangeSmiToInt32(val));
203 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
205 graph()->NewNode(common()->Phi(kMachFloat64, 2), load, number, merge);
211 Reduction ChangeLowering::ChangeUint32ToTagged(Node* val, Node* control) {
212 STATIC_ASSERT(kSmiTag == 0);
213 STATIC_ASSERT(kSmiTagMask == 1);
215 Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
216 SmiMaxValueConstant());
217 Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
219 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
220 Node* smi = graph()->NewNode(
221 machine()->WordShl(),
223 ? graph()->NewNode(machine()->ChangeUint32ToUint64(), val)
225 SmiShiftBitsConstant());
227 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
228 Node* heap_number = AllocateHeapNumberWithValue(
229 graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), if_false);
231 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
232 Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), smi,
239 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
242 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
245 CommonOperatorBuilder* ChangeLowering::common() const {
246 return jsgraph()->common();
250 MachineOperatorBuilder* ChangeLowering::machine() const {
251 return jsgraph()->machine();
254 } // namespace compiler
255 } // namespace internal