representation-change.h 13.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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_

#include "src/compiler/js-graph.h"
#include "src/compiler/simplified-operator.h"

namespace v8 {
namespace internal {
namespace compiler {

15 16 17
// Foward declarations.
class TypeCache;

18 19
enum IdentifyZeros { kIdentifyZeros, kDistinguishZeros };

20 21 22
class Truncation final {
 public:
  // Constructors.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
  static Truncation None() {
    return Truncation(TruncationKind::kNone, kIdentifyZeros);
  }
  static Truncation Bool() {
    return Truncation(TruncationKind::kBool, kIdentifyZeros);
  }
  static Truncation Word32() {
    return Truncation(TruncationKind::kWord32, kIdentifyZeros);
  }
  static Truncation Float64(IdentifyZeros identify_zeros = kDistinguishZeros) {
    return Truncation(TruncationKind::kFloat64, identify_zeros);
  }
  static Truncation Any(IdentifyZeros identify_zeros = kDistinguishZeros) {
    return Truncation(TruncationKind::kAny, identify_zeros);
  }
38 39

  static Truncation Generalize(Truncation t1, Truncation t2) {
40 41 42
    return Truncation(
        Generalize(t1.kind(), t2.kind()),
        GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
43 44 45
  }

  // Queries.
46
  bool IsUnused() const { return kind_ == TruncationKind::kNone; }
47 48 49
  bool IsUsedAsBool() const {
    return LessGeneral(kind_, TruncationKind::kBool);
  }
50
  bool IsUsedAsWord32() const {
51 52
    return LessGeneral(kind_, TruncationKind::kWord32);
  }
53
  bool IsUsedAsFloat64() const {
54 55
    return LessGeneral(kind_, TruncationKind::kFloat64);
  }
56
  bool IdentifiesUndefinedAndZero() {
57 58 59
    return LessGeneral(kind_, TruncationKind::kWord32) ||
           LessGeneral(kind_, TruncationKind::kBool);
  }
60 61 62
  bool IdentifiesZeroAndMinusZero() const {
    return identify_zeros() == kIdentifyZeros;
  }
63 64

  // Operators.
65 66 67
  bool operator==(Truncation other) const {
    return kind() == other.kind() && identify_zeros() == other.identify_zeros();
  }
68 69 70
  bool operator!=(Truncation other) const { return !(*this == other); }

  // Debug utilities.
71
  const char* description() const;
72
  bool IsLessGeneralThan(Truncation other) {
73 74
    return LessGeneral(kind(), other.kind()) &&
           LessGeneralIdentifyZeros(identify_zeros(), other.identify_zeros());
75
  }
76

77 78
  IdentifyZeros identify_zeros() const { return identify_zeros_; }

79 80 81 82 83 84 85 86 87
 private:
  enum class TruncationKind : uint8_t {
    kNone,
    kBool,
    kWord32,
    kFloat64,
    kAny
  };

88 89 90 91 92
  explicit Truncation(TruncationKind kind, IdentifyZeros identify_zeros)
      : kind_(kind), identify_zeros_(identify_zeros) {
    DCHECK(kind == TruncationKind::kAny || kind == TruncationKind::kFloat64 ||
           identify_zeros == kIdentifyZeros);
  }
93 94 95
  TruncationKind kind() const { return kind_; }

  TruncationKind kind_;
96
  IdentifyZeros identify_zeros_;
97

98
  static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2);
99 100
  static IdentifyZeros GeneralizeIdentifyZeros(IdentifyZeros i1,
                                               IdentifyZeros i2);
101
  static bool LessGeneral(TruncationKind rep1, TruncationKind rep2);
102
  static bool LessGeneralIdentifyZeros(IdentifyZeros u1, IdentifyZeros u2);
103 104
};

105 106 107 108
enum class TypeCheckKind : uint8_t {
  kNone,
  kSignedSmall,
  kSigned32,
109
  kNumber,
110 111
  kNumberOrOddball,
  kHeapObject
112
};
113

114 115 116 117
inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
  switch (type_check) {
    case TypeCheckKind::kNone:
      return os << "None";
118 119
    case TypeCheckKind::kSignedSmall:
      return os << "SignedSmall";
120 121
    case TypeCheckKind::kSigned32:
      return os << "Signed32";
122 123
    case TypeCheckKind::kNumber:
      return os << "Number";
124 125
    case TypeCheckKind::kNumberOrOddball:
      return os << "NumberOrOddball";
126 127
    case TypeCheckKind::kHeapObject:
      return os << "HeapObject";
128 129 130 131
  }
  UNREACHABLE();
}

132 133 134 135 136 137
// 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
138 139
//    is the preferred representation. For conversions that will require
//    checks, we also keep track of whether a minus zero check is needed.
140 141 142 143 144
//
// 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.
145 146 147
//    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.
148 149 150
class UseInfo {
 public:
  UseInfo(MachineRepresentation representation, Truncation truncation,
151 152
          TypeCheckKind type_check = TypeCheckKind::kNone,
          const VectorSlotPair& feedback = VectorSlotPair())
153 154
      : representation_(representation),
        truncation_(truncation),
155 156
        type_check_(type_check),
        feedback_(feedback) {}
157 158 159
  static UseInfo TruncatingWord32() {
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
  }
160 161 162 163 164
  static UseInfo Word64() {
    return UseInfo(MachineRepresentation::kWord64, Truncation::Any());
  }
  static UseInfo Word() {
    return UseInfo(MachineType::PointerRepresentation(), Truncation::Any());
165 166 167 168
  }
  static UseInfo Bool() {
    return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
  }
169 170
  static UseInfo Float32() {
    return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
171 172 173 174 175 176 177
  }
  static UseInfo TruncatingFloat64() {
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
  }
  static UseInfo AnyTagged() {
    return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
  }
178 179 180 181 182 183
  static UseInfo TaggedSigned() {
    return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
  }
  static UseInfo TaggedPointer() {
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
  }
184 185

