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