1 // 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.
5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_
10 #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"
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.
23 class RepresentationChanger {
25 RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
28 simplified_(simplified),
30 testing_type_errors_(false),
33 // TODO(titzer): should Word64 also be implicitly convertable to others?
34 static const MachineTypeUnion rWord =
35 kRepBit | kRepWord8 | kRepWord16 | kRepWord32;
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);
43 if ((use_type & kRepMask) == (output_type & kRepMask)) {
44 // Representations are the same. That's a no-op.
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.
54 if (use_type & kRepTagged) {
55 return GetTaggedRepresentationFor(node, output_type);
56 } else if (use_type & kRepFloat32) {
57 return GetFloat32RepresentationFor(node, output_type);
58 } else if (use_type & kRepFloat64) {
59 return GetFloat64RepresentationFor(node, output_type);
60 } 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);
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();
89 return TypeError(node, output_type, kRepTagged);
91 case IrOpcode::kFloat64Constant:
92 return jsgraph()->Constant(OpParameter<double>(node));
93 case IrOpcode::kFloat32Constant:
94 return jsgraph()->Constant(OpParameter<float>(node));
98 // Select the correct X -> Tagged operator.
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();
108 return TypeError(node, output_type, kRepTagged);
110 } else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged
111 node = InsertChangeFloat32ToFloat64(node);
112 op = simplified()->ChangeFloat64ToTagged();
113 } else if (output_type & kRepFloat64) {
114 op = simplified()->ChangeFloat64ToTagged();
116 return TypeError(node, output_type, kRepTagged);
118 return jsgraph()->graph()->NewNode(op, node);
121 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));
133 int32_t value = OpParameter<int32_t>(node);
134 return jsgraph()->Float32Constant(static_cast<float>(value));
136 case IrOpcode::kFloat32Constant:
137 return node; // No change necessary.
141 // Select the correct X -> Float32 operator.
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();
149 op = machine()->ChangeInt32ToFloat64();
151 // int32 -> float64 -> float32
152 node = jsgraph()->graph()->NewNode(op, node);
153 op = machine()->TruncateFloat64ToFloat32();
154 } else if (output_type & kRepTagged) {
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();
162 return TypeError(node, output_type, kRepFloat32);
164 return jsgraph()->graph()->NewNode(op, node);
167 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));
177 int32_t value = OpParameter<int32_t>(node);
178 return jsgraph()->Float64Constant(value);
180 case IrOpcode::kFloat64Constant:
181 return node; // No change necessary.
182 case IrOpcode::kFloat32Constant:
183 return jsgraph()->Float64Constant(OpParameter<float>(node));
187 // Select the correct X -> Float64 operator.
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();
195 op = machine()->ChangeInt32ToFloat64();
197 } else if (output_type & kRepTagged) {
198 op = simplified()->ChangeTaggedToFloat64();
199 } else if (output_type & kRepFloat32) {
200 op = machine()->ChangeFloat32ToFloat64();
202 return TypeError(node, output_type, kRepFloat64);
204 return jsgraph()->graph()->NewNode(op, node);
207 Node* MakeInt32Constant(double value) {
209 DCHECK(IsInt32Double(value));
210 int32_t iv = static_cast<int32_t>(value);
211 return jsgraph()->Int32Constant(iv);
213 DCHECK(IsUint32Double(value));
214 int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
215 return jsgraph()->Int32Constant(iv);
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)));
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();
245 return TypeError(node, output_type, kRepWord32);
247 return jsgraph()->graph()->NewNode(op, node);
250 Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
252 // Eagerly fold representation changes for constants.
253 switch (node->opcode()) {
254 case IrOpcode::kInt32Constant:
255 return node; // No change necessary.
256 case IrOpcode::kFloat32Constant:
257 return MakeInt32Constant(OpParameter<float>(node));
258 case IrOpcode::kNumberConstant:
259 case IrOpcode::kFloat64Constant:
260 return MakeInt32Constant(OpParameter<double>(node));
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();
270 op = machine()->ChangeFloat64ToInt32();
272 } else if (output_type & kRepFloat32) {
273 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32
274 if (output_type & kTypeUint32 || use_unsigned) {
275 op = machine()->ChangeFloat64ToUint32();
277 op = machine()->ChangeFloat64ToInt32();
279 } else if (output_type & kRepTagged) {
280 if (output_type & kTypeUint32 || use_unsigned) {
281 op = simplified()->ChangeTaggedToUint32();
283 op = simplified()->ChangeTaggedToInt32();
286 return TypeError(node, output_type, kRepWord32);
288 return jsgraph()->graph()->NewNode(op, node);
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;
297 return jsgraph()->OneConstant(); // value != 0
299 case IrOpcode::kHeapConstant: {
300 Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
301 DCHECK(*handle == isolate()->heap()->true_value() ||
302 *handle == isolate()->heap()->false_value());
303 return jsgraph()->Int32Constant(
304 *handle == isolate()->heap()->true_value() ? 1 : 0);
309 // Select the correct X -> Bit operator.
311 if (output_type & rWord) {
312 return node; // No change necessary.
313 } else if (output_type & kRepWord64) {
314 return node; // TODO(titzer): No change necessary, on 64-bit.
315 } else if (output_type & kRepTagged) {
316 op = simplified()->ChangeBoolToBit();
318 return TypeError(node, output_type, kRepBit);
320 return jsgraph()->graph()->NewNode(op, node);
323 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
324 if (output_type & kRepBit) {
325 return node; // Sloppy comparison -> word64
327 // Can't really convert Word64 to anything else. Purported to be internal.
328 return TypeError(node, output_type, kRepWord64);
331 const Operator* Int32OperatorFor(IrOpcode::Value opcode) {
333 case IrOpcode::kNumberAdd:
334 return machine()->Int32Add();
335 case IrOpcode::kNumberSubtract:
336 return machine()->Int32Sub();
337 case IrOpcode::kNumberMultiply:
338 return machine()->Int32Mul();
339 case IrOpcode::kNumberDivide:
340 return machine()->Int32Div();
341 case IrOpcode::kNumberModulus:
342 return machine()->Int32Mod();
343 case IrOpcode::kNumberEqual:
344 return machine()->Word32Equal();
345 case IrOpcode::kNumberLessThan:
346 return machine()->Int32LessThan();
347 case IrOpcode::kNumberLessThanOrEqual:
348 return machine()->Int32LessThanOrEqual();
355 const Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
357 case IrOpcode::kNumberAdd:
358 return machine()->Int32Add();
359 case IrOpcode::kNumberSubtract:
360 return machine()->Int32Sub();
361 case IrOpcode::kNumberMultiply:
362 return machine()->Int32Mul();
363 case IrOpcode::kNumberDivide:
364 return machine()->Uint32Div();
365 case IrOpcode::kNumberModulus:
366 return machine()->Uint32Mod();
367 case IrOpcode::kNumberEqual:
368 return machine()->Word32Equal();
369 case IrOpcode::kNumberLessThan:
370 return machine()->Uint32LessThan();
371 case IrOpcode::kNumberLessThanOrEqual:
372 return machine()->Uint32LessThanOrEqual();
379 const Operator* Float64OperatorFor(IrOpcode::Value opcode) {
381 case IrOpcode::kNumberAdd:
382 return machine()->Float64Add();
383 case IrOpcode::kNumberSubtract:
384 return machine()->Float64Sub();
385 case IrOpcode::kNumberMultiply:
386 return machine()->Float64Mul();
387 case IrOpcode::kNumberDivide:
388 return machine()->Float64Div();
389 case IrOpcode::kNumberModulus:
390 return machine()->Float64Mod();
391 case IrOpcode::kNumberEqual:
392 return machine()->Float64Equal();
393 case IrOpcode::kNumberLessThan:
394 return machine()->Float64LessThan();
395 case IrOpcode::kNumberLessThanOrEqual:
396 return machine()->Float64LessThanOrEqual();
403 MachineType TypeForBasePointer(const FieldAccess& access) {
404 return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
407 MachineType TypeForBasePointer(const ElementAccess& access) {
408 return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
411 MachineType TypeFromUpperBound(Type* type) {
412 if (type->Is(Type::None()))
413 return kTypeAny; // TODO(titzer): should be an error
414 if (type->Is(Type::Signed32())) return kTypeInt32;
415 if (type->Is(Type::Unsigned32())) return kTypeUint32;
416 if (type->Is(Type::Number())) return kTypeNumber;
417 if (type->Is(Type::Boolean())) return kTypeBool;
423 SimplifiedOperatorBuilder* simplified_;
426 friend class RepresentationChangerTester; // accesses the below fields.
428 bool testing_type_errors_; // If {true}, don't abort on a type error.
429 bool type_error_; // Set when a type error is detected.
431 Node* TypeError(Node* node, MachineTypeUnion output_type,
432 MachineTypeUnion use) {
434 if (!testing_type_errors_) {
435 std::ostringstream out_str;
436 out_str << static_cast<MachineType>(output_type);
438 std::ostringstream use_str;
439 use_str << static_cast<MachineType>(use);
441 V8_Fatal(__FILE__, __LINE__,
442 "RepresentationChangerError: node #%d:%s of "
443 "%s cannot be changed to %s",
444 node->id(), node->op()->mnemonic(), out_str.str().c_str(),
445 use_str.str().c_str());
450 Node* InsertChangeFloat32ToFloat64(Node* node) {
451 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
455 Node* InsertChangeTaggedToFloat64(Node* node) {
456 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
460 JSGraph* jsgraph() { return jsgraph_; }
461 Isolate* isolate() { return isolate_; }
462 SimplifiedOperatorBuilder* simplified() { return simplified_; }
463 MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
466 } // namespace compiler
467 } // namespace internal
470 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_