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 87735041 : static Truncation Generalize(Truncation t1, Truncation t2) {
40 : return Truncation(
41 : Generalize(t1.kind(), t2.kind()),
42 87735041 : GeneralizeIdentifyZeros(t1.identify_zeros(), t2.identify_zeros()));
43 : }
44 :
45 : // Queries.
46 : bool IsUnused() const { return kind_ == TruncationKind::kNone; }
47 : bool IsUsedAsBool() const {
48 266036 : return LessGeneral(kind_, TruncationKind::kBool);
49 : }
50 : bool IsUsedAsWord32() const {
51 1144412 : return LessGeneral(kind_, TruncationKind::kWord32);
52 : }
53 : bool IsUsedAsFloat64() const {
54 735079 : return LessGeneral(kind_, TruncationKind::kFloat64);
55 : }
56 19523 : bool IdentifiesNaNAndZero() {
57 24634 : return LessGeneral(kind_, TruncationKind::kWord32) ||
58 24634 : LessGeneral(kind_, TruncationKind::kBool);
59 : }
60 20318 : bool IdentifiesUndefinedAndNaNAndZero() {
61 21113 : return LessGeneral(kind_, TruncationKind::kFloat64) ||
62 21113 : LessGeneral(kind_, TruncationKind::kWord64);
63 : }
64 7143 : bool IdentifiesZeroAndMinusZero() const {
65 : return identify_zeros() == kIdentifyZeros;
66 : }
67 :
68 : // Operators.
69 155481445 : bool operator==(Truncation other) const {
70 155481445 : return kind() == other.kind() && identify_zeros() == other.identify_zeros();
71 : }
72 87733895 : 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 : return os;
136 : }
137 :
138 : // The {UseInfo} class is used to describe a use of an input of a node.
139 : //
140 : // This information is used in two different ways, based on the phase:
141 : //
142 : // 1. During propagation, the use info is used to inform the input node
143 : // about what part of the input is used (we call this truncation) and what
144 : // is the preferred representation. For conversions that will require
145 : // checks, we also keep track of whether a minus zero check is needed.
146 : //
147 : // 2. During lowering, the use info is used to properly convert the input
148 : // to the preferred representation. The preferred representation might be
149 : // insufficient to do the conversion (e.g. word32->float64 conv), so we also
150 : // need the signedness information to produce the correct value.
151 : class UseInfo {
152 : public:
153 : UseInfo(MachineRepresentation representation, Truncation truncation,
154 : TypeCheckKind type_check = TypeCheckKind::kNone)
155 : : representation_(representation),
156 : truncation_(truncation),
157 102262 : type_check_(type_check) {}
158 : static UseInfo TruncatingWord32() {
159 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32());
160 : }
161 : static UseInfo TruncatingWord64() {
162 : return UseInfo(MachineRepresentation::kWord64, Truncation::Word64());
163 : }
164 : static UseInfo Bool() {
165 : return UseInfo(MachineRepresentation::kBit, Truncation::Bool());
166 : }
167 : static UseInfo Float32() {
168 : return UseInfo(MachineRepresentation::kFloat32, Truncation::Any());
169 : }
170 : static UseInfo TruncatingFloat64() {
171 : return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64());
172 : }
173 : static UseInfo PointerInt() {
174 : return kPointerSize == 4 ? TruncatingWord32() : TruncatingWord64();
175 : }
176 : static UseInfo AnyTagged() {
177 : return UseInfo(MachineRepresentation::kTagged, Truncation::Any());
178 : }
179 : static UseInfo TaggedSigned() {
180 : return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any());
181 : }
182 : static UseInfo TaggedPointer() {
183 : return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any());
184 : }
185 :
186 : // Possibly deoptimizing conversions.
187 : static UseInfo CheckedHeapObjectAsTaggedPointer() {
188 : return UseInfo(MachineRepresentation::kTaggedPointer, Truncation::Any(),
189 : TypeCheckKind::kHeapObject);
190 : }
191 : static UseInfo CheckedSignedSmallAsTaggedSigned() {
192 : return UseInfo(MachineRepresentation::kTaggedSigned, Truncation::Any(),
193 : TypeCheckKind::kSignedSmall);
194 : }
195 : static UseInfo CheckedSignedSmallAsWord32(IdentifyZeros identify_zeros) {
196 : return UseInfo(MachineRepresentation::kWord32,
197 : Truncation::Any(identify_zeros),
198 : TypeCheckKind::kSignedSmall);
199 : }
200 : static UseInfo CheckedSigned32AsWord32(IdentifyZeros identify_zeros) {
201 : return UseInfo(MachineRepresentation::kWord32,
202 : Truncation::Any(identify_zeros), TypeCheckKind::kSigned32);
203 : }
204 : static UseInfo CheckedNumberAsFloat64() {
205 : return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64(),
206 : TypeCheckKind::kNumber);
207 : }
208 : static UseInfo CheckedNumberAsWord32() {
209 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
210 : TypeCheckKind::kNumber);
211 : }
212 : static UseInfo CheckedNumberOrOddballAsFloat64() {
213 : return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
214 : TypeCheckKind::kNumberOrOddball);
215 : }
216 : static UseInfo CheckedNumberOrOddballAsWord32() {
217 : return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
218 : TypeCheckKind::kNumberOrOddball);
219 : }
220 :
221 : // Undetermined representation.
222 : static UseInfo Any() {
223 : return UseInfo(MachineRepresentation::kNone, Truncation::Any());
224 : }
225 : static UseInfo AnyTruncatingToBool() {
226 : return UseInfo(MachineRepresentation::kNone, Truncation::Bool());
227 : }
228 :
229 : // Value not used.
230 : static UseInfo None() {
231 : return UseInfo(MachineRepresentation::kNone, Truncation::None());
232 : }
233 :
234 : MachineRepresentation representation() const { return representation_; }
235 : Truncation truncation() const { return truncation_; }
236 : TypeCheckKind type_check() const { return type_check_; }
237 : CheckForMinusZeroMode minus_zero_check() const {
238 : return truncation().IdentifiesZeroAndMinusZero()
239 : ? CheckForMinusZeroMode::kDontCheckForMinusZero
240 5450 : : CheckForMinusZeroMode::kCheckForMinusZero;
241 : }
242 :
243 : private:
244 : MachineRepresentation representation_;
245 : Truncation truncation_;
246 : TypeCheckKind type_check_;
247 : };
248 :
249 : // Contains logic related to changing the representation of values for constants
250 : // and other nodes, as well as lowering Simplified->Machine operators.
251 : // Eagerly folds any representation changes for constants.
252 : class RepresentationChanger final {
253 : public:
254 : RepresentationChanger(JSGraph* jsgraph, Isolate* isolate)
255 : : jsgraph_(jsgraph),
256 : isolate_(isolate),
257 : testing_type_errors_(false),
258 395303 : type_error_(false) {}
259 :
260 : // Changes representation from {output_type} to {use_rep}. The {truncation}
261 : // parameter is only used for sanity checking - if the changer cannot figure
262 : // out signedness for the word32->float64 conversion, then we check that the
263 : // uses truncate to word32 (so they do not care about signedness).
264 : Node* GetRepresentationFor(Node* node, MachineRepresentation output_rep,
265 : Type* output_type, Node* use_node,
266 : UseInfo use_info);
267 : const Operator* Int32OperatorFor(IrOpcode::Value opcode);
268 : const Operator* Int32OverflowOperatorFor(IrOpcode::Value opcode);
269 : const Operator* TaggedSignedOperatorFor(IrOpcode::Value opcode);
270 : const Operator* Uint32OperatorFor(IrOpcode::Value opcode);
271 : const Operator* Uint32OverflowOperatorFor(IrOpcode::Value opcode);
272 : const Operator* Float64OperatorFor(IrOpcode::Value opcode);
273 :
274 : MachineType TypeForBasePointer(const FieldAccess& access) {
275 : return access.tag() != 0 ? MachineType::AnyTagged()
276 : : MachineType::Pointer();
277 : }
278 :
279 : MachineType TypeForBasePointer(const ElementAccess& access) {
280 : return access.tag() != 0 ? MachineType::AnyTagged()
281 : : MachineType::Pointer();
282 : }
283 :
284 : private:
285 : JSGraph* jsgraph_;
286 : Isolate* isolate_;
287 :
288 : friend class RepresentationChangerTester; // accesses the below fields.
289 :
290 : bool testing_type_errors_; // If {true}, don't abort on a type error.
291 : bool type_error_; // Set when a type error is detected.
292 :
293 : Node* GetTaggedSignedRepresentationFor(Node* node,
294 : MachineRepresentation output_rep,
295 : Type* output_type, Node* use_node,
296 : UseInfo use_info);
297 : Node* GetTaggedPointerRepresentationFor(Node* node,
298 : MachineRepresentation output_rep,
299 : Type* output_type, Node* use_node,
300 : UseInfo use_info);
301 : Node* GetTaggedRepresentationFor(Node* node, MachineRepresentation output_rep,
302 : Type* output_type, Truncation truncation);
303 : Node* GetFloat32RepresentationFor(Node* node,
304 : MachineRepresentation output_rep,
305 : Type* output_type, Truncation truncation);
306 : Node* GetFloat64RepresentationFor(Node* node,
307 : MachineRepresentation output_rep,
308 : Type* output_type, Node* use_node,
309 : UseInfo use_info);
310 : Node* GetWord32RepresentationFor(Node* node, MachineRepresentation output_rep,
311 : Type* output_type, Node* use_node,
312 : UseInfo use_info);
313 : Node* GetBitRepresentationFor(Node* node, MachineRepresentation output_rep,
314 : Type* output_type);
315 : Node* GetWord64RepresentationFor(Node* node, MachineRepresentation output_rep,
316 : Type* output_type);
317 : Node* TypeError(Node* node, MachineRepresentation output_rep,
318 : Type* output_type, MachineRepresentation use);
319 : Node* MakeTruncatedInt32Constant(double value);
320 : Node* InsertChangeBitToTagged(Node* node);
321 : Node* InsertChangeFloat32ToFloat64(Node* node);
322 : Node* InsertChangeFloat64ToInt32(Node* node);
323 : Node* InsertChangeFloat64ToUint32(Node* node);
324 : Node* InsertChangeInt32ToFloat64(Node* node);
325 : Node* InsertChangeTaggedSignedToInt32(Node* node);
326 : Node* InsertChangeTaggedToFloat64(Node* node);
327 : Node* InsertChangeUint32ToFloat64(Node* node);
328 :
329 : Node* InsertConversion(Node* node, const Operator* op, Node* use_node);
330 :
331 : JSGraph* jsgraph() const { return jsgraph_; }
332 : Isolate* isolate() const { return isolate_; }
333 56362 : Factory* factory() const { return isolate()->factory(); }
334 963723 : SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
335 605121 : MachineOperatorBuilder* machine() { return jsgraph()->machine(); }
336 : };
337 :
338 : } // namespace compiler
339 : } // namespace internal
340 : } // namespace v8
341 :
342 : #endif // V8_COMPILER_REPRESENTATION_CHANGE_H_
|