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. 18 static Truncation None() { return Truncation(TruncationKind::kNone); } 19 static Truncation Bool() { return Truncation(TruncationKind::kBool); } 20 static Truncation Word32() { return Truncation(TruncationKind::kWord32); } 21 static Truncation Word64() { return Truncation(TruncationKind::kWord64); } 22 static Truncation Float64() { return Truncation(TruncationKind::kFloat64); } 23 static Truncation Any() { return Truncation(TruncationKind::kAny); } 24 25 static Truncation Generalize(Truncation t1, Truncation t2) { 26 return Truncation(Generalize(t1.kind(), t2.kind())); 27 } 28 29 // Queries. 30 bool IsUnused() const { return kind_ == TruncationKind::kNone; } 31 bool IsUsedAsBool() const { 32 return LessGeneral(kind_, TruncationKind::kBool); 33 } 34 bool IsUsedAsWord32() const { 35 return LessGeneral(kind_, TruncationKind::kWord32); 36 } 37 bool IsUsedAsFloat64() const { 38 return LessGeneral(kind_, TruncationKind::kFloat64); 39 } 40 bool IdentifiesNaNAndZero() { 41 return LessGeneral(kind_, TruncationKind::kWord32) || 42 LessGeneral(kind_, TruncationKind::kBool); 43 } 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; 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 69 explicit Truncation(TruncationKind 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) 125 : representation_(representation), 126 truncation_(truncation), 127 type_check_(type_check), 128 minus_zero_check_(minus_zero_check) {} 129 static UseInfo TruncatingWord32() { 130 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32()); 131 } 132 static UseInfo TruncatingWord64() { 133 return UseInfo(MachineRepresentation::kWord64, Truncation::Word64()); 134 } 135 static UseInfo Bool() { 136 return UseInfo(MachineRepresentation::kBit, Truncation::Bool()); 137 } 138 static UseInfo Float32() { 139 return UseInfo(MachineRepresentation::kFloat32, Truncation::Any()); 140 } 141 static UseInfo TruncatingFloat64() { 142 return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64()); 143 } 144 static UseInfo PointerInt() { 145 return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64(); 146 } 147 static UseInfo AnyTagged() { 148 return UseInfo(MachineRepresentation::kTagged, Truncation::Any()); 149 } 150 static UseInfo TaggedSigned() { 151 return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any()); 152 } 153 static UseInfo TaggedPointer() { 154 return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any()); 155 } 156 157 // Possibly deoptimizing conversions. 158 static UseInfo CheckedHeapObjectAsTaggedPointer() { 159 return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(), 160 TypeCheckKind::kHeapObject); 161 } 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 } 178 static UseInfo CheckedNumberAsFloat64() { 179 return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64(), 180 TypeCheckKind::kNumber); 181 } 182 static UseInfo CheckedNumberAsWord32() { 183 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(), 184 TypeCheckKind::kNumber); 185 } 186 static UseInfo CheckedNumberOrOddballAsFloat64() { 187 return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(), 188 TypeCheckKind::kNumberOrOddball); 189 } 190 static UseInfo CheckedNumberOrOddballAsWord32() { 191 return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(), 192 TypeCheckKind::kNumberOrOddball); 193 } 194 195 // Undetermined representation. 196 static UseInfo Any() { 197 return UseInfo(MachineRepresentation::kNone, Truncation::Any()); 198 } 199 static UseInfo AnyTruncatingToBool() { 200 return UseInfo(MachineRepresentation::kNone, Truncation::Bool()); 201 } 202 203 // Value not used. 204 static UseInfo None() { 205 return UseInfo(MachineRepresentation::kNone, Truncation::None()); 206 } 207 208 MachineRepresentation representation() const { return representation_; } 209 Truncation truncation() const { return truncation_; } 210 TypeCheckKind type_check() const { return type_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: 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* TaggedSignedOperatorFor(IrOpcode::Value opcode); 242 const Operator* Uint32OperatorFor(IrOpcode::Value opcode); 243 const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode); 244 const Operator* Float64OperatorFor(IrOpcode::Value opcode); 245 246 MachineType TypeForBasePointer(const FieldAccess& access) { 247 return access.tag() != 0 ? MachineType::AnyTagged() 248 : MachineType::Pointer(); 249 } 250 251 MachineType TypeForBasePointer(const ElementAccess& access) { 252 return access.tag() != 0 ? MachineType::AnyTagged() 253 : MachineType::Pointer(); 254 } 255 256 private: 257 JSGraph* jsgraph_; 258 Isolate* isolate_; 259 260 friend class RepresentationChangerTester; // accesses the below fields. 261 262 bool testing_type_errors_; // If {true}, don't abort on a type error. 263 bool type_error_; // Set when a type error is detected. 264 265 Node* GetTaggedSignedRepresentationFor(Node* node, 266 MachineRepresentation output_rep, 267 Type* output_type, Node* use_node, 268 UseInfo use_info); 269 Node* GetTaggedPointerRepresentationFor(Node* node, 270 MachineRepresentation output_rep, 271 Type* output_type, Node* use_node, 272 UseInfo use_info); 273 Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep, 274 Type* output_type, Truncation truncation); 275 Node* GetFloat32RepresentationFor(Node* node, 276 MachineRepresentation output_rep, 277 Type* output_type, Truncation truncation); 278 Node* GetFloat64RepresentationFor(Node* node, 279 MachineRepresentation output_rep, 280 Type* output_type, Node* use_node, 281 UseInfo use_info); 282 Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep, 283 Type* output_type, Node* use_node, 284 UseInfo use_info); 285 Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep, 286 Type* output_type); 287 Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep, 288 Type* output_type); 289 Node* TypeError(Node* node, MachineRepresentation output_rep, 290 Type* output_type, MachineRepresentation use); 291 Node* MakeTruncatedInt32Constant(double value); 292 Node* InsertChangeBitToTagged(Node* node); 293 Node* InsertChangeFloat32ToFloat64(Node* node); 294 Node* InsertChangeFloat64ToInt32(Node* node); 295 Node* InsertChangeFloat64ToUint32(Node* node); 296 Node* InsertChangeInt32ToFloat64(Node* node); 297 Node* InsertChangeTaggedSignedToInt32(Node* node); 298 Node* InsertChangeTaggedToFloat64(Node* node); 299 Node* InsertChangeUint32ToFloat64(Node* node); 300 301 Node* InsertConversion(Node* node, const Operator* op, Node* use_node); 302 303 JSGraph* jsgraph() const { return jsgraph_; } 304 Isolate* isolate() const { return isolate_; } 305 Factory* factory() const { return isolate()->factory(); } 306 SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); } 307 MachineOperatorBuilder* machine() { return jsgraph()->machine(); } 308 }; 309 310 } // namespace compiler 311 } // namespace internal 312 } // namespace v8 313 314 #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_ 315