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> | 8 #include <sstream> |
9 | 9 |
10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
11 #include "src/compiler/js-graph.h" | 11 #include "src/compiler/js-graph.h" |
12 #include "src/compiler/machine-operator.h" | 12 #include "src/compiler/machine-operator.h" |
13 #include "src/compiler/simplified-operator.h" | 13 #include "src/compiler/simplified-operator.h" |
14 | 14 |
15 namespace v8 { | 15 namespace v8 { |
16 namespace internal { | 16 namespace internal { |
17 namespace compiler { | 17 namespace compiler { |
18 | 18 |
| 19 class Truncation final { |
| 20 public: |
| 21 // Constructors. |
| 22 static Truncation None() { return Truncation(TruncationKind::kNone); } |
| 23 static Truncation Bool() { return Truncation(TruncationKind::kBool); } |
| 24 static Truncation Word32() { return Truncation(TruncationKind::kWord32); } |
| 25 static Truncation Word64() { return Truncation(TruncationKind::kWord64); } |
| 26 static Truncation Float32() { return Truncation(TruncationKind::kFloat32); } |
| 27 static Truncation Float64() { return Truncation(TruncationKind::kFloat64); } |
| 28 static Truncation Any() { return Truncation(TruncationKind::kAny); } |
| 29 |
| 30 static Truncation Generalize(Truncation t1, Truncation t2) { |
| 31 return Truncation(Generalize(t1.kind(), t2.kind())); |
| 32 } |
| 33 |
| 34 // Queries. |
| 35 bool TruncatesToWord32() const { |
| 36 return LessGeneral(kind_, TruncationKind::kWord32); |
| 37 } |
| 38 |
| 39 bool TruncatesNaNToZero() { |
| 40 return LessGeneral(kind_, TruncationKind::kWord32) || |
| 41 LessGeneral(kind_, TruncationKind::kBool); |
| 42 } |
| 43 |
| 44 bool TruncatesUndefinedToZeroOrNaN() { |
| 45 return LessGeneral(kind_, TruncationKind::kFloat64) || |
| 46 LessGeneral(kind_, TruncationKind::kWord64); |
| 47 } |
| 48 |
| 49 // Operators. |
| 50 bool operator==(Truncation other) const { return kind() == other.kind(); } |
| 51 bool operator!=(Truncation other) const { return !(*this == other); } |
| 52 |
| 53 // Debug utilities. |
| 54 const char* description() { |
| 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 |
| 75 private: |
| 76 enum class TruncationKind : uint8_t { |
| 77 kNone, |
| 78 kBool, |
| 79 kWord32, |
| 80 kWord64, |
| 81 kFloat32, |
| 82 kFloat64, |
| 83 kAny |
| 84 }; |
| 85 |
| 86 explicit Truncation(TruncationKind kind) : kind_(kind) {} |
| 87 TruncationKind kind() const { return kind_; } |
| 88 |
| 89 TruncationKind kind_; |
| 90 |
| 91 // Partial order for truncations: |
| 92 // |
| 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 }; |
| 144 |
| 145 |
19 // Contains logic related to changing the representation of values for constants | 146 // Contains logic related to changing the representation of values for constants |
20 // and other nodes, as well as lowering Simplified->Machine operators. | 147 // and other nodes, as well as lowering Simplified->Machine operators. |
21 // Eagerly folds any representation changes for constants. | 148 // Eagerly folds any representation changes for constants. |
22 class RepresentationChanger { | 149 class RepresentationChanger final { |
23 public: | 150 public: |
24 RepresentationChanger(JSGraph* jsgraph, Isolate* isolate) | 151 RepresentationChanger(JSGraph* jsgraph, Isolate* isolate) |
25 : jsgraph_(jsgraph), | 152 : jsgraph_(jsgraph), |
26 isolate_(isolate), | 153 isolate_(isolate), |
27 testing_type_errors_(false), | 154 testing_type_errors_(false), |
28 type_error_(false) {} | 155 type_error_(false) {} |
29 | 156 |
30 // TODO(titzer): should Word64 also be implicitly convertable to others? | 157 // TODO(titzer): should Word64 also be implicitly convertable to others? |
31 static bool IsWord(MachineTypeUnion type) { | 158 static bool IsWord(MachineTypeUnion type) { |
32 return (type & (kRepWord8 | kRepWord16 | kRepWord32)) != 0; | 159 return (type & (kRepWord8 | kRepWord16 | kRepWord32)) != 0; |
33 } | 160 } |
34 | 161 |
| 162 // Changes representation from {output_type} to {use_rep}. The {truncation} |
| 163 // 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 |
| 165 // uses truncate to word32 (so they do not care about signedness). |
35 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, | 166 Node* GetRepresentationFor(Node* node, MachineTypeUnion output_type, |
36 MachineTypeUnion use_type) { | 167 MachineTypeUnion use_rep, |
| 168 Truncation truncation = Truncation::None()) { |
| 169 DCHECK((use_rep & kRepMask) == use_rep); |
37 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { | 170 if (!base::bits::IsPowerOfTwo32(output_type & kRepMask)) { |
38 // There should be only one output representation. | 171 // There should be only one output representation. |
39 return TypeError(node, output_type, use_type); | 172 return TypeError(node, output_type, use_rep); |
40 } | 173 } |
41 if ((use_type & kRepMask) == (output_type & kRepMask)) { | 174 if (use_rep == (output_type & kRepMask)) { |
42 // Representations are the same. That's a no-op. | 175 // Representations are the same. That's a no-op. |
43 return node; | 176 return node; |
44 } | 177 } |
45 if (IsWord(use_type) && IsWord(output_type)) { | 178 if (IsWord(use_rep) && IsWord(output_type)) { |
46 // Both are words less than or equal to 32-bits. | 179 // Both are words less than or equal to 32-bits. |
47 // Since loads of integers from memory implicitly sign or zero extend the | 180 // Since loads of integers from memory implicitly sign or zero extend the |
48 // value to the full machine word size and stores implicitly truncate, | 181 // value to the full machine word size and stores implicitly truncate, |
49 // no representation change is necessary. | 182 // no representation change is necessary. |
50 return node; | 183 return node; |
51 } | 184 } |
52 if (use_type & kRepTagged) { | 185 if (use_rep & kRepTagged) { |
53 return GetTaggedRepresentationFor(node, output_type); | 186 return GetTaggedRepresentationFor(node, output_type); |
54 } else if (use_type & kRepFloat32) { | 187 } else if (use_rep & kRepFloat32) { |
55 return GetFloat32RepresentationFor(node, output_type, use_type); | 188 return GetFloat32RepresentationFor(node, output_type, truncation); |
56 } else if (use_type & kRepFloat64) { | 189 } else if (use_rep & kRepFloat64) { |
57 return GetFloat64RepresentationFor(node, output_type, use_type); | 190 return GetFloat64RepresentationFor(node, output_type, truncation); |
58 } else if (use_type & kRepBit) { | 191 } else if (use_rep & kRepBit) { |
59 return GetBitRepresentationFor(node, output_type); | 192 return GetBitRepresentationFor(node, output_type); |
60 } else if (IsWord(use_type)) { | 193 } else if (IsWord(use_rep)) { |
61 return GetWord32RepresentationFor(node, output_type); | 194 return GetWord32RepresentationFor(node, output_type); |
62 } else if (use_type & kRepWord64) { | 195 } else if (use_rep & kRepWord64) { |
63 return GetWord64RepresentationFor(node, output_type); | 196 return GetWord64RepresentationFor(node, output_type); |
64 } else { | 197 } else { |
65 return node; | 198 return node; |
66 } | 199 } |
67 } | 200 } |
68 | 201 |
69 Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) { | 202 Node* GetTaggedRepresentationFor(Node* node, MachineTypeUnion output_type) { |
70 // Eagerly fold representation changes for constants. | 203 // Eagerly fold representation changes for constants. |
71 switch (node->opcode()) { | 204 switch (node->opcode()) { |
72 case IrOpcode::kNumberConstant: | 205 case IrOpcode::kNumberConstant: |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 op = simplified()->ChangeFloat64ToTagged(); | 242 op = simplified()->ChangeFloat64ToTagged(); |
110 } else if (output_type & kRepFloat64) { | 243 } else if (output_type & kRepFloat64) { |
111 op = simplified()->ChangeFloat64ToTagged(); | 244 op = simplified()->ChangeFloat64ToTagged(); |
112 } else { | 245 } else { |
113 return TypeError(node, output_type, kRepTagged); | 246 return TypeError(node, output_type, kRepTagged); |
114 } | 247 } |
115 return jsgraph()->graph()->NewNode(op, node); | 248 return jsgraph()->graph()->NewNode(op, node); |
116 } | 249 } |
117 | 250 |
118 Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type, | 251 Node* GetFloat32RepresentationFor(Node* node, MachineTypeUnion output_type, |
119 MachineTypeUnion truncation) { | 252 Truncation truncation) { |
120 // Eagerly fold representation changes for constants. | 253 // Eagerly fold representation changes for constants. |
121 switch (node->opcode()) { | 254 switch (node->opcode()) { |
122 case IrOpcode::kFloat64Constant: | 255 case IrOpcode::kFloat64Constant: |
123 case IrOpcode::kNumberConstant: | 256 case IrOpcode::kNumberConstant: |
124 return jsgraph()->Float32Constant( | 257 return jsgraph()->Float32Constant( |
125 DoubleToFloat32(OpParameter<double>(node))); | 258 DoubleToFloat32(OpParameter<double>(node))); |
126 case IrOpcode::kInt32Constant: | 259 case IrOpcode::kInt32Constant: |
127 if (output_type & kTypeUint32) { | 260 if (output_type & kTypeUint32) { |
128 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); | 261 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
129 return jsgraph()->Float32Constant(static_cast<float>(value)); | 262 return jsgraph()->Float32Constant(static_cast<float>(value)); |
130 } else { | 263 } else { |
131 int32_t value = OpParameter<int32_t>(node); | 264 int32_t value = OpParameter<int32_t>(node); |
132 return jsgraph()->Float32Constant(static_cast<float>(value)); | 265 return jsgraph()->Float32Constant(static_cast<float>(value)); |
133 } | 266 } |
134 case IrOpcode::kFloat32Constant: | 267 case IrOpcode::kFloat32Constant: |
135 return node; // No change necessary. | 268 return node; // No change necessary. |
136 default: | 269 default: |
137 break; | 270 break; |
138 } | 271 } |
139 // Select the correct X -> Float32 operator. | 272 // Select the correct X -> Float32 operator. |
140 const Operator* op; | 273 const Operator* op; |
141 if (output_type & kRepBit) { | 274 if (output_type & kRepBit) { |
142 return TypeError(node, output_type, kRepFloat32); | 275 return TypeError(node, output_type, kRepFloat32); |
143 } else if (IsWord(output_type)) { | 276 } else if (IsWord(output_type)) { |
144 if (output_type & kTypeUint32) { | 277 if (output_type & kTypeUint32) { |
145 op = machine()->ChangeUint32ToFloat64(); | 278 op = machine()->ChangeUint32ToFloat64(); |
146 } else { | 279 } else { |
147 // Either the output is int32 or the uses only care about the | 280 // Either the output is int32 or the uses only care about the |
148 // low 32 bits (so we can pick int32 safely). | 281 // low 32 bits (so we can pick int32 safely). |
149 DCHECK(output_type & kTypeInt32 || | 282 DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32()); |
150 !(truncation & ~(kTypeInt32 | kTypeUint32 | kRepMask))); | |
151 op = machine()->ChangeInt32ToFloat64(); | 283 op = machine()->ChangeInt32ToFloat64(); |
152 } | 284 } |
153 // int32 -> float64 -> float32 | 285 // int32 -> float64 -> float32 |
154 node = jsgraph()->graph()->NewNode(op, node); | 286 node = jsgraph()->graph()->NewNode(op, node); |
155 op = machine()->TruncateFloat64ToFloat32(); | 287 op = machine()->TruncateFloat64ToFloat32(); |
156 } else if (output_type & kRepTagged) { | 288 } else if (output_type & kRepTagged) { |
157 op = simplified() | 289 op = simplified() |
158 ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32 | 290 ->ChangeTaggedToFloat64(); // tagged -> float64 -> float32 |
159 node = jsgraph()->graph()->NewNode(op, node); | 291 node = jsgraph()->graph()->NewNode(op, node); |
160 op = machine()->TruncateFloat64ToFloat32(); | 292 op = machine()->TruncateFloat64ToFloat32(); |
161 } else if (output_type & kRepFloat64) { | 293 } else if (output_type & kRepFloat64) { |
162 op = machine()->TruncateFloat64ToFloat32(); | 294 op = machine()->TruncateFloat64ToFloat32(); |
163 } else { | 295 } else { |
164 return TypeError(node, output_type, kRepFloat32); | 296 return TypeError(node, output_type, kRepFloat32); |
165 } | 297 } |
166 return jsgraph()->graph()->NewNode(op, node); | 298 return jsgraph()->graph()->NewNode(op, node); |
167 } | 299 } |
168 | 300 |
169 Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type, | 301 Node* GetFloat64RepresentationFor(Node* node, MachineTypeUnion output_type, |
170 MachineTypeUnion use_type) { | 302 Truncation truncation) { |
171 // Eagerly fold representation changes for constants. | 303 // Eagerly fold representation changes for constants. |
172 switch (node->opcode()) { | 304 switch (node->opcode()) { |
173 case IrOpcode::kNumberConstant: | 305 case IrOpcode::kNumberConstant: |
174 return jsgraph()->Float64Constant(OpParameter<double>(node)); | 306 return jsgraph()->Float64Constant(OpParameter<double>(node)); |
175 case IrOpcode::kInt32Constant: | 307 case IrOpcode::kInt32Constant: |
176 if (output_type & kTypeUint32) { | 308 if (output_type & kTypeUint32) { |
177 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); | 309 uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node)); |
178 return jsgraph()->Float64Constant(static_cast<double>(value)); | 310 return jsgraph()->Float64Constant(static_cast<double>(value)); |
179 } else { | 311 } else { |
180 int32_t value = OpParameter<int32_t>(node); | 312 int32_t value = OpParameter<int32_t>(node); |
181 return jsgraph()->Float64Constant(value); | 313 return jsgraph()->Float64Constant(value); |
182 } | 314 } |
183 case IrOpcode::kFloat64Constant: | 315 case IrOpcode::kFloat64Constant: |
184 return node; // No change necessary. | 316 return node; // No change necessary. |
185 case IrOpcode::kFloat32Constant: | 317 case IrOpcode::kFloat32Constant: |
186 return jsgraph()->Float64Constant(OpParameter<float>(node)); | 318 return jsgraph()->Float64Constant(OpParameter<float>(node)); |
187 default: | 319 default: |
188 break; | 320 break; |
189 } | 321 } |
190 // Select the correct X -> Float64 operator. | 322 // Select the correct X -> Float64 operator. |
191 const Operator* op; | 323 const Operator* op; |
192 if (output_type & kRepBit) { | 324 if (output_type & kRepBit) { |
193 return TypeError(node, output_type, kRepFloat64); | 325 return TypeError(node, output_type, kRepFloat64); |
194 } else if (IsWord(output_type)) { | 326 } else if (IsWord(output_type)) { |
195 if (output_type & kTypeUint32) { | 327 if (output_type & kTypeUint32) { |
196 op = machine()->ChangeUint32ToFloat64(); | 328 op = machine()->ChangeUint32ToFloat64(); |
197 } else { | 329 } else { |
198 // Either the output is int32 or the uses only care about the | 330 // Either the output is int32 or the uses only care about the |
199 // low 32 bits (so we can pick int32 safely). | 331 // low 32 bits (so we can pick int32 safely). |
200 DCHECK(output_type & kTypeInt32 || | 332 DCHECK(output_type & kTypeInt32 || truncation.TruncatesToWord32()); |
201 !(use_type & ~(kTypeInt32 | kTypeUint32 | kRepMask))); | |
202 op = machine()->ChangeInt32ToFloat64(); | 333 op = machine()->ChangeInt32ToFloat64(); |
203 } | 334 } |
204 } else if (output_type & kRepTagged) { | 335 } else if (output_type & kRepTagged) { |
205 op = simplified()->ChangeTaggedToFloat64(); | 336 op = simplified()->ChangeTaggedToFloat64(); |
206 } else if (output_type & kRepFloat32) { | 337 } else if (output_type & kRepFloat32) { |
207 op = machine()->ChangeFloat32ToFloat64(); | 338 op = machine()->ChangeFloat32ToFloat64(); |
208 } else { | 339 } else { |
209 return TypeError(node, output_type, kRepFloat64); | 340 return TypeError(node, output_type, kRepFloat64); |
210 } | 341 } |
211 return jsgraph()->graph()->NewNode(op, node); | 342 return jsgraph()->graph()->NewNode(op, node); |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 Factory* factory() const { return isolate()->factory(); } | 598 Factory* factory() const { return isolate()->factory(); } |
468 SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } | 599 SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } |
469 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } | 600 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } |
470 }; | 601 }; |
471 | 602 |
472 } // namespace compiler | 603 } // namespace compiler |
473 } // namespace internal | 604 } // namespace internal |
474 } // namespace v8 | 605 } // namespace v8 |
475 | 606 |
476 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ | 607 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ |
OLD | NEW |