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