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