representation-change.h 12.1 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 18 19 20 21 22 23 24 25 26 27 28 29
class Truncation final {
 public:
  // Constructors.
  static Truncation None() { return Truncation(TruncationKind::kNone); }
  static Truncation Bool() { return Truncation(TruncationKind::kBool); }
  static Truncation Word32() { return Truncation(TruncationKind::kWord32); }
  static Truncation Word64() { return Truncation(TruncationKind::kWord64); }
  static Truncation Float64() { return Truncation(TruncationKind::kFloat64); }
  static Truncation Any() { return Truncation(TruncationKind::kAny); }

  static Truncation Generalize(Truncation t1, Truncation t2) {
    return Truncation(Generalize(t1.kind(), t2.kind()));
  }

  // Queries.
30
  bool IsUnused() const { return kind_ == TruncationKind::kNone; }
31 32 33
  bool IsUsedAsBool() const {
    return LessGeneral(kind_, TruncationKind::kBool);
  }
34
  bool IsUsedAsWord32() const {
35 36
    return LessGeneral(kind_, TruncationKind::kWord32);
  }
37
  bool IsUsedAsFloat64() const {
38 39
    return LessGeneral(kind_, TruncationKind::kFloat64);
  }
40
  bool IdentifiesNaNAndZero() {
41 42 43
    return LessGeneral(kind_, TruncationKind::kWord32) ||
           LessGeneral(kind_, TruncationKind::kBool);
  }
44
  bool IdentifiesUndefinedAndNaNAndZero() {
45 46 47 48 49 50 51 52 53
    return LessGeneral(kind_, TruncationKind::kFloat64) ||
           LessGeneral(kind_, TruncationKind::kWord64);
  }

  // Operators.
  bool operator==(Truncation other) const { return kind() == other.kind(); }
  bool operator!=(Truncation other) const { return !(*this == other); }

  // Debug utilities.
54
  const char* description() const;
55 56 57
  bool IsLessGeneralThan(Truncation other) {
    return LessGeneral(kind(), other.kind());
  }
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

 private:
  enum class TruncationKind : uint8_t {
    kNone,
    kBool,
    kWord32,
    kWord64,
    kFloat64,
    kAny
  };

  explicit Truncation(TruncationKind kind) : kind_(kind) {}
  TruncationKind kind() const { return kind_; }

  TruncationKind kind_;

74 75
  static TruncationKind Generalize(TruncationKind rep1, TruncationKind rep2);
  static bool LessGeneral(TruncationKind rep1, TruncationKind rep2);
76 77
};

78 79 80 81
enum class TypeCheckKind : uint8_t {
  kNone,
  kSignedSmall,
  kSigned32,
82
  kNumber,
83 84
  kNumberOrOddball,
  kHeapObject
85
};
86

87 88 89 90
inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
  switch (type_check) {
    case TypeCheckKind::kNone:
      return os << "None";
91 92
    case TypeCheckKind::kSignedSmall:
      return os << "SignedSmall";
93 94
    case TypeCheckKind::kSigned32:
      return os << "Signed32";
95 96
    case TypeCheckKind::kNumber:
      return os << "Number";
97 98
    case TypeCheckKind::kNumberOrOddball:
      return os << "NumberOrOddball";
99 100
    case TypeCheckKind::kHeapObject:
      return os << "HeapObject";
101 102 103 104 105
  }
  UNREACHABLE();
  return os;
}

106 107 108 109 110 111
// 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
112 113
//    is the preferred representation. For conversions that will require
//    checks, we also keep track of whether a minus zero check is needed.
114 115 116 117 118 119 120 121
//
// 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.
class UseInfo {
 public:
  UseInfo(MachineRepresentation representation, Truncation truncation,
122 123 124
          TypeCheckKind type_check = TypeCheckKind::kNone,
          CheckForMinusZeroMode minus_zero_check =
              CheckForMinusZeroMode::kCheckForMinusZero)
125 126
      : representation_(representation),
        truncation_(truncation),
127 128
        type_check_(type_check),
        minus_zero_check_(minus_zero_check) {}
129 130 131 132 133 134 135 136 137
  static UseInfo TruncatingWord32() {
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
  }
  static UseInfo TruncatingWord64() {
    return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
  }
  static UseInfo Bool() {
    return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
  }
138 139
  static UseInfo Float32() {
    return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
140 141 142 143 144 145 146 147 148 149
  }
  static UseInfo TruncatingFloat64() {
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
  }
  static UseInfo PointerInt() {
    return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
  }
  static UseInfo AnyTagged() {
    return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
  }
150 151 152 153 154 155
  static UseInfo TaggedSigned() {
    return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
  }
  static UseInfo TaggedPointer() {
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
  }
156 157

