OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/change-lowering.h" | 5 #include "src/compiler/change-lowering.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/compiler/diamond.h" | |
9 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/linkage.h" | 9 #include "src/compiler/linkage.h" |
11 #include "src/compiler/machine-operator.h" | 10 #include "src/compiler/machine-operator.h" |
12 #include "src/compiler/node-properties.h" | 11 #include "src/compiler/node-properties.h" |
13 #include "src/compiler/operator-properties.h" | 12 #include "src/compiler/operator-properties.h" |
14 | 13 |
15 namespace v8 { | 14 namespace v8 { |
16 namespace internal { | 15 namespace internal { |
17 namespace compiler { | 16 namespace compiler { |
18 | 17 |
(...skipping 21 matching lines...) Expand all Loading... |
40 return ChangeUint32ToTagged(node->InputAt(0), control); | 39 return ChangeUint32ToTagged(node->InputAt(0), control); |
41 default: | 40 default: |
42 return NoChange(); | 41 return NoChange(); |
43 } | 42 } |
44 UNREACHABLE(); | 43 UNREACHABLE(); |
45 return NoChange(); | 44 return NoChange(); |
46 } | 45 } |
47 | 46 |
48 | 47 |
49 Node* ChangeLowering::HeapNumberValueIndexConstant() { | 48 Node* ChangeLowering::HeapNumberValueIndexConstant() { |
50 STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0); | 49 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag); |
51 const int heap_number_value_offset = | |
52 ((HeapNumber::kValueOffset / kPointerSize) * (machine()->Is64() ? 8 : 4)); | |
53 return jsgraph()->IntPtrConstant(heap_number_value_offset - kHeapObjectTag); | |
54 } | 50 } |
55 | 51 |
56 | 52 |
57 Node* ChangeLowering::SmiMaxValueConstant() { | 53 Node* ChangeLowering::SmiMaxValueConstant() { |
58 const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize() | 54 return jsgraph()->Int32Constant(Smi::kMaxValue); |
59 : SmiTagging<8>::SmiValueSize(); | |
60 return jsgraph()->Int32Constant( | |
61 -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1)); | |
62 } | 55 } |
63 | 56 |
64 | 57 |
65 Node* ChangeLowering::SmiShiftBitsConstant() { | 58 Node* ChangeLowering::SmiShiftBitsConstant() { |
66 const int smi_shift_size = machine()->Is32() ? SmiTagging<4>::SmiShiftSize() | 59 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize); |
67 : SmiTagging<8>::SmiShiftSize(); | |
68 return jsgraph()->IntPtrConstant(smi_shift_size + kSmiTagSize); | |
69 } | 60 } |
70 | 61 |
71 | 62 |
72 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) { | 63 Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) { |
73 // The AllocateHeapNumberStub does not use the context, so we can safely pass | 64 // The AllocateHeapNumberStub does not use the context, so we can safely pass |
74 // in Smi zero here. | 65 // in Smi zero here. |
75 Callable callable = CodeFactory::AllocateHeapNumber(isolate()); | 66 Callable callable = CodeFactory::AllocateHeapNumber(isolate()); |
76 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( | 67 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( |
77 isolate(), jsgraph()->zone(), callable.descriptor(), 0, | 68 isolate(), jsgraph()->zone(), callable.descriptor(), 0, |
78 CallDescriptor::kNoFlags); | 69 CallDescriptor::kNoFlags); |
79 Node* target = jsgraph()->HeapConstant(callable.code()); | 70 Node* target = jsgraph()->HeapConstant(callable.code()); |
80 Node* context = jsgraph()->NoContextConstant(); | 71 Node* context = jsgraph()->NoContextConstant(); |
81 Node* effect = graph()->NewNode(common()->ValueEffect(1), value); | 72 Node* effect = graph()->NewNode(common()->ValueEffect(1), value); |
82 Node* heap_number = graph()->NewNode(common()->Call(descriptor), target, | 73 Node* heap_number = graph()->NewNode(common()->Call(descriptor), target, |
83 context, effect, control); | 74 context, effect, control); |
84 Node* store = graph()->NewNode( | 75 Node* store = graph()->NewNode( |
85 machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)), | 76 machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)), |
86 heap_number, HeapNumberValueIndexConstant(), value, heap_number, control); | 77 heap_number, HeapNumberValueIndexConstant(), value, heap_number, control); |
87 return graph()->NewNode(common()->Finish(1), heap_number, store); | 78 return graph()->NewNode(common()->Finish(1), heap_number, store); |
88 } | 79 } |
89 | 80 |
90 | 81 |
91 Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) { | 82 Node* ChangeLowering::ChangeInt32ToFloat64(Node* value) { |
92 return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value); | 83 return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value); |
93 } | 84 } |
94 | 85 |
95 | 86 |
| 87 Node* ChangeLowering::ChangeInt32ToSmi(Node* value) { |
| 88 if (machine()->Is64()) { |
| 89 value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value); |
| 90 } |
| 91 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant()); |
| 92 } |
| 93 |
| 94 |
96 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) { | 95 Node* ChangeLowering::ChangeSmiToFloat64(Node* value) { |
97 return ChangeInt32ToFloat64(ChangeSmiToInt32(value)); | 96 return ChangeInt32ToFloat64(ChangeSmiToInt32(value)); |
98 } | 97 } |
99 | 98 |
100 | 99 |
101 Node* ChangeLowering::ChangeSmiToInt32(Node* value) { | 100 Node* ChangeLowering::ChangeSmiToInt32(Node* value) { |
102 value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant()); | 101 value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant()); |
103 if (machine()->Is64()) { | 102 if (machine()->Is64()) { |
104 value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value); | 103 value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value); |
105 } | 104 } |
(...skipping 22 matching lines...) Expand all Loading... |
128 | 127 |
129 | 128 |
130 Node* ChangeLowering::TestNotSmi(Node* value) { | 129 Node* ChangeLowering::TestNotSmi(Node* value) { |
131 STATIC_ASSERT(kSmiTag == 0); | 130 STATIC_ASSERT(kSmiTag == 0); |
132 STATIC_ASSERT(kSmiTagMask == 1); | 131 STATIC_ASSERT(kSmiTagMask == 1); |
133 return graph()->NewNode(machine()->WordAnd(), value, | 132 return graph()->NewNode(machine()->WordAnd(), value, |
134 jsgraph()->IntPtrConstant(kSmiTagMask)); | 133 jsgraph()->IntPtrConstant(kSmiTagMask)); |
135 } | 134 } |
136 | 135 |
137 | 136 |
138 Node* ChangeLowering::Uint32LessThanOrEqual(Node* lhs, Node* rhs) { | 137 Reduction ChangeLowering::ChangeBitToBool(Node* value, Node* control) { |
139 return graph()->NewNode(machine()->Uint32LessThanOrEqual(), lhs, rhs); | 138 return Replace(graph()->NewNode(common()->Select(kMachAnyTagged), value, |
140 } | |
141 | |
142 | |
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(), | 139 jsgraph()->TrueConstant(), |
147 jsgraph()->FalseConstant())); | 140 jsgraph()->FalseConstant())); |
148 } | 141 } |
149 | 142 |
150 | 143 |
151 Reduction ChangeLowering::ChangeBoolToBit(Node* val) { | 144 Reduction ChangeLowering::ChangeBoolToBit(Node* value) { |
152 return Replace( | 145 return Replace(graph()->NewNode(machine()->WordEqual(), value, |
153 graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant())); | 146 jsgraph()->TrueConstant())); |
154 } | 147 } |
155 | 148 |
156 | 149 |
157 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) { | 150 Reduction ChangeLowering::ChangeFloat64ToTagged(Node* value, Node* control) { |
158 return Replace(AllocateHeapNumberWithValue(val, control)); | 151 return Replace(AllocateHeapNumberWithValue(value, control)); |
159 } | 152 } |
160 | 153 |
161 | 154 |
162 Reduction ChangeLowering::ChangeInt32ToTagged(Node* value, Node* control) { | 155 Reduction ChangeLowering::ChangeInt32ToTagged(Node* value, Node* control) { |
163 if (machine()->Is64()) { | 156 if (machine()->Is64() || |
164 return Replace(graph()->NewNode( | 157 NodeProperties::GetBounds(value).upper->Is(Type::SignedSmall())) { |
165 machine()->Word64Shl(), | 158 return Replace(ChangeInt32ToSmi(value)); |
166 graph()->NewNode(machine()->ChangeInt32ToInt64(), value), | |
167 SmiShiftBitsConstant())); | |
168 } else if (NodeProperties::GetBounds(value).upper->Is(Type::SignedSmall())) { | |
169 return Replace( | |
170 graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant())); | |
171 } | 159 } |
172 | 160 |
173 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value); | 161 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value); |
| 162 |
174 Node* ovf = graph()->NewNode(common()->Projection(1), add); | 163 Node* ovf = graph()->NewNode(common()->Projection(1), add); |
| 164 Node* branch = |
| 165 graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control); |
175 | 166 |
176 Diamond d(graph(), common(), ovf, BranchHint::kFalse); | 167 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
177 d.Chain(control); | 168 Node* vtrue = |
178 return Replace( | 169 AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), if_true); |
179 d.Phi(kMachAnyTagged, | 170 |
180 AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), d.if_true), | 171 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
181 graph()->NewNode(common()->Projection(0), add))); | 172 Node* vfalse = graph()->NewNode(common()->Projection(0), add); |
| 173 |
| 174 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 175 Node* phi = |
| 176 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge); |
| 177 |
| 178 return Replace(phi); |
182 } | 179 } |
183 | 180 |
184 | 181 |
185 Reduction ChangeLowering::ChangeTaggedToUI32(Node* value, Node* control, | 182 Reduction ChangeLowering::ChangeTaggedToUI32(Node* value, Node* control, |
186 Signedness signedness) { | 183 Signedness signedness) { |
| 184 if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedSigned())) { |
| 185 return Replace(ChangeSmiToInt32(value)); |
| 186 } |
| 187 |
187 const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32; | 188 const MachineType type = (signedness == kSigned) ? kMachInt32 : kMachUint32; |
188 const Operator* op = (signedness == kSigned) | 189 const Operator* op = (signedness == kSigned) |
189 ? machine()->ChangeFloat64ToInt32() | 190 ? machine()->ChangeFloat64ToInt32() |
190 : machine()->ChangeFloat64ToUint32(); | 191 : machine()->ChangeFloat64ToUint32(); |
191 Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse); | 192 |
192 d.Chain(control); | 193 if (NodeProperties::GetBounds(value).upper->Is(Type::TaggedPointer())) { |
193 return Replace( | 194 return Replace(graph()->NewNode(op, LoadHeapNumberValue(value, control))); |
194 d.Phi(type, graph()->NewNode(op, LoadHeapNumberValue(value, d.if_true)), | 195 } |
195 ChangeSmiToInt32(value))); | 196 |
| 197 Node* check = TestNotSmi(value); |
| 198 Node* branch = |
| 199 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 200 |
| 201 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 202 Node* vtrue = graph()->NewNode(op, LoadHeapNumberValue(value, if_true)); |
| 203 |
| 204 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 205 Node* vfalse = ChangeSmiToInt32(value); |
| 206 |
| 207 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 208 Node* phi = graph()->NewNode(common()->Phi(type, 2), vtrue, vfalse, merge); |
| 209 |
| 210 return Replace(phi); |
196 } | 211 } |
197 | 212 |
198 | 213 |
199 namespace { | 214 namespace { |
200 | 215 |
201 bool CanCover(Node* value, IrOpcode::Value opcode) { | 216 bool CanCover(Node* value, IrOpcode::Value opcode) { |
202 if (value->opcode() != opcode) return false; | 217 if (value->opcode() != opcode) return false; |
203 bool first = true; | 218 bool first = true; |
204 for (Edge const edge : value->use_edges()) { | 219 for (Edge const edge : value->use_edges()) { |
205 if (NodeProperties::IsControlEdge(edge)) continue; | 220 if (NodeProperties::IsControlEdge(edge)) continue; |
(...skipping 13 matching lines...) Expand all Loading... |
219 // ChangeTaggedToFloat64(JSToNumber(x)) => | 234 // ChangeTaggedToFloat64(JSToNumber(x)) => |
220 // if IsSmi(x) then ChangeSmiToFloat64(x) | 235 // if IsSmi(x) then ChangeSmiToFloat64(x) |
221 // else let y = JSToNumber(x) in | 236 // else let y = JSToNumber(x) in |
222 // if IsSmi(y) then ChangeSmiToFloat64(y) | 237 // if IsSmi(y) then ChangeSmiToFloat64(y) |
223 // else LoadHeapNumberValue(y) | 238 // else LoadHeapNumberValue(y) |
224 Node* const object = NodeProperties::GetValueInput(value, 0); | 239 Node* const object = NodeProperties::GetValueInput(value, 0); |
225 Node* const context = NodeProperties::GetContextInput(value); | 240 Node* const context = NodeProperties::GetContextInput(value); |
226 Node* const effect = NodeProperties::GetEffectInput(value); | 241 Node* const effect = NodeProperties::GetEffectInput(value); |
227 Node* const control = NodeProperties::GetControlInput(value); | 242 Node* const control = NodeProperties::GetControlInput(value); |
228 | 243 |
229 Diamond d1(graph(), common(), TestNotSmi(object), BranchHint::kFalse); | 244 const Operator* merge_op = common()->Merge(2); |
230 d1.Chain(control); | 245 const Operator* ephi_op = common()->EffectPhi(2); |
| 246 const Operator* phi_op = common()->Phi(kMachFloat64, 2); |
231 | 247 |
232 DCHECK_EQ(FLAG_turbo_deoptimization, | 248 Node* check1 = TestNotSmi(object); |
233 OperatorProperties::GetFrameStateInputCount(value->op()) == 1); | 249 Node* branch1 = |
234 Node* number = | 250 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control); |
| 251 |
| 252 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); |
| 253 Node* vtrue1 = |
235 FLAG_turbo_deoptimization | 254 FLAG_turbo_deoptimization |
236 ? graph()->NewNode(value->op(), object, context, | 255 ? graph()->NewNode(value->op(), object, context, |
237 NodeProperties::GetFrameStateInput(value, 0), | 256 NodeProperties::GetFrameStateInput(value, 0), |
238 effect, d1.if_true) | 257 effect, if_true1) |
239 : graph()->NewNode(value->op(), object, context, effect, | 258 : graph()->NewNode(value->op(), object, context, effect, if_true1); |
240 d1.if_true); | 259 Node* etrue1 = vtrue1; |
241 Diamond d2(graph(), common(), TestNotSmi(number)); | 260 { |
242 d2.Nest(d1, true); | 261 Node* check2 = TestNotSmi(vtrue1); |
243 Node* phi2 = d2.Phi(kMachFloat64, LoadHeapNumberValue(number, d2.if_true), | 262 Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_true1); |
244 ChangeSmiToFloat64(number)); | |
245 | 263 |
246 Node* phi1 = d1.Phi(kMachFloat64, phi2, ChangeSmiToFloat64(object)); | 264 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2); |
247 Node* ephi1 = d1.EffectPhi(number, effect); | 265 Node* vtrue2 = LoadHeapNumberValue(vtrue1, if_true2); |
248 | 266 |
249 for (Edge edge : value->use_edges()) { | 267 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2); |
250 if (NodeProperties::IsEffectEdge(edge)) { | 268 Node* vfalse2 = ChangeSmiToFloat64(vtrue1); |
251 edge.UpdateTo(ephi1); | 269 |
252 } | 270 if_true1 = graph()->NewNode(merge_op, if_true2, if_false2); |
| 271 vtrue1 = graph()->NewNode(phi_op, vtrue2, vfalse2, if_true1); |
253 } | 272 } |
| 273 |
| 274 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); |
| 275 Node* vfalse1 = ChangeSmiToFloat64(object); |
| 276 Node* efalse1 = effect; |
| 277 |
| 278 Node* merge1 = graph()->NewNode(merge_op, if_true1, if_false1); |
| 279 Node* ephi1 = graph()->NewNode(ephi_op, etrue1, efalse1, merge1); |
| 280 Node* phi1 = graph()->NewNode(phi_op, vtrue1, vfalse1, merge1); |
| 281 |
| 282 NodeProperties::ReplaceWithValue(value, phi1, ephi1, merge1); |
254 return Replace(phi1); | 283 return Replace(phi1); |
255 } | 284 } |
256 | 285 |
257 Diamond d(graph(), common(), TestNotSmi(value), BranchHint::kFalse); | 286 Node* check = TestNotSmi(value); |
258 d.Chain(control); | 287 Node* branch = |
259 Node* load = LoadHeapNumberValue(value, d.if_true); | 288 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
260 Node* number = ChangeSmiToFloat64(value); | 289 |
261 return Replace(d.Phi(kMachFloat64, load, number)); | 290 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 291 Node* vtrue = LoadHeapNumberValue(value, if_true); |
| 292 |
| 293 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 294 Node* vfalse = ChangeSmiToFloat64(value); |
| 295 |
| 296 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 297 Node* phi = |
| 298 graph()->NewNode(common()->Phi(kMachFloat64, 2), vtrue, vfalse, merge); |
| 299 |
| 300 return Replace(phi); |
262 } | 301 } |
263 | 302 |
264 | 303 |
265 Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) { | 304 Reduction ChangeLowering::ChangeUint32ToTagged(Node* value, Node* control) { |
266 Diamond d(graph(), common(), | 305 if (NodeProperties::GetBounds(value).upper->Is(Type::UnsignedSmall())) { |
267 Uint32LessThanOrEqual(value, SmiMaxValueConstant()), | 306 return Replace(ChangeUint32ToSmi(value)); |
268 BranchHint::kTrue); | 307 } |
269 d.Chain(control); | 308 |
270 return Replace(d.Phi( | 309 Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, |
271 kMachAnyTagged, ChangeUint32ToSmi(value), | 310 SmiMaxValueConstant()); |
272 AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), d.if_false))); | 311 Node* branch = |
| 312 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 313 |
| 314 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 315 Node* vtrue = ChangeUint32ToSmi(value); |
| 316 |
| 317 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 318 Node* vfalse = |
| 319 AllocateHeapNumberWithValue(ChangeUint32ToFloat64(value), if_false); |
| 320 |
| 321 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 322 Node* phi = |
| 323 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), vtrue, vfalse, merge); |
| 324 |
| 325 return Replace(phi); |
273 } | 326 } |
274 | 327 |
275 | 328 |
276 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); } | 329 Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); } |
277 | 330 |
278 | 331 |
279 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); } | 332 Graph* ChangeLowering::graph() const { return jsgraph()->graph(); } |
280 | 333 |
281 | 334 |
282 CommonOperatorBuilder* ChangeLowering::common() const { | 335 CommonOperatorBuilder* ChangeLowering::common() const { |
283 return jsgraph()->common(); | 336 return jsgraph()->common(); |
284 } | 337 } |
285 | 338 |
286 | 339 |
287 MachineOperatorBuilder* ChangeLowering::machine() const { | 340 MachineOperatorBuilder* ChangeLowering::machine() const { |
288 return jsgraph()->machine(); | 341 return jsgraph()->machine(); |
289 } | 342 } |
290 | 343 |
291 } // namespace compiler | 344 } // namespace compiler |
292 } // namespace internal | 345 } // namespace internal |
293 } // namespace v8 | 346 } // namespace v8 |
OLD | NEW |