• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/base/bits.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node-properties-inl.h"
12 #include "src/compiler/simplified-operator.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 // Contains logic related to changing the representation of values for constants
19 // and other nodes, as well as lowering Simplified->Machine operators.
20 // Eagerly folds any representation changes for constants.
21 class RepresentationChanger {
22  public:
RepresentationChanger(JSGraph * jsgraph,SimplifiedOperatorBuilder * simplified,Isolate * isolate)23   RepresentationChanger(JSGraph* jsgraph, SimplifiedOperatorBuilder* simplified,
24                         Isolate* isolate)
25       : jsgraph_(jsgraph),
26         simplified_(simplified),
27         isolate_(isolate),
28         testing_type_errors_(false),
29         type_error_(false) {}
30 
31   // TODO(titzer): should Word64 also be implicitly convertable to others?
32   static const MachineTypeUnion rWord =
33       kRepBit | kRepWord8 | kRepWord16 | kRepWord32;
34 
GetRepresentationFor(Node * node,MachineTypeUnion output_type,MachineTypeUnion use_type)35   Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type,
36                              MachineTypeUnion use_type) {
37     if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) {
38       // There should be only one output representation.
39       return TypeError(node, output_type, use_type);
40     }
41     if ((use_type & kRepMask) == (output_type & kRepMask)) {
42       // Representations are the same. That's a no-op.
43       return node;
44     }
45     if ((use_type & rWord) && (output_type & rWord)) {
46       // Both are words less than or equal to 32-bits.
47       // Since loads of integers from memory implicitly sign or zero extend the
48       // value to the full machine word size and stores implicitly truncate,
49       // no representation change is necessary.
50       return node;
51     }
52     if (use_type & kRepTagged) {
53       return GetTaggedRepresentationFor(node, output_type);
54     } else if (use_type & kRepFloat64) {
55       return GetFloat64RepresentationFor(node, output_type);
56     } else if (use_type & kRepFloat32) {
57       return TypeError(node, output_type, use_type);  // TODO(titzer): handle
58     } else if (use_type & kRepBit) {
59       return GetBitRepresentationFor(node, output_type);
60     } else if (use_type & rWord) {
61       return GetWord32RepresentationFor(node, output_type,
62                                         use_type & kTypeUint32);
63     } else if (use_type & kRepWord64) {
64       return GetWord64RepresentationFor(node, output_type);
65     } else {
66       return node;
67     }
68   }
69 
GetTaggedRepresentationFor(Node * node,MachineTypeUnion output_type)70   Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) {
71     // Eagerly fold representation changes for constants.
72     switch (node->opcode()) {
73       case IrOpcode::kNumberConstant:
74       case IrOpcode::kHeapConstant:
75         return node;  // No change necessary.
76       case IrOpcode::kInt32Constant:
77         if (output_type & kTypeUint32) {
78           uint32_t value = OpParameter<uint32_t>(node);
79           return jsgraph()->Constant(static_cast<double>(value));
80         } else if (output_type & kTypeInt32) {
81           int32_t value = OpParameter<int32_t>(node);
82           return jsgraph()->Constant(value);
83         } else if (output_type & kRepBit) {
84           return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
85                                                  : jsgraph()->TrueConstant();
86         } else {
87           return TypeError(node, output_type, kRepTagged);
88         }
89       case IrOpcode::kFloat64Constant:
90         return jsgraph()->Constant(OpParameter<double>(node));
91       default:
92         break;
93     }
94     // Select the correct X -> Tagged operator.
95     const Operator* op;
96     if (output_type & kRepBit) {
97       op = simplified()->ChangeBitToBool();
98     } else if (output_type & rWord) {
99       if (output_type & kTypeUint32) {
100         op = simplified()->ChangeUint32ToTagged();
101       } else if (output_type & kTypeInt32) {
102         op = simplified()->ChangeInt32ToTagged();
103       } else {
104         return TypeError(node, output_type, kRepTagged);
105       }
106     } else if (output_type & kRepFloat64) {
107       op = simplified()->ChangeFloat64ToTagged();
108     } else {
109       return TypeError(node, output_type, kRepTagged);
110     }
111     return jsgraph()->graph()->NewNode(op, node);
112   }
113 
GetFloat64RepresentationFor(Node * node,MachineTypeUnion output_type)114   Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type) {
115     // Eagerly fold representation changes for constants.
116     switch (node->opcode()) {
117       case IrOpcode::kNumberConstant:
118         return jsgraph()->Float64Constant(OpParameter<double>(node));
119       case IrOpcode::kInt32Constant:
120         if (output_type & kTypeUint32) {
121           uint32_t value = OpParameter<uint32_t>(node);
122           return jsgraph()->Float64Constant(static_cast<double>(value));
123         } else {
124           int32_t value = OpParameter<int32_t>(node);
125           return jsgraph()->Float64Constant(value);
126         }
127       case IrOpcode::kFloat64Constant:
128         return node;  // No change necessary.
129       default:
130         break;
131     }
132     // Select the correct X -> Float64 operator.
133     const Operator* op;
134     if (output_type & kRepBit) {
135       return TypeError(node, output_type, kRepFloat64);
136     } else if (output_type & rWord) {
137       if (output_type & kTypeUint32) {
138         op = machine()->ChangeUint32ToFloat64();
139       } else {
140         op = machine()->ChangeInt32ToFloat64();
141       }
142     } else if (output_type & kRepTagged) {
143       op = simplified()->ChangeTaggedToFloat64();
144     } else {
145       return TypeError(node, output_type, kRepFloat64);
146     }
147     return jsgraph()->graph()->NewNode(op, node);
148   }
149 
GetWord32RepresentationFor(Node * node,MachineTypeUnion output_type,bool use_unsigned)150   Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type,
151                                    bool use_unsigned) {
152     // Eagerly fold representation changes for constants.
153     switch (node->opcode()) {
154       case IrOpcode::kInt32Constant:
155         return node;  // No change necessary.
156       case IrOpcode::kNumberConstant:
157       case IrOpcode::kFloat64Constant: {
158         double value = OpParameter<double>(node);
159         if (value < 0) {
160           DCHECK(IsInt32Double(value));
161           int32_t iv = static_cast<int32_t>(value);
162           return jsgraph()->Int32Constant(iv);
163         } else {
164           DCHECK(IsUint32Double(value));
165           int32_t iv = static_cast<int32_t>(static_cast<uint32_t>(value));
166           return jsgraph()->Int32Constant(iv);
167         }
168       }
169       default:
170         break;
171     }
172     // Select the correct X -> Word32 operator.
173     const Operator* op = NULL;
174     if (output_type & kRepFloat64) {
175       if (output_type & kTypeUint32 || use_unsigned) {
176         op = machine()->ChangeFloat64ToUint32();
177       } else {
178         op = machine()->ChangeFloat64ToInt32();
179       }
180     } else if (output_type & kRepTagged) {
181       if (output_type & kTypeUint32 || use_unsigned) {
182         op = simplified()->ChangeTaggedToUint32();
183       } else {
184         op = simplified()->ChangeTaggedToInt32();
185       }
186     } else {
187       return TypeError(node, output_type, kRepWord32);
188     }
189     return jsgraph()->graph()->NewNode(op, node);
190   }
191 
GetBitRepresentationFor(Node * node,MachineTypeUnion output_type)192   Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) {
193     // Eagerly fold representation changes for constants.
194     switch (node->opcode()) {
195       case IrOpcode::kInt32Constant: {
196         int32_t value = OpParameter<int32_t>(node);
197         if (value == 0 || value == 1) return node;
198         return jsgraph()->OneConstant();  // value != 0
199       }
200       case IrOpcode::kHeapConstant: {
201         Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
202         DCHECK(*handle == isolate()->heap()->true_value() ||
203                *handle == isolate()->heap()->false_value());
204         return jsgraph()->Int32Constant(
205             *handle == isolate()->heap()->true_value() ? 1 : 0);
206       }
207       default:
208         break;
209     }
210     // Select the correct X -> Bit operator.
211     const Operator* op;
212     if (output_type & rWord) {
213       return node;  // No change necessary.
214     } else if (output_type & kRepWord64) {
215       return node;  // TODO(titzer): No change necessary, on 64-bit.
216     } else if (output_type & kRepTagged) {
217       op = simplified()->ChangeBoolToBit();
218     } else {
219       return TypeError(node, output_type, kRepBit);
220     }
221     return jsgraph()->graph()->NewNode(op, node);
222   }
223 
GetWord64RepresentationFor(Node * node,MachineTypeUnion output_type)224   Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) {
225     if (output_type & kRepBit) {
226       return node;  // Sloppy comparison -> word64
227     }
228     // Can't really convert Word64 to anything else. Purported to be internal.
229     return TypeError(node, output_type, kRepWord64);
230   }
231 
Int32OperatorFor(IrOpcode::Value opcode)232   const Operator* Int32OperatorFor(IrOpcode::Value opcode) {
233     switch (opcode) {
234       case IrOpcode::kNumberAdd:
235         return machine()->Int32Add();
236       case IrOpcode::kNumberSubtract:
237         return machine()->Int32Sub();
238       case IrOpcode::kNumberMultiply:
239         return machine()->Int32Mul();
240       case IrOpcode::kNumberDivide:
241         return machine()->Int32Div();
242       case IrOpcode::kNumberModulus:
243         return machine()->Int32Mod();
244       case IrOpcode::kNumberEqual:
245         return machine()->Word32Equal();
246       case IrOpcode::kNumberLessThan:
247         return machine()->Int32LessThan();
248       case IrOpcode::kNumberLessThanOrEqual:
249         return machine()->Int32LessThanOrEqual();
250       default:
251         UNREACHABLE();
252         return NULL;
253     }
254   }
255 
Uint32OperatorFor(IrOpcode::Value opcode)256   const Operator* Uint32OperatorFor(IrOpcode::Value opcode) {
257     switch (opcode) {
258       case IrOpcode::kNumberAdd:
259         return machine()->Int32Add();
260       case IrOpcode::kNumberSubtract:
261         return machine()->Int32Sub();
262       case IrOpcode::kNumberMultiply:
263         return machine()->Int32Mul();
264       case IrOpcode::kNumberDivide:
265         return machine()->Int32UDiv();
266       case IrOpcode::kNumberModulus:
267         return machine()->Int32UMod();
268       case IrOpcode::kNumberEqual:
269         return machine()->Word32Equal();
270       case IrOpcode::kNumberLessThan:
271         return machine()->Uint32LessThan();
272       case IrOpcode::kNumberLessThanOrEqual:
273         return machine()->Uint32LessThanOrEqual();
274       default:
275         UNREACHABLE();
276         return NULL;
277     }
278   }
279 
Float64OperatorFor(IrOpcode::Value opcode)280   const Operator* Float64OperatorFor(IrOpcode::Value opcode) {
281     switch (opcode) {
282       case IrOpcode::kNumberAdd:
283         return machine()->Float64Add();
284       case IrOpcode::kNumberSubtract:
285         return machine()->Float64Sub();
286       case IrOpcode::kNumberMultiply:
287         return machine()->Float64Mul();
288       case IrOpcode::kNumberDivide:
289         return machine()->Float64Div();
290       case IrOpcode::kNumberModulus:
291         return machine()->Float64Mod();
292       case IrOpcode::kNumberEqual:
293         return machine()->Float64Equal();
294       case IrOpcode::kNumberLessThan:
295         return machine()->Float64LessThan();
296       case IrOpcode::kNumberLessThanOrEqual:
297         return machine()->Float64LessThanOrEqual();
298       default:
299         UNREACHABLE();
300         return NULL;
301     }
302   }
303 
TypeForBasePointer(const FieldAccess & access)304   MachineType TypeForBasePointer(const FieldAccess& access) {
305     return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
306   }
307 
TypeForBasePointer(const ElementAccess & access)308   MachineType TypeForBasePointer(const ElementAccess& access) {
309     return access.tag() != 0 ? kMachAnyTagged : kMachPtr;
310   }
311 
TypeFromUpperBound(Type * type)312   MachineType TypeFromUpperBound(Type* type) {
313     if (type->Is(Type::None()))
314       return kTypeAny;  // TODO(titzer): should be an error
315     if (type->Is(Type::Signed32())) return kTypeInt32;
316     if (type->Is(Type::Unsigned32())) return kTypeUint32;
317     if (type->Is(Type::Number())) return kTypeNumber;
318     if (type->Is(Type::Boolean())) return kTypeBool;
319     return kTypeAny;
320   }
321 
322  private:
323   JSGraph* jsgraph_;
324   SimplifiedOperatorBuilder* simplified_;
325   Isolate* isolate_;
326 
327   friend class RepresentationChangerTester;  // accesses the below fields.
328 
329   bool testing_type_errors_;  // If {true}, don't abort on a type error.
330   bool type_error_;           // Set when a type error is detected.
331 
TypeError(Node * node,MachineTypeUnion output_type,MachineTypeUnion use)332   Node* TypeError(Node* node, MachineTypeUnion output_type,
333                   MachineTypeUnion use) {
334     type_error_ = true;
335     if (!testing_type_errors_) {
336       OStringStream out_str;
337       out_str << static_cast<MachineType>(output_type);
338 
339       OStringStream use_str;
340       use_str << static_cast<MachineType>(use);
341 
342       V8_Fatal(__FILE__, __LINE__,
343                "RepresentationChangerError: node #%d:%s of "
344                "%s cannot be changed to %s",
345                node->id(), node->op()->mnemonic(), out_str.c_str(),
346                use_str.c_str());
347     }
348     return node;
349   }
350 
jsgraph()351   JSGraph* jsgraph() { return jsgraph_; }
isolate()352   Isolate* isolate() { return isolate_; }
simplified()353   SimplifiedOperatorBuilder* simplified() { return simplified_; }
machine()354   MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
355 };
356 }
357 }
358 }  // namespace v8::internal::compiler
359 
360 #endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_
361