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 : enum IdentifyZeros { kIdentifyZeros, kDistinguishZeros };
16 :
17 : class Truncation final {
18 : public:
19 : // Constructors.
20 : static Truncation None() {
21 : return Truncation(TruncationKind::kNone, kIdentifyZeros);
22 : }
23 : static Truncation Bool() {
24 : return Truncation(TruncationKind::kBool, kIdentifyZeros);
25 : }
26 : static Truncation Word32() {
27 : return Truncation(TruncationKind::kWord32, kIdentifyZeros);
28 : }
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 :
39 91597272 : static Truncation Generalize(Truncation t1, Truncation t2) {
40 : return Truncation(
41 : Generalize(t1.kind(), t2.kind()),
42 91597272 : GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
43 : }
44 :
45 : // Queries.
46 : bool IsUnused() const { return kind_ == TruncationKind::kNone; }
47 : bool IsUsedAsBool() const {
48 180046 : return LessGeneral(kind_, TruncationKind::kBool);
49 : }
50 : bool IsUsedAsWord32() const {
51 1420817 : return LessGeneral(kind_, TruncationKind::kWord32);
52 : }
53 : bool IsUsedAsFloat64() const {
54 799017 : return LessGeneral(kind_, TruncationKind::kFloat64);
55 : }
56 : bool IdentifiesUndefinedAndZero() {
57 : return LessGeneral(kind_, TruncationKind::kWord32) ||
58 : LessGeneral(kind_, TruncationKind::kBool);
59 : }
60 : bool IdentifiesUndefinedAndNaN() {
61 : return LessGeneral(kind_, TruncationKind::kFloat64) ||
62 : LessGeneral(kind_, TruncationKind::kWord64);
63 : }
64 6120 : bool IdentifiesZeroAndMinusZero() const {
65 : return identify_zeros() == kIdentifyZeros;
66 : }
67 :
68 : // Operators.
69 163626343 : bool operator==(Truncation other) const {
70 163626343 : return kind() == other.kind() && identify_zeros() == other.identify_zeros();
71 : }
72 91596678 : bool operator!=(Truncation other) const { return !(*this == other); }
73 :
74 : // Debug utilities.
75 : const char* description() const;
76 : bool IsLessGeneralThan(Truncation other) {
77 : return LessGeneral(kind(), other.kind()) &&
78 : LessGeneralIdentifyZeros(identify_zeros(), other.identify_zeros());
79 : }
80 :
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 :
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 : }
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 : class UseInfo {
151 : public:
152 : UseInfo(MachineRepresentation representation, Truncation truncation,
153 : TypeCheckKind type_check = TypeCheckKind::kNone)
154 : : representation_(representation),
155 : truncation_(truncation),
156 131386 : type_check_(type_check) {}
157 : static UseInfo TruncatingWord32() {
158 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
159 : }
160 : static UseInfo TruncatingWord64() {
161 : return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
162 : }
163 : static UseInfo Bool() {
164 : return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
165 : }
166 : static UseInfo Float32() {
167 : return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
168 : }
169 : static UseInfo TruncatingFloat64() {
170 : return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
171 : }
172 : static UseInfo PointerInt() {
173 : return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
174 : }
175 : static UseInfo AnyTagged() {
176 : return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
177 : }
178 : static UseInfo TaggedSigned() {
179 : return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
180 : }
181 : static UseInfo TaggedPointer() {
182 : return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
183 : }
184 :
185 : // Possibly deoptimizing conversions.
186 : static UseInfo CheckedHeapObjectAsTaggedPointer() {
187 : return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
188 : TypeCheckKind::kHeapObject);
189 : }
190 : static UseInfo CheckedSignedSmallAsTaggedSigned() {
191 : return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any(),
192 : TypeCheckKind::kSignedSmall);
193 : }
194 : static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros) {
195 : return UseInfo(MachineRepresentation::kWord32,
196 : Truncation::Any(identify_zeros),
197 : TypeCheckKind::kSignedSmall);
198 : }
199 : static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros) {
200 : return UseInfo(MachineRepresentation::kWord32,
201 : Truncation::Any(identify_zeros), TypeCheckKind::kSigned32);
202 : }
203 : static UseInfo CheckedNumberAsFloat64() {
204 : return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
205 : TypeCheckKind::kNumber);
206 : }
207 : static UseInfo CheckedNumberAsWord32() {
208 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
209 : TypeCheckKind::kNumber);
210 : }
211 : static UseInfo CheckedNumberOrOddballAsFloat64() {
212 : return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
213 : TypeCheckKind::kNumberOrOddball);
214 : }
215 : static UseInfo CheckedNumberOrOddballAsWord32() {
216 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
217 : TypeCheckKind::kNumberOrOddball);
218 : }
219 :
220 : // Undetermined representation.
221 : static UseInfo Any() {
222 : return UseInfo(MachineRepresentation::kNone, Truncation::Any());
223 : }
224 : static UseInfo AnyTruncatingToBool() {
225 : return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
226 : }
227 :
228 : // Value not used.
229 : static UseInfo None() {
230 : return UseInfo(MachineRepresentation::kNone, Truncation::None());
231 : }
232 :
233 : MachineRepresentation representation() const { return representation_; }
234 : Truncation truncation() const { return truncation_; }
235 : TypeCheckKind type_check() const { return type_check_; }
236 : CheckForMinusZeroMode minus_zero_check() const {
237 : return truncation().IdentifiesZeroAndMinusZero()
238 : ? CheckForMinusZeroMode::kDontCheckForMinusZero
239 6015 : : CheckForMinusZeroMode::kCheckForMinusZero;
240 : }
241 :
242 : private:
243 : MachineRepresentation representation_;
244 : Truncation truncation_;
245 : TypeCheckKind type_check_;
246 : };
247 :
248 : // Contains logic related to changing the representation of values for constants
249 : // and other nodes, as well as lowering Simplified->Machine operators.
250 : // Eagerly folds any representation changes for constants.
251 : class RepresentationChanger final {
252 : public:
253 : RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
254 : : jsgraph_(jsgraph),
255 : isolate_(isolate),
256 : testing_type_errors_(false),
257 443668 : type_error_(false) {}
258 :
259 : // Changes representation from {output_type} to {use_rep}. The {truncation}
260 : // parameter is only used for sanity checking - if the changer cannot figure
261 : // out signedness for the word32->float64 conversion, then we check that the
262 : // uses truncate to word32 (so they do not care about signedness).
263 : Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
264 : Type* output_type, Node* use_node,
265 : UseInfo use_info);
266 : const Operator* Int32OperatorFor(IrOpcode::Value opcode);
267 : const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
268 : const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode);
269 : const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
270 : const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode);
271 : const Operator* Float64OperatorFor(IrOpcode::Value opcode);
272 :
273 : MachineType TypeForBasePointer(const FieldAccess& access) {
274 : return access.tag() != 0 ? MachineType::AnyTagged()
275 : : MachineType::Pointer();
276 : }
277 :
278 : MachineType TypeForBasePointer(const ElementAccess& access) {
279 : return access.tag() != 0 ? MachineType::AnyTagged()
280 : : MachineType::Pointer();
281 : }
282 :
283 : private:
284 : JSGraph* jsgraph_;
285 : Isolate* isolate_;
286 :
287 : friend class RepresentationChangerTester; // accesses the below fields.
288 :
289 : bool testing_type_errors_; // If {true}, don't abort on a type error.
290 : bool type_error_; // Set when a type error is detected.
291 :
292 : Node* GetTaggedSignedRepresentationFor(Node* node,
293 : MachineRepresentation output_rep,
294 : Type* output_type, Node* use_node,
295 : UseInfo use_info);
296 : Node* GetTaggedPointerRepresentationFor(Node* node,
297 : MachineRepresentation output_rep,
298 : Type* output_type, Node* use_node,
299 : UseInfo use_info);
300 : Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
301 : Type* output_type, Truncation truncation);
302 : Node* GetFloat32RepresentationFor(Node* node,
303 : MachineRepresentation output_rep,
304 : Type* output_type, Truncation truncation);
305 : Node* GetFloat64RepresentationFor(Node* node,
306 : MachineRepresentation output_rep,
307 : Type* output_type, Node* use_node,
308 : UseInfo use_info);
309 : Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
310 : Type* output_type, Node* use_node,
311 : UseInfo use_info);
312 : Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
313 : Type* output_type);
314 : Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
315 : Type* output_type);
316 : Node* TypeError(Node* node, MachineRepresentation output_rep,
317 : Type* output_type, MachineRepresentation use);
318 : Node* MakeTruncatedInt32Constant(double value);
319 : Node* InsertChangeBitToTagged(Node* node);
320 : Node* InsertChangeFloat32ToFloat64(Node* node);
321 : Node* InsertChangeFloat64ToInt32(Node* node);
322 : Node* InsertChangeFloat64ToUint32(Node* node);
323 : Node* InsertChangeInt32ToFloat64(Node* node);
324 : Node* InsertChangeTaggedSignedToInt32(Node* node);
325 : Node* InsertChangeTaggedToFloat64(Node* node);
326 : Node* InsertChangeUint32ToFloat64(Node* node);
327 :
328 : Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
329 :
330 : JSGraph* jsgraph() const { return jsgraph_; }
331 : Isolate* isolate() const { return isolate_; }
332 46663 : Factory* factory() const { return isolate()->factory(); }
333 899931 : SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
334 542995 : MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
335 : };
336 :
337 : } // namespace compiler
338 : } // namespace internal
339 : } // namespace v8
340 :
341 : #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_
|