representation-change.h 16.7 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_REPRESENTATION_CHANGE_H_
#define V8_COMPILER_REPRESENTATION_CHANGE_H_

8
#include "src/compiler/feedback-source.h"
9 10 11 12 13 14 15
#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"

namespace v8 {
namespace internal {
namespace compiler {

16
// Foward declarations.
17
class SimplifiedLoweringVerifier;
18 19
class TypeCache;

20
enum IdentifyZeros : uint8_t { kIdentifyZeros, kDistinguishZeros };
21

22 23 24
class Truncation final {
 public:
  // Constructors.
25 26 27 28 29 30 31 32 33
  static Truncation None() {
    return Truncation(TruncationKind::kNone, kIdentifyZeros);
  }
  static Truncation Bool() {
    return Truncation(TruncationKind::kBool, kIdentifyZeros);
  }
  static Truncation Word32() {
    return Truncation(TruncationKind::kWord32, kIdentifyZeros);
  }
34 35 36
  static Truncation Word64() {
    return Truncation(TruncationKind::kWord64, kIdentifyZeros);
  }
37 38 39 40
  static Truncation OddballAndBigIntToNumber(
      IdentifyZeros identify_zeros = kDistinguishZeros) {
    return Truncation(TruncationKind::kOddballAndBigIntToNumber,
                      identify_zeros);
41 42 43 44
  }
  static Truncation Any(IdentifyZeros identify_zeros = kDistinguishZeros) {
    return Truncation(TruncationKind::kAny, identify_zeros);
  }
45 46

