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