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 : static Truncation Generalize(Truncation t1, Truncation t2) {
40 : return Truncation(
41 : Generalize(t1.kind(), t2.kind()),
42 99943196 : GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
43 : }
44 :
45 : // Queries.
46 : bool IsUnused() const { return kind_ == TruncationKind::kNone; }
47 : bool IsUsedAsBool() const {
48 153173 : return LessGeneral(kind_, TruncationKind::kBool);
49 : }
50 : bool IsUsedAsWord32() const {
51 1543427 : return LessGeneral(kind_, TruncationKind::kWord32);
52 : }
53 : bool IsUsedAsFloat64() const {
54 779572 : 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 99940391 : return kind() == other.kind() && identify_zeros() == other.identify_zeros();
67 : }
68 99940391 : bool operator!=(Truncation other) const { return !(*this == other); }
69 :
70 : // Debug utilities.
71 : const char* description() const;
72 : bool IsLessGeneralThan(Truncation other) {
73 0 : 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 270028147 : feedback_(feedback) {}
160 : static UseInfo TruncatingWord32() {
161 6445534 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
162 : }
163 : static UseInfo Word64() {
164 47638 : return UseInfo(MachineRepresentation::kWord64, Truncation::Any());
165 : }
166 : static UseInfo Word() {
167 1647034 : return UseInfo(MachineType::PointerRepresentation(), Truncation::Any());
168 : }
169 : static UseInfo Bool() {
170 4172227 : return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
171 : }
172 : static UseInfo Float32() {
173 5560 : return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
174 : }
175 : static UseInfo TruncatingFloat64(
176 : IdentifyZeros identify_zeros = kDistinguishZeros) {
177 : return UseInfo(MachineRepresentation::kFloat64,
178 1931241 : Truncation::Float64(identify_zeros));
179 : }
180 : static UseInfo AnyTagged() {
181 293566722 : return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
182 : }
183 : static UseInfo TaggedSigned() {
184 1762652 : return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
185 : }
186 : static UseInfo TaggedPointer() {
187 : return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
188 : }
189 : static UseInfo AnyCompressed() {
190 0 : return UseInfo(MachineRepresentation::kCompressed, Truncation::Any());
191 : }
192 : static UseInfo CompressedSigned() {
193 0 : return UseInfo(MachineRepresentation::kCompressedSigned, Truncation::Any());
194 : }
195 : static UseInfo CompressedPointer() {
196 : return UseInfo(MachineRepresentation::kCompressedPointer,
197 : Truncation::Any());
198 : }
199 :
200 : // Possibly deoptimizing conversions.
201 : static UseInfo CheckedHeapObjectAsTaggedPointer(
202 : const VectorSlotPair& feedback) {
203 : return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
204 : TypeCheckKind::kHeapObject, feedback);
205 : }
206 : static UseInfo CheckedSignedSmallAsTaggedSigned(
207 : const VectorSlotPair& feedback,
208 : IdentifyZeros identify_zeros = kDistinguishZeros) {
209 : return UseInfo(MachineRepresentation::kTaggedSigned,
210 : Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
211 : feedback);
212 : }
213 : static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros,
214 : const VectorSlotPair& feedback) {
215 : return UseInfo(MachineRepresentation::kWord32,
216 : Truncation::Any(identify_zeros), TypeCheckKind::kSignedSmall,
217 : feedback);
218 : }
219 : static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros,
220 : const VectorSlotPair& feedback) {
221 : return UseInfo(MachineRepresentation::kWord32,
222 : Truncation::Any(identify_zeros), TypeCheckKind::kSigned32,
223 : feedback);
224 : }
225 : static UseInfo CheckedSigned64AsWord64(IdentifyZeros identify_zeros,
226 : const VectorSlotPair& feedback) {
227 : return UseInfo(MachineRepresentation::kWord64,
228 : Truncation::Any(identify_zeros), TypeCheckKind::kSigned64,
229 : feedback);
230 : }
231 : static UseInfo CheckedNumberAsFloat64(IdentifyZeros identify_zeros,
232 : const VectorSlotPair& feedback) {
233 : return UseInfo(MachineRepresentation::kFloat64,
234 : Truncation::Any(identify_zeros), TypeCheckKind::kNumber,
235 : feedback);
236 : }
237 : static UseInfo CheckedNumberAsWord32(const VectorSlotPair& feedback) {
238 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
239 : TypeCheckKind::kNumber, feedback);
240 : }
241 : static UseInfo CheckedNumberOrOddballAsFloat64(
242 : IdentifyZeros identify_zeros, const VectorSlotPair& feedback) {
243 : return UseInfo(MachineRepresentation::kFloat64,
244 : Truncation::Any(identify_zeros),
245 : TypeCheckKind::kNumberOrOddball, feedback);
246 : }
247 : static UseInfo CheckedNumberOrOddballAsWord32(
248 : const VectorSlotPair& feedback) {
249 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
250 : TypeCheckKind::kNumberOrOddball, feedback);
251 : }
252 :
253 : // Undetermined representation.
254 : static UseInfo Any() {
255 32014314 : return UseInfo(MachineRepresentation::kNone, Truncation::Any());
256 : }
257 : static UseInfo AnyTruncatingToBool() {
258 13016 : return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
259 : }
260 :
261 : // Value not used.
262 : static UseInfo None() {
263 192208995 : return UseInfo(MachineRepresentation::kNone, Truncation::None());
264 : }
265 :
266 : MachineRepresentation representation() const { return representation_; }
267 : Truncation truncation() const { return truncation_; }
268 : TypeCheckKind type_check() const { return type_check_; }
269 : CheckForMinusZeroMode minus_zero_check() const {
270 : return truncation().IdentifiesZeroAndMinusZero()
271 : ? CheckForMinusZeroMode::kDontCheckForMinusZero
272 4920 : : CheckForMinusZeroMode::kCheckForMinusZero;
273 : }
274 : const VectorSlotPair& feedback() const { return feedback_; }
275 :
276 : private:
277 : MachineRepresentation representation_;
278 : Truncation truncation_;
279 : TypeCheckKind type_check_;
280 : VectorSlotPair feedback_;
281 : };
282 :
283 : // Contains logic related to changing the representation of values for constants
284 : // and other nodes, as well as lowering Simplified->Machine operators.
285 : // Eagerly folds any representation changes for constants.
286 : class V8_EXPORT_PRIVATE RepresentationChanger final {
287 : public:
288 : RepresentationChanger(JSGraph* jsgraph, Isolate* isolate);
289 :
290 : // Changes representation from {output_type} to {use_rep}. The {truncation}
291 : // parameter is only used for sanity checking - if the changer cannot figure
292 : // out signedness for the word32->float64 conversion, then we check that the
293 : // uses truncate to word32 (so they do not care about signedness).
294 : Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
295 : Type output_type, Node* use_node,
296 : UseInfo use_info);
297 : const Operator* Int32OperatorFor(IrOpcode::Value opcode);
298 : const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
299 : const Operator* Int64OperatorFor(IrOpcode::Value opcode);
300 : const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode);
301 : const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
302 : const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode);
303 : const Operator* Float64OperatorFor(IrOpcode::Value opcode);
304 :
305 : MachineType TypeForBasePointer(const FieldAccess& access) {
306 : return access.tag() != 0 ? MachineType::AnyTagged()
307 : : MachineType::Pointer();
308 : }
309 :
310 : MachineType TypeForBasePointer(const ElementAccess& access) {
311 : return access.tag() != 0 ? MachineType::AnyTagged()
312 : : MachineType::Pointer();
313 : }
314 :
315 : private:
316 : TypeCache const* cache_;
317 : JSGraph* jsgraph_;
318 : Isolate* isolate_;
319 :
320 : friend class RepresentationChangerTester; // accesses the below fields.
321 :
322 : bool testing_type_errors_; // If {true}, don't abort on a type error.
323 : bool type_error_; // Set when a type error is detected.
324 :
325 : Node* GetTaggedSignedRepresentationFor(Node* node,
326 : MachineRepresentation output_rep,
327 : Type output_type, Node* use_node,
328 : UseInfo use_info);
329 : Node* GetTaggedPointerRepresentationFor(Node* node,
330 : MachineRepresentation output_rep,
331 : Type output_type, Node* use_node,
332 : UseInfo use_info);
333 : Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
334 : Type output_type, Truncation truncation);
335 : Node* GetCompressedSignedRepresentationFor(Node* node,
336 : MachineRepresentation output_rep,
337 : Type output_type, Node* use_node,
338 : UseInfo use_info);
339 : Node* GetCompressedPointerRepresentationFor(Node* node,
340 : MachineRepresentation output_rep,
341 : Type output_type, Node* use_node,
342 : UseInfo use_info);
343 : Node* GetCompressedRepresentationFor(Node* node,
344 : MachineRepresentation output_rep,
345 : Type output_type, Truncation truncation);
346 : Node* GetFloat32RepresentationFor(Node* node,
347 : MachineRepresentation output_rep,
348 : Type output_type, Truncation truncation);
349 : Node* GetFloat64RepresentationFor(Node* node,
350 : MachineRepresentation output_rep,
351 : Type output_type, Node* use_node,
352 : UseInfo use_info);
353 : Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
354 : Type output_type, Node* use_node,
355 : UseInfo use_info);
356 : Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
357 : Type output_type);
358 : Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
359 : Type output_type, Node* use_node,
360 : UseInfo use_info);
361 : Node* TypeError(Node* node, MachineRepresentation output_rep,
362 : Type output_type, MachineRepresentation use);
363 : Node* MakeTruncatedInt32Constant(double value);
364 : Node* InsertChangeBitToTagged(Node* node);
365 : Node* InsertChangeFloat32ToFloat64(Node* node);
366 : Node* InsertChangeFloat64ToInt32(Node* node);
367 : Node* InsertChangeFloat64ToUint32(Node* node);
368 : Node* InsertChangeInt32ToFloat64(Node* node);
369 : Node* InsertChangeTaggedSignedToInt32(Node* node);
370 : Node* InsertChangeTaggedToFloat64(Node* node);
371 : Node* InsertChangeUint32ToFloat64(Node* node);
372 : Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
373 : Node* InsertTruncateInt64ToInt32(Node* node);
374 : Node* InsertUnconditionalDeopt(Node* node, DeoptimizeReason reason);
375 :
376 : JSGraph* jsgraph() const { return jsgraph_; }
377 : Isolate* isolate() const { return isolate_; }
378 : Factory* factory() const { return isolate()->factory(); }
379 : SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
380 : MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
381 : };
382 :
383 : } // namespace compiler
384 : } // namespace internal
385 : } // namespace v8
386 :
387 : #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_
|