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