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 
10 namespace v8 {
11 namespace internal {
12 namespace compiler {
13 
~ChangeLowering()14 ChangeLowering::~ChangeLowering() {}
15 
16 
Reduce(Node * node)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);
36     default:
37       return NoChange();
38   }
39   UNREACHABLE();
40   return NoChange();
41 }
42 
43 
HeapNumberValueIndexConstant()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);
49 }
50 
51 
SmiMaxValueConstant()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));
57 }
58 
59 
SmiShiftBitsConstant()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);
64 }
65 
66 
AllocateHeapNumberWithValue(Node * value,Node * control)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);
85 }
86 
87 
ChangeSmiToInt32(Node * value)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);
92   }
93   return value;
94 }
95 
96 
LoadHeapNumberValue(Node * value,Node * control)97 Node* 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 
ChangeBitToBool(Node * val,Node * control)104 Reduction 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 
ChangeBoolToBit(Node * val)122 Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
123   return Replace(
124       graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
125 }
126 
127 
ChangeFloat64ToTagged(Node * val,Node * control)128 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
129   return Replace(AllocateHeapNumberWithValue(val, control));
130 }
131 
132 
ChangeInt32ToTagged(Node * val,Node * control)133 Reduction 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 
ChangeTaggedToUI32(Node * val,Node * control,Signedness signedness)161 Reduction 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 
ChangeTaggedToFloat64(Node * val,Node * control)188 Reduction 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 
ChangeUint32ToTagged(Node * val,Node * control)211 Reduction 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 
isolate() const239 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
240 
241 
graph() const242 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
243 
244 
common() const245 CommonOperatorBuilder* ChangeLowering::common() const {
246   return jsgraph()->common();
247 }
248 
249 
machine() const250 MachineOperatorBuilder* ChangeLowering::machine() const {
251   return jsgraph()->machine();
252 }
253 
254 }  // namespace compiler
255 }  // namespace internal
256 }  // namespace v8
257