| 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 |