blob: 2f7720beb3705599929416c442e2f1ab910677dc [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17const 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::kFloat32:
28 return "truncate-to-float32";
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 kFloat32 kBool
48// ^ ^ ^
49// \ | /
50// \ | /
51// \ | /
52// \ | /
53// \ | /
54// kNone
55
56// static
57Truncation::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 // All other combinations are illegal.
67 FATAL("Tried to combine incompatible truncations");
68 return TruncationKind::kNone;
69}
70
71
72// static
73bool Truncation::LessGeneral(TruncationKind rep1, TruncationKind rep2) {
74 switch (rep1) {
75 case TruncationKind::kNone:
76 return true;
77 case TruncationKind::kBool:
78 return rep2 == TruncationKind::kBool || rep2 == TruncationKind::kAny;
79 case TruncationKind::kWord32:
80 return rep2 == TruncationKind::kWord32 ||
81 rep2 == TruncationKind::kWord64 ||
82 rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
83 case TruncationKind::kWord64:
84 return rep2 == TruncationKind::kWord64;
85 case TruncationKind::kFloat32:
86 return rep2 == TruncationKind::kFloat32 ||
87 rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
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
98namespace {
99
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000100bool IsWord(MachineRepresentation rep) {
101 return rep == MachineRepresentation::kWord8 ||
102 rep == MachineRepresentation::kWord16 ||
103 rep == MachineRepresentation::kWord32;
104}
105
106} // namespace
107
108
109// Changes representation from {output_rep} to {use_rep}. The {truncation}
110// parameter is only used for sanity checking - if the changer cannot figure
111// out signedness for the word32->float64 conversion, then we check that the
112// uses truncate to word32 (so they do not care about signedness).
113Node* RepresentationChanger::GetRepresentationFor(
114 Node* node, MachineRepresentation output_rep, Type* output_type,
115 MachineRepresentation use_rep, Truncation truncation) {
116 if (output_rep == MachineRepresentation::kNone) {
117 // The output representation should be set.
118 return TypeError(node, output_rep, output_type, use_rep);
119 }
120 if (use_rep == output_rep) {
121 // Representations are the same. That's a no-op.
122 return node;
123 }
124 if (IsWord(use_rep) && IsWord(output_rep)) {
125 // Both are words less than or equal to 32-bits.
126 // Since loads of integers from memory implicitly sign or zero extend the
127 // value to the full machine word size and stores implicitly truncate,
128 // no representation change is necessary.
129 return node;
130 }
131 switch (use_rep) {
132 case MachineRepresentation::kTagged:
133 return GetTaggedRepresentationFor(node, output_rep, output_type);
134 case MachineRepresentation::kFloat32:
135 return GetFloat32RepresentationFor(node, output_rep, output_type,
136 truncation);
137 case MachineRepresentation::kFloat64:
138 return GetFloat64RepresentationFor(node, output_rep, output_type,
139 truncation);
140 case MachineRepresentation::kBit:
141 return GetBitRepresentationFor(node, output_rep, output_type);
142 case MachineRepresentation::kWord8:
143 case MachineRepresentation::kWord16:
144 case MachineRepresentation::kWord32:
145 return GetWord32RepresentationFor(node, output_rep, output_type);
146 case MachineRepresentation::kWord64:
147 return GetWord64RepresentationFor(node, output_rep, output_type);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 case MachineRepresentation::kSimd128: // Fall through.
149 // TODO(bbudge) Handle conversions between tagged and untagged.
150 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 case MachineRepresentation::kNone:
152 return node;
153 }
154 UNREACHABLE();
155 return nullptr;
156}
157
158
159Node* RepresentationChanger::GetTaggedRepresentationFor(
160 Node* node, MachineRepresentation output_rep, Type* output_type) {
161 // Eagerly fold representation changes for constants.
162 switch (node->opcode()) {
163 case IrOpcode::kNumberConstant:
164 case IrOpcode::kHeapConstant:
165 return node; // No change necessary.
166 case IrOpcode::kInt32Constant:
167 if (output_type->Is(Type::Signed32())) {
168 int32_t value = OpParameter<int32_t>(node);
169 return jsgraph()->Constant(value);
170 } else if (output_type->Is(Type::Unsigned32())) {
171 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node));
172 return jsgraph()->Constant(static_cast<double>(value));
173 } else if (output_rep == MachineRepresentation::kBit) {
174 return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
175 : jsgraph()->TrueConstant();
176 } else {
177 return TypeError(node, output_rep, output_type,
178 MachineRepresentation::kTagged);
179 }
180 case IrOpcode::kFloat64Constant:
181 return jsgraph()->Constant(OpParameter<double>(node));
182 case IrOpcode::kFloat32Constant:
183 return jsgraph()->Constant(OpParameter<float>(node));
184 default:
185 break;
186 }
187 // Select the correct X -> Tagged operator.
188 const Operator* op;
189 if (output_rep == MachineRepresentation::kBit) {
190 op = simplified()->ChangeBitToBool();
191 } else if (IsWord(output_rep)) {
192 if (output_type->Is(Type::Unsigned32())) {
193 op = simplified()->ChangeUint32ToTagged();
194 } else if (output_type->Is(Type::Signed32())) {
195 op = simplified()->ChangeInt32ToTagged();
196 } else {
197 return TypeError(node, output_rep, output_type,
198 MachineRepresentation::kTagged);
199 }
200 } else if (output_rep ==
201 MachineRepresentation::kFloat32) { // float32 -> float64 -> tagged
202 node = InsertChangeFloat32ToFloat64(node);
203 op = simplified()->ChangeFloat64ToTagged();
204 } else if (output_rep == MachineRepresentation::kFloat64) {
205 op = simplified()->ChangeFloat64ToTagged();
206 } else {
207 return TypeError(node, output_rep, output_type,
208 MachineRepresentation::kTagged);
209 }
210 return jsgraph()->graph()->NewNode(op, node);
211}
212
213
214Node* RepresentationChanger::GetFloat32RepresentationFor(
215 Node* node, MachineRepresentation output_rep, Type* output_type,
216 Truncation truncation) {
217 // Eagerly fold representation changes for constants.
218 switch (node->opcode()) {
219 case IrOpcode::kFloat64Constant:
220 case IrOpcode::kNumberConstant:
221 return jsgraph()->Float32Constant(
222 DoubleToFloat32(OpParameter<double>(node)));
223 case IrOpcode::kInt32Constant:
224 if (output_type->Is(Type::Unsigned32())) {
225 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node));
226 return jsgraph()->Float32Constant(static_cast<float>(value));
227 } else {
228 int32_t value = OpParameter<int32_t>(node);
229 return jsgraph()->Float32Constant(static_cast<float>(value));
230 }
231 case IrOpcode::kFloat32Constant:
232 return node; // No change necessary.
233 default:
234 break;
235 }
236 // Select the correct X -> Float32 operator.
237 const Operator* op;
238 if (output_rep == MachineRepresentation::kBit) {
239 return TypeError(node, output_rep, output_type,
240 MachineRepresentation::kFloat32);
241 } else if (IsWord(output_rep)) {
242 if (output_type->Is(Type::Signed32())) {
243 op = machine()->ChangeInt32ToFloat64();
244 } else {
245 // Either the output is int32 or the uses only care about the
246 // low 32 bits (so we can pick int32 safely).
247 DCHECK(output_type->Is(Type::Unsigned32()) ||
248 truncation.TruncatesToWord32());
249 op = machine()->ChangeUint32ToFloat64();
250 }
251 // int32 -> float64 -> float32
252 node = jsgraph()->graph()->NewNode(op, node);
253 op = machine()->TruncateFloat64ToFloat32();
254 } else if (output_rep == MachineRepresentation::kTagged) {
255 op = simplified()->ChangeTaggedToFloat64(); // tagged -> float64 -> float32
256 node = jsgraph()->graph()->NewNode(op, node);
257 op = machine()->TruncateFloat64ToFloat32();
258 } else if (output_rep == MachineRepresentation::kFloat64) {
259 op = machine()->TruncateFloat64ToFloat32();
260 } else {
261 return TypeError(node, output_rep, output_type,
262 MachineRepresentation::kFloat32);
263 }
264 return jsgraph()->graph()->NewNode(op, node);
265}
266
267
268Node* RepresentationChanger::GetFloat64RepresentationFor(
269 Node* node, MachineRepresentation output_rep, Type* output_type,
270 Truncation truncation) {
271 // Eagerly fold representation changes for constants.
272 switch (node->opcode()) {
273 case IrOpcode::kNumberConstant:
274 return jsgraph()->Float64Constant(OpParameter<double>(node));
275 case IrOpcode::kInt32Constant:
276 if (output_type->Is(Type::Signed32())) {
277 int32_t value = OpParameter<int32_t>(node);
278 return jsgraph()->Float64Constant(value);
279 } else {
280 DCHECK(output_type->Is(Type::Unsigned32()));
281 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node));
282 return jsgraph()->Float64Constant(static_cast<double>(value));
283 }
284 case IrOpcode::kFloat64Constant:
285 return node; // No change necessary.
286 case IrOpcode::kFloat32Constant:
287 return jsgraph()->Float64Constant(OpParameter<float>(node));
288 default:
289 break;
290 }
291 // Select the correct X -> Float64 operator.
292 const Operator* op;
293 if (output_rep == MachineRepresentation::kBit) {
294 return TypeError(node, output_rep, output_type,
295 MachineRepresentation::kFloat64);
296 } else if (IsWord(output_rep)) {
297 if (output_type->Is(Type::Signed32())) {
298 op = machine()->ChangeInt32ToFloat64();
299 } else {
300 // Either the output is int32 or the uses only care about the
301 // low 32 bits (so we can pick int32 safely).
302 DCHECK(output_type->Is(Type::Unsigned32()) ||
303 truncation.TruncatesToWord32());
304 op = machine()->ChangeUint32ToFloat64();
305 }
306 } else if (output_rep == MachineRepresentation::kTagged) {
307 op = simplified()->ChangeTaggedToFloat64();
308 } else if (output_rep == MachineRepresentation::kFloat32) {
309 op = machine()->ChangeFloat32ToFloat64();
310 } else {
311 return TypeError(node, output_rep, output_type,
312 MachineRepresentation::kFloat64);
313 }
314 return jsgraph()->graph()->NewNode(op, node);
315}
316
317
318Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) {
319 return jsgraph()->Int32Constant(DoubleToInt32(value));
320}
321
322
323Node* RepresentationChanger::GetWord32RepresentationFor(
324 Node* node, MachineRepresentation output_rep, Type* output_type) {
325 // Eagerly fold representation changes for constants.
326 switch (node->opcode()) {
327 case IrOpcode::kInt32Constant:
328 return node; // No change necessary.
329 case IrOpcode::kFloat32Constant:
330 return MakeTruncatedInt32Constant(OpParameter<float>(node));
331 case IrOpcode::kNumberConstant:
332 case IrOpcode::kFloat64Constant:
333 return MakeTruncatedInt32Constant(OpParameter<double>(node));
334 default:
335 break;
336 }
337 // Select the correct X -> Word32 operator.
338 const Operator* op;
339 Type* type = NodeProperties::GetType(node);
340
341 if (output_rep == MachineRepresentation::kBit) {
342 return node; // Sloppy comparison -> word32
343 } else if (output_rep == MachineRepresentation::kFloat64) {
344 // TODO(jarin) Use only output_type here, once we intersect it with the
345 // type inferred by the typer.
346 if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
347 op = machine()->ChangeFloat64ToUint32();
348 } else if (output_type->Is(Type::Signed32()) ||
349 type->Is(Type::Signed32())) {
350 op = machine()->ChangeFloat64ToInt32();
351 } else {
352 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
353 }
354 } else if (output_rep == MachineRepresentation::kFloat32) {
355 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32
356 if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
357 op = machine()->ChangeFloat64ToUint32();
358 } else if (output_type->Is(Type::Signed32()) ||
359 type->Is(Type::Signed32())) {
360 op = machine()->ChangeFloat64ToInt32();
361 } else {
362 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
363 }
364 } else if (output_rep == MachineRepresentation::kTagged) {
365 if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
366 op = simplified()->ChangeTaggedToUint32();
367 } else if (output_type->Is(Type::Signed32()) ||
368 type->Is(Type::Signed32())) {
369 op = simplified()->ChangeTaggedToInt32();
370 } else {
371 node = InsertChangeTaggedToFloat64(node);
372 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
373 }
374 } else {
375 return TypeError(node, output_rep, output_type,
376 MachineRepresentation::kWord32);
377 }
378 return jsgraph()->graph()->NewNode(op, node);
379}
380
381
382Node* RepresentationChanger::GetBitRepresentationFor(
383 Node* node, MachineRepresentation output_rep, Type* output_type) {
384 // Eagerly fold representation changes for constants.
385 switch (node->opcode()) {
386 case IrOpcode::kHeapConstant: {
387 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
388 DCHECK(value.is_identical_to(factory()->true_value()) ||
389 value.is_identical_to(factory()->false_value()));
390 return jsgraph()->Int32Constant(
391 value.is_identical_to(factory()->true_value()) ? 1 : 0);
392 }
393 default:
394 break;
395 }
396 // Select the correct X -> Bit operator.
397 const Operator* op;
398 if (output_rep == MachineRepresentation::kTagged) {
399 op = simplified()->ChangeBoolToBit();
400 } else {
401 return TypeError(node, output_rep, output_type,
402 MachineRepresentation::kBit);
403 }
404 return jsgraph()->graph()->NewNode(op, node);
405}
406
407
408Node* RepresentationChanger::GetWord64RepresentationFor(
409 Node* node, MachineRepresentation output_rep, Type* output_type) {
410 if (output_rep == MachineRepresentation::kBit) {
411 return node; // Sloppy comparison -> word64
412 }
413 // Can't really convert Word64 to anything else. Purported to be internal.
414 return TypeError(node, output_rep, output_type,
415 MachineRepresentation::kWord64);
416}
417
418
419const Operator* RepresentationChanger::Int32OperatorFor(
420 IrOpcode::Value opcode) {
421 switch (opcode) {
422 case IrOpcode::kNumberAdd:
423 return machine()->Int32Add();
424 case IrOpcode::kNumberSubtract:
425 return machine()->Int32Sub();
426 case IrOpcode::kNumberMultiply:
427 return machine()->Int32Mul();
428 case IrOpcode::kNumberDivide:
429 return machine()->Int32Div();
430 case IrOpcode::kNumberModulus:
431 return machine()->Int32Mod();
432 case IrOpcode::kNumberBitwiseOr:
433 return machine()->Word32Or();
434 case IrOpcode::kNumberBitwiseXor:
435 return machine()->Word32Xor();
436 case IrOpcode::kNumberBitwiseAnd:
437 return machine()->Word32And();
438 case IrOpcode::kNumberEqual:
439 return machine()->Word32Equal();
440 case IrOpcode::kNumberLessThan:
441 return machine()->Int32LessThan();
442 case IrOpcode::kNumberLessThanOrEqual:
443 return machine()->Int32LessThanOrEqual();
444 default:
445 UNREACHABLE();
446 return nullptr;
447 }
448}
449
450
451const Operator* RepresentationChanger::Uint32OperatorFor(
452 IrOpcode::Value opcode) {
453 switch (opcode) {
454 case IrOpcode::kNumberAdd:
455 return machine()->Int32Add();
456 case IrOpcode::kNumberSubtract:
457 return machine()->Int32Sub();
458 case IrOpcode::kNumberMultiply:
459 return machine()->Int32Mul();
460 case IrOpcode::kNumberDivide:
461 return machine()->Uint32Div();
462 case IrOpcode::kNumberModulus:
463 return machine()->Uint32Mod();
464 case IrOpcode::kNumberEqual:
465 return machine()->Word32Equal();
466 case IrOpcode::kNumberLessThan:
467 return machine()->Uint32LessThan();
468 case IrOpcode::kNumberLessThanOrEqual:
469 return machine()->Uint32LessThanOrEqual();
470 default:
471 UNREACHABLE();
472 return nullptr;
473 }
474}
475
476
477const Operator* RepresentationChanger::Float64OperatorFor(
478 IrOpcode::Value opcode) {
479 switch (opcode) {
480 case IrOpcode::kNumberAdd:
481 return machine()->Float64Add();
482 case IrOpcode::kNumberSubtract:
483 return machine()->Float64Sub();
484 case IrOpcode::kNumberMultiply:
485 return machine()->Float64Mul();
486 case IrOpcode::kNumberDivide:
487 return machine()->Float64Div();
488 case IrOpcode::kNumberModulus:
489 return machine()->Float64Mod();
490 case IrOpcode::kNumberEqual:
491 return machine()->Float64Equal();
492 case IrOpcode::kNumberLessThan:
493 return machine()->Float64LessThan();
494 case IrOpcode::kNumberLessThanOrEqual:
495 return machine()->Float64LessThanOrEqual();
496 default:
497 UNREACHABLE();
498 return nullptr;
499 }
500}
501
502
503Node* RepresentationChanger::TypeError(Node* node,
504 MachineRepresentation output_rep,
505 Type* output_type,
506 MachineRepresentation use) {
507 type_error_ = true;
508 if (!testing_type_errors_) {
509 std::ostringstream out_str;
510 out_str << output_rep << " (";
511 output_type->PrintTo(out_str, Type::SEMANTIC_DIM);
512 out_str << ")";
513
514 std::ostringstream use_str;
515 use_str << use;
516
517 V8_Fatal(__FILE__, __LINE__,
518 "RepresentationChangerError: node #%d:%s of "
519 "%s cannot be changed to %s",
520 node->id(), node->op()->mnemonic(), out_str.str().c_str(),
521 use_str.str().c_str());
522 }
523 return node;
524}
525
526
527Node* RepresentationChanger::InsertChangeFloat32ToFloat64(Node* node) {
528 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), node);
529}
530
531
532Node* RepresentationChanger::InsertChangeTaggedToFloat64(Node* node) {
533 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
534 node);
535}
536
537} // namespace compiler
538} // namespace internal
539} // namespace v8