  // Possibly deoptimizing conversions.
158 159 160 161
  static UseInfo CheckedHeapObjectAsTaggedPointer() {
    return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
                   TypeCheckKind::kHeapObject);
  }
162 163 164 165
  static UseInfo CheckedSignedSmallAsTaggedSigned() {
    return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any(),
                   TypeCheckKind::kSignedSmall);
  }
166 167 168
  static UseInfo CheckedSignedSmallAsWord32(
      CheckForMinusZeroMode minus_zero_mode =
          CheckForMinusZeroMode::kCheckForMinusZero) {
169
    return UseInfo(MachineRepresentation::kWord32, Truncation::Any(),
170
                   TypeCheckKind::kSignedSmall, minus_zero_mode);
171
  }
172 173 174
  static UseInfo CheckedSigned32AsWord32(
      CheckForMinusZeroMode minus_zero_mode =
          CheckForMinusZeroMode::kCheckForMinusZero) {
175
    return UseInfo(MachineRepresentation::kWord32, Truncation::Any(),
176
                   TypeCheckKind::kSigned32, minus_zero_mode);
177
  }
178 179 180 181 182 183 184 185
  static UseInfo CheckedNumberAsFloat64() {
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64(),
                   TypeCheckKind::kNumber);
  }
  static UseInfo CheckedNumberAsWord32() {
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
                   TypeCheckKind::kNumber);
  }
186
  static UseInfo CheckedNumberOrOddballAsFloat64() {
187
    return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
188
                   TypeCheckKind::kNumberOrOddball);
189
  }
190 191 192 193
  static UseInfo CheckedNumberOrOddballAsWord32() {
    return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
                   TypeCheckKind::kNumberOrOddball);
  }
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

  // 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_; }
211
  CheckForMinusZeroMode minus_zero_check() const { return minus_zero_check_; }
212 213 214 215 216

 private:
  MachineRepresentation representation_;
  Truncation truncation_;
  TypeCheckKind type_check_;
217 218
  // TODO(jarin) Integrate with truncations.
  CheckForMinusZeroMode minus_zero_check_;
219
};
220

221 222 223
// 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.
224
class RepresentationChanger final {
225
 public:
226
  RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
227 228 229 230 231
      : jsgraph_(jsgraph),
        isolate_(isolate),
        testing_type_errors_(false),
        type_error_(false) {}

232 233 234 235
  // 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).
236
  Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
237 238
                             Type* output_type, Node* use_node,
                             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 248
    return access.tag() != 0 ? MachineType::AnyTagged()
                             : MachineType::Pointer();
249 250
  }

251
  MachineType TypeForBasePointer(const ElementAccess& access) {
252 253
    return access.tag() != 0 ? MachineType::AnyTagged()
                             : MachineType::Pointer();
254 255 256 257 258 259 260 261 262 263 264
  }

 private:
  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.

265 266
  Node* GetTaggedSignedRepresentationFor(Node* node,
                                         MachineRepresentation output_rep,
267 268
                                         Type* output_type, Node* use_node,
                                         UseInfo use_info);
269 270
  Node* GetTaggedPointerRepresentationFor(Node* node,
                                          MachineRepresentation output_rep,
271 272
                                          Type* output_type, Node* use_node,
                                          UseInfo use_info);
273
  Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
274
                                   Type* output_type, Truncation truncation);
275 276 277 278 279
  Node* GetFloat32RepresentationFor(Node* node,
                                    MachineRepresentation output_rep,
                                    Type* output_type, Truncation truncation);
  Node* GetFloat64RepresentationFor(Node* node,
                                    MachineRepresentation output_rep,
280 281
                                    Type* output_type, Node* use_node,
                                    UseInfo use_info);
282
  Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
283 284
                                   Type* output_type, Node* use_node,
                                   UseInfo use_info);
285 286 287 288 289 290
  Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
                                Type* output_type);
  Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
                                   Type* output_type);
  Node* TypeError(Node* node, MachineRepresentation output_rep,
                  Type* output_type, MachineRepresentation use);
291
  Node* MakeTruncatedInt32Constant(double value);
292
  Node* InsertChangeBitToTagged(Node* node);
293
  Node* InsertChangeFloat32ToFloat64(Node* node);
294 295
  Node* InsertChangeFloat64ToInt32(Node* node);
  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 302
  Node* InsertConversion(Node* node, const Operator* op, Node* use_node);

303 304
  JSGraph* jsgraph() const { return jsgraph_; }
  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 311 312

}  // namespace compiler
}  // namespace internal
}  // namespace v8
313 314

#endif  // V8_COMPILER_REPRESENTATION_CHANGE_H_