Line data Source code
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 88835260 : static Truncation Generalize(Truncation t1, Truncation t2) {
40 : return Truncation(
41 : Generalize(t1.kind(), t2.kind()),
42 88835260 : GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
43 : }
44 :
45 : // Queries.
46 : bool IsUnused() const { return kind_ == TruncationKind::kNone; }
47 : bool IsUsedAsBool() const {
48 133292 : return LessGeneral(kind_, TruncationKind::kBool);
49 : }
50 : bool IsUsedAsWord32() const {
51 1545673 : return LessGeneral(kind_, TruncationKind::kWord32);
52 : }
53 : bool IsUsedAsFloat64() const {
54 769916 : return LessGeneral(kind_, TruncationKind::kFloat64);
55 : }
56 : bool IdentifiesUndefinedAndZero() {
57 : return LessGeneral(kind_, TruncationKind::kWord32) ||
58 : LessGeneral(kind_, TruncationKind::kBool);
59 : }
60 5975 : bool IdentifiesZeroAndMinusZero() const {
61 77883 : return identify_zeros() == kIdentifyZeros;
62 : }
63 :
64 : // Operators.
65 159028516 : bool operator==(Truncation other) const {
66 159028516 : return kind() == other.kind() && identify_zeros() == other.identify_zeros();
67 : }
68 88834375 : bool operator!=(Truncation other) const { return !(*this == other); }
69 :
70 : // Debug utilities.
71 : const char* description() const;
72 21 : bool IsLessGeneralThan(Truncation other) {
73 21 : return LessGeneral(kind(), other.kind()) &&
74 14 : 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 239752304 : feedback_(feedback) {}
160 : static UseInfo TruncatingWord32() {
161 7911856 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
162 : }
163 : static UseInfo Word64() {
164 167286 : return UseInfo(MachineRepresentation::kWord64, Truncation::Any());
165 : }
166 : static UseInfo Word() {
167 1655366 : return UseInfo(MachineType::PointerRepresentation(), Truncation::Any());
168 : }
169 : static UseInfo Bool() {
170 4025603 : return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
171 : }
172 : static UseInfo Float32() {
173 5152 : return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
174 : }
175 : static UseInfo TruncatingFloat64(
176 : IdentifyZeros identify_zeros = kDistinguishZeros) {
177 : return UseInfo(MachineRepresentation::kFloat64,
178 1985643 : Truncation::Float64(identify_zeros));
179 : }
180 : static UseInfo AnyTagged() {
181 258764402 : return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
182 : }
183 : static UseInfo TaggedSigned() {
184 1643335 : 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 250780 : 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 29638429 : return UseInfo(MachineRepresentation::kNone, Truncation::Any());
245 : }
246 : static UseInfo AnyTruncatingToBool() {
247 13478 : return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
248 : }
249 :
250 : // Value not used.
251 : static UseInfo None() {
252 167357591 : 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 5091 : : 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.
275 : class RepresentationChanger final {
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 159694 : Factory* factory() const { return isolate()->factory(); }
357 874241 : SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
358 537599 : MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
359 : };
360 :
361 : } // namespace compiler
362 : } // namespace internal
363 : } // namespace v8
364 :
365 : #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_
|