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#include "src/compiler/machine-operator.h"
7
8#include "src/compiler/js-graph.h"
9
10namespace v8 {
11namespace internal {
12namespace compiler {
13
14ChangeLowering::~ChangeLowering() {}
15
16
17Reduction 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);
36    default:
37      return NoChange();
38  }
39  UNREACHABLE();
40  return NoChange();
41}
42
43
44Node* 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);
49}
50
51
52Node* 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));
57}
58
59
60Node* 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);
64}
65
66
67Node* 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);
85}
86
87
88Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
89  value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
90  if (machine()->Is64()) {
91    value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
92  }
93  return value;
94}
95
96
97Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
98  return graph()->NewNode(machine()->Load(kMachFloat64), value,
99                          HeapNumberValueIndexConstant(),
100                          graph()->NewNode(common()->ControlEffect(), control));
101}
102
103
104Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
105  Node* branch = graph()->NewNode(common()->Branch(), val, control);
106
107  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
108  Node* true_value = jsgraph()->TrueConstant();
109
110  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
111  Node* false_value = jsgraph()->FalseConstant();
112
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);
117
118  return Replace(phi);
119}
120
121
122Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
123  return Replace(
124      graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
125}
126
127
128Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
129  return Replace(AllocateHeapNumberWithValue(val, control));
130}
131
132
133Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
134  if (machine()->Is64()) {
135    return Replace(
136        graph()->NewNode(machine()->Word64Shl(),
137                         graph()->NewNode(machine()->ChangeInt32ToInt64(), val),
138                         SmiShiftBitsConstant()));
139  }
140
141  Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
142  Node* ovf = graph()->NewNode(common()->Projection(1), add);
143
144  Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
145
146  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
147  Node* heap_number = AllocateHeapNumberWithValue(
148      graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
149
150  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
151  Node* smi = graph()->NewNode(common()->Projection(0), add);
152
153  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
154  Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), heap_number,
155                               smi, merge);
156
157  return Replace(phi);
158}
159
160
161Reduction ChangeLowering::ChangeTaggedToUI32(Node* val, Node* control,
162                                             Signedness signedness) {
163  STATIC_ASSERT(kSmiTag == 0);
164  STATIC_ASSERT(kSmiTagMask == 1);
165
166  Node* tag = graph()->NewNode(machine()->WordAnd(), val,
167                               jsgraph()->Int32Constant(kSmiTagMask));
168  Node* branch = graph()->NewNode(common()->Branch(), tag, control);
169
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));
175
176  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
177  Node* number = ChangeSmiToInt32(val);
178
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);
183
184  return Replace(phi);
185}
186
187
188Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
189  STATIC_ASSERT(kSmiTag == 0);
190  STATIC_ASSERT(kSmiTagMask == 1);
191
192  Node* tag = graph()->NewNode(machine()->WordAnd(), val,
193                               jsgraph()->Int32Constant(kSmiTagMask));
194  Node* branch = graph()->NewNode(common()->Branch(), tag, control);
195
196  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
197  Node* load = LoadHeapNumberValue(val, if_true);
198
199  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
200  Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(),
201                                  ChangeSmiToInt32(val));
202
203  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
204  Node* phi =
205      graph()->NewNode(common()->Phi(kMachFloat64, 2), load, number, merge);
206
207  return Replace(phi);
208}
209
210
211Reduction ChangeLowering::ChangeUint32ToTagged(Node* val, Node* control) {
212  STATIC_ASSERT(kSmiTag == 0);
213  STATIC_ASSERT(kSmiTagMask == 1);
214
215  Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
216                               SmiMaxValueConstant());
217  Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
218
219  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
220  Node* smi = graph()->NewNode(
221      machine()->WordShl(),
222      machine()->Is64()
223          ? graph()->NewNode(machine()->ChangeUint32ToUint64(), val)
224          : val,
225      SmiShiftBitsConstant());
226
227  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
228  Node* heap_number = AllocateHeapNumberWithValue(
229      graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), if_false);
230
231  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
232  Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), smi,
233                               heap_number, merge);
234
235  return Replace(phi);
236}
237
238
239Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
240
241
242Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
243
244
245CommonOperatorBuilder* ChangeLowering::common() const {
246  return jsgraph()->common();
247}
248
249
250MachineOperatorBuilder* ChangeLowering::machine() const {
251  return jsgraph()->machine();
252}
253
254}  // namespace compiler
255}  // namespace internal
256}  // namespace v8
257