blob: 8720afdde3ff8938e46ed2f1ab19a647e591e3da [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
6#define V8_COMPILER_REPRESENTATION_CHANGE_H_
7
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include <sstream>
9
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/base/bits.h"
11#include "src/compiler/js-graph.h"
12#include "src/compiler/machine-operator.h"
13#include "src/compiler/node-properties-inl.h"
14#include "src/compiler/simplified-operator.h"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20// Contains logic related to changing the representation of values for constants
21// and other nodes, as well as lowering Simplified->Machine operators.
22// Eagerly folds any representation changes for constants.
23class RepresentationChanger {
24 public:
25 RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
26 Isolate* isolate)
27 : jsgraph_(jsgraph),
28 simplified_(simplified),
29 isolate_(isolate),
30 testing_type_errors_(false),
31 type_error_(false) {}
32
33 // TODO(titzer): should Word64 also be implicitly convertable to others?
34 static const MachineTypeUnion rWord =
35 kRepBit | kRepWord8 | kRepWord16 | kRepWord32;
36
37 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type,
38 MachineTypeUnion use_type) {
39 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
40 // There should be only one output representation.
41 return TypeError(node, output_type, use_type);
42 }
43 if ((use_type & kRepMask) == (output_type & kRepMask)) {
44 // Representations are the same. That's a no-op.
45 return node;
46 }
47 if ((use_type & rWord) && (output_type & rWord)) {
48 // Both are words less than or equal to 32-bits.
49 // Since loads of integers from memory implicitly sign or zero extend the
50 // value to the full machine word size and stores implicitly truncate,
51 // no representation change is necessary.
52 return node;
53 }
54 if (use_type & kRepTagged) {
55 return GetTaggedRepresentationFor(node, output_type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040056 } else if (use_type & kRepFloat32) {
57 return GetFloat32RepresentationFor(node, output_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058 } else if (use_type & kRepFloat64) {
59 return GetFloat64RepresentationFor(node, output_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 } else if (use_type & kRepBit) {
61 return GetBitRepresentationFor(node, output_type);
62 } else if (use_type & rWord) {
63 return GetWord32RepresentationFor(node, output_type,
64 use_type & kTypeUint32);
65 } else if (use_type & kRepWord64) {
66 return GetWord64RepresentationFor(node, output_type);
67 } else {
68 return node;
69 }
70 }
71
72 Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) {
73 // Eagerly fold representation changes for constants.
74 switch (node->opcode()) {
75 case IrOpcode::kNumberConstant:
76 case IrOpcode::kHeapConstant:
77 return node; // No change necessary.
78 case IrOpcode::kInt32Constant:
79 if (output_type & kTypeUint32) {
80 uint32_t value = OpParameter<uint32_t>(node);
81 return jsgraph()->Constant(static_cast<double>(value));
82 } else if (output_type & kTypeInt32) {
83 int32_t value = OpParameter<int32_t>(node);
84 return jsgraph()->Constant(value);
85 } else if (output_type & kRepBit) {
86 return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
87 : jsgraph()->TrueConstant();
88 } else {
89 return TypeError(node, output_type, kRepTagged);
90 }
91 case IrOpcode::kFloat64Constant:
92 return jsgraph()->Constant(OpParameter<double>(node));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040093 case IrOpcode::kFloat32Constant:
94 return jsgraph()->Constant(OpParameter<float>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095 default:
96 break;
97 }
98 // Select the correct X -> Tagged operator.
99 const Operator* op;
100 if (output_type & kRepBit) {
101 op = simplified()->ChangeBitToBool();
102 } else if (output_type & rWord) {
103 if (output_type & kTypeUint32) {
104 op = simplified()->ChangeUint32ToTagged();
105 } else if (output_type & kTypeInt32) {
106 op = simplified()->ChangeInt32ToTagged();
107 } else {
108 return TypeError(node, output_type, kRepTagged);
109 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400110 } else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged
111 node = InsertChangeFloat32ToFloat64(node);
112 op = simplified()->ChangeFloat64ToTagged();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 } else if (output_type & kRepFloat64) {
114 op = simplified()->ChangeFloat64ToTagged();
115 } else {
116 return TypeError(node, output_type, kRepTagged);
117 }
118 return jsgraph()->graph()->NewNode(op, node);
119 }
120
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400121 Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type) {
122 // Eagerly fold representation changes for constants.
123 switch (node->opcode()) {
124 case IrOpcode::kFloat64Constant:
125 case IrOpcode::kNumberConstant:
126 return jsgraph()->Float32Constant(
127 DoubleToFloat32(OpParameter<double>(node)));
128 case IrOpcode::kInt32Constant:
129 if (output_type & kTypeUint32) {
130 uint32_t value = OpParameter<uint32_t>(node);
131 return jsgraph()->Float32Constant(static_cast<float>(value));
132 } else {
133 int32_t value = OpParameter<int32_t>(node);
134 return jsgraph()->Float32Constant(static_cast<float>(value));
135 }
136 case IrOpcode::kFloat32Constant:
137 return node; // No change necessary.
138 default:
139 break;
140 }
141 // Select the correct X -> Float32 operator.
142 const Operator* op;
143 if (output_type & kRepBit) {
144 return TypeError(node, output_type, kRepFloat32);
145 } else if (output_type & rWord) {
146 if (output_type & kTypeUint32) {
147 op = machine()->ChangeUint32ToFloat64();
148 } else {
149 op = machine()->ChangeInt32ToFloat64();
150 }
151 // int32 -> float64 -> float32
152 node = jsgraph()->graph()->NewNode(op, node);
153 op = machine()->TruncateFloat64ToFloat32();
154 } else if (output_type & kRepTagged) {
155 op = simplified()
156 ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32
157 node = jsgraph()->graph()->NewNode(op, node);
158 op = machine()->TruncateFloat64ToFloat32();
159 } else if (output_type & kRepFloat64) {
160 op = machine()->TruncateFloat64ToFloat32();
161 } else {
162 return TypeError(node, output_type, kRepFloat32);
163 }
164 return jsgraph()->graph()->NewNode(op, node);
165 }
166
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
168 // Eagerly fold representation changes for constants.
169 switch (node->opcode()) {
170 case IrOpcode::kNumberConstant:
171 return jsgraph()->Float64Constant(OpParameter<double>(node));
172 case IrOpcode::kInt32Constant:
173 if (output_type & kTypeUint32) {
174 uint32_t value = OpParameter<uint32_t>(node);
175 return jsgraph()->Float64Constant(static_cast<double>(value));
176 } else {
177 int32_t value = OpParameter<int32_t>(node);
178 return jsgraph()->Float64Constant(value);
179 }
180 case IrOpcode::kFloat64Constant:
181 return node; // No change necessary.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400182 case IrOpcode::kFloat32Constant:
183 return jsgraph()->Float64Constant(OpParameter<float>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 default:
185 break;
186 }
187 // Select the correct X -> Float64 operator.
188 const Operator* op;
189 if (output_type & kRepBit) {
190 return TypeError(node, output_type, kRepFloat64);
191 } else if (output_type & rWord) {
192 if (output_type & kTypeUint32) {
193 op = machine()->ChangeUint32ToFloat64();
194 } else {
195 op = machine()->ChangeInt32ToFloat64();
196 }
197 } else if (output_type & kRepTagged) {
198 op = simplified()->ChangeTaggedToFloat64();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 } else if (output_type & kRepFloat32) {
200 op = machine()->ChangeFloat32ToFloat64();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 } else {
202 return TypeError(node, output_type, kRepFloat64);
203 }
204 return jsgraph()->graph()->NewNode(op, node);
205 }
206
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400207 Node* MakeInt32Constant(double value) {
208 if (value < 0) {
209 DCHECK(IsInt32Double(value));
210 int32_t iv = static_cast<int32_t>(value);
211 return jsgraph()->Int32Constant(iv);
212 } else {
213 DCHECK(IsUint32Double(value));
214 int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
215 return jsgraph()->Int32Constant(iv);
216 }
217 }
218
219 Node* GetTruncatedWord32For(Node* node, MachineTypeUnion output_type) {
220 // Eagerly fold truncations for constants.
221 switch (node->opcode()) {
222 case IrOpcode::kInt32Constant:
223 return node; // No change necessary.
224 case IrOpcode::kFloat32Constant:
225 return jsgraph()->Int32Constant(
226 DoubleToInt32(OpParameter<float>(node)));
227 case IrOpcode::kNumberConstant:
228 case IrOpcode::kFloat64Constant:
229 return jsgraph()->Int32Constant(
230 DoubleToInt32(OpParameter<double>(node)));
231 default:
232 break;
233 }
234 // Select the correct X -> Word32 truncation operator.
235 const Operator* op = NULL;
236 if (output_type & kRepFloat64) {
237 op = machine()->TruncateFloat64ToInt32();
238 } else if (output_type & kRepFloat32) {
239 node = InsertChangeFloat32ToFloat64(node);
240 op = machine()->TruncateFloat64ToInt32();
241 } else if (output_type & kRepTagged) {
242 node = InsertChangeTaggedToFloat64(node);
243 op = machine()->TruncateFloat64ToInt32();
244 } else {
245 return TypeError(node, output_type, kRepWord32);
246 }
247 return jsgraph()->graph()->NewNode(op, node);
248 }
249
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250 Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
251 bool use_unsigned) {
252 // Eagerly fold representation changes for constants.
253 switch (node->opcode()) {
254 case IrOpcode::kInt32Constant:
255 return node; // No change necessary.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256 case IrOpcode::kFloat32Constant:
257 return MakeInt32Constant(OpParameter<float>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000258 case IrOpcode::kNumberConstant:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400259 case IrOpcode::kFloat64Constant:
260 return MakeInt32Constant(OpParameter<double>(node));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261 default:
262 break;
263 }
264 // Select the correct X -> Word32 operator.
265 const Operator* op = NULL;
266 if (output_type & kRepFloat64) {
267 if (output_type & kTypeUint32 || use_unsigned) {
268 op = machine()->ChangeFloat64ToUint32();
269 } else {
270 op = machine()->ChangeFloat64ToInt32();
271 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400272 } else if (output_type & kRepFloat32) {
273 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32
274 if (output_type & kTypeUint32 || use_unsigned) {
275 op = machine()->ChangeFloat64ToUint32();
276 } else {
277 op = machine()->ChangeFloat64ToInt32();
278 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279 } else if (output_type & kRepTagged) {
280 if (output_type & kTypeUint32 || use_unsigned) {
281 op = simplified()->ChangeTaggedToUint32();
282 } else {
283 op = simplified()->ChangeTaggedToInt32();
284 }
285 } else {
286 return TypeError(node, output_type, kRepWord32);
287 }
288 return jsgraph()->graph()->NewNode(op, node);
289 }
290
291 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) {
292 // Eagerly fold representation changes for constants.
293 switch (node->opcode()) {
294 case IrOpcode::kInt32Constant: {
295 int32_t value = OpParameter<int32_t>(node);
296 if (value == 0 || value == 1) return node;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400297 return jsgraph()->Int32Constant(1); // value != 0
298 }
299 case IrOpcode::kNumberConstant: {
300 double value = OpParameter<double>(node);
301 if (std::isnan(value) || value == 0.0) {
302 return jsgraph()->Int32Constant(0);
303 }
304 return jsgraph()->Int32Constant(1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 }
306 case IrOpcode::kHeapConstant: {
307 Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
308 DCHECK(*handle == isolate()->heap()->true_value() ||
309 *handle == isolate()->heap()->false_value());
310 return jsgraph()->Int32Constant(
311 *handle == isolate()->heap()->true_value() ? 1 : 0);
312 }
313 default:
314 break;
315 }
316 // Select the correct X -> Bit operator.
317 const Operator* op;
318 if (output_type & rWord) {
319 return node; // No change necessary.
320 } else if (output_type & kRepWord64) {
321 return node; // TODO(titzer): No change necessary, on 64-bit.
322 } else if (output_type & kRepTagged) {
323 op = simplified()->ChangeBoolToBit();
324 } else {
325 return TypeError(node, output_type, kRepBit);
326 }
327 return jsgraph()->graph()->NewNode(op, node);
328 }
329
330 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
331 if (output_type & kRepBit) {
332 return node; // Sloppy comparison -> word64
333 }
334 // Can't really convert Word64 to anything else. Purported to be internal.
335 return TypeError(node, output_type, kRepWord64);
336 }
337
338 const Operator* Int32OperatorFor(IrOpcode::Value opcode) {
339 switch (opcode) {
340 case IrOpcode::kNumberAdd:
341 return machine()->Int32Add();
342 case IrOpcode::kNumberSubtract:
343 return machine()->Int32Sub();
344 case IrOpcode::kNumberMultiply:
345 return machine()->Int32Mul();
346 case IrOpcode::kNumberDivide:
347 return machine()->Int32Div();
348 case IrOpcode::kNumberModulus:
349 return machine()->Int32Mod();
350 case IrOpcode::kNumberEqual:
351 return machine()->Word32Equal();
352 case IrOpcode::kNumberLessThan:
353 return machine()->Int32LessThan();
354 case IrOpcode::kNumberLessThanOrEqual:
355 return machine()->Int32LessThanOrEqual();
356 default:
357 UNREACHABLE();
358 return NULL;
359 }
360 }
361
362 const Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
363 switch (opcode) {
364 case IrOpcode::kNumberAdd:
365 return machine()->Int32Add();
366 case IrOpcode::kNumberSubtract:
367 return machine()->Int32Sub();
368 case IrOpcode::kNumberMultiply:
369 return machine()->Int32Mul();
370 case IrOpcode::kNumberDivide:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 return machine()->Uint32Div();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 case IrOpcode::kNumberModulus:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373 return machine()->Uint32Mod();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000374 case IrOpcode::kNumberEqual:
375 return machine()->Word32Equal();
376 case IrOpcode::kNumberLessThan:
377 return machine()->Uint32LessThan();
378 case IrOpcode::kNumberLessThanOrEqual:
379 return machine()->Uint32LessThanOrEqual();
380 default:
381 UNREACHABLE();
382 return NULL;
383 }
384 }
385
386 const Operator* Float64OperatorFor(IrOpcode::Value opcode) {
387 switch (opcode) {
388 case IrOpcode::kNumberAdd:
389 return machine()->Float64Add();
390 case IrOpcode::kNumberSubtract:
391 return machine()->Float64Sub();
392 case IrOpcode::kNumberMultiply:
393 return machine()->Float64Mul();
394 case IrOpcode::kNumberDivide:
395 return machine()->Float64Div();
396 case IrOpcode::kNumberModulus:
397 return machine()->Float64Mod();
398 case IrOpcode::kNumberEqual:
399 return machine()->Float64Equal();
400 case IrOpcode::kNumberLessThan:
401 return machine()->Float64LessThan();
402 case IrOpcode::kNumberLessThanOrEqual:
403 return machine()->Float64LessThanOrEqual();
404 default:
405 UNREACHABLE();
406 return NULL;
407 }
408 }
409
410 MachineType TypeForBasePointer(const FieldAccess& access) {
411 return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
412 }
413
414 MachineType TypeForBasePointer(const ElementAccess& access) {
415 return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
416 }
417
418 MachineType TypeFromUpperBound(Type* type) {
419 if (type->Is(Type::None()))
420 return kTypeAny; // TODO(titzer): should be an error
421 if (type->Is(Type::Signed32())) return kTypeInt32;
422 if (type->Is(Type::Unsigned32())) return kTypeUint32;
423 if (type->Is(Type::Number())) return kTypeNumber;
424 if (type->Is(Type::Boolean())) return kTypeBool;
425 return kTypeAny;
426 }
427
428 private:
429 JSGraph* jsgraph_;
430 SimplifiedOperatorBuilder* simplified_;
431 Isolate* isolate_;
432
433 friend class RepresentationChangerTester; // accesses the below fields.
434
435 bool testing_type_errors_; // If {true}, don't abort on a type error.
436 bool type_error_; // Set when a type error is detected.
437
438 Node* TypeError(Node* node, MachineTypeUnion output_type,
439 MachineTypeUnion use) {
440 type_error_ = true;
441 if (!testing_type_errors_) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400442 std::ostringstream out_str;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443 out_str << static_cast<MachineType>(output_type);
444
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400445 std::ostringstream use_str;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 use_str << static_cast<MachineType>(use);
447
448 V8_Fatal(__FILE__, __LINE__,
449 "RepresentationChangerError: node #%d:%s of "
450 "%s cannot be changed to %s",
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400451 node->id(), node->op()->mnemonic(), out_str.str().c_str(),
452 use_str.str().c_str());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000453 }
454 return node;
455 }
456
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400457 Node* InsertChangeFloat32ToFloat64(Node* node) {
458 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
459 node);
460 }
461
462 Node* InsertChangeTaggedToFloat64(Node* node) {
463 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
464 node);
465 }
466
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000467 JSGraph* jsgraph() { return jsgraph_; }
468 Isolate* isolate() { return isolate_; }
469 SimplifiedOperatorBuilder* simplified() { return simplified_; }
470 MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
471};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400472
473} // namespace compiler
474} // namespace internal
475} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476
477#endif // V8_COMPILER_REPRESENTATION_CHANGE_H_