Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / representation-change.h
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.
4
5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_
7
8 #include <sstream>
9
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"
15
16 namespace v8 {
17 namespace internal {
18 namespace 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.
23 class 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);
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);
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));
93       case IrOpcode::kFloat32Constant:
94         return jsgraph()->Constant(OpParameter<float>(node));
95       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       }
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();
115     } else {
116       return TypeError(node, output_type, kRepTagged);
117     }
118     return jsgraph()->graph()->NewNode(op, node);
119   }
120
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));
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
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));
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.
182       case IrOpcode::kFloat32Constant:
183         return jsgraph()->Float64Constant(OpParameter<float>(node));
184       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();
199     } else if (output_type & kRepFloat32) {
200       op = machine()->ChangeFloat32ToFloat64();
201     } else {
202       return TypeError(node, output_type, kRepFloat64);
203     }
204     return jsgraph()->graph()->NewNode(op, node);
205   }
206
207   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
250   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.
256       case IrOpcode::kFloat32Constant:
257         return MakeInt32Constant(OpParameter<float>(node));
258       case IrOpcode::kNumberConstant:
259       case IrOpcode::kFloat64Constant:
260         return MakeInt32Constant(OpParameter<double>(node));
261       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       }
272     } 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       }
279     } 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;
297         return jsgraph()->OneConstant();  // value != 0
298       }
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);
305       }
306       default:
307         break;
308     }
309     // Select the correct X -> Bit operator.
310     const Operator* op;
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();
317     } else {
318       return TypeError(node, output_type, kRepBit);
319     }
320     return jsgraph()->graph()->NewNode(op, node);
321   }
322
323   Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
324     if (output_type & kRepBit) {
325       return node;  // Sloppy comparison -> word64
326     }
327     // Can't really convert Word64 to anything else. Purported to be internal.
328     return TypeError(node, output_type, kRepWord64);
329   }
330
331   const Operator* Int32OperatorFor(IrOpcode::Value opcode) {
332     switch (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();
349       default:
350         UNREACHABLE();
351         return NULL;
352     }
353   }
354
355   const Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
356     switch (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();
373       default:
374         UNREACHABLE();
375         return NULL;
376     }
377   }
378
379   const Operator* Float64OperatorFor(IrOpcode::Value opcode) {
380     switch (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();
397       default:
398         UNREACHABLE();
399         return NULL;
400     }
401   }
402
403   MachineType TypeForBasePointer(const FieldAccess& access) {
404     return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
405   }
406
407   MachineType TypeForBasePointer(const ElementAccess& access) {
408     return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
409   }
410
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;
418     return kTypeAny;
419   }
420
421  private:
422   JSGraph* jsgraph_;
423   SimplifiedOperatorBuilder* simplified_;
424   Isolate* isolate_;
425
426   friend class RepresentationChangerTester;  // accesses the below fields.
427
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.
430
431   Node* TypeError(Node* node, MachineTypeUnion output_type,
432                   MachineTypeUnion use) {
433     type_error_ = true;
434     if (!testing_type_errors_) {
435       std::ostringstream out_str;
436       out_str << static_cast<MachineType>(output_type);
437
438       std::ostringstream use_str;
439       use_str << static_cast<MachineType>(use);
440
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());
446     }
447     return node;
448   }
449
450   Node* InsertChangeFloat32ToFloat64(Node* node) {
451     return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(),
452                                        node);
453   }
454
455   Node* InsertChangeTaggedToFloat64(Node* node) {
456     return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
457                                        node);
458   }
459
460   JSGraph* jsgraph() { return jsgraph_; }
461   Isolate* isolate() { return isolate_; }
462   SimplifiedOperatorBuilder* simplified() { return simplified_; }
463   MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
464 };
465
466 }  // namespace compiler
467 }  // namespace internal
468 }  // namespace v8
469
470 #endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_