Upstream version 9.38.198.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 "src/compiler/js-graph.h"
9 #include "src/compiler/machine-operator.h"
10 #include "src/compiler/node-properties-inl.h"
11 #include "src/compiler/simplified-operator.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
17 // The types and representations tracked during representation inference
18 // and change insertion.
19 // TODO(titzer): First, merge MachineType and RepType.
20 // TODO(titzer): Second, Use the real type system instead of RepType.
21 enum RepType {
22   // Representations.
23   rBit = 1 << 0,
24   rWord32 = 1 << 1,
25   rWord64 = 1 << 2,
26   rFloat64 = 1 << 3,
27   rTagged = 1 << 4,
28
29   // Types.
30   tBool = 1 << 5,
31   tInt32 = 1 << 6,
32   tUint32 = 1 << 7,
33   tInt64 = 1 << 8,
34   tUint64 = 1 << 9,
35   tNumber = 1 << 10,
36   tAny = 1 << 11
37 };
38
39 #define REP_TYPE_STRLEN 24
40
41 typedef uint16_t RepTypeUnion;
42
43
44 inline void RenderRepTypeUnion(char* buf, RepTypeUnion info) {
45   base::OS::SNPrintF(buf, REP_TYPE_STRLEN, "{%s%s%s%s%s %s%s%s%s%s%s%s}",
46                      (info & rBit) ? "k" : " ", (info & rWord32) ? "w" : " ",
47                      (info & rWord64) ? "q" : " ",
48                      (info & rFloat64) ? "f" : " ",
49                      (info & rTagged) ? "t" : " ", (info & tBool) ? "Z" : " ",
50                      (info & tInt32) ? "I" : " ", (info & tUint32) ? "U" : " ",
51                      (info & tInt64) ? "L" : " ", (info & tUint64) ? "J" : " ",
52                      (info & tNumber) ? "N" : " ", (info & tAny) ? "*" : " ");
53 }
54
55
56 const RepTypeUnion rMask = rBit | rWord32 | rWord64 | rFloat64 | rTagged;
57 const RepTypeUnion tMask =
58     tBool | tInt32 | tUint32 | tInt64 | tUint64 | tNumber | tAny;
59 const RepType rPtr = kPointerSize == 4 ? rWord32 : rWord64;
60
61 // Contains logic related to changing the representation of values for constants
62 // and other nodes, as well as lowering Simplified->Machine operators.
63 // Eagerly folds any representation changes for constants.
64 class RepresentationChanger {
65  public:
66   RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
67                         MachineOperatorBuilder* machine, Isolate* isolate)
68       : jsgraph_(jsgraph),
69         simplified_(simplified),
70         machine_(machine),
71         isolate_(isolate),
72         testing_type_errors_(false),
73         type_error_(false) {}
74
75
76   Node* GetRepresentationFor(Node* node, RepTypeUnion output_type,
77                              RepTypeUnion use_type) {
78     if (!IsPowerOf2(output_type & rMask)) {
79       // There should be only one output representation.
80       return TypeError(node, output_type, use_type);
81     }
82     if ((use_type & rMask) == (output_type & rMask)) {
83       // Representations are the same. That's a no-op.
84       return node;
85     }
86     if (use_type & rTagged) {
87       return GetTaggedRepresentationFor(node, output_type);
88     } else if (use_type & rFloat64) {
89       return GetFloat64RepresentationFor(node, output_type);
90     } else if (use_type & rWord32) {
91       return GetWord32RepresentationFor(node, output_type);
92     } else if (use_type & rBit) {
93       return GetBitRepresentationFor(node, output_type);
94     } else if (use_type & rWord64) {
95       return GetWord64RepresentationFor(node, output_type);
96     } else {
97       return node;
98     }
99   }
100
101   Node* GetTaggedRepresentationFor(Node* node, RepTypeUnion output_type) {
102     // Eagerly fold representation changes for constants.
103     switch (node->opcode()) {
104       case IrOpcode::kNumberConstant:
105       case IrOpcode::kHeapConstant:
106         return node;  // No change necessary.
107       case IrOpcode::kInt32Constant:
108         if (output_type & tUint32) {
109           uint32_t value = ValueOf<uint32_t>(node->op());
110           return jsgraph()->Constant(static_cast<double>(value));
111         } else if (output_type & tInt32) {
112           int32_t value = ValueOf<int32_t>(node->op());
113           return jsgraph()->Constant(value);
114         } else if (output_type & rBit) {
115           return ValueOf<int32_t>(node->op()) == 0 ? jsgraph()->FalseConstant()
116                                                    : jsgraph()->TrueConstant();
117         } else {
118           return TypeError(node, output_type, rTagged);
119         }
120       case IrOpcode::kFloat64Constant:
121         return jsgraph()->Constant(ValueOf<double>(node->op()));
122       default:
123         break;
124     }
125     // Select the correct X -> Tagged operator.
126     Operator* op;
127     if (output_type & rBit) {
128       op = simplified()->ChangeBitToBool();
129     } else if (output_type & rWord32) {
130       if (output_type & tUint32) {
131         op = simplified()->ChangeUint32ToTagged();
132       } else if (output_type & tInt32) {
133         op = simplified()->ChangeInt32ToTagged();
134       } else {
135         return TypeError(node, output_type, rTagged);
136       }
137     } else if (output_type & rFloat64) {
138       op = simplified()->ChangeFloat64ToTagged();
139     } else {
140       return TypeError(node, output_type, rTagged);
141     }
142     return jsgraph()->graph()->NewNode(op, node);
143   }
144
145   Node* GetFloat64RepresentationFor(Node* node, RepTypeUnion output_type) {
146     // Eagerly fold representation changes for constants.
147     switch (node->opcode()) {
148       case IrOpcode::kNumberConstant:
149         return jsgraph()->Float64Constant(ValueOf<double>(node->op()));
150       case IrOpcode::kInt32Constant:
151         if (output_type & tUint32) {
152           uint32_t value = ValueOf<uint32_t>(node->op());
153           return jsgraph()->Float64Constant(static_cast<double>(value));
154         } else {
155           int32_t value = ValueOf<int32_t>(node->op());
156           return jsgraph()->Float64Constant(value);
157         }
158       case IrOpcode::kFloat64Constant:
159         return node;  // No change necessary.
160       default:
161         break;
162     }
163     // Select the correct X -> Float64 operator.
164     Operator* op;
165     if (output_type & rWord32) {
166       if (output_type & tUint32) {
167         op = machine()->ChangeUint32ToFloat64();
168       } else if (output_type & tInt32) {
169         op = machine()->ChangeInt32ToFloat64();
170       } else {
171         return TypeError(node, output_type, rFloat64);
172       }
173     } else if (output_type & rTagged) {
174       op = simplified()->ChangeTaggedToFloat64();
175     } else {
176       return TypeError(node, output_type, rFloat64);
177     }
178     return jsgraph()->graph()->NewNode(op, node);
179   }
180
181   Node* GetWord32RepresentationFor(Node* node, RepTypeUnion output_type) {
182     // Eagerly fold representation changes for constants.
183     switch (node->opcode()) {
184       case IrOpcode::kInt32Constant:
185         return node;  // No change necessary.
186       case IrOpcode::kNumberConstant:
187       case IrOpcode::kFloat64Constant: {
188         if (output_type & tUint32) {
189           int32_t value = static_cast<int32_t>(
190               static_cast<uint32_t>(ValueOf<double>(node->op())));
191           return jsgraph()->Int32Constant(value);
192         } else if (output_type & tInt32) {
193           int32_t value = FastD2I(ValueOf<double>(node->op()));
194           return jsgraph()->Int32Constant(value);
195         } else {
196           return TypeError(node, output_type, rWord32);
197         }
198       }
199       default:
200         break;
201     }
202     // Select the correct X -> Word32 operator.
203     Operator* op = NULL;
204     if (output_type & rFloat64) {
205       if (output_type & tUint32) {
206         op = machine()->ChangeFloat64ToUint32();
207       } else if (output_type & tInt32) {
208         op = machine()->ChangeFloat64ToInt32();
209       } else {
210         return TypeError(node, output_type, rWord32);
211       }
212     } else if (output_type & rTagged) {
213       if (output_type & tUint32) {
214         op = simplified()->ChangeTaggedToUint32();
215       } else if (output_type & tInt32) {
216         op = simplified()->ChangeTaggedToInt32();
217       } else {
218         return TypeError(node, output_type, rWord32);
219       }
220     } else if (output_type & rBit) {
221       return node;  // Sloppy comparison -> word32.
222     } else {
223       return TypeError(node, output_type, rWord32);
224     }
225     return jsgraph()->graph()->NewNode(op, node);
226   }
227
228   Node* GetBitRepresentationFor(Node* node, RepTypeUnion output_type) {
229     // Eagerly fold representation changes for constants.
230     switch (node->opcode()) {
231       case IrOpcode::kInt32Constant: {
232         int32_t value = ValueOf<int32_t>(node->op());
233         if (value == 0 || value == 1) return node;
234         return jsgraph()->OneConstant();  // value != 0
235       }
236       case IrOpcode::kHeapConstant: {
237         Handle<Object> handle = ValueOf<Handle<Object> >(node->op());
238         DCHECK(*handle == isolate()->heap()->true_value() ||
239                *handle == isolate()->heap()->false_value());
240         return jsgraph()->Int32Constant(
241             *handle == isolate()->heap()->true_value() ? 1 : 0);
242       }
243       default:
244         break;
245     }
246     // Select the correct X -> Bit operator.
247     Operator* op;
248     if (output_type & rWord32) {
249       return node;  // No change necessary.
250     } else if (output_type & rWord64) {
251       return node;  // TODO(titzer): No change necessary, on 64-bit.
252     } else if (output_type & rTagged) {
253       op = simplified()->ChangeBoolToBit();
254     } else {
255       return TypeError(node, output_type, rBit);
256     }
257     return jsgraph()->graph()->NewNode(op, node);
258   }
259
260   Node* GetWord64RepresentationFor(Node* node, RepTypeUnion output_type) {
261     if (output_type & rBit) {
262       return node;  // Sloppy comparison -> word64
263     }
264     // Can't really convert Word64 to anything else. Purported to be internal.
265     return TypeError(node, output_type, rWord64);
266   }
267
268   static RepType TypeForMachineType(MachineType rep) {
269     // TODO(titzer): merge MachineType and RepType.
270     switch (rep) {
271       case kMachineWord8:
272         return rWord32;
273       case kMachineWord16:
274         return rWord32;
275       case kMachineWord32:
276         return rWord32;
277       case kMachineWord64:
278         return rWord64;
279       case kMachineFloat64:
280         return rFloat64;
281       case kMachineTagged:
282         return rTagged;
283       default:
284         UNREACHABLE();
285         return static_cast<RepType>(0);
286     }
287   }
288
289   Operator* Int32OperatorFor(IrOpcode::Value opcode) {
290     switch (opcode) {
291       case IrOpcode::kNumberAdd:
292         return machine()->Int32Add();
293       case IrOpcode::kNumberSubtract:
294         return machine()->Int32Sub();
295       case IrOpcode::kNumberEqual:
296         return machine()->Word32Equal();
297       case IrOpcode::kNumberLessThan:
298         return machine()->Int32LessThan();
299       case IrOpcode::kNumberLessThanOrEqual:
300         return machine()->Int32LessThanOrEqual();
301       default:
302         UNREACHABLE();
303         return NULL;
304     }
305   }
306
307   Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
308     switch (opcode) {
309       case IrOpcode::kNumberAdd:
310         return machine()->Int32Add();
311       case IrOpcode::kNumberSubtract:
312         return machine()->Int32Sub();
313       case IrOpcode::kNumberEqual:
314         return machine()->Word32Equal();
315       case IrOpcode::kNumberLessThan:
316         return machine()->Uint32LessThan();
317       case IrOpcode::kNumberLessThanOrEqual:
318         return machine()->Uint32LessThanOrEqual();
319       default:
320         UNREACHABLE();
321         return NULL;
322     }
323   }
324
325   Operator* Float64OperatorFor(IrOpcode::Value opcode) {
326     switch (opcode) {
327       case IrOpcode::kNumberAdd:
328         return machine()->Float64Add();
329       case IrOpcode::kNumberSubtract:
330         return machine()->Float64Sub();
331       case IrOpcode::kNumberMultiply:
332         return machine()->Float64Mul();
333       case IrOpcode::kNumberDivide:
334         return machine()->Float64Div();
335       case IrOpcode::kNumberModulus:
336         return machine()->Float64Mod();
337       case IrOpcode::kNumberEqual:
338         return machine()->Float64Equal();
339       case IrOpcode::kNumberLessThan:
340         return machine()->Float64LessThan();
341       case IrOpcode::kNumberLessThanOrEqual:
342         return machine()->Float64LessThanOrEqual();
343       default:
344         UNREACHABLE();
345         return NULL;
346     }
347   }
348
349   RepType TypeForField(const FieldAccess& access) {
350     RepType tElement = static_cast<RepType>(0);  // TODO(titzer)
351     RepType rElement = TypeForMachineType(access.representation);
352     return static_cast<RepType>(tElement | rElement);
353   }
354
355   RepType TypeForElement(const ElementAccess& access) {
356     RepType tElement = static_cast<RepType>(0);  // TODO(titzer)
357     RepType rElement = TypeForMachineType(access.representation);
358     return static_cast<RepType>(tElement | rElement);
359   }
360
361   RepType TypeForBasePointer(const FieldAccess& access) {
362     if (access.tag() != 0) return static_cast<RepType>(tAny | rTagged);
363     return kPointerSize == 8 ? rWord64 : rWord32;
364   }
365
366   RepType TypeForBasePointer(const ElementAccess& access) {
367     if (access.tag() != 0) return static_cast<RepType>(tAny | rTagged);
368     return kPointerSize == 8 ? rWord64 : rWord32;
369   }
370
371   RepType TypeFromUpperBound(Type* type) {
372     if (type->Is(Type::None()))
373       return tAny;  // TODO(titzer): should be an error
374     if (type->Is(Type::Signed32())) return tInt32;
375     if (type->Is(Type::Unsigned32())) return tUint32;
376     if (type->Is(Type::Number())) return tNumber;
377     if (type->Is(Type::Boolean())) return tBool;
378     return tAny;
379   }
380
381  private:
382   JSGraph* jsgraph_;
383   SimplifiedOperatorBuilder* simplified_;
384   MachineOperatorBuilder* machine_;
385   Isolate* isolate_;
386
387   friend class RepresentationChangerTester;  // accesses the below fields.
388
389   bool testing_type_errors_;  // If {true}, don't abort on a type error.
390   bool type_error_;           // Set when a type error is detected.
391
392   Node* TypeError(Node* node, RepTypeUnion output_type, RepTypeUnion use) {
393     type_error_ = true;
394     if (!testing_type_errors_) {
395       char buf1[REP_TYPE_STRLEN];
396       char buf2[REP_TYPE_STRLEN];
397       RenderRepTypeUnion(buf1, output_type);
398       RenderRepTypeUnion(buf2, use);
399       V8_Fatal(__FILE__, __LINE__,
400                "RepresentationChangerError: node #%d:%s of rep"
401                "%s cannot be changed to rep%s",
402                node->id(), node->op()->mnemonic(), buf1, buf2);
403     }
404     return node;
405   }
406
407   JSGraph* jsgraph() { return jsgraph_; }
408   Isolate* isolate() { return isolate_; }
409   SimplifiedOperatorBuilder* simplified() { return simplified_; }
410   MachineOperatorBuilder* machine() { return machine_; }
411 };
412 }
413 }
414 }  // namespace v8::internal::compiler
415
416 #endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_