  // Possibly deoptimizing conversions.
186 187 188 189
  static UseInfo CheckedHeapObjectAsTaggedPointer() {
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
                   TypeCheckKind::kHeapObject);
  }
190 191
  static UseInfo CheckedSignedSmallAsTaggedSigned(
      const VectorSlotPair& feedback) {
192
    return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any(),
193
                   TypeCheckKind::kSignedSmall, feedback);
194
  }
195 196
  static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros,
                                            const VectorSlotPair& feedback) {
197
    return UseInfo(MachineRepresentation::kWord32,
198 199
                   Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
                   feedback);
200
  }
201 202
  static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros,
                                         const VectorSlotPair& feedback) {
203
    return UseInfo(MachineRepresentation::kWord32,
204 205
                   Truncation::Any(identify_zeros), TypeCheckKind::kSigned32,
                   feedback);
206
  }
207
  static UseInfo CheckedNumberAsFloat64(const VectorSlotPair& feedback) {
208
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
209
                   TypeCheckKind::kNumber, feedback);
210
  }
211
  static UseInfo CheckedNumberAsWord32(const VectorSlotPair& feedback) {
212
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
213
                   TypeCheckKind::kNumber, feedback);
214
  }
215 216
  static UseInfo CheckedNumberOrOddballAsFloat64(
      const VectorSlotPair& feedback) {
217
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
218
                   TypeCheckKind::kNumberOrOddball, feedback);
219
  }
220 221
  static UseInfo CheckedNumberOrOddballAsWord32(
      const VectorSlotPair& feedback) {
222
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
223
                   TypeCheckKind::kNumberOrOddball, feedback);
224
  }
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

  // 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_; }
242 243 244 245 246
  CheckForMinusZeroMode minus_zero_check() const {
    return truncation().IdentifiesZeroAndMinusZero()
               ? CheckForMinusZeroMode::kDontCheckForMinusZero
               : CheckForMinusZeroMode::kCheckForMinusZero;
  }
