1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_ 6 #define V8_COMPILER_REPRESENTATION_CHANGE_H_ 7 8 #include "src/compiler/js-graph.h" 9 #include "src/compiler/simplified-operator.h" 10 11 namespace v8 { 12 namespace internal { 13 namespace compiler { 14 15 enum IdentifyZeros { kIdentifyZeros, kDistinguishZeros }; 16 17 class Truncation final { 18 public: 19 // Constructors. None()20 static Truncation None() { 21 return Truncation(TruncationKind::kNone, kIdentifyZeros); 22 } Bool()23 static Truncation Bool() { 24 return Truncation(TruncationKind::kBool, kIdentifyZeros); 25 } Word32()26 static Truncation Word32() { 27 return Truncation(TruncationKind::kWord32, kIdentifyZeros); 28 } Word64()29 static Truncation Word64() { 30 return Truncation(TruncationKind::kWord64, kIdentifyZeros); 31 } 32 static Truncation Float64(IdentifyZeros identify_zeros = kDistinguishZeros) { 33 return Truncation(TruncationKind::kFloat64, identify_zeros); 34 } 35 static Truncation Any(IdentifyZeros identify_zeros = kDistinguishZeros) { 36 return Truncation(TruncationKind::kAny, identify_zeros); 37 } 38 Generalize(Truncation t1,Truncation t2)39 static Truncation Generalize(Truncation t1, Truncation t2) { 40 return Truncation( 41 Generalize(t1.kind(), t2.kind()), 42 GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros())); 43 } 44 45 // Queries. IsUnused()46 bool IsUnused() const { return kind_ == TruncationKind::kNone; } IsUsedAsBool()47 bool IsUsedAsBool() const { 48 return LessGeneral(kind_, TruncationKind::kBool); 49 } IsUsedAsWord32()50 bool IsUsedAsWord32() const { 51 return LessGeneral(kind_, TruncationKind::kWord32); 52 } IsUsedAsFloat64()53 bool IsUsedAsFloat64() const { 54 return LessGeneral(kind_, TruncationKind::kFloat64); 55 } IdentifiesUndefinedAndZero()56 bool IdentifiesUndefinedAndZero() { 57 return LessGeneral(kind_, TruncationKind::kWord32) || 58 LessGeneral(kind_, TruncationKind::kBool); 59 } IdentifiesUndefinedAndNaN()60 bool IdentifiesUndefinedAndNaN() { 61 return LessGeneral(kind_, TruncationKind::kFloat64) || 62 LessGeneral(kind_, TruncationKind::kWord64); 63 } IdentifiesZeroAndMinusZero()64 bool IdentifiesZeroAndMinusZero() const { 65 return identify_zeros() == kIdentifyZeros; 66 } 67 68 // Operators. 69 bool operator==(Truncation other) const { 70 return kind() == other.kind() && identify_zeros() == other.identify_zeros(); 71 } 72 bool operator!=(Truncation other) const { return !(*this == other); } 73 74 // Debug utilities. 75 const char* description() const; IsLessGeneralThan(Truncation other)76 bool IsLessGeneralThan(Truncation other) { 77 return LessGeneral(kind(), other.kind()) && 78 LessGeneralIdentifyZeros(identify_zeros(), other.identify_zeros()); 79 } 80 identify_zeros()81 IdentifyZeros identify_zeros() const { return identify_zeros_; } 82 83 private: 84 enum class TruncationKind : uint8_t { 85 kNone, 86 kBool, 87 kWord32, 88 kWord64, 89 kFloat64, 90 kAny 91 }; 92 Truncation(TruncationKind kind,IdentifyZeros identify_zeros)93 explicit Truncation(TruncationKind kind, IdentifyZeros identify_zeros) 94 : kind_(kind), identify_zeros_(identify_zeros) { 95 DCHECK(kind == TruncationKind::kAny || kind == TruncationKind::kFloat64 || 96 identify_zeros == kIdentifyZeros); 97 } kind()98 TruncationKind kind() const { return kind_; } 99 100 TruncationKind kind_; 101 IdentifyZeros identify_zeros_; 102 103 static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2); 104 static IdentifyZeros GeneralizeIdentifyZeros(IdentifyZeros i1, 105 IdentifyZeros i2); 106 static bool LessGeneral(TruncationKind rep1, TruncationKind rep2); 107 static bool LessGeneralIdentifyZeros(IdentifyZeros u1, IdentifyZeros u2); 108 }; 109 110 enum class TypeCheckKind : uint8_t { 111 kNone, 112 kSignedSmall, 113 kSigned32, 114 kNumber, 115 kNumberOrOddball, 116 kHeapObject 117 }; 118 119 inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) { 120 switch (type_check) { 121 case TypeCheckKind::kNone: 122 return os << "None"; 123 case TypeCheckKind::kSignedSmall: 124 return os << "SignedSmall"; 125 case TypeCheckKind::kSigned32: 126 return os << "Signed32"; 127 case TypeCheckKind::kNumber: 128 return os << "Number"; 129 case TypeCheckKind::kNumberOrOddball: 130 return os << "NumberOrOddball"; 131 case TypeCheckKind::kHeapObject: 132 return os << "HeapObject"; 133 } 134 UNREACHABLE(); 135 } 136 137 // The {UseInfo} class is used to describe a use of an input of a node. 138 // 139 // This information is used in two different ways, based on the phase: 140 // 141 // 1. During propagation, the use info is used to inform the input node 142 // about what part of the input is used (we call this truncation) and what 143 // is the preferred representation. For conversions that will require 144 // checks, we also keep track of whether a minus zero check is needed. 145 // 146 // 2. During lowering, the use info is used to properly convert the input 147 // to the preferred representation. The preferred representation might be 148 // insufficient to do the conversion (e.g. word32->float64 conv), so we also 149 // need the signedness information to produce the correct value. 150 // Additionally, use info may contain {CheckParameters} which contains 151 // information for the deoptimizer such as a CallIC on which speculation 152 // should be disallowed if the check fails. 153 class UseInfo { 154 public: 155 UseInfo(MachineRepresentation representation, Truncation truncation, 156 TypeCheckKind type_check = TypeCheckKind::kNone, 157 const VectorSlotPair& feedback = VectorSlotPair()) representation_(representation)158 : representation_(representation), 159 truncation_(truncation), 160 type_check_(type_check), 161 feedback_(feedback) {} TruncatingWord32()162 static UseInfo TruncatingWord32() { 163 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32()); 164 } TruncatingWord64()165 static UseInfo TruncatingWord64() { 166 return UseInfo(MachineRepresentation::kWord64, Truncation::Word64()); 167 } Bool()168 static UseInfo Bool() { 169 return UseInfo(MachineRepresentation::kBit, Truncation::Bool()); 170 } Float32()171 static UseInfo Float32() { 172 return UseInfo(MachineRepresentation::kFloat32, Truncation::Any()); 173 } TruncatingFloat64()174 static UseInfo TruncatingFloat64() { 175 return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64()); 176 } PointerInt()177 static UseInfo PointerInt() { 178 return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64(); 179 } AnyTagged()180 static UseInfo AnyTagged() { 181 return UseInfo(MachineRepresentation::kTagged, Truncation::Any()); 182 } TaggedSigned()183 static UseInfo TaggedSigned() { 184 return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any()); 185 } TaggedPointer()186 static UseInfo TaggedPointer() { 187 return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any()); 188 } 189 190 // Possibly deoptimizing conversions. CheckedHeapObjectAsTaggedPointer()191 static UseInfo CheckedHeapObjectAsTaggedPointer() { 192 return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(), 193 TypeCheckKind::kHeapObject); 194 } CheckedSignedSmallAsTaggedSigned(const VectorSlotPair & feedback)195 static UseInfo CheckedSignedSmallAsTaggedSigned( 196 const VectorSlotPair& feedback) { 197 return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any(), 198 TypeCheckKind::kSignedSmall, feedback); 199 } CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros,const VectorSlotPair & feedback)200 static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros, 201 const VectorSlotPair& feedback) { 202 return UseInfo(MachineRepresentation::kWord32, 203 Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall, 204 feedback); 205 } CheckedSigned32AsWord32(IdentifyZeros identify_zeros,const VectorSlotPair & feedback)206 static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros, 207 const VectorSlotPair& feedback) { 208 return UseInfo(MachineRepresentation::kWord32, 209 Truncation::Any(identify_zeros), TypeCheckKind::kSigned32, 210 feedback); 211 } CheckedNumberAsFloat64(const VectorSlotPair & feedback)212 static UseInfo CheckedNumberAsFloat64(const VectorSlotPair& feedback) { 213 return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(), 214 TypeCheckKind::kNumber, feedback); 215 } CheckedNumberAsWord32(const VectorSlotPair & feedback)216 static UseInfo CheckedNumberAsWord32(const VectorSlotPair& feedback) { 217 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(), 218 TypeCheckKind::kNumber, feedback); 219 } CheckedNumberOrOddballAsFloat64(const VectorSlotPair & feedback)220 static UseInfo CheckedNumberOrOddballAsFloat64( 221 const VectorSlotPair& feedback) { 222 return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(), 223 TypeCheckKind::kNumberOrOddball, feedback); 224 } CheckedNumberOrOddballAsWord32(const VectorSlotPair & feedback)225 static UseInfo CheckedNumberOrOddballAsWord32( 226 const VectorSlotPair& feedback) { 227 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(), 228 TypeCheckKind::kNumberOrOddball, feedback); 229 } 230 231 // Undetermined representation. Any()232 static UseInfo Any() { 233 return UseInfo(MachineRepresentation::kNone, Truncation::Any()); 234 } AnyTruncatingToBool()235 static UseInfo AnyTruncatingToBool() { 236 return UseInfo(MachineRepresentation::kNone, Truncation::Bool()); 237 } 238 239 // Value not used. None()240 static UseInfo None() { 241 return UseInfo(MachineRepresentation::kNone, Truncation::None()); 242 } 243 representation()244 MachineRepresentation representation() const { return representation_; } truncation()245 Truncation truncation() const { return truncation_; } type_check()246 TypeCheckKind type_check() const { return type_check_; } minus_zero_check()247 CheckForMinusZeroMode minus_zero_check() const { 248 return truncation().IdentifiesZeroAndMinusZero() 249 ? CheckForMinusZeroMode::kDontCheckForMinusZero 250 : CheckForMinusZeroMode::kCheckForMinusZero; 251 } feedback()252 const VectorSlotPair& feedback() const { return feedback_; } 253 254 private: 255 MachineRepresentation representation_; 256 Truncation truncation_; 257 TypeCheckKind type_check_; 258 VectorSlotPair feedback_; 259 }; 260 261 // Contains logic related to changing the representation of values for constants 262 // and other nodes, as well as lowering Simplified->Machine operators. 263 // Eagerly folds any representation changes for constants. 264 class RepresentationChanger final { 265 public: RepresentationChanger(JSGraph * jsgraph,Isolate * isolate)266 RepresentationChanger(JSGraph* jsgraph, Isolate* isolate) 267 : jsgraph_(jsgraph), 268 isolate_(isolate), 269 testing_type_errors_(false), 270 type_error_(false) {} 271 272 // Changes representation from {output_type} to {use_rep}. The {truncation} 273 // parameter is only used for sanity checking - if the changer cannot figure 274 // out signedness for the word32->float64 conversion, then we check that the 275 // uses truncate to word32 (so they do not care about signedness). 276 Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep, 277 Type output_type, Node* use_node, 278 UseInfo use_info); 279 const Operator* Int32OperatorFor(IrOpcode::Value opcode); 280 const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode); 281 const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode); 282 const Operator* Uint32OperatorFor(IrOpcode::Value opcode); 283 const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode); 284 const Operator* Float64OperatorFor(IrOpcode::Value opcode); 285 TypeForBasePointer(const FieldAccess & access)286 MachineType TypeForBasePointer(const FieldAccess& access) { 287 return access.tag() != 0 ? MachineType::AnyTagged() 288 : MachineType::Pointer(); 289 } 290 TypeForBasePointer(const ElementAccess & access)291 MachineType TypeForBasePointer(const ElementAccess& access) { 292 return access.tag() != 0 ? MachineType::AnyTagged() 293 : MachineType::Pointer(); 294 } 295 296 private: 297 JSGraph* jsgraph_; 298 Isolate* isolate_; 299 300 friend class RepresentationChangerTester; // accesses the below fields. 301 302 bool testing_type_errors_; // If {true}, don't abort on a type error. 303 bool type_error_; // Set when a type error is detected. 304 305 Node* GetTaggedSignedRepresentationFor(Node* node, 306 MachineRepresentation output_rep, 307 Type output_type, Node* use_node, 308 UseInfo use_info); 309 Node* GetTaggedPointerRepresentationFor(Node* node, 310 MachineRepresentation output_rep, 311 Type output_type, Node* use_node, 312 UseInfo use_info); 313 Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep, 314 Type output_type, Truncation truncation); 315 Node* GetFloat32RepresentationFor(Node* node, 316 MachineRepresentation output_rep, 317 Type output_type, Truncation truncation); 318 Node* GetFloat64RepresentationFor(Node* node, 319 MachineRepresentation output_rep, 320 Type output_type, Node* use_node, 321 UseInfo use_info); 322 Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep, 323 Type output_type, Node* use_node, 324 UseInfo use_info); 325 Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep, 326 Type output_type); 327 Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep, 328 Type output_type); 329 Node* TypeError(Node* node, MachineRepresentation output_rep, 330 Type output_type, MachineRepresentation use); 331 Node* MakeTruncatedInt32Constant(double value); 332 Node* InsertChangeBitToTagged(Node* node); 333 Node* InsertChangeFloat32ToFloat64(Node* node); 334 Node* InsertChangeFloat64ToInt32(Node* node); 335 Node* InsertChangeFloat64ToUint32(Node* node); 336 Node* InsertChangeInt32ToFloat64(Node* node); 337 Node* InsertChangeTaggedSignedToInt32(Node* node); 338 Node* InsertChangeTaggedToFloat64(Node* node); 339 Node* InsertChangeUint32ToFloat64(Node* node); 340 Node* InsertConversion(Node* node, const Operator* op, Node* use_node); 341 void InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason); 342 jsgraph()343 JSGraph* jsgraph() const { return jsgraph_; } isolate()344 Isolate* isolate() const { return isolate_; } factory()345 Factory* factory() const { return isolate()->factory(); } simplified()346 SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } machine()347 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } 348 }; 349 350 } // namespace compiler 351 } // namespace internal 352 } // namespace v8 353 354 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ 355