  static Truncation Generalize(Truncation t1, Truncation t2) {
47 48 49
    return Truncation(
        Generalize(t1.kind(), t2.kind()),
        GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
50 51 52
  }

  // Queries.
53
  bool IsUnused() const { return kind_ == TruncationKind::kNone; }
54 55 56
  bool IsUsedAsBool() const {
    return LessGeneral(kind_, TruncationKind::kBool);
  }
57
  bool IsUsedAsWord32() const {
58 59
    return LessGeneral(kind_, TruncationKind::kWord32);
  }
60 61 62
  bool IsUsedAsWord64() const {
    return LessGeneral(kind_, TruncationKind::kWord64);
  }
63 64
  bool TruncatesOddballAndBigIntToNumber() const {
    return LessGeneral(kind_, TruncationKind::kOddballAndBigIntToNumber);
65
  }
66
  bool IdentifiesUndefinedAndZero() {
67 68 69
    return LessGeneral(kind_, TruncationKind::kWord32) ||
           LessGeneral(kind_, TruncationKind::kBool);
  }
70 71 72
  bool IdentifiesZeroAndMinusZero() const {
    return identify_zeros() == kIdentifyZeros;
  }
73 74

  // Operators.
75 76 77
  bool operator==(Truncation other) const {
    return kind() == other.kind() && identify_zeros() == other.identify_zeros();
  }
78 79 80
  bool operator!=(Truncation other) const { return !(*this == other); }

  // Debug utilities.
81
  const char* description() const;
82
  bool IsLessGeneralThan(Truncation other) const {
83 84
    return LessGeneral(kind(), other.kind()) &&
           LessGeneralIdentifyZeros(identify_zeros(), other.identify_zeros());
85
  }
86

87 88
  IdentifyZeros identify_zeros() const { return identify_zeros_; }

89 90 91 92 93
 private:
  enum class TruncationKind : uint8_t {
    kNone,
    kBool,
    kWord32,
94
    kWord64,
95
    kOddballAndBigIntToNumber,
96 97 98
    kAny
  };

99
  explicit Truncation(TruncationKind kind, IdentifyZeros identify_zeros)
100 101
      : kind_(kind), identify_zeros_(identify_zeros) {}

102 103
  TruncationKind kind() const { return kind_; }

104
  friend class SimplifiedLoweringVerifier;
105 106
  TruncationKind kind_;
  IdentifyZeros identify_zeros_;
107

108
  static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2);
109 110
  static IdentifyZeros GeneralizeIdentifyZeros(IdentifyZeros i1,
                                               IdentifyZeros i2);
111
  static bool LessGeneral(TruncationKind rep1, TruncationKind rep2);
112
  static bool LessGeneralIdentifyZeros(IdentifyZeros u1, IdentifyZeros u2);
113 114
};

115 116 117 118
enum class TypeCheckKind : uint8_t {
  kNone,
  kSignedSmall,
  kSigned32,
119
  kSigned64,
120
  kNumber,
121
  kNumberOrBoolean,
122
  kNumberOrOddball,
123 124
  kHeapObject,
  kBigInt,
125
  kArrayIndex
126
};
127

128 129 130 131
inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
  switch (type_check) {
    case TypeCheckKind::kNone:
      return os << "None";
132 133
    case TypeCheckKind::kSignedSmall:
      return os << "SignedSmall";
134 135
    case TypeCheckKind::kSigned32:
      return os << "Signed32";
136 137
    case TypeCheckKind::kSigned64:
      return os << "Signed64";
138 139
    case TypeCheckKind::kNumber:
      return os << "Number";
140 141
    case TypeCheckKind::kNumberOrBoolean:
      return os << "NumberOrBoolean";
142 143
    case TypeCheckKind::kNumberOrOddball:
      return os << "NumberOrOddball";
144 145
    case TypeCheckKind::kHeapObject:
      return os << "HeapObject";
146 147
    case TypeCheckKind::kBigInt:
      return os << "BigInt";
148 149
    case TypeCheckKind::kArrayIndex:
      return os << "ArrayIndex";
150 151 152 153
  }
  UNREACHABLE();
}

154 155 156 157 158 159
// The {UseInfo} class is used to describe a use of an input of a node.
//
// This information is used in two different ways, based on the phase:
//
// 1. During propagation, the use info is used to inform the input node
//    about what part of the input is used (we call this truncation) and what
160 161
//    is the preferred representation. For conversions that will require
//    checks, we also keep track of whether a minus zero check is needed.
162 163 164 165 166
//
// 2. During lowering, the use info is used to properly convert the input
//    to the preferred representation. The preferred representation might be
//    insufficient to do the conversion (e.g. word32->float64 conv), so we also
//    need the signedness information to produce the correct value.
167 168 169
//    Additionally, use info may contain {CheckParameters} which contains
//    information for the deoptimizer such as a CallIC on which speculation
//    should be disallowed if the check fails.
170 171 172
class UseInfo {
 public:
  UseInfo(MachineRepresentation representation, Truncation truncation,
173
          TypeCheckKind type_check = TypeCheckKind::kNone,
174
          const FeedbackSource& feedback = FeedbackSource())
175 176
      : representation_(representation),
        truncation_(truncation),
177 178
        type_check_(type_check),
        feedback_(feedback) {}
179 180 181
  static UseInfo TruncatingWord32() {
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
  }
182
  static UseInfo CheckedBigIntTruncatingWord64(const FeedbackSource& feedback) {
183 184 185
    // Note that Trunction::Word64() can safely use kIdentifyZero, because
    // TypeCheckKind::kBigInt will make sure we deopt for anything other than
    // type BigInt anyway.
186
    return UseInfo(MachineRepresentation::kWord64, Truncation::Word64(),
187
                   TypeCheckKind::kBigInt, feedback);
188
  }
189 190 191 192 193
  static UseInfo Word64() {
    return UseInfo(MachineRepresentation::kWord64, Truncation::Any());
  }
  static UseInfo Word() {
    return UseInfo(MachineType::PointerRepresentation(), Truncation::Any());
194 195 196 197
  }
  static UseInfo Bool() {
    return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
  }
198 199
  static UseInfo Float32() {
    return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
200
  }
201 202 203
  static UseInfo Float64() {
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Any());
  }
204 205 206
  static UseInfo TruncatingFloat64(
      IdentifyZeros identify_zeros = kDistinguishZeros) {
    return UseInfo(MachineRepresentation::kFloat64,
207
                   Truncation::OddballAndBigIntToNumber(identify_zeros));
208 209 210 211
  }
  static UseInfo AnyTagged() {
    return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
  }
212 213 214 215 216 217
  static UseInfo TaggedSigned() {
    return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
  }
  static UseInfo TaggedPointer() {
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
  }
218 219

