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