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