  // Possibly deoptimizing conversions.
220
  static UseInfo CheckedTaggedAsArrayIndex(const FeedbackSource& feedback) {
221
    return UseInfo(MachineType::PointerRepresentation(),
222 223 224
                   Truncation::Any(kIdentifyZeros), TypeCheckKind::kArrayIndex,
                   feedback);
  }
225
  static UseInfo CheckedHeapObjectAsTaggedPointer(
226
      const FeedbackSource& feedback) {
227
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
228
                   TypeCheckKind::kHeapObject, feedback);
229
  }
230

231
  static UseInfo CheckedBigIntAsTaggedPointer(const FeedbackSource& feedback) {
232 233 234 235
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
                   TypeCheckKind::kBigInt, feedback);
  }

236
  static UseInfo CheckedSignedSmallAsTaggedSigned(
237
      const FeedbackSource& feedback,
238 239 240 241
      IdentifyZeros identify_zeros = kDistinguishZeros) {
    return UseInfo(MachineRepresentation::kTaggedSigned,
                   Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
                   feedback);
242
  }
243
  static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros,
244
                                            const FeedbackSource& feedback) {
245
    return UseInfo(MachineRepresentation::kWord32,
246 247
                   Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
                   feedback);
248
  }
249
  static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros,
250
                                         const FeedbackSource& feedback) {
251
    return UseInfo(MachineRepresentation::kWord32,
252 253
                   Truncation::Any(identify_zeros), TypeCheckKind::kSigned32,
                   feedback);
254
  }
255
  static UseInfo CheckedSigned64AsWord64(IdentifyZeros identify_zeros,
256
                                         const FeedbackSource& feedback) {
257 258 259 260
    return UseInfo(MachineRepresentation::kWord64,
                   Truncation::Any(identify_zeros), TypeCheckKind::kSigned64,
                   feedback);
  }
261
  static UseInfo CheckedNumberAsFloat64(IdentifyZeros identify_zeros,
262
                                        const FeedbackSource& feedback) {
263 264 265
    return UseInfo(MachineRepresentation::kFloat64,
                   Truncation::Any(identify_zeros), TypeCheckKind::kNumber,
                   feedback);
266
  }
267
  static UseInfo CheckedNumberAsWord32(const FeedbackSource& feedback) {
268
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
269
                   TypeCheckKind::kNumber, feedback);
270
  }
271 272 273 274 275 276
  static UseInfo CheckedNumberOrBooleanAsFloat64(
      IdentifyZeros identify_zeros, const FeedbackSource& feedback) {
    return UseInfo(MachineRepresentation::kFloat64,
                   Truncation::Any(identify_zeros),
                   TypeCheckKind::kNumberOrBoolean, feedback);
  }
277
  static UseInfo CheckedNumberOrOddballAsFloat64(
278
      IdentifyZeros identify_zeros, const FeedbackSource& feedback) {
279 280
    return UseInfo(MachineRepresentation::kFloat64,
                   Truncation::Any(identify_zeros),
281
                   TypeCheckKind::kNumberOrOddball, feedback);
282
  }
283
  static UseInfo CheckedNumberOrOddballAsWord32(
284
      const FeedbackSource& feedback) {
285
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
286
                   TypeCheckKind::kNumberOrOddball, feedback);
287
  }
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

  // Undetermined representation.
  static UseInfo Any() {
    return UseInfo(MachineRepresentation::kNone, Truncation::Any());
  }
  static UseInfo AnyTruncatingToBool() {
    return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
  }

  // Value not used.
  static UseInfo None() {
    return UseInfo(MachineRepresentation::kNone, Truncation::None());
  }

  MachineRepresentation representation() const { return representation_; }
  Truncation truncation() const { return truncation_; }
  TypeCheckKind type_check() const { return type_check_; }
305 306 307 308 309
  CheckForMinusZeroMode minus_zero_check() const {
    return truncation().IdentifiesZeroAndMinusZero()
               ? CheckForMinusZeroMode::kDontCheckForMinusZero
               : CheckForMinusZeroMode::kCheckForMinusZero;
  }
310
  const FeedbackSource& feedback() const { return feedback_; }
311 312 313 314 315

 private:
  MachineRepresentation representation_;
  Truncation truncation_;
  TypeCheckKind type_check_;
316
  FeedbackSource feedback_;
317
};
318