247
  const VectorSlotPair& feedback() const { return feedback_; }
248 249 250 251 252

 private:
  MachineRepresentation representation_;
  Truncation truncation_;
  TypeCheckKind type_check_;
253
  VectorSlotPair feedback_;
254
};
255

256 257 258
// 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.
259
class RepresentationChanger final {
260
 public:
261
  RepresentationChanger(JSGraph* jsgraph, Isolate* isolate);
262

263 264 265 266
  // Changes representation from {output_type} to {use_rep}. The {truncation}
  // parameter is only used for sanity checking - if the changer cannot figure
  // out signedness for the word32->float64 conversion, then we check that the
  // uses truncate to word32 (so they do not care about signedness).
267
  Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
268
                             Type output_type, Node* use_node,
269
                             UseInfo use_info);
270
  const Operator* Int32OperatorFor(IrOpcode::Value opcode);
271
  const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
272
  const Operator* Int64OperatorFor(IrOpcode::Value opcode);
273
  const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode);
274
  const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
275
  const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode);
276
  const Operator* Float64OperatorFor(IrOpcode::Value opcode);
277

278
  MachineType TypeForBasePointer(const FieldAccess& access) {
279 280
    return access.tag() != 0 ? MachineType::AnyTagged()
                             : MachineType::Pointer();
281 282
  }

283
  MachineType TypeForBasePointer(const ElementAccess& access) {
284 285
    return access.tag() != 0 ? MachineType::AnyTagged()
                             : MachineType::Pointer();
286 287 288
  }

 private:
289
  TypeCache const& cache_;
290 291 292 293 294 295 296 297
  JSGraph* jsgraph_;
  Isolate* isolate_;

  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.

298 299
  Node* GetTaggedSignedRepresentationFor(Node* node,
                                         MachineRepresentation output_rep,
300
                                         Type output_type, Node* use_node,
301
                                         UseInfo use_info);
302 303
  Node* GetTaggedPointerRepresentationFor(Node* node,
                                          MachineRepresentation output_rep,
304
                                          Type output_type, Node* use_node,
305
                                          UseInfo use_info);
306
  Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
307
                                   Type output_type, Truncation truncation);
308 309
  Node* GetFloat32RepresentationFor(Node* node,
                                    MachineRepresentation output_rep,
310
                                    Type output_type, Truncation truncation);
311 312
  Node* GetFloat64RepresentationFor(Node* node,
                                    MachineRepresentation output_rep,
313
                                    Type output_type, Node* use_node,
314
                                    UseInfo use_info);
315
  Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
316
                                   Type output_type, Node* use_node,
317
                                   UseInfo use_info);
318
  Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
319
                                Type output_type);
320
  Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
321
                                   Type output_type);
322
  Node* TypeError(Node* node, MachineRepresentation output_rep,
323
                  Type output_type, MachineRepresentation use);
324
  Node* MakeTruncatedInt32Constant(double value);
325
  Node* InsertChangeBitToTagged(Node* node);
326
  Node* InsertChangeFloat32ToFloat64(Node* node);
327 328
  Node* InsertChangeFloat64ToInt32(Node* node);
  Node* InsertChangeFloat64ToUint32(Node* node);
329
  Node* InsertChangeInt32ToFloat64(Node* node);
330
  Node* InsertChangeTaggedSignedToInt32(Node* node);
331
  Node* InsertChangeTaggedToFloat64(Node* node);
332
  Node* InsertChangeUint32ToFloat64(Node* node);
333
  Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
334
  Node* InsertTruncateInt64ToInt32(Node* node);
335
  Node* InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason);
336

337 338
  JSGraph* jsgraph() const { return jsgraph_; }
  Isolate* isolate() const { return isolate_; }
339
  Factory* factory() const { return isolate()->factory(); }
340
  SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
341
  MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
342
};
343 344 345 346

}  // namespace compiler
}  // namespace internal
}  // namespace v8
347 348

#endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_