1 // Copyright 2015 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/representation-change.h"
6
7 #include <sstream>
8
9 #include "src/base/bits.h"
10 #include "src/code-factory.h"
11 #include "src/compiler/machine-operator.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
description() const17 const char* Truncation::description() const {
18 switch (kind()) {
19 case TruncationKind::kNone:
20 return "no-value-use";
21 case TruncationKind::kBool:
22 return "truncate-to-bool";
23 case TruncationKind::kWord32:
24 return "truncate-to-word32";
25 case TruncationKind::kWord64:
26 return "truncate-to-word64";
27 case TruncationKind::kFloat64:
28 return "truncate-to-float64";
29 case TruncationKind::kAny:
30 return "no-truncation";
31 }
32 UNREACHABLE();
33 return nullptr;
34 }
35
36
37 // Partial order for truncations:
38 //
39 // kWord64 kAny
40 // ^ ^
41 // \ |
42 // \ kFloat64 <--+
43 // \ ^ |
44 // \ / |
45 // kWord32 kBool
46 // ^ ^
47 // \ /
48 // \ /
49 // \ /
50 // \ /
51 // \ /
52 // kNone
53
54 // static
Generalize(TruncationKind rep1,TruncationKind rep2)55 Truncation::TruncationKind Truncation::Generalize(TruncationKind rep1,
56 TruncationKind rep2) {
57 if (LessGeneral(rep1, rep2)) return rep2;
58 if (LessGeneral(rep2, rep1)) return rep1;
59 // Handle the generalization of float64-representable values.
60 if (LessGeneral(rep1, TruncationKind::kFloat64) &&
61 LessGeneral(rep2, TruncationKind::kFloat64)) {
62 return TruncationKind::kFloat64;
63 }
64 // Handle the generalization of any-representable values.
65 if (LessGeneral(rep1, TruncationKind::kAny) &&
66 LessGeneral(rep2, TruncationKind::kAny)) {
67 return TruncationKind::kAny;
68 }
69 // All other combinations are illegal.
70 FATAL("Tried to combine incompatible truncations");
71 return TruncationKind::kNone;
72 }
73
74
75 // static
LessGeneral(TruncationKind rep1,TruncationKind rep2)76 bool Truncation::LessGeneral(TruncationKind rep1, TruncationKind rep2) {
77 switch (rep1) {
78 case TruncationKind::kNone:
79 return true;
80 case TruncationKind::kBool:
81 return rep2 == TruncationKind::kBool || rep2 == TruncationKind::kAny;
82 case TruncationKind::kWord32:
83 return rep2 == TruncationKind::kWord32 ||
84 rep2 == TruncationKind::kWord64 ||
85 rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
86 case TruncationKind::kWord64:
87 return rep2 == TruncationKind::kWord64;
88 case TruncationKind::kFloat64:
89 return rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
90 case TruncationKind::kAny:
91 return rep2 == TruncationKind::kAny;
92 }
93 UNREACHABLE();
94 return false;
95 }
96
97
98 namespace {
99
IsWord(MachineRepresentation rep)100 bool IsWord(MachineRepresentation rep) {
101 return rep == MachineRepresentation::kWord8 ||
102 rep == MachineRepresentation::kWord16 ||
103 rep == MachineRepresentation::kWord32;
104 }
105
106 } // namespace
107
108 // Changes representation from {output_rep} to {use_rep}. The {truncation}
109 // parameter is only used for sanity checking - if the changer cannot figure
110 // out signedness for the word32->float64 conversion, then we check that the
111 // uses truncate to word32 (so they do not care about signedness).
GetRepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Node * use_node,UseInfo use_info)112 Node* RepresentationChanger::GetRepresentationFor(
113 Node* node, MachineRepresentation output_rep, Type* output_type,
114 Node* use_node, UseInfo use_info) {
115 if (output_rep == MachineRepresentation::kNone &&
116 output_type->IsInhabited()) {
117 // The output representation should be set if the type is inhabited (i.e.,
118 // if the value is possible).
119 return TypeError(node, output_rep, output_type, use_info.representation());
120 }
121
122 // Handle the no-op shortcuts when no checking is necessary.
123 if (use_info.type_check() == TypeCheckKind::kNone ||
124 output_rep != MachineRepresentation::kWord32) {
125 if (use_info.representation() == output_rep) {
126 // Representations are the same. That's a no-op.
127 return node;
128 }
129 if (IsWord(use_info.representation()) && IsWord(output_rep)) {
130 // Both are words less than or equal to 32-bits.
131 // Since loads of integers from memory implicitly sign or zero extend the
132 // value to the full machine word size and stores implicitly truncate,
133 // no representation change is necessary.
134 return node;
135 }
136 }
137
138 switch (use_info.representation()) {
139 case MachineRepresentation::kTaggedSigned:
140 DCHECK(use_info.type_check() == TypeCheckKind::kNone ||
141 use_info.type_check() == TypeCheckKind::kSignedSmall);
142 return GetTaggedSignedRepresentationFor(node, output_rep, output_type,
143 use_node, use_info);
144 case MachineRepresentation::kTaggedPointer:
145 DCHECK(use_info.type_check() == TypeCheckKind::kNone ||
146 use_info.type_check() == TypeCheckKind::kHeapObject);
147 return GetTaggedPointerRepresentationFor(node, output_rep, output_type,
148 use_node, use_info);
149 case MachineRepresentation::kTagged:
150 DCHECK(use_info.type_check() == TypeCheckKind::kNone);
151 return GetTaggedRepresentationFor(node, output_rep, output_type,
152 use_info.truncation());
153 case MachineRepresentation::kFloat32:
154 DCHECK(use_info.type_check() == TypeCheckKind::kNone);
155 return GetFloat32RepresentationFor(node, output_rep, output_type,
156 use_info.truncation());
157 case MachineRepresentation::kFloat64:
158 return GetFloat64RepresentationFor(node, output_rep, output_type,
159 use_node, use_info);
160 case MachineRepresentation::kBit:
161 DCHECK(use_info.type_check() == TypeCheckKind::kNone);
162 return GetBitRepresentationFor(node, output_rep, output_type);
163 case MachineRepresentation::kWord8:
164 case MachineRepresentation::kWord16:
165 case MachineRepresentation::kWord32:
166 return GetWord32RepresentationFor(node, output_rep, output_type, use_node,
167 use_info);
168 case MachineRepresentation::kWord64:
169 DCHECK(use_info.type_check() == TypeCheckKind::kNone);
170 return GetWord64RepresentationFor(node, output_rep, output_type);
171 case MachineRepresentation::kSimd128: // Fall through.
172 // TODO(bbudge) Handle conversions between tagged and untagged.
173 break;
174 case MachineRepresentation::kNone:
175 return node;
176 }
177 UNREACHABLE();
178 return nullptr;
179 }
180
GetTaggedSignedRepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Node * use_node,UseInfo use_info)181 Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
182 Node* node, MachineRepresentation output_rep, Type* output_type,
183 Node* use_node, UseInfo use_info) {
184 // Eagerly fold representation changes for constants.
185 switch (node->opcode()) {
186 case IrOpcode::kNumberConstant:
187 if (output_type->Is(Type::SignedSmall())) {
188 return node;
189 }
190 break;
191 default:
192 break;
193 }
194 // Select the correct X -> Tagged operator.
195 const Operator* op;
196 if (output_type->Is(Type::None())) {
197 // This is an impossible value; it should not be used at runtime.
198 // We just provide a dummy value here.
199 return jsgraph()->Constant(0);
200 } else if (IsWord(output_rep)) {
201 if (output_type->Is(Type::Signed31())) {
202 op = simplified()->ChangeInt31ToTaggedSigned();
203 } else if (output_type->Is(Type::Signed32())) {
204 if (SmiValuesAre32Bits()) {
205 op = simplified()->ChangeInt32ToTagged();
206 } else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
207 op = simplified()->CheckedInt32ToTaggedSigned();
208 } else {
209 return TypeError(node, output_rep, output_type,
210 MachineRepresentation::kTaggedSigned);
211 }
212 } else if (output_type->Is(Type::Unsigned32()) &&
213 use_info.type_check() == TypeCheckKind::kSignedSmall) {
214 op = simplified()->CheckedUint32ToTaggedSigned();
215 } else {
216 return TypeError(node, output_rep, output_type,
217 MachineRepresentation::kTaggedSigned);
218 }
219 } else if (output_rep == MachineRepresentation::kFloat64) {
220 if (output_type->Is(Type::Signed31())) {
221 // float64 -> int32 -> tagged signed
222 node = InsertChangeFloat64ToInt32(node);
223 op = simplified()->ChangeInt31ToTaggedSigned();
224 } else if (output_type->Is(Type::Signed32())) {
225 // float64 -> int32 -> tagged signed
226 node = InsertChangeFloat64ToInt32(node);
227 if (SmiValuesAre32Bits()) {
228 op = simplified()->ChangeInt32ToTagged();
229 } else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
230 op = simplified()->CheckedInt32ToTaggedSigned();
231 } else {
232 return TypeError(node, output_rep, output_type,
233 MachineRepresentation::kTaggedSigned);
234 }
235 } else if (output_type->Is(Type::Unsigned32()) &&
236 use_info.type_check() == TypeCheckKind::kSignedSmall) {
237 // float64 -> uint32 -> tagged signed
238 node = InsertChangeFloat64ToUint32(node);
239 op = simplified()->CheckedUint32ToTaggedSigned();
240 } else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
241 op = simplified()->CheckedFloat64ToInt32(
242 output_type->Maybe(Type::MinusZero())
243 ? CheckForMinusZeroMode::kCheckForMinusZero
244 : CheckForMinusZeroMode::kDontCheckForMinusZero);
245 node = InsertConversion(node, op, use_node);
246 if (SmiValuesAre32Bits()) {
247 op = simplified()->ChangeInt32ToTagged();
248 } else {
249 op = simplified()->CheckedInt32ToTaggedSigned();
250 }
251 } else {
252 return TypeError(node, output_rep, output_type,
253 MachineRepresentation::kTaggedSigned);
254 }
255 } else if (output_rep == MachineRepresentation::kFloat32) {
256 if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
257 op = machine()->ChangeFloat32ToFloat64();
258 node = InsertConversion(node, op, use_node);
259 op = simplified()->CheckedFloat64ToInt32(
260 output_type->Maybe(Type::MinusZero())
261 ? CheckForMinusZeroMode::kCheckForMinusZero
262 : CheckForMinusZeroMode::kDontCheckForMinusZero);
263 node = InsertConversion(node, op, use_node);
264 if (SmiValuesAre32Bits()) {
265 op = simplified()->ChangeInt32ToTagged();
266 } else {
267 op = simplified()->CheckedInt32ToTaggedSigned();
268 }
269 } else {
270 return TypeError(node, output_rep, output_type,
271 MachineRepresentation::kTaggedSigned);
272 }
273 } else if (CanBeTaggedPointer(output_rep) &&
274 use_info.type_check() == TypeCheckKind::kSignedSmall) {
275 op = simplified()->CheckedTaggedToTaggedSigned();
276 } else if (output_rep == MachineRepresentation::kBit &&
277 use_info.type_check() == TypeCheckKind::kSignedSmall) {
278 // TODO(turbofan): Consider adding a Bailout operator that just deopts.
279 // Also use that for MachineRepresentation::kPointer case above.
280 node = InsertChangeBitToTagged(node);
281 op = simplified()->CheckedTaggedToTaggedSigned();
282 } else {
283 return TypeError(node, output_rep, output_type,
284 MachineRepresentation::kTaggedSigned);
285 }
286 return InsertConversion(node, op, use_node);
287 }
288
GetTaggedPointerRepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Node * use_node,UseInfo use_info)289 Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
290 Node* node, MachineRepresentation output_rep, Type* output_type,
291 Node* use_node, UseInfo use_info) {
292 // Eagerly fold representation changes for constants.
293 switch (node->opcode()) {
294 case IrOpcode::kHeapConstant:
295 return node; // No change necessary.
296 case IrOpcode::kInt32Constant:
297 case IrOpcode::kFloat64Constant:
298 case IrOpcode::kFloat32Constant:
299 UNREACHABLE();
300 default:
301 break;
302 }
303 // Select the correct X -> TaggedPointer operator.
304 Operator const* op;
305 if (output_type->Is(Type::None())) {
306 // This is an impossible value; it should not be used at runtime.
307 // We just provide a dummy value here.
308 return jsgraph()->TheHoleConstant();
309 } else if (output_rep == MachineRepresentation::kBit) {
310 return node;
311 } else if (IsWord(output_rep)) {
312 if (output_type->Is(Type::Unsigned32())) {
313 // uint32 -> float64 -> tagged
314 node = InsertChangeUint32ToFloat64(node);
315 } else if (output_type->Is(Type::Signed32())) {
316 // int32 -> float64 -> tagged
317 node = InsertChangeInt32ToFloat64(node);
318 } else {
319 return TypeError(node, output_rep, output_type,
320 MachineRepresentation::kTaggedPointer);
321 }
322 op = simplified()->ChangeFloat64ToTaggedPointer();
323 } else if (output_rep == MachineRepresentation::kFloat32) {
324 // float32 -> float64 -> tagged
325 node = InsertChangeFloat32ToFloat64(node);
326 op = simplified()->ChangeFloat64ToTaggedPointer();
327 } else if (output_rep == MachineRepresentation::kFloat64) {
328 // float64 -> tagged
329 op = simplified()->ChangeFloat64ToTaggedPointer();
330 } else if (CanBeTaggedSigned(output_rep) &&
331 use_info.type_check() == TypeCheckKind::kHeapObject) {
332 if (!output_type->Maybe(Type::SignedSmall())) {
333 return node;
334 }
335 // TODO(turbofan): Consider adding a Bailout operator that just deopts
336 // for TaggedSigned output representation.
337 op = simplified()->CheckedTaggedToTaggedPointer();
338 } else {
339 return TypeError(node, output_rep, output_type,
340 MachineRepresentation::kTaggedPointer);
341 }
342 return InsertConversion(node, op, use_node);
343 }
344
GetTaggedRepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Truncation truncation)345 Node* RepresentationChanger::GetTaggedRepresentationFor(
346 Node* node, MachineRepresentation output_rep, Type* output_type,
347 Truncation truncation) {
348 // Eagerly fold representation changes for constants.
349 switch (node->opcode()) {
350 case IrOpcode::kNumberConstant:
351 case IrOpcode::kHeapConstant:
352 return node; // No change necessary.
353 case IrOpcode::kInt32Constant:
354 case IrOpcode::kFloat64Constant:
355 case IrOpcode::kFloat32Constant:
356 UNREACHABLE();
357 break;
358 default:
359 break;
360 }
361 if (output_rep == MachineRepresentation::kTaggedSigned ||
362 output_rep == MachineRepresentation::kTaggedPointer) {
363 // this is a no-op.
364 return node;
365 }
366 // Select the correct X -> Tagged operator.
367 const Operator* op;
368 if (output_type->Is(Type::None())) {
369 // This is an impossible value; it should not be used at runtime.
370 // We just provide a dummy value here.
371 return jsgraph()->TheHoleConstant();
372 } else if (output_rep == MachineRepresentation::kBit) {
373 if (output_type->Is(Type::Boolean())) {
374 op = simplified()->ChangeBitToTagged();
375 } else {
376 return TypeError(node, output_rep, output_type,
377 MachineRepresentation::kTagged);
378 }
379 } else if (IsWord(output_rep)) {
380 if (output_type->Is(Type::Signed31())) {
381 op = simplified()->ChangeInt31ToTaggedSigned();
382 } else if (output_type->Is(Type::Signed32())) {
383 op = simplified()->ChangeInt32ToTagged();
384 } else if (output_type->Is(Type::Unsigned32()) ||
385 truncation.IsUsedAsWord32()) {
386 // Either the output is uint32 or the uses only care about the
387 // low 32 bits (so we can pick uint32 safely).
388 op = simplified()->ChangeUint32ToTagged();
389 } else {
390 return TypeError(node, output_rep, output_type,
391 MachineRepresentation::kTagged);
392 }
393 } else if (output_rep ==
394 MachineRepresentation::kFloat32) { // float32 -> float64 -> tagged
395 node = InsertChangeFloat32ToFloat64(node);
396 op = simplified()->ChangeFloat64ToTagged();
397 } else if (output_rep == MachineRepresentation::kFloat64) {
398 if (output_type->Is(Type::Signed31())) { // float64 -> int32 -> tagged
399 node = InsertChangeFloat64ToInt32(node);
400 op = simplified()->ChangeInt31ToTaggedSigned();
401 } else if (output_type->Is(
402 Type::Signed32())) { // float64 -> int32 -> tagged
403 node = InsertChangeFloat64ToInt32(node);
404 op = simplified()->ChangeInt32ToTagged();
405 } else if (output_type->Is(
406 Type::Unsigned32())) { // float64 -> uint32 -> tagged
407 node = InsertChangeFloat64ToUint32(node);
408 op = simplified()->ChangeUint32ToTagged();
409 } else {
410 op = simplified()->ChangeFloat64ToTagged();
411 }
412 } else {
413 return TypeError(node, output_rep, output_type,
414 MachineRepresentation::kTagged);
415 }
416 return jsgraph()->graph()->NewNode(op, node);
417 }
418
419
GetFloat32RepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Truncation truncation)420 Node* RepresentationChanger::GetFloat32RepresentationFor(
421 Node* node, MachineRepresentation output_rep, Type* output_type,
422 Truncation truncation) {
423 // Eagerly fold representation changes for constants.
424 switch (node->opcode()) {
425 case IrOpcode::kNumberConstant:
426 return jsgraph()->Float32Constant(
427 DoubleToFloat32(OpParameter<double>(node)));
428 case IrOpcode::kInt32Constant:
429 case IrOpcode::kFloat64Constant:
430 case IrOpcode::kFloat32Constant:
431 UNREACHABLE();
432 break;
433 default:
434 break;
435 }
436 // Select the correct X -> Float32 operator.
437 const Operator* op = nullptr;
438 if (output_type->Is(Type::None())) {
439 // This is an impossible value; it should not be used at runtime.
440 // We just provide a dummy value here.
441 return jsgraph()->Float32Constant(0.0f);
442 } else if (IsWord(output_rep)) {
443 if (output_type->Is(Type::Signed32())) {
444 // int32 -> float64 -> float32
445 op = machine()->ChangeInt32ToFloat64();
446 node = jsgraph()->graph()->NewNode(op, node);
447 op = machine()->TruncateFloat64ToFloat32();
448 } else if (output_type->Is(Type::Unsigned32()) ||
449 truncation.IsUsedAsWord32()) {
450 // Either the output is uint32 or the uses only care about the
451 // low 32 bits (so we can pick uint32 safely).
452
453 // uint32 -> float64 -> float32
454 op = machine()->ChangeUint32ToFloat64();
455 node = jsgraph()->graph()->NewNode(op, node);
456 op = machine()->TruncateFloat64ToFloat32();
457 }
458 } else if (output_rep == MachineRepresentation::kTagged ||
459 output_rep == MachineRepresentation::kTaggedPointer) {
460 if (output_type->Is(Type::NumberOrOddball())) {
461 // tagged -> float64 -> float32
462 if (output_type->Is(Type::Number())) {
463 op = simplified()->ChangeTaggedToFloat64();
464 } else {
465 op = simplified()->TruncateTaggedToFloat64();
466 }
467 node = jsgraph()->graph()->NewNode(op, node);
468 op = machine()->TruncateFloat64ToFloat32();
469 }
470 } else if (output_rep == MachineRepresentation::kFloat64) {
471 op = machine()->TruncateFloat64ToFloat32();
472 }
473 if (op == nullptr) {
474 return TypeError(node, output_rep, output_type,
475 MachineRepresentation::kFloat32);
476 }
477 return jsgraph()->graph()->NewNode(op, node);
478 }
479
GetFloat64RepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Node * use_node,UseInfo use_info)480 Node* RepresentationChanger::GetFloat64RepresentationFor(
481 Node* node, MachineRepresentation output_rep, Type* output_type,
482 Node* use_node, UseInfo use_info) {
483 // Eagerly fold representation changes for constants.
484 if ((use_info.type_check() == TypeCheckKind::kNone)) {
485 // TODO(jarin) Handle checked constant conversions.
486 switch (node->opcode()) {
487 case IrOpcode::kNumberConstant:
488 return jsgraph()->Float64Constant(OpParameter<double>(node));
489 case IrOpcode::kInt32Constant:
490 case IrOpcode::kFloat64Constant:
491 case IrOpcode::kFloat32Constant:
492 UNREACHABLE();
493 break;
494 default:
495 break;
496 }
497 }
498 // Select the correct X -> Float64 operator.
499 const Operator* op = nullptr;
500 if (output_type->Is(Type::None())) {
501 // This is an impossible value; it should not be used at runtime.
502 // We just provide a dummy value here.
503 return jsgraph()->Float64Constant(0.0);
504 } else if (IsWord(output_rep)) {
505 if (output_type->Is(Type::Signed32())) {
506 op = machine()->ChangeInt32ToFloat64();
507 } else if (output_type->Is(Type::Unsigned32()) ||
508 use_info.truncation().IsUsedAsWord32()) {
509 // Either the output is uint32 or the uses only care about the
510 // low 32 bits (so we can pick uint32 safely).
511 op = machine()->ChangeUint32ToFloat64();
512 }
513 } else if (output_rep == MachineRepresentation::kBit) {
514 op = machine()->ChangeUint32ToFloat64();
515 } else if (output_rep == MachineRepresentation::kTagged ||
516 output_rep == MachineRepresentation::kTaggedSigned ||
517 output_rep == MachineRepresentation::kTaggedPointer) {
518 if (output_type->Is(Type::Undefined())) {
519 return jsgraph()->Float64Constant(
520 std::numeric_limits<double>::quiet_NaN());
521
522 } else if (output_rep == MachineRepresentation::kTaggedSigned) {
523 node = InsertChangeTaggedSignedToInt32(node);
524 op = machine()->ChangeInt32ToFloat64();
525 } else if (output_type->Is(Type::Number())) {
526 op = simplified()->ChangeTaggedToFloat64();
527 } else if (output_type->Is(Type::NumberOrOddball())) {
528 // TODO(jarin) Here we should check that truncation is Number.
529 op = simplified()->TruncateTaggedToFloat64();
530 } else if (use_info.type_check() == TypeCheckKind::kNumber ||
531 (use_info.type_check() == TypeCheckKind::kNumberOrOddball &&
532 !output_type->Maybe(Type::BooleanOrNullOrNumber()))) {
533 op = simplified()->CheckedTaggedToFloat64(CheckTaggedInputMode::kNumber);
534 } else if (use_info.type_check() == TypeCheckKind::kNumberOrOddball) {
535 op = simplified()->CheckedTaggedToFloat64(
536 CheckTaggedInputMode::kNumberOrOddball);
537 }
538 } else if (output_rep == MachineRepresentation::kFloat32) {
539 op = machine()->ChangeFloat32ToFloat64();
540 }
541 if (op == nullptr) {
542 return TypeError(node, output_rep, output_type,
543 MachineRepresentation::kFloat64);
544 }
545 return InsertConversion(node, op, use_node);
546 }
547
MakeTruncatedInt32Constant(double value)548 Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) {
549 return jsgraph()->Int32Constant(DoubleToInt32(value));
550 }
551
GetWord32RepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type,Node * use_node,UseInfo use_info)552 Node* RepresentationChanger::GetWord32RepresentationFor(
553 Node* node, MachineRepresentation output_rep, Type* output_type,
554 Node* use_node, UseInfo use_info) {
555 // Eagerly fold representation changes for constants.
556 switch (node->opcode()) {
557 case IrOpcode::kInt32Constant:
558 case IrOpcode::kFloat32Constant:
559 case IrOpcode::kFloat64Constant:
560 UNREACHABLE();
561 break;
562 case IrOpcode::kNumberConstant: {
563 double const fv = OpParameter<double>(node);
564 if (use_info.type_check() == TypeCheckKind::kNone ||
565 ((use_info.type_check() == TypeCheckKind::kSignedSmall ||
566 use_info.type_check() == TypeCheckKind::kSigned32) &&
567 IsInt32Double(fv))) {
568 return MakeTruncatedInt32Constant(fv);
569 }
570 break;
571 }
572 default:
573 break;
574 }
575
576 // Select the correct X -> Word32 operator.
577 const Operator* op = nullptr;
578 if (output_type->Is(Type::None())) {
579 // This is an impossible value; it should not be used at runtime.
580 // We just provide a dummy value here.
581 return jsgraph()->Int32Constant(0);
582 } else if (output_rep == MachineRepresentation::kBit) {
583 return node; // Sloppy comparison -> word32
584 } else if (output_rep == MachineRepresentation::kFloat64) {
585 if (output_type->Is(Type::Unsigned32())) {
586 op = machine()->ChangeFloat64ToUint32();
587 } else if (output_type->Is(Type::Signed32())) {
588 op = machine()->ChangeFloat64ToInt32();
589 } else if (use_info.truncation().IsUsedAsWord32()) {
590 op = machine()->TruncateFloat64ToWord32();
591 } else if (use_info.type_check() == TypeCheckKind::kSignedSmall ||
592 use_info.type_check() == TypeCheckKind::kSigned32) {
593 op = simplified()->CheckedFloat64ToInt32(
594 output_type->Maybe(Type::MinusZero())
595 ? use_info.minus_zero_check()
596 : CheckForMinusZeroMode::kDontCheckForMinusZero);
597 }
598 } else if (output_rep == MachineRepresentation::kFloat32) {
599 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32
600 if (output_type->Is(Type::Unsigned32())) {
601 op = machine()->ChangeFloat64ToUint32();
602 } else if (output_type->Is(Type::Signed32())) {
603 op = machine()->ChangeFloat64ToInt32();
604 } else if (use_info.truncation().IsUsedAsWord32()) {
605 op = machine()->TruncateFloat64ToWord32();
606 } else if (use_info.type_check() == TypeCheckKind::kSignedSmall ||
607 use_info.type_check() == TypeCheckKind::kSigned32) {
608 op = simplified()->CheckedFloat64ToInt32(
609 output_type->Maybe(Type::MinusZero())
610 ? CheckForMinusZeroMode::kCheckForMinusZero
611 : CheckForMinusZeroMode::kDontCheckForMinusZero);
612 }
613 } else if (output_rep == MachineRepresentation::kTaggedSigned) {
614 if (output_type->Is(Type::Signed32())) {
615 op = simplified()->ChangeTaggedSignedToInt32();
616 } else if (use_info.truncation().IsUsedAsWord32()) {
617 if (use_info.type_check() != TypeCheckKind::kNone) {
618 op = simplified()->CheckedTruncateTaggedToWord32();
619 } else {
620 op = simplified()->TruncateTaggedToWord32();
621 }
622 }
623 } else if (output_rep == MachineRepresentation::kTagged ||
624 output_rep == MachineRepresentation::kTaggedPointer) {
625 if (output_type->Is(Type::Unsigned32())) {
626 op = simplified()->ChangeTaggedToUint32();
627 } else if (output_type->Is(Type::Signed32())) {
628 op = simplified()->ChangeTaggedToInt32();
629 } else if (use_info.truncation().IsUsedAsWord32()) {
630 if (use_info.type_check() != TypeCheckKind::kNone) {
631 op = simplified()->CheckedTruncateTaggedToWord32();
632 } else {
633 op = simplified()->TruncateTaggedToWord32();
634 }
635 } else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
636 op = simplified()->CheckedTaggedSignedToInt32();
637 } else if (use_info.type_check() == TypeCheckKind::kSigned32) {
638 op = simplified()->CheckedTaggedToInt32(
639 output_type->Maybe(Type::MinusZero())
640 ? CheckForMinusZeroMode::kCheckForMinusZero
641 : CheckForMinusZeroMode::kDontCheckForMinusZero);
642 }
643 } else if (output_rep == MachineRepresentation::kWord32) {
644 // Only the checked case should get here, the non-checked case is
645 // handled in GetRepresentationFor.
646 if (use_info.type_check() == TypeCheckKind::kSignedSmall ||
647 use_info.type_check() == TypeCheckKind::kSigned32) {
648 if (output_type->Is(Type::Signed32())) {
649 return node;
650 } else if (output_type->Is(Type::Unsigned32())) {
651 op = simplified()->CheckedUint32ToInt32();
652 }
653 } else {
654 DCHECK_EQ(TypeCheckKind::kNumberOrOddball, use_info.type_check());
655 return node;
656 }
657 } else if (output_rep == MachineRepresentation::kWord8 ||
658 output_rep == MachineRepresentation::kWord16) {
659 DCHECK(use_info.representation() == MachineRepresentation::kWord32);
660 DCHECK(use_info.type_check() == TypeCheckKind::kSignedSmall ||
661 use_info.type_check() == TypeCheckKind::kSigned32);
662 return node;
663 }
664
665 if (op == nullptr) {
666 return TypeError(node, output_rep, output_type,
667 MachineRepresentation::kWord32);
668 }
669 return InsertConversion(node, op, use_node);
670 }
671
InsertConversion(Node * node,const Operator * op,Node * use_node)672 Node* RepresentationChanger::InsertConversion(Node* node, const Operator* op,
673 Node* use_node) {
674 if (op->ControlInputCount() > 0) {
675 // If the operator can deoptimize (which means it has control
676 // input), we need to connect it to the effect and control chains.
677 Node* effect = NodeProperties::GetEffectInput(use_node);
678 Node* control = NodeProperties::GetControlInput(use_node);
679 Node* conversion = jsgraph()->graph()->NewNode(op, node, effect, control);
680 NodeProperties::ReplaceEffectInput(use_node, conversion);
681 return conversion;
682 }
683 return jsgraph()->graph()->NewNode(op, node);
684 }
685
686
GetBitRepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type)687 Node* RepresentationChanger::GetBitRepresentationFor(
688 Node* node, MachineRepresentation output_rep, Type* output_type) {
689 // Eagerly fold representation changes for constants.
690 switch (node->opcode()) {
691 case IrOpcode::kHeapConstant: {
692 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
693 return jsgraph()->Int32Constant(value->BooleanValue() ? 1 : 0);
694 }
695 default:
696 break;
697 }
698 // Select the correct X -> Bit operator.
699 const Operator* op;
700 if (output_type->Is(Type::None())) {
701 // This is an impossible value; it should not be used at runtime.
702 // We just provide a dummy value here.
703 return jsgraph()->Int32Constant(0);
704 } else if (output_rep == MachineRepresentation::kTagged ||
705 output_rep == MachineRepresentation::kTaggedPointer) {
706 if (output_type->Is(Type::BooleanOrNullOrUndefined())) {
707 // true is the only trueish Oddball.
708 op = simplified()->ChangeTaggedToBit();
709 } else {
710 op = simplified()->TruncateTaggedToBit();
711 }
712 } else if (output_rep == MachineRepresentation::kTaggedSigned) {
713 node = jsgraph()->graph()->NewNode(machine()->WordEqual(), node,
714 jsgraph()->IntPtrConstant(0));
715 return jsgraph()->graph()->NewNode(machine()->Word32Equal(), node,
716 jsgraph()->Int32Constant(0));
717 } else if (IsWord(output_rep)) {
718 node = jsgraph()->graph()->NewNode(machine()->Word32Equal(), node,
719 jsgraph()->Int32Constant(0));
720 return jsgraph()->graph()->NewNode(machine()->Word32Equal(), node,
721 jsgraph()->Int32Constant(0));
722 } else if (output_rep == MachineRepresentation::kFloat32) {
723 node = jsgraph()->graph()->NewNode(machine()->Float32Abs(), node);
724 return jsgraph()->graph()->NewNode(machine()->Float32LessThan(),
725 jsgraph()->Float32Constant(0.0), node);
726 } else if (output_rep == MachineRepresentation::kFloat64) {
727 node = jsgraph()->graph()->NewNode(machine()->Float64Abs(), node);
728 return jsgraph()->graph()->NewNode(machine()->Float64LessThan(),
729 jsgraph()->Float64Constant(0.0), node);
730 } else {
731 return TypeError(node, output_rep, output_type,
732 MachineRepresentation::kBit);
733 }
734 return jsgraph()->graph()->NewNode(op, node);
735 }
736
GetWord64RepresentationFor(Node * node,MachineRepresentation output_rep,Type * output_type)737 Node* RepresentationChanger::GetWord64RepresentationFor(
738 Node* node, MachineRepresentation output_rep, Type* output_type) {
739 if (output_type->Is(Type::None())) {
740 // This is an impossible value; it should not be used at runtime.
741 // We just provide a dummy value here.
742 return jsgraph()->Int64Constant(0);
743 } else if (output_rep == MachineRepresentation::kBit) {
744 return node; // Sloppy comparison -> word64
745 }
746 // Can't really convert Word64 to anything else. Purported to be internal.
747 return TypeError(node, output_rep, output_type,
748 MachineRepresentation::kWord64);
749 }
750
Int32OperatorFor(IrOpcode::Value opcode)751 const Operator* RepresentationChanger::Int32OperatorFor(
752 IrOpcode::Value opcode) {
753 switch (opcode) {
754 case IrOpcode::kSpeculativeNumberAdd: // Fall through.
755 case IrOpcode::kNumberAdd:
756 return machine()->Int32Add();
757 case IrOpcode::kSpeculativeNumberSubtract: // Fall through.
758 case IrOpcode::kNumberSubtract:
759 return machine()->Int32Sub();
760 case IrOpcode::kSpeculativeNumberMultiply:
761 case IrOpcode::kNumberMultiply:
762 return machine()->Int32Mul();
763 case IrOpcode::kSpeculativeNumberDivide:
764 case IrOpcode::kNumberDivide:
765 return machine()->Int32Div();
766 case IrOpcode::kSpeculativeNumberModulus:
767 case IrOpcode::kNumberModulus:
768 return machine()->Int32Mod();
769 case IrOpcode::kSpeculativeNumberBitwiseOr: // Fall through.
770 case IrOpcode::kNumberBitwiseOr:
771 return machine()->Word32Or();
772 case IrOpcode::kSpeculativeNumberBitwiseXor: // Fall through.
773 case IrOpcode::kNumberBitwiseXor:
774 return machine()->Word32Xor();
775 case IrOpcode::kSpeculativeNumberBitwiseAnd: // Fall through.
776 case IrOpcode::kNumberBitwiseAnd:
777 return machine()->Word32And();
778 case IrOpcode::kNumberEqual:
779 case IrOpcode::kSpeculativeNumberEqual:
780 return machine()->Word32Equal();
781 case IrOpcode::kNumberLessThan:
782 case IrOpcode::kSpeculativeNumberLessThan:
783 return machine()->Int32LessThan();
784 case IrOpcode::kNumberLessThanOrEqual:
785 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
786 return machine()->Int32LessThanOrEqual();
787 default:
788 UNREACHABLE();
789 return nullptr;
790 }
791 }
792
Int32OverflowOperatorFor(IrOpcode::Value opcode)793 const Operator* RepresentationChanger::Int32OverflowOperatorFor(
794 IrOpcode::Value opcode) {
795 switch (opcode) {
796 case IrOpcode::kSpeculativeNumberAdd:
797 return simplified()->CheckedInt32Add();
798 case IrOpcode::kSpeculativeNumberSubtract:
799 return simplified()->CheckedInt32Sub();
800 case IrOpcode::kSpeculativeNumberDivide:
801 return simplified()->CheckedInt32Div();
802 case IrOpcode::kSpeculativeNumberModulus:
803 return simplified()->CheckedInt32Mod();
804 default:
805 UNREACHABLE();
806 return nullptr;
807 }
808 }
809
Uint32OperatorFor(IrOpcode::Value opcode)810 const Operator* RepresentationChanger::Uint32OperatorFor(
811 IrOpcode::Value opcode) {
812 switch (opcode) {
813 case IrOpcode::kNumberAdd:
814 return machine()->Int32Add();
815 case IrOpcode::kNumberSubtract:
816 return machine()->Int32Sub();
817 case IrOpcode::kSpeculativeNumberMultiply:
818 case IrOpcode::kNumberMultiply:
819 return machine()->Int32Mul();
820 case IrOpcode::kSpeculativeNumberDivide:
821 case IrOpcode::kNumberDivide:
822 return machine()->Uint32Div();
823 case IrOpcode::kSpeculativeNumberModulus:
824 case IrOpcode::kNumberModulus:
825 return machine()->Uint32Mod();
826 case IrOpcode::kNumberEqual:
827 case IrOpcode::kSpeculativeNumberEqual:
828 return machine()->Word32Equal();
829 case IrOpcode::kNumberLessThan:
830 case IrOpcode::kSpeculativeNumberLessThan:
831 return machine()->Uint32LessThan();
832 case IrOpcode::kNumberLessThanOrEqual:
833 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
834 return machine()->Uint32LessThanOrEqual();
835 case IrOpcode::kNumberClz32:
836 return machine()->Word32Clz();
837 case IrOpcode::kNumberImul:
838 return machine()->Int32Mul();
839 default:
840 UNREACHABLE();
841 return nullptr;
842 }
843 }
844
Uint32OverflowOperatorFor(IrOpcode::Value opcode)845 const Operator* RepresentationChanger::Uint32OverflowOperatorFor(
846 IrOpcode::Value opcode) {
847 switch (opcode) {
848 case IrOpcode::kSpeculativeNumberDivide:
849 return simplified()->CheckedUint32Div();
850 case IrOpcode::kSpeculativeNumberModulus:
851 return simplified()->CheckedUint32Mod();
852 default:
853 UNREACHABLE();
854 return nullptr;
855 }
856 }
857
Float64OperatorFor(IrOpcode::Value opcode)858 const Operator* RepresentationChanger::Float64OperatorFor(
859 IrOpcode::Value opcode) {
860 switch (opcode) {
861 case IrOpcode::kSpeculativeNumberAdd:
862 case IrOpcode::kNumberAdd:
863 return machine()->Float64Add();
864 case IrOpcode::kSpeculativeNumberSubtract:
865 case IrOpcode::kNumberSubtract:
866 return machine()->Float64Sub();
867 case IrOpcode::kSpeculativeNumberMultiply:
868 case IrOpcode::kNumberMultiply:
869 return machine()->Float64Mul();
870 case IrOpcode::kSpeculativeNumberDivide:
871 case IrOpcode::kNumberDivide:
872 return machine()->Float64Div();
873 case IrOpcode::kSpeculativeNumberModulus:
874 case IrOpcode::kNumberModulus:
875 return machine()->Float64Mod();
876 case IrOpcode::kNumberEqual:
877 case IrOpcode::kSpeculativeNumberEqual:
878 return machine()->Float64Equal();
879 case IrOpcode::kNumberLessThan:
880 case IrOpcode::kSpeculativeNumberLessThan:
881 return machine()->Float64LessThan();
882 case IrOpcode::kNumberLessThanOrEqual:
883 case IrOpcode::kSpeculativeNumberLessThanOrEqual:
884 return machine()->Float64LessThanOrEqual();
885 case IrOpcode::kNumberAbs:
886 return machine()->Float64Abs();
887 case IrOpcode::kNumberAcos:
888 return machine()->Float64Acos();
889 case IrOpcode::kNumberAcosh:
890 return machine()->Float64Acosh();
891 case IrOpcode::kNumberAsin:
892 return machine()->Float64Asin();
893 case IrOpcode::kNumberAsinh:
894 return machine()->Float64Asinh();
895 case IrOpcode::kNumberAtan:
896 return machine()->Float64Atan();
897 case IrOpcode::kNumberAtanh:
898 return machine()->Float64Atanh();
899 case IrOpcode::kNumberAtan2:
900 return machine()->Float64Atan2();
901 case IrOpcode::kNumberCbrt:
902 return machine()->Float64Cbrt();
903 case IrOpcode::kNumberCeil:
904 return machine()->Float64RoundUp().placeholder();
905 case IrOpcode::kNumberCos:
906 return machine()->Float64Cos();
907 case IrOpcode::kNumberCosh:
908 return machine()->Float64Cosh();
909 case IrOpcode::kNumberExp:
910 return machine()->Float64Exp();
911 case IrOpcode::kNumberExpm1:
912 return machine()->Float64Expm1();
913 case IrOpcode::kNumberFloor:
914 return machine()->Float64RoundDown().placeholder();
915 case IrOpcode::kNumberFround:
916 return machine()->TruncateFloat64ToFloat32();
917 case IrOpcode::kNumberLog:
918 return machine()->Float64Log();
919 case IrOpcode::kNumberLog1p:
920 return machine()->Float64Log1p();
921 case IrOpcode::kNumberLog2:
922 return machine()->Float64Log2();
923 case IrOpcode::kNumberLog10:
924 return machine()->Float64Log10();
925 case IrOpcode::kNumberMax:
926 return machine()->Float64Max();
927 case IrOpcode::kNumberMin:
928 return machine()->Float64Min();
929 case IrOpcode::kNumberPow:
930 return machine()->Float64Pow();
931 case IrOpcode::kNumberSin:
932 return machine()->Float64Sin();
933 case IrOpcode::kNumberSinh:
934 return machine()->Float64Sinh();
935 case IrOpcode::kNumberSqrt:
936 return machine()->Float64Sqrt();
937 case IrOpcode::kNumberTan:
938 return machine()->Float64Tan();
939 case IrOpcode::kNumberTanh:
940 return machine()->Float64Tanh();
941 case IrOpcode::kNumberTrunc:
942 return machine()->Float64RoundTruncate().placeholder();
943 case IrOpcode::kNumberSilenceNaN:
944 return machine()->Float64SilenceNaN();
945 default:
946 UNREACHABLE();
947 return nullptr;
948 }
949 }
950
951
TypeError(Node * node,MachineRepresentation output_rep,Type * output_type,MachineRepresentation use)952 Node* RepresentationChanger::TypeError(Node* node,
953 MachineRepresentation output_rep,
954 Type* output_type,
955 MachineRepresentation use) {
956 type_error_ = true;
957 if (!testing_type_errors_) {
958 std::ostringstream out_str;
959 out_str << output_rep << " (";
960 output_type->PrintTo(out_str);
961 out_str << ")";
962
963 std::ostringstream use_str;
964 use_str << use;
965
966 V8_Fatal(__FILE__, __LINE__,
967 "RepresentationChangerError: node #%d:%s of "
968 "%s cannot be changed to %s",
969 node->id(), node->op()->mnemonic(), out_str.str().c_str(),
970 use_str.str().c_str());
971 }
972 return node;
973 }
974
InsertChangeBitToTagged(Node * node)975 Node* RepresentationChanger::InsertChangeBitToTagged(Node* node) {
976 return jsgraph()->graph()->NewNode(simplified()->ChangeBitToTagged(), node);
977 }
978
InsertChangeFloat32ToFloat64(Node * node)979 Node* RepresentationChanger::InsertChangeFloat32ToFloat64(Node* node) {
980 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), node);
981 }
982
InsertChangeFloat64ToUint32(Node * node)983 Node* RepresentationChanger::InsertChangeFloat64ToUint32(Node* node) {
984 return jsgraph()->graph()->NewNode(machine()->ChangeFloat64ToUint32(), node);
985 }
986
InsertChangeFloat64ToInt32(Node * node)987 Node* RepresentationChanger::InsertChangeFloat64ToInt32(Node* node) {
988 return jsgraph()->graph()->NewNode(machine()->ChangeFloat64ToInt32(), node);
989 }
990
InsertChangeInt32ToFloat64(Node * node)991 Node* RepresentationChanger::InsertChangeInt32ToFloat64(Node* node) {
992 return jsgraph()->graph()->NewNode(machine()->ChangeInt32ToFloat64(), node);
993 }
994
InsertChangeTaggedSignedToInt32(Node * node)995 Node* RepresentationChanger::InsertChangeTaggedSignedToInt32(Node* node) {
996 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(),
997 node);
998 }
999
InsertChangeTaggedToFloat64(Node * node)1000 Node* RepresentationChanger::InsertChangeTaggedToFloat64(Node* node) {
1001 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
1002 node);
1003 }
1004
InsertChangeUint32ToFloat64(Node * node)1005 Node* RepresentationChanger::InsertChangeUint32ToFloat64(Node* node) {
1006 return jsgraph()->graph()->NewNode(machine()->ChangeUint32ToFloat64(), node);
1007 }
1008
1009 } // namespace compiler
1010 } // namespace internal
1011 } // namespace v8
1012