OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ | 5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ |
6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_ | 6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_ |
7 | 7 |
8 #include <sstream> | |
9 | |
10 #include "src/base/bits.h" | |
11 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
12 #include "src/compiler/machine-operator.h" | |
13 #include "src/compiler/simplified-operator.h" | 9 #include "src/compiler/simplified-operator.h" |
14 | 10 |
15 namespace v8 { | 11 namespace v8 { |
16 namespace internal { | 12 namespace internal { |
17 namespace compiler { | 13 namespace compiler { |
18 | 14 |
19 class Truncation final { | 15 class Truncation final { |
20 public: | 16 public: |
21 // Constructors. | 17 // Constructors. |
22 static Truncation None() { return Truncation(TruncationKind::kNone); } | 18 static Truncation None() { return Truncation(TruncationKind::kNone); } |
23 static Truncation Bool() { return Truncation(TruncationKind::kBool); } | 19 static Truncation Bool() { return Truncation(TruncationKind::kBool); } |
24 static Truncation Word32() { return Truncation(TruncationKind::kWord32); } | 20 static Truncation Word32() { return Truncation(TruncationKind::kWord32); } |
25 static Truncation Word64() { return Truncation(TruncationKind::kWord64); } | 21 static Truncation Word64() { return Truncation(TruncationKind::kWord64); } |
26 static Truncation Float32() { return Truncation(TruncationKind::kFloat32); } | 22 static Truncation Float32() { return Truncation(TruncationKind::kFloat32); } |
27 static Truncation Float64() { return Truncation(TruncationKind::kFloat64); } | 23 static Truncation Float64() { return Truncation(TruncationKind::kFloat64); } |
28 static Truncation Any() { return Truncation(TruncationKind::kAny); } | 24 static Truncation Any() { return Truncation(TruncationKind::kAny); } |
29 | 25 |
30 static Truncation Generalize(Truncation t1, Truncation t2) { | 26 static Truncation Generalize(Truncation t1, Truncation t2) { |
31 return Truncation(Generalize(t1.kind(), t2.kind())); | 27 return Truncation(Generalize(t1.kind(), t2.kind())); |
32 } | 28 } |
33 | 29 |
34 // Queries. | 30 // Queries. |
35 bool TruncatesToWord32() const { | 31 bool TruncatesToWord32() const { |
36 return LessGeneral(kind_, TruncationKind::kWord32); | 32 return LessGeneral(kind_, TruncationKind::kWord32); |
37 } | 33 } |
38 | |
39 bool TruncatesNaNToZero() { | 34 bool TruncatesNaNToZero() { |
40 return LessGeneral(kind_, TruncationKind::kWord32) || | 35 return LessGeneral(kind_, TruncationKind::kWord32) || |
41 LessGeneral(kind_, TruncationKind::kBool); | 36 LessGeneral(kind_, TruncationKind::kBool); |
42 } | 37 } |
43 | |
44 bool TruncatesUndefinedToZeroOrNaN() { | 38 bool TruncatesUndefinedToZeroOrNaN() { |
45 return LessGeneral(kind_, TruncationKind::kFloat64) || | 39 return LessGeneral(kind_, TruncationKind::kFloat64) || |
46 LessGeneral(kind_, TruncationKind::kWord64); | 40 LessGeneral(kind_, TruncationKind::kWord64); |
47 } | 41 } |
48 | 42 |
49 // Operators. | 43 // Operators. |
50 bool operator==(Truncation other) const { return kind() == other.kind(); } | 44 bool operator==(Truncation other) const { return kind() == other.kind(); } |
51 bool operator!=(Truncation other) const { return !(*this == other); } | 45 bool operator!=(Truncation other) const { return !(*this == other); } |
52 | 46 |
53 // Debug utilities. | 47 // Debug utilities. |
54 const char* description() { | 48 const char* description() const; |
55 switch (kind()) { | |
56 case TruncationKind::kNone: | |
57 return "no-value-use"; | |
58 case TruncationKind::kBool: | |
59 return "truncate-to-bool"; | |
60 case TruncationKind::kWord32: | |
61 return "truncate-to-word32"; | |
62 case TruncationKind::kWord64: | |
63 return "truncate-to-word64"; | |
64 case TruncationKind::kFloat32: | |
65 return "truncate-to-float32"; | |
66 case TruncationKind::kFloat64: | |
67 return "truncate-to-float64"; | |
68 case TruncationKind::kAny: | |
69 return "no-truncation"; | |
70 } | |
71 UNREACHABLE(); | |
72 return nullptr; | |
73 } | |
74 | 49 |
75 private: | 50 private: |
76 enum class TruncationKind : uint8_t { | 51 enum class TruncationKind : uint8_t { |
77 kNone, | 52 kNone, |
78 kBool, | 53 kBool, |
79 kWord32, | 54 kWord32, |
80 kWord64, | 55 kWord64, |
81 kFloat32, | 56 kFloat32, |
82 kFloat64, | 57 kFloat64, |
83 kAny | 58 kAny |
84 }; | 59 }; |
85 | 60 |
86 explicit Truncation(TruncationKind kind) : kind_(kind) {} | 61 explicit Truncation(TruncationKind kind) : kind_(kind) {} |
87 TruncationKind kind() const { return kind_; } | 62 TruncationKind kind() const { return kind_; } |
88 | 63 |
89 TruncationKind kind_; | 64 TruncationKind kind_; |
90 | 65 |
91 // Partial order for truncations: | 66 static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2); |
92 // | 67 static bool LessGeneral(TruncationKind rep1, TruncationKind rep2); |
93 // kWord64 kAny | |
94 // ^ ^ | |
95 // \ | | |
96 // \ kFloat64 <--+ | |
97 // \ ^ ^ | | |
98 // \ / | | | |
99 // kWord32 kFloat32 kBool | |
100 // ^ ^ ^ | |
101 // \ | / | |
102 // \ | / | |
103 // \ | / | |
104 // \ | / | |
105 // \ | / | |
106 // kNone | |
107 static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2) { | |
108 if (LessGeneral(rep1, rep2)) return rep2; | |
109 if (LessGeneral(rep2, rep1)) return rep1; | |
110 // Handle the generalization of float64-representable values. | |
111 if (LessGeneral(rep1, TruncationKind::kFloat64) && | |
112 LessGeneral(rep2, TruncationKind::kFloat64)) { | |
113 return TruncationKind::kFloat64; | |
114 } | |
115 // All other combinations are illegal. | |
116 FATAL("Tried to combine incompatible representations"); | |
117 return TruncationKind::kNone; | |
118 } | |
119 | |
120 static bool LessGeneral(TruncationKind rep1, TruncationKind rep2) { | |
121 switch (rep1) { | |
122 case TruncationKind::kNone: | |
123 return true; | |
124 case TruncationKind::kBool: | |
125 return rep2 == TruncationKind::kBool || rep2 == TruncationKind::kAny; | |
126 case TruncationKind::kWord32: | |
127 return rep2 == TruncationKind::kWord32 || | |
128 rep2 == TruncationKind::kWord64 || | |
129 rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny; | |
130 case TruncationKind::kWord64: | |
131 return rep2 == TruncationKind::kWord64; | |
132 case TruncationKind::kFloat32: | |
133 return rep2 == TruncationKind::kFloat32 || | |
134 rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny; | |
135 case TruncationKind::kFloat64: | |
136 return rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny; | |
137 case TruncationKind::kAny: | |
138 return rep2 == TruncationKind::kAny; | |
139 } | |
140 UNREACHABLE(); | |
141 return false; | |
142 } | |
143 }; | 68 }; |
144 | 69 |
145 | 70 |
146 // Contains logic related to changing the representation of values for constants | 71 // Contains logic related to changing the representation of values for constants |
147 // and other nodes, as well as lowering Simplified->Machine operators. | 72 // and other nodes, as well as lowering Simplified->Machine operators. |
148 // Eagerly folds any representation changes for constants. | 73 // Eagerly folds any representation changes for constants. |
149 class RepresentationChanger final { | 74 class RepresentationChanger final { |
150 public: | 75 public: |
151 RepresentationChanger(JSGraph* jsgraph, Isolate* isolate) | 76 RepresentationChanger(JSGraph* jsgraph, Isolate* isolate) |
152 : jsgraph_(jsgraph), | 77 : jsgraph_(jsgraph), |
153 isolate_(isolate), | 78 isolate_(isolate), |
154 testing_type_errors_(false), | 79 testing_type_errors_(false), |
155 type_error_(false) {} | 80 type_error_(false) {} |
156 | 81 |
157 // TODO(titzer): should Word64 also be implicitly convertable to others? | |
158 static bool IsWord(MachineTypeUnion type) { | |
159 return (type & (kRepWord8 | kRepWord16 | kRepWord32)) != 0; | |
160 } | |
161 | |
162 // Changes representation from {output_type} to {use_rep}. The {truncation} | 82 // Changes representation from {output_type} to {use_rep}. The {truncation} |
163 // parameter is only used for sanity checking - if the changer cannot figure | 83 // parameter is only used for sanity checking - if the changer cannot figure |
164 // out signedness for the word32->float64 conversion, then we check that the | 84 // out signedness for the word32->float64 conversion, then we check that the |
165 // uses truncate to word32 (so they do not care about signedness). | 85 // uses truncate to word32 (so they do not care about signedness). |
166 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, | 86 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, |
167 MachineTypeUnion use_rep, | 87 MachineTypeUnion use_rep, |
168 Truncation truncation = Truncation::None()) { | 88 Truncation truncation = Truncation::None()); |
169 DCHECK((use_rep & kRepMask) == use_rep); | 89 const Operator* Int32OperatorFor(IrOpcode::Value opcode); |
170 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { | 90 const Operator* Uint32OperatorFor(IrOpcode::Value opcode); |
171 // There should be only one output representation. | 91 const Operator* Float64OperatorFor(IrOpcode::Value opcode); |
172 return TypeError(node, output_type, use_rep); | 92 MachineType TypeFromUpperBound(Type* type); |
173 } | |
174 if (use_rep == (output_type & kRepMask)) { | |
175 // Representations are the same. That's a no-op. | |
176 return node; | |
177 } | |
178 if (IsWord(use_rep) && IsWord(output_type)) { | |
179 // Both are words less than or equal to 32-bits. | |
180 // Since loads of integers from memory implicitly sign or zero extend the | |
181 // value to the full machine word size and stores implicitly truncate, | |
182 // no representation change is necessary. | |
183 return node; | |
184 } | |
185 if (use_rep & kRepTagged) { | |
186 return GetTaggedRepresentationFor(node, output_type); | |
187 } else if (use_rep & kRepFloat32) { | |
188 return GetFloat32RepresentationFor(node, output_type, truncation); | |
189 } else if (use_rep & kRepFloat64) { | |
190 return GetFloat64RepresentationFor(node, output_type, truncation); | |
191 } else if (use_rep & kRepBit) { | |
192 return GetBitRepresentationFor(node, output_type); | |
193 } else if (IsWord(use_rep)) { | |
194 return GetWord32RepresentationFor(node, output_type); | |
195 } else if (use_rep & kRepWord64) { | |
196 return GetWord64RepresentationFor(node, output_type); | |
197 } else { | |
198 return node; | |
199 } | |
200 } | |
201 | |
202 Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) { | |
203 // Eagerly fold representation changes for constants. | |
204 switch (node->opcode()) { | |
205 case IrOpcode::kNumberConstant: | |
206 case IrOpcode::kHeapConstant: | |
207 return node; // No change necessary. | |
208 case IrOpcode::kInt32Constant: | |
209 if (output_type & kTypeUint32) { | |
210 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); | |
211 return jsgraph()->Constant(static_cast<double>(value)); | |
212 } else if (output_type & kTypeInt32) { | |
213 int32_t value = OpParameter<int32_t>(node); | |
214 return jsgraph()->Constant(value); | |
215 } else if (output_type & kRepBit) { | |
216 return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant() | |
217 : jsgraph()->TrueConstant(); | |
218 } else { | |
219 return TypeError(node, output_type, kRepTagged); | |
220 } | |
221 case IrOpcode::kFloat64Constant: | |
222 return jsgraph()->Constant(OpParameter<double>(node)); | |
223 case IrOpcode::kFloat32Constant: | |
224 return jsgraph()->Constant(OpParameter<float>(node)); | |
225 default: | |
226 break; | |
227 } | |
228 // Select the correct X -> Tagged operator. | |
229 const Operator* op; | |
230 if (output_type & kRepBit) { | |
231 op = simplified()->ChangeBitToBool(); | |
232 } else if (IsWord(output_type)) { | |
233 if (output_type & kTypeUint32) { | |
234 op = simplified()->ChangeUint32ToTagged(); | |
235 } else if (output_type & kTypeInt32) { | |
236 op = simplified()->ChangeInt32ToTagged(); | |
237 } else { | |
238 return TypeError(node, output_type, kRepTagged); | |
239 } | |
240 } else if (output_type & kRepFloat32) { // float32 -> float64 -> tagged | |
241 node = InsertChangeFloat32ToFloat64(node); | |
242 op = simplified()->ChangeFloat64ToTagged(); | |
243 } else if (output_type & kRepFloat64) { | |
244 op = simplified()->ChangeFloat64ToTagged(); | |
245 } else { | |
246 return TypeError(node, output_type, kRepTagged); | |
247 } | |
248 return jsgraph()->graph()->NewNode(op, node); | |
249 } | |
250 | |
251 Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type, | |
252 Truncation truncation) { | |
253 // Eagerly fold representation changes for constants. | |
254 switch (node->opcode()) { | |
255 case IrOpcode::kFloat64Constant: | |
256 case IrOpcode::kNumberConstant: | |
257 return jsgraph()->Float32Constant( | |
258 DoubleToFloat32(OpParameter<double>(node))); | |
259 case IrOpcode::kInt32Constant: | |
260 if (output_type & kTypeUint32) { | |
261 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); | |
262 return jsgraph()->Float32Constant(static_cast<float>(value)); | |
263 } else { | |
264 int32_t value = OpParameter<int32_t>(node); | |
265 return jsgraph()->Float32Constant(static_cast<float>(value)); | |
266 } | |
267 case IrOpcode::kFloat32Constant: | |
268 return node; // No change necessary. | |
269 default: | |
270 break; | |
271 } | |
272 // Select the correct X -> Float32 operator. | |
273 const Operator* op; | |
274 if (output_type & kRepBit) { | |
275 return TypeError(node, output_type, kRepFloat32); | |
276 } else if (IsWord(output_type)) { | |
277 if (output_type & kTypeUint32) { | |
278 op = machine()->ChangeUint32ToFloat64(); | |
279 } else { | |
280 // Either the output is int32 or the uses only care about the | |
281 // low 32 bits (so we can pick int32 safely). | |
282 DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32()); | |
283 op = machine()->ChangeInt32ToFloat64(); | |
284 } | |
285 // int32 -> float64 -> float32 | |
286 node = jsgraph()->graph()->NewNode(op, node); | |
287 op = machine()->TruncateFloat64ToFloat32(); | |
288 } else if (output_type & kRepTagged) { | |
289 op = simplified() | |
290 ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32 | |
291 node = jsgraph()->graph()->NewNode(op, node); | |
292 op = machine()->TruncateFloat64ToFloat32(); | |
293 } else if (output_type & kRepFloat64) { | |
294 op = machine()->TruncateFloat64ToFloat32(); | |
295 } else { | |
296 return TypeError(node, output_type, kRepFloat32); | |
297 } | |
298 return jsgraph()->graph()->NewNode(op, node); | |
299 } | |
300 | |
301 Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type, | |
302 Truncation truncation) { | |
303 // Eagerly fold representation changes for constants. | |
304 switch (node->opcode()) { | |
305 case IrOpcode::kNumberConstant: | |
306 return jsgraph()->Float64Constant(OpParameter<double>(node)); | |
307 case IrOpcode::kInt32Constant: | |
308 if (output_type & kTypeUint32) { | |
309 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); | |
310 return jsgraph()->Float64Constant(static_cast<double>(value)); | |
311 } else { | |
312 int32_t value = OpParameter<int32_t>(node); | |
313 return jsgraph()->Float64Constant(value); | |
314 } | |
315 case IrOpcode::kFloat64Constant: | |
316 return node; // No change necessary. | |
317 case IrOpcode::kFloat32Constant: | |
318 return jsgraph()->Float64Constant(OpParameter<float>(node)); | |
319 default: | |
320 break; | |
321 } | |
322 // Select the correct X -> Float64 operator. | |
323 const Operator* op; | |
324 if (output_type & kRepBit) { | |
325 return TypeError(node, output_type, kRepFloat64); | |
326 } else if (IsWord(output_type)) { | |
327 if (output_type & kTypeUint32) { | |
328 op = machine()->ChangeUint32ToFloat64(); | |
329 } else { | |
330 // Either the output is int32 or the uses only care about the | |
331 // low 32 bits (so we can pick int32 safely). | |
332 DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32()); | |
333 op = machine()->ChangeInt32ToFloat64(); | |
334 } | |
335 } else if (output_type & kRepTagged) { | |
336 op = simplified()->ChangeTaggedToFloat64(); | |
337 } else if (output_type & kRepFloat32) { | |
338 op = machine()->ChangeFloat32ToFloat64(); | |
339 } else { | |
340 return TypeError(node, output_type, kRepFloat64); | |
341 } | |
342 return jsgraph()->graph()->NewNode(op, node); | |
343 } | |
344 | |
345 Node* MakeTruncatedInt32Constant(double value) { | |
346 return jsgraph()->Int32Constant(DoubleToInt32(value)); | |
347 } | |
348 | |
349 Node* GetTruncatedWord32For(Node* node, MachineTypeUnion output_type) { | |
350 // Eagerly fold truncations for constants. | |
351 switch (node->opcode()) { | |
352 case IrOpcode::kInt32Constant: | |
353 return node; // No change necessary. | |
354 case IrOpcode::kFloat32Constant: | |
355 return jsgraph()->Int32Constant( | |
356 DoubleToInt32(OpParameter<float>(node))); | |
357 case IrOpcode::kNumberConstant: | |
358 case IrOpcode::kFloat64Constant: | |
359 return jsgraph()->Int32Constant( | |
360 DoubleToInt32(OpParameter<double>(node))); | |
361 default: | |
362 break; | |
363 } | |
364 // Select the correct X -> Word32 truncation operator. | |
365 const Operator* op = NULL; | |
366 if (output_type & kRepFloat64) { | |
367 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); | |
368 } else if (output_type & kRepFloat32) { | |
369 node = InsertChangeFloat32ToFloat64(node); | |
370 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); | |
371 } else if (output_type & kRepTagged) { | |
372 node = InsertChangeTaggedToFloat64(node); | |
373 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); | |
374 } else { | |
375 return TypeError(node, output_type, kRepWord32); | |
376 } | |
377 return jsgraph()->graph()->NewNode(op, node); | |
378 } | |
379 | |
380 Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type) { | |
381 // Eagerly fold representation changes for constants. | |
382 switch (node->opcode()) { | |
383 case IrOpcode::kInt32Constant: | |
384 return node; // No change necessary. | |
385 case IrOpcode::kFloat32Constant: | |
386 return MakeTruncatedInt32Constant(OpParameter<float>(node)); | |
387 case IrOpcode::kNumberConstant: | |
388 case IrOpcode::kFloat64Constant: | |
389 return MakeTruncatedInt32Constant(OpParameter<double>(node)); | |
390 default: | |
391 break; | |
392 } | |
393 // Select the correct X -> Word32 operator. | |
394 const Operator* op; | |
395 Type* type = NodeProperties::GetType(node); | |
396 | |
397 if (output_type & kRepBit) { | |
398 return node; // Sloppy comparison -> word32 | |
399 } else if (output_type & kRepFloat64) { | |
400 if (output_type & kTypeUint32 || type->Is(Type::Unsigned32())) { | |
401 op = machine()->ChangeFloat64ToUint32(); | |
402 } else if (output_type & kTypeInt32 || type->Is(Type::Signed32())) { | |
403 op = machine()->ChangeFloat64ToInt32(); | |
404 } else { | |
405 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); | |
406 } | |
407 } else if (output_type & kRepFloat32) { | |
408 node = InsertChangeFloat32ToFloat64(node); // float32 -> float64 -> int32 | |
409 if (output_type & kTypeUint32 || type->Is(Type::Unsigned32())) { | |
410 op = machine()->ChangeFloat64ToUint32(); | |
411 } else if (output_type & kTypeInt32 || type->Is(Type::Signed32())) { | |
412 op = machine()->ChangeFloat64ToInt32(); | |
413 } else { | |
414 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); | |
415 } | |
416 } else if (output_type & kRepTagged) { | |
417 if (output_type & kTypeUint32 || type->Is(Type::Unsigned32())) { | |
418 op = simplified()->ChangeTaggedToUint32(); | |
419 } else if (output_type & kTypeInt32 || type->Is(Type::Signed32())) { | |
420 op = simplified()->ChangeTaggedToInt32(); | |
421 } else { | |
422 node = InsertChangeTaggedToFloat64(node); | |
423 op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript); | |
424 } | |
425 } else { | |
426 return TypeError(node, output_type, kRepWord32); | |
427 } | |
428 return jsgraph()->graph()->NewNode(op, node); | |
429 } | |
430 | |
431 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type) { | |
432 // Eagerly fold representation changes for constants. | |
433 switch (node->opcode()) { | |
434 case IrOpcode::kHeapConstant: { | |
435 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node); | |
436 DCHECK(value.is_identical_to(factory()->true_value()) || | |
437 value.is_identical_to(factory()->false_value())); | |
438 return jsgraph()->Int32Constant( | |
439 value.is_identical_to(factory()->true_value()) ? 1 : 0); | |
440 } | |
441 default: | |
442 break; | |
443 } | |
444 // Select the correct X -> Bit operator. | |
445 const Operator* op; | |
446 if (output_type & kRepTagged) { | |
447 op = simplified()->ChangeBoolToBit(); | |
448 } else { | |
449 return TypeError(node, output_type, kRepBit); | |
450 } | |
451 return jsgraph()->graph()->NewNode(op, node); | |
452 } | |
453 | |
454 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type) { | |
455 if (output_type & kRepBit) { | |
456 return node; // Sloppy comparison -> word64 | |
457 } | |
458 // Can't really convert Word64 to anything else. Purported to be internal. | |
459 return TypeError(node, output_type, kRepWord64); | |
460 } | |
461 | |
462 const Operator* Int32OperatorFor(IrOpcode::Value opcode) { | |
463 switch (opcode) { | |
464 case IrOpcode::kNumberAdd: | |
465 return machine()->Int32Add(); | |
466 case IrOpcode::kNumberSubtract: | |
467 return machine()->Int32Sub(); | |
468 case IrOpcode::kNumberMultiply: | |
469 return machine()->Int32Mul(); | |
470 case IrOpcode::kNumberDivide: | |
471 return machine()->Int32Div(); | |
472 case IrOpcode::kNumberModulus: | |
473 return machine()->Int32Mod(); | |
474 case IrOpcode::kNumberBitwiseOr: | |
475 return machine()->Word32Or(); | |
476 case IrOpcode::kNumberBitwiseXor: | |
477 return machine()->Word32Xor(); | |
478 case IrOpcode::kNumberBitwiseAnd: | |
479 return machine()->Word32And(); | |
480 case IrOpcode::kNumberEqual: | |
481 return machine()->Word32Equal(); | |
482 case IrOpcode::kNumberLessThan: | |
483 return machine()->Int32LessThan(); | |
484 case IrOpcode::kNumberLessThanOrEqual: | |
485 return machine()->Int32LessThanOrEqual(); | |
486 default: | |
487 UNREACHABLE(); | |
488 return NULL; | |
489 } | |
490 } | |
491 | |
492 const Operator* Uint32OperatorFor(IrOpcode::Value opcode) { | |
493 switch (opcode) { | |
494 case IrOpcode::kNumberAdd: | |
495 return machine()->Int32Add(); | |
496 case IrOpcode::kNumberSubtract: | |
497 return machine()->Int32Sub(); | |
498 case IrOpcode::kNumberMultiply: | |
499 return machine()->Int32Mul(); | |
500 case IrOpcode::kNumberDivide: | |
501 return machine()->Uint32Div(); | |
502 case IrOpcode::kNumberModulus: | |
503 return machine()->Uint32Mod(); | |
504 case IrOpcode::kNumberEqual: | |
505 return machine()->Word32Equal(); | |
506 case IrOpcode::kNumberLessThan: | |
507 return machine()->Uint32LessThan(); | |
508 case IrOpcode::kNumberLessThanOrEqual: | |
509 return machine()->Uint32LessThanOrEqual(); | |
510 default: | |
511 UNREACHABLE(); | |
512 return NULL; | |
513 } | |
514 } | |
515 | |
516 const Operator* Float64OperatorFor(IrOpcode::Value opcode) { | |
517 switch (opcode) { | |
518 case IrOpcode::kNumberAdd: | |
519 return machine()->Float64Add(); | |
520 case IrOpcode::kNumberSubtract: | |
521 return machine()->Float64Sub(); | |
522 case IrOpcode::kNumberMultiply: | |
523 return machine()->Float64Mul(); | |
524 case IrOpcode::kNumberDivide: | |
525 return machine()->Float64Div(); | |
526 case IrOpcode::kNumberModulus: | |
527 return machine()->Float64Mod(); | |
528 case IrOpcode::kNumberEqual: | |
529 return machine()->Float64Equal(); | |
530 case IrOpcode::kNumberLessThan: | |
531 return machine()->Float64LessThan(); | |
532 case IrOpcode::kNumberLessThanOrEqual: | |
533 return machine()->Float64LessThanOrEqual(); | |
534 default: | |
535 UNREACHABLE(); | |
536 return NULL; | |
537 } | |
538 } | |
539 | 93 |
540 MachineType TypeForBasePointer(const FieldAccess& access) { | 94 MachineType TypeForBasePointer(const FieldAccess& access) { |
541 return access.tag() != 0 ? kMachAnyTagged : kMachPtr; | 95 return access.tag() != 0 ? kMachAnyTagged : kMachPtr; |
542 } | 96 } |
543 | 97 |
544 MachineType TypeForBasePointer(const ElementAccess& access) { | 98 MachineType TypeForBasePointer(const ElementAccess& access) { |
545 return access.tag() != 0 ? kMachAnyTagged : kMachPtr; | 99 return access.tag() != 0 ? kMachAnyTagged : kMachPtr; |
546 } | 100 } |
547 | 101 |
548 MachineType TypeFromUpperBound(Type* type) { | |
549 if (type->Is(Type::None())) | |
550 return kTypeAny; // TODO(titzer): should be an error | |
551 if (type->Is(Type::Signed32())) return kTypeInt32; | |
552 if (type->Is(Type::Unsigned32())) return kTypeUint32; | |
553 if (type->Is(Type::Number())) return kTypeNumber; | |
554 if (type->Is(Type::Boolean())) return kTypeBool; | |
555 return kTypeAny; | |
556 } | |
557 | |
558 private: | 102 private: |
559 JSGraph* jsgraph_; | 103 JSGraph* jsgraph_; |
560 Isolate* isolate_; | 104 Isolate* isolate_; |
561 | 105 |
562 friend class RepresentationChangerTester; // accesses the below fields. | 106 friend class RepresentationChangerTester; // accesses the below fields. |
563 | 107 |
564 bool testing_type_errors_; // If {true}, don't abort on a type error. | 108 bool testing_type_errors_; // If {true}, don't abort on a type error. |
565 bool type_error_; // Set when a type error is detected. | 109 bool type_error_; // Set when a type error is detected. |
566 | 110 |
| 111 Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type); |
| 112 Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type, |
| 113 Truncation truncation); |
| 114 Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type, |
| 115 Truncation truncation); |
| 116 Node* GetWord32RepresentationFor(Node* node, MachineTypeUnion output_type); |
| 117 Node* GetBitRepresentationFor(Node* node, MachineTypeUnion output_type); |
| 118 Node* GetWord64RepresentationFor(Node* node, MachineTypeUnion output_type); |
567 Node* TypeError(Node* node, MachineTypeUnion output_type, | 119 Node* TypeError(Node* node, MachineTypeUnion output_type, |
568 MachineTypeUnion use) { | 120 MachineTypeUnion use); |
569 type_error_ = true; | 121 Node* MakeTruncatedInt32Constant(double value); |
570 if (!testing_type_errors_) { | 122 Node* InsertChangeFloat32ToFloat64(Node* node); |
571 std::ostringstream out_str; | 123 Node* InsertChangeTaggedToFloat64(Node* node); |
572 out_str << static_cast<MachineType>(output_type); | |
573 | |
574 std::ostringstream use_str; | |
575 use_str << static_cast<MachineType>(use); | |
576 | |
577 V8_Fatal(__FILE__, __LINE__, | |
578 "RepresentationChangerError: node #%d:%s of " | |
579 "%s cannot be changed to %s", | |
580 node->id(), node->op()->mnemonic(), out_str.str().c_str(), | |
581 use_str.str().c_str()); | |
582 } | |
583 return node; | |
584 } | |
585 | |
586 Node* InsertChangeFloat32ToFloat64(Node* node) { | |
587 return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), | |
588 node); | |
589 } | |
590 | |
591 Node* InsertChangeTaggedToFloat64(Node* node) { | |
592 return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(), | |
593 node); | |
594 } | |
595 | 124 |
596 JSGraph* jsgraph() const { return jsgraph_; } | 125 JSGraph* jsgraph() const { return jsgraph_; } |
597 Isolate* isolate() const { return isolate_; } | 126 Isolate* isolate() const { return isolate_; } |
598 Factory* factory() const { return isolate()->factory(); } | 127 Factory* factory() const { return isolate()->factory(); } |
599 SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } | 128 SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } |
600 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } | 129 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } |
601 }; | 130 }; |
602 | 131 |
603 } // namespace compiler | 132 } // namespace compiler |
604 } // namespace internal | 133 } // namespace internal |
605 } // namespace v8 | 134 } // namespace v8 |
606 | 135 |
607 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ | 136 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ |
OLD | NEW |