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