319 320 321
// Contains logic related to changing the representation of values for constants
// and other nodes, as well as lowering Simplified->Machine operators.
// Eagerly folds any representation changes for constants.
322
class V8_EXPORT_PRIVATE RepresentationChanger final {
323
 public:
324 325
  RepresentationChanger(JSGraph* jsgraph, JSHeapBroker* broker,
                        SimplifiedLoweringVerifier* verifier);
326

327
  // Changes representation from {output_type} to {use_rep}. The {truncation}
328
  // parameter is only used for checking - if the changer cannot figure
329 330
  // out signedness for the word32->float64 conversion, then we check that the
  // uses truncate to word32 (so they do not care about signedness).
331
  Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
332
                             Type output_type, Node* use_node,
333
                             UseInfo use_info);
334
  const Operator* Int32OperatorFor(IrOpcode::Value opcode);
335
  const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
336
  const Operator* Int64OperatorFor(IrOpcode::Value opcode);
337
  const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode);
338
  const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
339
  const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode);
340
  const Operator* Float64OperatorFor(IrOpcode::Value opcode);
341

342
  MachineType TypeForBasePointer(const FieldAccess& access) {
343 344
    return access.tag() != 0 ? MachineType::AnyTagged()
                             : MachineType::Pointer();
345 346
  }

347
  MachineType TypeForBasePointer(const ElementAccess& access) {
348 349
    return access.tag() != 0 ? MachineType::AnyTagged()
                             : MachineType::Pointer();
350 351
  }

352 353
  bool verification_enabled() const { return verifier_ != nullptr; }

354
 private:
355
  TypeCache const* cache_;
356
  JSGraph* jsgraph_;
357
  JSHeapBroker* broker_;
358
  SimplifiedLoweringVerifier* verifier_;
359 360 361 362 363 364

  friend class RepresentationChangerTester;  // accesses the below fields.

  bool testing_type_errors_;  // If {true}, don't abort on a type error.
  bool type_error_;           // Set when a type error is detected.

365 366
  Node* GetTaggedSignedRepresentationFor(Node* node,
                                         MachineRepresentation output_rep,
367
                                         Type output_type, Node* use_node,
368
                                         UseInfo use_info);
369 370
  Node* GetTaggedPointerRepresentationFor(Node* node,
                                          MachineRepresentation output_rep,
371
                                          Type output_type, Node* use_node,
372
                                          UseInfo use_info);
373
  Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
374
                                   Type output_type, Truncation truncation);
375 376
  Node* GetFloat32RepresentationFor(Node* node,
                                    MachineRepresentation output_rep,
377
                                    Type output_type, Truncation truncation);
378 379
  Node* GetFloat64RepresentationFor(Node* node,
                                    MachineRepresentation output_rep,
380
                                    Type output_type, Node* use_node,
381
                                    UseInfo use_info);
382
  Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
383
                                   Type output_type, Node* use_node,
384
                                   UseInfo use_info);
385
  Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
386
                                Type output_type);
387
  Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
388 389
                                   Type output_type, Node* use_node,
                                   UseInfo use_info);
390
  Node* TypeError(Node* node, MachineRepresentation output_rep,
391
                  Type output_type, MachineRepresentation use);
392
  Node* MakeTruncatedInt32Constant(double value);
393
  Node* InsertChangeBitToTagged(Node* node);
394
  Node* InsertChangeFloat32ToFloat64(Node* node);
395 396
  Node* InsertChangeFloat64ToInt32(Node* node);
  Node* InsertChangeFloat64ToUint32(Node* node);
397
  Node* InsertChangeInt32ToFloat64(Node* node);
398
  Node* InsertChangeTaggedSignedToInt32(Node* node);
399
  Node* InsertChangeTaggedToFloat64(Node* node);
400
  Node* InsertChangeUint32ToFloat64(Node* node);
401
  Node* InsertCheckedFloat64ToInt32(Node* node, CheckForMinusZeroMode check,
402
                                    const FeedbackSource& feedback,
403
                                    Node* use_node);
404
  Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
405
  Node* InsertTruncateInt64ToInt32(Node* node);
406 407
  Node* InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason,
                                 const FeedbackSource& feedback = {});
408
  Node* InsertTypeOverrideForVerifier(const Type& type, Node* node);
409

410
  JSGraph* jsgraph() const { return jsgraph_; }
411
  Isolate* isolate() const;
412
  Factory* factory() const { return isolate()->factory(); }
413
  SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
414
  MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
415
};
416 417 418 419

}  // namespace compiler
}  // namespace internal
}  // namespace v8
420 421

#endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_