]>
Commit | Line | Data |
---|---|---|
ed1e77d3 A |
1 | /* |
2 | * Copyright (C) 2015 Apple Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #include "config.h" | |
27 | #include "DFGIntegerRangeOptimizationPhase.h" | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "DFGBlockMapInlines.h" | |
32 | #include "DFGGraph.h" | |
33 | #include "DFGInsertionSet.h" | |
34 | #include "DFGPhase.h" | |
35 | #include "DFGPredictionPropagationPhase.h" | |
36 | #include "DFGVariableAccessDataDump.h" | |
37 | #include "JSCInlines.h" | |
38 | ||
39 | namespace JSC { namespace DFG { | |
40 | ||
41 | namespace { | |
42 | ||
43 | const bool verbose = false; | |
44 | ||
45 | int64_t clampedSumImpl() { return 0; } | |
46 | ||
47 | template<typename... Args> | |
48 | int64_t clampedSumImpl(int left, Args... args) | |
49 | { | |
50 | return static_cast<int64_t>(left) + clampedSumImpl(args...); | |
51 | } | |
52 | ||
53 | template<typename... Args> | |
54 | int clampedSum(Args... args) | |
55 | { | |
56 | int64_t result = clampedSumImpl(args...); | |
57 | return static_cast<int>(std::min( | |
58 | static_cast<int64_t>(std::numeric_limits<int>::max()), | |
59 | std::max( | |
60 | static_cast<int64_t>(std::numeric_limits<int>::min()), | |
61 | result))); | |
62 | } | |
63 | ||
64 | class Relationship { | |
65 | public: | |
66 | enum Kind { | |
67 | LessThan, | |
68 | Equal, | |
69 | NotEqual, | |
70 | GreaterThan | |
71 | }; | |
72 | ||
73 | static Kind flipped(Kind kind) | |
74 | { | |
75 | switch (kind) { | |
76 | case LessThan: | |
77 | return GreaterThan; | |
78 | case Equal: | |
79 | return Equal; | |
80 | case NotEqual: | |
81 | return NotEqual; | |
82 | case GreaterThan: | |
83 | return LessThan; | |
84 | } | |
85 | RELEASE_ASSERT_NOT_REACHED(); | |
86 | return kind; | |
87 | } | |
88 | ||
89 | Relationship() | |
90 | : m_left(nullptr) | |
91 | , m_right(nullptr) | |
92 | , m_kind(Equal) | |
93 | , m_offset(0) | |
94 | { | |
95 | } | |
96 | ||
97 | Relationship(Node* left, Node* right, Kind kind, int offset = 0) | |
98 | : m_left(left) | |
99 | , m_right(right) | |
100 | , m_kind(kind) | |
101 | , m_offset(offset) | |
102 | { | |
103 | RELEASE_ASSERT(m_left); | |
104 | RELEASE_ASSERT(m_right); | |
105 | RELEASE_ASSERT(m_left != m_right); | |
106 | } | |
107 | ||
108 | static Relationship safeCreate(Node* left, Node* right, Kind kind, int offset = 0) | |
109 | { | |
110 | if (!left || !right || left == right) | |
111 | return Relationship(); | |
112 | return Relationship(left, right, kind, offset); | |
113 | } | |
114 | ||
115 | typedef void* (Relationship::*UnspecifiedBoolType); | |
116 | ||
117 | explicit operator bool() const { return m_left; } | |
118 | ||
119 | Node* left() const { return m_left; } | |
120 | Node* right() const { return m_right; } | |
121 | Kind kind() const { return m_kind; } | |
122 | int offset() const { return m_offset; } | |
123 | ||
124 | Relationship flipped() const | |
125 | { | |
126 | if (!*this) | |
127 | return Relationship(); | |
128 | ||
129 | // This should return Relationship() if -m_offset overflows. For example: | |
130 | // | |
131 | // @a > @b - 2**31 | |
132 | // | |
133 | // If we flip it we get: | |
134 | // | |
135 | // @b < @a + 2**31 | |
136 | // | |
137 | // Except that the sign gets flipped since it's INT_MIN: | |
138 | // | |
139 | // @b < @a - 2**31 | |
140 | // | |
141 | // And that makes no sense. To see how little sense it makes, consider: | |
142 | // | |
143 | // @a > @zero - 2**31 | |
144 | // | |
145 | // We would flip it to mean: | |
146 | // | |
147 | // @zero < @a - 2**31 | |
148 | // | |
149 | // Which is absurd. | |
150 | ||
151 | if (m_offset == std::numeric_limits<int>::min()) | |
152 | return Relationship(); | |
153 | ||
154 | return Relationship(m_right, m_left, flipped(m_kind), -m_offset); | |
155 | } | |
156 | ||
157 | Relationship inverse() const | |
158 | { | |
159 | if (!*this) | |
160 | return *this; | |
161 | ||
162 | switch (m_kind) { | |
163 | case Equal: | |
164 | return Relationship(m_left, m_right, NotEqual, m_offset); | |
165 | case NotEqual: | |
166 | return Relationship(m_left, m_right, Equal, m_offset); | |
167 | case LessThan: | |
168 | if (sumOverflows<int>(m_offset, -1)) | |
169 | return Relationship(); | |
170 | return Relationship(m_left, m_right, GreaterThan, m_offset - 1); | |
171 | case GreaterThan: | |
172 | if (sumOverflows<int>(m_offset, 1)) | |
173 | return Relationship(); | |
174 | return Relationship(m_left, m_right, LessThan, m_offset + 1); | |
175 | } | |
176 | ||
177 | RELEASE_ASSERT_NOT_REACHED(); | |
178 | } | |
179 | ||
180 | bool isCanonical() const { return m_left < m_right; } | |
181 | ||
182 | Relationship canonical() const | |
183 | { | |
184 | if (isCanonical()) | |
185 | return *this; | |
186 | return flipped(); | |
187 | } | |
188 | ||
189 | bool sameNodesAs(const Relationship& other) const | |
190 | { | |
191 | return m_left == other.m_left | |
192 | && m_right == other.m_right; | |
193 | } | |
194 | ||
195 | bool operator==(const Relationship& other) const | |
196 | { | |
197 | return sameNodesAs(other) | |
198 | && m_kind == other.m_kind | |
199 | && m_offset == other.m_offset; | |
200 | } | |
201 | ||
202 | bool operator!=(const Relationship& other) const | |
203 | { | |
204 | return !(*this == other); | |
205 | } | |
206 | ||
207 | bool operator<(const Relationship& other) const | |
208 | { | |
209 | if (m_left != other.m_left) | |
210 | return m_left < other.m_left; | |
211 | if (m_right != other.m_right) | |
212 | return m_right < other.m_right; | |
213 | if (m_kind != other.m_kind) | |
214 | return m_kind < other.m_kind; | |
215 | return m_offset < other.m_offset; | |
216 | } | |
217 | ||
218 | // If possible, returns a form of this relationship where the given node is the left | |
219 | // side. Returns a null relationship if this relationship cannot say anything about this | |
220 | // node. | |
221 | Relationship forNode(Node* node) const | |
222 | { | |
223 | if (m_left == node) | |
224 | return *this; | |
225 | if (m_right == node) | |
226 | return flipped(); | |
227 | return Relationship(); | |
228 | } | |
229 | ||
230 | void setLeft(Node* left) | |
231 | { | |
232 | RELEASE_ASSERT(left != m_right); | |
233 | m_left = left; | |
234 | } | |
235 | bool addToOffset(int offset) | |
236 | { | |
237 | if (sumOverflows<int>(m_offset, offset)) | |
238 | return false; | |
239 | m_offset += offset; | |
240 | return true; | |
241 | } | |
242 | ||
243 | // Attempts to create a relationship that summarizes the union of this relationship and | |
244 | // the other relationship. The null relationship is returned to indicate TOP. This is used | |
245 | // for merging the current relationship-at-head for some pair of nodes and a new | |
246 | // relationship-at-head being proposed by a predecessor. We wish to create a new | |
247 | // relationship that is true whenever either of them are true, which ensuring that we don't | |
248 | // do this forever. Anytime we create a relationship that is not equal to either of the | |
249 | // previous ones, we will cause the analysis fixpoint to reexecute. | |
250 | // | |
251 | // If *this and other are identical, we just return it. | |
252 | // | |
253 | // If they are different, we pick from a finite set of "general" relationships: | |
254 | // | |
255 | // Eq: this == other + C, where C is -1, 0, or 1. | |
256 | // Lt: this < other + C, where C is -1, 0, or 1. | |
257 | // Gt: this > other + C, where C is -1, 0, or 1. | |
258 | // Ne: this != other + C, where C is -1, 0, or 1. | |
259 | // TOP: the null relationship. | |
260 | // | |
261 | // Constraining C to -1,0,1 is necessary to ensure that the set of general relationships is | |
262 | // finite. This finite set of relationships forms a pretty simple lattice where a | |
263 | // relA->relB means "relB is more general than relA". For example, this<other+1 is more | |
264 | // general than this==other. I'll leave it as an exercise for the reader to see that a | |
265 | // graph between the 13 general relationships is indeed a lattice. The fact that the set of | |
266 | // general relationships is a finite lattice ensures monotonicity of the fixpoint, since | |
267 | // any merge over not-identical relationships returns a relationship that is closer to the | |
268 | // TOP relationship than either of the original relationships. Here's how convergence is | |
269 | // achieved for any pair of relationships over the same nodes: | |
270 | // | |
271 | // - If they are identical, then returning *this means that we won't be responsible for | |
272 | // causing another fixpoint iteration. Once all merges reach this point, we're done. | |
273 | // | |
274 | // - If they are different, then we pick the most constraining of the 13 general | |
275 | // relationships that is true if either *this or other are true. This means that if the | |
276 | // relationships are not identical, the merged relationship will be closer to TOP than | |
277 | // either of the originals. Returning a different relationship means that we will be | |
278 | // responsible for the fixpoint to reloop, but we can only do this at most 13 times since | |
279 | // that's how "deep" the general relationship lattice is. | |
280 | // | |
281 | // Note that C being constrained to -1,0,1 also ensures that we never have to return a | |
282 | // combination of Lt and Gt, as in for example this<other+C && this>other-D. That's why | |
283 | // this function can return zero or one relationships rather than a list of relationships. | |
284 | // The only possible values of C and D where this would work are -1 and 1, but in that case | |
285 | // we just say this==other. That said, the logic for merging two == relationships, like | |
286 | // this==other+C || this==other+D is to attempt to create these two relationships: | |
287 | // this>other+min(C,D)-1 && this<other+max(C,D)+1. But only one of these relationships will | |
288 | // belong to the set of general relationships. | |
289 | // | |
290 | // Here's an example of this in action: | |
291 | // | |
292 | // for (var i = a; ; ++i) { } | |
293 | // | |
294 | // Without C being constrained to -1,0,1, we could end up looping forever: first we'd say | |
295 | // that i==a, then we might say that i<a+2, then i<a+3, then i<a+4, etc. We won't do this | |
296 | // because i<a+2 is not a valid general relationship: so when we merge i==a from the first | |
297 | // iteration and i==a+1 from the second iteration, we create i>a-1 and i<a+2 but then | |
298 | // realize that only i>a-1 is a valid general relationship. This gives us exactly what we | |
299 | // want: a statement that i>=a. | |
300 | Relationship merge(const Relationship& other) const | |
301 | { | |
302 | if (!sameNodesAs(other)) | |
303 | return Relationship(); | |
304 | ||
305 | // Handle the super obvious case first. | |
306 | if (*this == other) | |
307 | return *this; | |
308 | ||
309 | // This does some interesting permutations to reduce the amount of duplicate code. For | |
310 | // example: | |
311 | // | |
312 | // initially: @a != @b, @a > @b | |
313 | // @b != @a, @b < @a | |
314 | // @b < @a, @b != @a | |
315 | // finally: @b != a, @b < @a | |
316 | // | |
317 | // Another example: | |
318 | // | |
319 | // initially: @a < @b, @a != @b | |
320 | // finally: @a != @b, @a < @b | |
321 | ||
322 | Relationship a = *this; | |
323 | Relationship b = other; | |
324 | bool needFlip = false; | |
325 | ||
326 | // Get rid of GreaterThan. | |
327 | if (a.m_kind == GreaterThan || b.m_kind == GreaterThan) { | |
328 | a = a.flipped(); | |
329 | b = b.flipped(); | |
330 | ||
331 | // In rare cases, we might not be able to flip. Just give up on life in those | |
332 | // cases. | |
333 | if (!a || !b) | |
334 | return Relationship(); | |
335 | ||
336 | needFlip = true; | |
337 | ||
338 | // If we still have GreaterThan, then it means that we started with @a < @b and | |
339 | // @a > @b. That's pretty much always a tautology; we don't attempt to do smart | |
340 | // things for that case for now. | |
341 | if (a.m_kind == GreaterThan || b.m_kind == GreaterThan) | |
342 | return Relationship(); | |
343 | } | |
344 | ||
345 | // Make sure that if we have a LessThan, then it's first. | |
346 | if (b.m_kind == LessThan) | |
347 | std::swap(a, b); | |
348 | ||
349 | // Make sure that if we have a NotEqual, then it's first. | |
350 | if (b.m_kind == NotEqual) | |
351 | std::swap(a, b); | |
352 | ||
353 | Relationship result = a.mergeImpl(b); | |
354 | ||
355 | if (needFlip) | |
356 | return result.flipped(); | |
357 | ||
358 | return result; | |
359 | } | |
360 | ||
361 | // Attempts to construct one Relationship that adequately summarizes the intersection of | |
362 | // this and other. Returns a null relationship if the filtration should be expressed as two | |
363 | // different relationships. Returning null is always safe because relationship lists in | |
364 | // this phase always imply intersection. So, you could soundly skip calling this method and | |
365 | // just put both relationships into the list. But, that could lead the fixpoint to diverge. | |
366 | // Hence this will attempt to combine the two relationships into one as a convergence hack. | |
367 | // In some cases, it will do something conservative. It's always safe for this to return | |
368 | // *this, or to return other. It'll do that sometimes, mainly to accelerate convergence for | |
369 | // things that we don't think are important enough to slow down the analysis. | |
370 | Relationship filter(const Relationship& other) const | |
371 | { | |
372 | // We are only interested in merging relationships over the same nodes. | |
373 | ASSERT(sameNodesAs(other)); | |
374 | ||
375 | if (*this == other) | |
376 | return *this; | |
377 | ||
378 | // From here we can assume that the two relationships are not identical. Usually we use | |
379 | // this to assume that we have different offsets anytime that everything but the offset | |
380 | // is identical. | |
381 | ||
382 | // We want equality to take precedent over everything else, and we don't want multiple | |
383 | // independent claims of equality. That would just be a contradiction. When it does | |
384 | // happen, we will be conservative in the sense that we will pick one. | |
385 | if (m_kind == Equal) | |
386 | return *this; | |
387 | if (other.m_kind == Equal) | |
388 | return other; | |
389 | ||
390 | // Useful helper for flipping. | |
391 | auto filterFlipped = [&] () -> Relationship { | |
392 | // If we cannot flip, then just conservatively return *this. | |
393 | Relationship a = flipped(); | |
394 | Relationship b = other.flipped(); | |
395 | if (!a || !b) | |
396 | return *this; | |
397 | Relationship result = a.filter(b); | |
398 | if (!result) | |
399 | return Relationship(); | |
400 | result = result.flipped(); | |
401 | if (!result) | |
402 | return *this; | |
403 | return result; | |
404 | }; | |
405 | ||
406 | if (m_kind == NotEqual) { | |
407 | if (other.m_kind == NotEqual) { | |
408 | // We could do something smarter here. We could even keep both NotEqual's. We | |
409 | // would need to make sure that we correctly collapsed them when merging. But | |
410 | // for now, we just pick one of them and hope for the best. | |
411 | return *this; | |
412 | } | |
413 | ||
414 | if (other.m_kind == GreaterThan) { | |
415 | // Implement this in terms of NotEqual.filter(LessThan). | |
416 | return filterFlipped(); | |
417 | } | |
418 | ||
419 | ASSERT(other.m_kind == LessThan); | |
420 | // We have two claims: | |
421 | // @a != @b + C | |
422 | // @a < @b + D | |
423 | // | |
424 | // If C >= D, then the NotEqual is redundant. | |
425 | // If C < D - 1, then we could keep both, but for now we just keep the LessThan. | |
426 | // If C == D - 1, then the LessThan can be turned into: | |
427 | // | |
428 | // @a < @b + C | |
429 | // | |
430 | // Note that C == this.m_offset, D == other.m_offset. | |
431 | ||
432 | if (m_offset == other.m_offset - 1) | |
433 | return Relationship(m_left, m_right, LessThan, m_offset); | |
434 | ||
435 | return other; | |
436 | } | |
437 | ||
438 | if (other.m_kind == NotEqual) | |
439 | return other.filter(*this); | |
440 | ||
441 | if (m_kind == LessThan) { | |
442 | if (other.m_kind == LessThan) { | |
443 | return Relationship( | |
444 | m_left, m_right, LessThan, std::min(m_offset, other.m_offset)); | |
445 | } | |
446 | ||
447 | ASSERT(other.m_kind == GreaterThan); | |
448 | if (sumOverflows<int>(m_offset, -1)) | |
449 | return Relationship(); | |
450 | if (sumOverflows<int>(other.m_offset, 1)) | |
451 | return Relationship(); | |
452 | if (m_offset - 1 == other.m_offset + 1) | |
453 | return Relationship(m_left, m_right, Equal, m_offset - 1); | |
454 | ||
455 | return Relationship(); | |
456 | } | |
457 | ||
458 | ASSERT(m_kind == GreaterThan); | |
459 | return filterFlipped(); | |
460 | } | |
461 | ||
462 | int minValueOfLeft() const | |
463 | { | |
464 | if (m_left->isInt32Constant()) | |
465 | return m_left->asInt32(); | |
466 | ||
467 | if (m_kind == LessThan || m_kind == NotEqual) | |
468 | return std::numeric_limits<int>::min(); | |
469 | ||
470 | int minRightValue = std::numeric_limits<int>::min(); | |
471 | if (m_right->isInt32Constant()) | |
472 | minRightValue = m_right->asInt32(); | |
473 | ||
474 | if (m_kind == GreaterThan) | |
475 | return clampedSum(minRightValue, m_offset, 1); | |
476 | ASSERT(m_kind == Equal); | |
477 | return clampedSum(minRightValue, m_offset); | |
478 | } | |
479 | ||
480 | int maxValueOfLeft() const | |
481 | { | |
482 | if (m_left->isInt32Constant()) | |
483 | return m_left->asInt32(); | |
484 | ||
485 | if (m_kind == GreaterThan || m_kind == NotEqual) | |
486 | return std::numeric_limits<int>::max(); | |
487 | ||
488 | int maxRightValue = std::numeric_limits<int>::max(); | |
489 | if (m_right->isInt32Constant()) | |
490 | maxRightValue = m_right->asInt32(); | |
491 | ||
492 | if (m_kind == LessThan) | |
493 | return clampedSum(maxRightValue, m_offset, -1); | |
494 | ASSERT(m_kind == Equal); | |
495 | return clampedSum(maxRightValue, m_offset); | |
496 | } | |
497 | ||
498 | void dump(PrintStream& out) const | |
499 | { | |
500 | // This prints out the relationship without any whitespace, like @x<@y+42. This | |
501 | // optimizes for the clarity of a list of relationships. It's easier to read something | |
502 | // like [@1<@2+3, @4==@5-6] than it would be if there was whitespace inside the | |
503 | // relationships. | |
504 | ||
505 | if (!*this) { | |
506 | out.print("null"); | |
507 | return; | |
508 | } | |
509 | ||
510 | out.print(m_left); | |
511 | switch (m_kind) { | |
512 | case LessThan: | |
513 | out.print("<"); | |
514 | break; | |
515 | case Equal: | |
516 | out.print("=="); | |
517 | break; | |
518 | case NotEqual: | |
519 | out.print("!="); | |
520 | break; | |
521 | case GreaterThan: | |
522 | out.print(">"); | |
523 | break; | |
524 | } | |
525 | out.print(m_right); | |
526 | if (m_offset > 0) | |
527 | out.print("+", m_offset); | |
528 | else if (m_offset < 0) | |
529 | out.print("-", -static_cast<int64_t>(m_offset)); | |
530 | } | |
531 | ||
532 | private: | |
533 | Relationship mergeImpl(const Relationship& other) const | |
534 | { | |
535 | ASSERT(sameNodesAs(other)); | |
536 | ASSERT(m_kind != GreaterThan); | |
537 | ASSERT(other.m_kind != GreaterThan); | |
538 | ASSERT(*this != other); | |
539 | ||
540 | // The purpose of this method is to guarantee that: | |
541 | // | |
542 | // - We avoid having more than one Relationship over the same two nodes. Therefore, if | |
543 | // the merge could be expressed as two Relationships, we prefer to instead pick the | |
544 | // less precise single Relationship form even if that means TOP. | |
545 | // | |
546 | // - If the difference between two Relationships is just the m_offset, then we create a | |
547 | // Relationship that has an offset of -1, 0, or 1. This is an essential convergence | |
548 | // hack. We need -1 and 1 to support <= and >=. | |
549 | ||
550 | // From here we can assume that the two relationships are not identical. Usually we use | |
551 | // this to assume that we have different offsets anytime that everything but the offset | |
552 | // is identical. | |
553 | ||
554 | if (m_kind == NotEqual) { | |
555 | if (other.m_kind == NotEqual) | |
556 | return Relationship(); // Different offsets, so tautology. | |
557 | ||
558 | if (other.m_kind == Equal) { | |
559 | if (m_offset != other.m_offset) { | |
560 | // Saying that you might be B when you've already said that you're anything | |
561 | // but A, where A and B are different, is a tautology. You could just say | |
562 | // that you're anything but A. Adding "(a == b + 1)" to "(a != b + 5)" has | |
563 | // no value. | |
564 | return *this; | |
565 | } | |
566 | // Otherwise, same offsets: we're saying that you're either A or you're not | |
567 | // equal to A. | |
568 | ||
569 | return Relationship(); | |
570 | } | |
571 | ||
572 | RELEASE_ASSERT(other.m_kind == LessThan); | |
573 | // We have these claims, and we're merging them: | |
574 | // @a != @b + C | |
575 | // @a < @b + D | |
576 | // | |
577 | // If we have C == D, then the merge is clearly just the NotEqual. | |
578 | // If we have C < D, then the merge is a tautology. | |
579 | // If we have C > D, then we could keep both claims, but we are cheap, so we | |
580 | // don't. We just use the NotEqual. | |
581 | ||
582 | if (m_offset < other.m_offset) | |
583 | return Relationship(); | |
584 | ||
585 | return *this; | |
586 | } | |
587 | ||
588 | if (m_kind == LessThan) { | |
589 | if (other.m_kind == LessThan) { | |
590 | // Figure out what offset to select to merge them. The appropriate offsets are | |
591 | // -1, 0, or 1. | |
592 | ||
593 | // First figure out what offset we'd like to use. | |
594 | int bestOffset = std::max(m_offset, other.m_offset); | |
595 | ||
596 | // We have something like @a < @b + 2. We can't represent this under the | |
597 | // -1,0,1 rule. | |
598 | if (bestOffset <= 1) | |
599 | return Relationship(m_left, m_right, LessThan, std::max(bestOffset, -1)); | |
600 | ||
601 | return Relationship(); | |
602 | } | |
603 | ||
604 | // The only thing left is Equal. We would have eliminated the GreaterThan's, and | |
605 | // if we merge LessThan and NotEqual, the NotEqual always comes first. | |
606 | RELEASE_ASSERT(other.m_kind == Equal); | |
607 | ||
608 | // This is the really interesting case. We have: | |
609 | // | |
610 | // @a < @b + C | |
611 | // | |
612 | // and: | |
613 | // | |
614 | // @a == @b + D | |
615 | // | |
616 | // Therefore we'd like to return: | |
617 | // | |
618 | // @a < @b + max(C, D + 1) | |
619 | ||
620 | int bestOffset = std::max(m_offset, other.m_offset + 1); | |
621 | ||
622 | // We have something like @a < @b + 2. We can't do it. | |
623 | if (bestOffset <= 1) | |
624 | return Relationship(m_left, m_right, LessThan, std::max(bestOffset, -1)); | |
625 | ||
626 | return Relationship(); | |
627 | } | |
628 | ||
629 | // The only thing left is Equal, since we would have gotten rid of the GreaterThan's. | |
630 | RELEASE_ASSERT(m_kind == Equal); | |
631 | ||
632 | // We would never see NotEqual, because those always come first. We would never | |
633 | // see GreaterThan, because we would have eliminated those. We would never see | |
634 | // LessThan, because those always come first. | |
635 | ||
636 | RELEASE_ASSERT(other.m_kind == Equal); | |
637 | // We have @a == @b + C and @a == @b + D, where C != D. Turn this into some | |
638 | // inequality that involves a constant that is -1,0,1. Note that we will never have | |
639 | // lessThan and greaterThan because the constants are constrained to -1,0,1. The only | |
640 | // way for both of them to be valid is a<b+1 and a>b-1, but then we would have said | |
641 | // a==b. | |
642 | ||
643 | Relationship lessThan; | |
644 | Relationship greaterThan; | |
645 | ||
646 | int lessThanEqOffset = std::max(m_offset, other.m_offset); | |
647 | if (lessThanEqOffset >= -2 && lessThanEqOffset <= 0) { | |
648 | lessThan = Relationship( | |
649 | m_left, other.m_right, LessThan, lessThanEqOffset + 1); | |
650 | ||
651 | ASSERT(lessThan.offset() >= -1 && lessThan.offset() <= 1); | |
652 | } | |
653 | ||
654 | int greaterThanEqOffset = std::min(m_offset, other.m_offset); | |
655 | if (greaterThanEqOffset >= 0 && greaterThanEqOffset <= 2) { | |
656 | greaterThan = Relationship( | |
657 | m_left, other.m_right, GreaterThan, greaterThanEqOffset - 1); | |
658 | ||
659 | ASSERT(greaterThan.offset() >= -1 && greaterThan.offset() <= 1); | |
660 | } | |
661 | ||
662 | if (lessThan) { | |
663 | // Both relationships cannot be valid; see above. | |
664 | RELEASE_ASSERT(!greaterThan); | |
665 | ||
666 | return lessThan; | |
667 | } | |
668 | ||
669 | return greaterThan; | |
670 | } | |
671 | ||
672 | Node* m_left; | |
673 | Node* m_right; | |
674 | Kind m_kind; | |
675 | int m_offset; // This offset can be arbitrarily large. | |
676 | }; | |
677 | ||
678 | typedef HashMap<Node*, Vector<Relationship>> RelationshipMap; | |
679 | ||
680 | class IntegerRangeOptimizationPhase : public Phase { | |
681 | public: | |
682 | IntegerRangeOptimizationPhase(Graph& graph) | |
683 | : Phase(graph, "integer range optimization") | |
684 | , m_zero(nullptr) | |
685 | , m_relationshipsAtHead(graph) | |
686 | , m_insertionSet(graph) | |
687 | { | |
688 | } | |
689 | ||
690 | bool run() | |
691 | { | |
692 | ASSERT(m_graph.m_form == SSA); | |
693 | ||
694 | // Before we do anything, make sure that we have a zero constant at the top. | |
695 | for (Node* node : *m_graph.block(0)) { | |
696 | if (node->isInt32Constant() && !node->asInt32()) { | |
697 | m_zero = node; | |
698 | break; | |
699 | } | |
700 | } | |
701 | if (!m_zero) { | |
702 | m_zero = m_insertionSet.insertConstant(0, NodeOrigin(), jsNumber(0)); | |
703 | m_insertionSet.execute(m_graph.block(0)); | |
704 | } | |
705 | ||
706 | if (verbose) { | |
707 | dataLog("Graph before integer range optimization:\n"); | |
708 | m_graph.dump(); | |
709 | } | |
710 | ||
711 | // This performs a fixpoint over the blocks in reverse post-order. Logically, we | |
712 | // maintain a list of relationships at each point in the program. The list should be | |
713 | // read as an intersection. For example if we have {rel1, rel2, ..., relN}, you should | |
714 | // read this as: | |
715 | // | |
716 | // TOP && rel1 && rel2 && ... && relN | |
717 | // | |
718 | // This allows us to express things like: | |
719 | // | |
720 | // @a > @b - 42 && @a < @b + 25 | |
721 | // | |
722 | // But not things like: | |
723 | // | |
724 | // @a < @b - 42 || @a > @b + 25 | |
725 | // | |
726 | // We merge two lists by merging each relationship in one list with each relationship | |
727 | // in the other list. Merging two relationships will yield a relationship list; as with | |
728 | // all such lists it is an intersction. Merging relationships over different variables | |
729 | // always yields the empty list (i.e. TOP). This merge style is sound because if we | |
730 | // have: | |
731 | // | |
732 | // (A && B && C) || (D && E && F) | |
733 | // | |
734 | // Then a valid merge is just one that will return true if A, B, C are all true, or | |
735 | // that will return true if D, E, F are all true. Our merge style essentially does: | |
736 | // | |
737 | // (A || D) && (A || E) && (A || F) && (B || D) && (B || E) && (B || F) && | |
738 | // (C || D) && (C || E) && (C || F) | |
739 | // | |
740 | // If A && B && C is true, then this returns true. If D && E && F is true, this also | |
741 | // returns true. | |
742 | // | |
743 | // While this appears at first like a kind of expression explosion, in practice it | |
744 | // isn't. The code that handles this knows that the merge of two relationships over | |
745 | // different variables is TOP (i.e. the empty list). For example if A above is @a < @b | |
746 | // and B above is @c > @d, where @a, @b, @c, and @d are different nodes, the merge will | |
747 | // yield nothing. In fact, the merge algorithm will skip such merges entirely because | |
748 | // the relationship lists are actually keyed by node. | |
749 | // | |
750 | // Note that it's always safe to drop any of relationship from the relationship list. | |
751 | // This merely increases the likelihood of the "expression" yielding true, i.e. being | |
752 | // closer to TOP. Optimizations are only performed if we can establish that the | |
753 | // expression implied by the relationship list is false for all of those cases where | |
754 | // some check would have failed. | |
755 | // | |
756 | // There is no notion of BOTTOM because we treat blocks that haven't had their | |
757 | // state-at-head set as a special case: we just transfer all live relationships to such | |
758 | // a block. After the head of a block is set, we perform the merging as above. In all | |
759 | // other places where we would ordinarily need BOTTOM, we approximate it by having some | |
760 | // non-BOTTOM relationship. | |
761 | ||
762 | BlockList postOrder = m_graph.blocksInPostOrder(); | |
763 | ||
764 | // This loop analyzes the IR to give us m_relationshipsAtHead for each block. This | |
765 | // may reexecute blocks many times, but it is guaranteed to converge. The state of | |
766 | // the relationshipsAtHead over any pair of nodes converge monotonically towards the | |
767 | // TOP relationship (i.e. no relationships in the relationship list). The merge rule | |
768 | // when between the current relationshipsAtHead and the relationships being propagated | |
769 | // from a predecessor ensures monotonicity by converting disagreements into one of a | |
770 | // small set of "general" relationships. There are 12 such relationshis, plus TOP. See | |
771 | // the comment above Relationship::merge() for details. | |
772 | bool changed = true; | |
773 | while (changed) { | |
774 | changed = false; | |
775 | for (unsigned postOrderIndex = postOrder.size(); postOrderIndex--;) { | |
776 | BasicBlock* block = postOrder[postOrderIndex]; | |
777 | DFG_ASSERT( | |
778 | m_graph, nullptr, | |
779 | block == m_graph.block(0) || m_seenBlocks.contains(block)); | |
780 | ||
781 | m_relationships = m_relationshipsAtHead[block]; | |
782 | ||
783 | for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { | |
784 | Node* node = block->at(nodeIndex); | |
785 | if (verbose) | |
786 | dataLog("Analysis: at ", node, ": ", listDump(sortedRelationships()), "\n"); | |
787 | executeNode(node); | |
788 | } | |
789 | ||
790 | // Now comes perhaps the most important piece of cleverness: if we Branch, and | |
791 | // the predicate involves some relation over integers, we propagate different | |
792 | // information to the taken and notTaken paths. This handles: | |
793 | // - Branch on int32. | |
794 | // - Branch on LogicalNot on int32. | |
795 | // - Branch on compare on int32's. | |
796 | // - Branch on LogicalNot of compare on int32's. | |
797 | Node* terminal = block->terminal(); | |
798 | bool alreadyMerged = false; | |
799 | if (terminal->op() == Branch) { | |
800 | Relationship relationshipForTrue; | |
801 | BranchData* branchData = terminal->branchData(); | |
802 | ||
803 | bool invert = false; | |
804 | if (terminal->child1()->op() == LogicalNot) { | |
805 | terminal = terminal->child1().node(); | |
806 | invert = true; | |
807 | } | |
808 | ||
809 | if (terminal->child1().useKind() == Int32Use) { | |
810 | relationshipForTrue = Relationship::safeCreate( | |
811 | terminal->child1().node(), m_zero, Relationship::NotEqual, 0); | |
812 | } else { | |
813 | Node* compare = terminal->child1().node(); | |
814 | switch (compare->op()) { | |
815 | case CompareEq: | |
816 | case CompareStrictEq: | |
817 | case CompareLess: | |
818 | case CompareLessEq: | |
819 | case CompareGreater: | |
820 | case CompareGreaterEq: { | |
821 | if (!compare->isBinaryUseKind(Int32Use)) | |
822 | break; | |
823 | ||
824 | switch (compare->op()) { | |
825 | case CompareEq: | |
826 | case CompareStrictEq: | |
827 | relationshipForTrue = Relationship::safeCreate( | |
828 | compare->child1().node(), compare->child2().node(), | |
829 | Relationship::Equal, 0); | |
830 | break; | |
831 | case CompareLess: | |
832 | relationshipForTrue = Relationship::safeCreate( | |
833 | compare->child1().node(), compare->child2().node(), | |
834 | Relationship::LessThan, 0); | |
835 | break; | |
836 | case CompareLessEq: | |
837 | relationshipForTrue = Relationship::safeCreate( | |
838 | compare->child1().node(), compare->child2().node(), | |
839 | Relationship::LessThan, 1); | |
840 | break; | |
841 | case CompareGreater: | |
842 | relationshipForTrue = Relationship::safeCreate( | |
843 | compare->child1().node(), compare->child2().node(), | |
844 | Relationship::GreaterThan, 0); | |
845 | break; | |
846 | case CompareGreaterEq: | |
847 | relationshipForTrue = Relationship::safeCreate( | |
848 | compare->child1().node(), compare->child2().node(), | |
849 | Relationship::GreaterThan, -1); | |
850 | break; | |
851 | default: | |
852 | DFG_CRASH(m_graph, compare, "Invalid comparison node type"); | |
853 | break; | |
854 | } | |
855 | break; | |
856 | } | |
857 | ||
858 | default: | |
859 | break; | |
860 | } | |
861 | } | |
862 | ||
863 | if (invert) | |
864 | relationshipForTrue = relationshipForTrue.inverse(); | |
865 | ||
866 | if (relationshipForTrue) { | |
867 | RelationshipMap forTrue = m_relationships; | |
868 | RelationshipMap forFalse = m_relationships; | |
869 | ||
870 | if (verbose) | |
871 | dataLog("Dealing with true:\n"); | |
872 | setRelationship(forTrue, relationshipForTrue); | |
873 | if (Relationship relationshipForFalse = relationshipForTrue.inverse()) { | |
874 | if (verbose) | |
875 | dataLog("Dealing with false:\n"); | |
876 | setRelationship(forFalse, relationshipForFalse); | |
877 | } | |
878 | ||
879 | changed |= mergeTo(forTrue, branchData->taken.block); | |
880 | changed |= mergeTo(forFalse, branchData->notTaken.block); | |
881 | alreadyMerged = true; | |
882 | } | |
883 | } | |
884 | ||
885 | if (!alreadyMerged) { | |
886 | for (BasicBlock* successor : block->successors()) | |
887 | changed |= mergeTo(m_relationships, successor); | |
888 | } | |
889 | } | |
890 | } | |
891 | ||
892 | // Now we transform the code based on the results computed in the previous loop. | |
893 | changed = false; | |
894 | for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { | |
895 | m_relationships = m_relationshipsAtHead[block]; | |
896 | for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { | |
897 | Node* node = block->at(nodeIndex); | |
898 | if (verbose) | |
899 | dataLog("Transformation: at ", node, ": ", listDump(sortedRelationships()), "\n"); | |
900 | ||
901 | // This ends up being pretty awkward to write because we need to decide if we | |
902 | // optimize by using the relationships before the operation, but we need to | |
903 | // call executeNode() before we optimize. | |
904 | switch (node->op()) { | |
905 | case ArithAdd: { | |
906 | if (!node->isBinaryUseKind(Int32Use)) | |
907 | break; | |
908 | if (node->arithMode() != Arith::CheckOverflow) | |
909 | break; | |
910 | if (!node->child2()->isInt32Constant()) | |
911 | break; | |
912 | ||
913 | auto iter = m_relationships.find(node->child1().node()); | |
914 | if (iter == m_relationships.end()) | |
915 | break; | |
916 | ||
917 | int minValue = std::numeric_limits<int>::min(); | |
918 | int maxValue = std::numeric_limits<int>::max(); | |
919 | for (Relationship relationship : iter->value) { | |
920 | minValue = std::max(minValue, relationship.minValueOfLeft()); | |
921 | maxValue = std::min(maxValue, relationship.maxValueOfLeft()); | |
922 | } | |
923 | ||
924 | if (sumOverflows<int>(minValue, node->child2()->asInt32()) || | |
925 | sumOverflows<int>(maxValue, node->child2()->asInt32())) | |
926 | break; | |
927 | ||
928 | executeNode(block->at(nodeIndex)); | |
929 | node->setArithMode(Arith::Unchecked); | |
930 | changed = true; | |
931 | break; | |
932 | } | |
933 | ||
934 | case CheckInBounds: { | |
935 | auto iter = m_relationships.find(node->child1().node()); | |
936 | if (iter == m_relationships.end()) | |
937 | break; | |
938 | ||
939 | bool nonNegative = false; | |
940 | bool lessThanLength = false; | |
941 | for (Relationship relationship : iter->value) { | |
942 | if (relationship.minValueOfLeft() >= 0) | |
943 | nonNegative = true; | |
944 | ||
945 | if (relationship.right() == node->child2()) { | |
946 | if (relationship.kind() == Relationship::Equal | |
947 | && relationship.offset() < 0) | |
948 | lessThanLength = true; | |
949 | ||
950 | if (relationship.kind() == Relationship::LessThan | |
951 | && relationship.offset() <= 0) | |
952 | lessThanLength = true; | |
953 | } | |
954 | } | |
955 | ||
956 | if (nonNegative && lessThanLength) { | |
957 | executeNode(block->at(nodeIndex)); | |
958 | node->remove(); | |
959 | changed = true; | |
960 | } | |
961 | break; | |
962 | } | |
963 | ||
964 | default: | |
965 | break; | |
966 | } | |
967 | ||
968 | executeNode(block->at(nodeIndex)); | |
969 | } | |
970 | } | |
971 | ||
972 | return changed; | |
973 | } | |
974 | ||
975 | private: | |
976 | void executeNode(Node* node) | |
977 | { | |
978 | switch (node->op()) { | |
979 | case CheckInBounds: { | |
980 | setRelationship(Relationship::safeCreate(node->child1().node(), node->child2().node(), Relationship::LessThan)); | |
981 | setRelationship(Relationship::safeCreate(node->child1().node(), m_zero, Relationship::GreaterThan, -1)); | |
982 | break; | |
983 | } | |
984 | ||
985 | case ArithAdd: { | |
986 | // We're only interested in int32 additions and we currently only know how to | |
987 | // handle the non-wrapping ones. | |
988 | if (!node->isBinaryUseKind(Int32Use)) | |
989 | break; | |
990 | ||
991 | // FIXME: We could handle the unchecked arithmetic case. We just do it don't right | |
992 | // now. | |
993 | if (node->arithMode() != Arith::CheckOverflow) | |
994 | break; | |
995 | ||
996 | // Handle add: @value + constant. | |
997 | if (!node->child2()->isInt32Constant()) | |
998 | break; | |
999 | ||
1000 | int offset = node->child2()->asInt32(); | |
1001 | ||
1002 | // We add a relationship for @add == @value + constant, and then we copy the | |
1003 | // relationships for @value. This gives us a one-deep view of @value's existing | |
1004 | // relationships, which matches the one-deep search in setRelationship(). | |
1005 | ||
1006 | setRelationship( | |
1007 | Relationship(node, node->child1().node(), Relationship::Equal, offset)); | |
1008 | ||
1009 | auto iter = m_relationships.find(node->child1().node()); | |
1010 | if (iter != m_relationships.end()) { | |
1011 | Vector<Relationship> toAdd; | |
1012 | for (Relationship relationship : iter->value) { | |
1013 | // We have: | |
1014 | // add: ArithAdd(@x, C) | |
1015 | // @x op @y + D | |
1016 | // | |
1017 | // The following certainly holds: | |
1018 | // @x == @add - C | |
1019 | // | |
1020 | // Which allows us to substitute: | |
1021 | // @add - C op @y + D | |
1022 | // | |
1023 | // And then carry the C over: | |
1024 | // @add op @y + D + C | |
1025 | ||
1026 | Relationship newRelationship = relationship; | |
1027 | ASSERT(newRelationship.left() == node->child1().node()); | |
1028 | ||
1029 | if (newRelationship.right() == node) | |
1030 | continue; | |
1031 | newRelationship.setLeft(node); | |
1032 | if (newRelationship.addToOffset(offset)) | |
1033 | toAdd.append(newRelationship); | |
1034 | } | |
1035 | for (Relationship relationship : toAdd) | |
1036 | setRelationship(relationship, 0); | |
1037 | } | |
1038 | ||
1039 | // Now we want to establish that both the input and the output of the addition are | |
1040 | // within a particular range of integers. | |
1041 | ||
1042 | if (offset > 0) { | |
1043 | // If we have "add: @value + 1" then we know that @value <= max - 1, i.e. that | |
1044 | // @value < max. | |
1045 | if (!sumOverflows<int>(std::numeric_limits<int>::max(), -offset, 1)) { | |
1046 | setRelationship( | |
1047 | Relationship::safeCreate( | |
1048 | node->child1().node(), m_zero, Relationship::LessThan, | |
1049 | std::numeric_limits<int>::max() - offset + 1), | |
1050 | 0); | |
1051 | } | |
1052 | ||
1053 | // If we have "add: @value + 1" then we know that @add >= min + 1, i.e. that | |
1054 | // @add > min. | |
1055 | if (!sumOverflows<int>(std::numeric_limits<int>::min(), offset, -1)) { | |
1056 | setRelationship( | |
1057 | Relationship( | |
1058 | node, m_zero, Relationship::GreaterThan, | |
1059 | std::numeric_limits<int>::min() + offset - 1), | |
1060 | 0); | |
1061 | } | |
1062 | } | |
1063 | ||
1064 | if (offset < 0 && offset != std::numeric_limits<int>::min()) { | |
1065 | // If we have "add: @value - 1" then we know that @value >= min + 1, i.e. that | |
1066 | // @value > min. | |
1067 | if (!sumOverflows<int>(std::numeric_limits<int>::min(), offset, -1)) { | |
1068 | setRelationship( | |
1069 | Relationship::safeCreate( | |
1070 | node->child1().node(), m_zero, Relationship::GreaterThan, | |
1071 | std::numeric_limits<int>::min() + offset - 1), | |
1072 | 0); | |
1073 | } | |
1074 | ||
1075 | // If we have "add: @value + 1" then we know that @add <= max - 1, i.e. that | |
1076 | // @add < max. | |
1077 | if (!sumOverflows<int>(std::numeric_limits<int>::max(), -offset, 1)) { | |
1078 | setRelationship( | |
1079 | Relationship( | |
1080 | node, m_zero, Relationship::LessThan, | |
1081 | std::numeric_limits<int>::max() - offset + 1), | |
1082 | 0); | |
1083 | } | |
1084 | } | |
1085 | break; | |
1086 | } | |
1087 | ||
1088 | case GetArrayLength: { | |
1089 | setRelationship(Relationship(node, m_zero, Relationship::GreaterThan, -1)); | |
1090 | break; | |
1091 | } | |
1092 | ||
1093 | case Upsilon: { | |
1094 | setRelationship( | |
1095 | Relationship::safeCreate( | |
1096 | node->child1().node(), node->phi(), Relationship::Equal, 0)); | |
1097 | ||
1098 | auto iter = m_relationships.find(node->child1().node()); | |
1099 | if (iter != m_relationships.end()) { | |
1100 | Vector<Relationship> toAdd; | |
1101 | for (Relationship relationship : iter->value) { | |
1102 | Relationship newRelationship = relationship; | |
1103 | if (node->phi() == newRelationship.right()) | |
1104 | continue; | |
1105 | newRelationship.setLeft(node->phi()); | |
1106 | toAdd.append(newRelationship); | |
1107 | } | |
1108 | for (Relationship relationship : toAdd) | |
1109 | setRelationship(relationship); | |
1110 | } | |
1111 | break; | |
1112 | } | |
1113 | ||
1114 | default: | |
1115 | break; | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | void setRelationship(Relationship relationship, unsigned timeToLive = 1) | |
1120 | { | |
1121 | setRelationship(m_relationships, relationship, timeToLive); | |
1122 | } | |
1123 | ||
1124 | void setRelationship( | |
1125 | RelationshipMap& relationshipMap, Relationship relationship, unsigned timeToLive = 1) | |
1126 | { | |
1127 | setOneSide(relationshipMap, relationship, timeToLive); | |
1128 | setOneSide(relationshipMap, relationship.flipped(), timeToLive); | |
1129 | } | |
1130 | ||
1131 | void setOneSide( | |
1132 | RelationshipMap& relationshipMap, Relationship relationship, unsigned timeToLive = 1) | |
1133 | { | |
1134 | if (!relationship) | |
1135 | return; | |
1136 | ||
1137 | if (verbose) | |
1138 | dataLog(" Setting: ", relationship, " (ttl = ", timeToLive, ")\n"); | |
1139 | ||
1140 | auto result = relationshipMap.add( | |
1141 | relationship.left(), Vector<Relationship>()); | |
1142 | Vector<Relationship>& relationships = result.iterator->value; | |
1143 | Vector<Relationship> toAdd; | |
1144 | bool found = false; | |
1145 | for (Relationship& otherRelationship : relationships) { | |
1146 | if (otherRelationship.sameNodesAs(relationship)) { | |
1147 | if (Relationship filtered = otherRelationship.filter(relationship)) { | |
1148 | ASSERT(filtered.left() == relationship.left()); | |
1149 | otherRelationship = filtered; | |
1150 | found = true; | |
1151 | } | |
1152 | } | |
1153 | ||
1154 | if (timeToLive && otherRelationship.kind() == Relationship::Equal) { | |
1155 | if (verbose) | |
1156 | dataLog(" Considering: ", otherRelationship, "\n"); | |
1157 | ||
1158 | // We have: | |
1159 | // @a op @b + C | |
1160 | // @a == @c + D | |
1161 | // | |
1162 | // This implies: | |
1163 | // @c + D op @b + C | |
1164 | // @c op @b + C - D | |
1165 | // | |
1166 | // Where: @a == relationship.left(), @b == relationship.right(), | |
1167 | // @a == otherRelationship.left(), @c == otherRelationship.right(). | |
1168 | ||
1169 | if (otherRelationship.offset() != std::numeric_limits<int>::min()) { | |
1170 | Relationship newRelationship = relationship; | |
1171 | if (newRelationship.right() != otherRelationship.right()) { | |
1172 | newRelationship.setLeft(otherRelationship.right()); | |
1173 | if (newRelationship.addToOffset(-otherRelationship.offset())) | |
1174 | toAdd.append(newRelationship); | |
1175 | } | |
1176 | } | |
1177 | } | |
1178 | } | |
1179 | ||
1180 | if (!found) | |
1181 | relationships.append(relationship); | |
1182 | ||
1183 | for (Relationship anotherRelationship : toAdd) { | |
1184 | ASSERT(timeToLive); | |
1185 | setOneSide(relationshipMap, anotherRelationship, timeToLive - 1); | |
1186 | } | |
1187 | } | |
1188 | ||
1189 | bool mergeTo(RelationshipMap& relationshipMap, BasicBlock* target) | |
1190 | { | |
1191 | if (verbose) { | |
1192 | dataLog("Merging to ", pointerDump(target), ":\n"); | |
1193 | dataLog(" Incoming: ", listDump(sortedRelationships(relationshipMap)), "\n"); | |
1194 | dataLog(" At head: ", listDump(sortedRelationships(m_relationshipsAtHead[target])), "\n"); | |
1195 | } | |
1196 | ||
1197 | if (m_seenBlocks.add(target)) { | |
1198 | // This is a new block. We copy subject to liveness pruning. | |
1199 | auto isLive = [&] (Node* node) { | |
1200 | if (node == m_zero) | |
1201 | return true; | |
1202 | return target->ssa->liveAtHead.contains(node); | |
1203 | }; | |
1204 | ||
1205 | for (auto& entry : relationshipMap) { | |
1206 | if (!isLive(entry.key)) | |
1207 | continue; | |
1208 | ||
1209 | Vector<Relationship> values; | |
1210 | for (Relationship relationship : entry.value) { | |
1211 | ASSERT(relationship.left() == entry.key); | |
1212 | if (isLive(relationship.right())) { | |
1213 | if (verbose) | |
1214 | dataLog(" Propagating ", relationship, "\n"); | |
1215 | values.append(relationship); | |
1216 | } | |
1217 | } | |
1218 | ||
1219 | std::sort(values.begin(), values.end()); | |
1220 | m_relationshipsAtHead[target].add(entry.key, values); | |
1221 | } | |
1222 | return true; | |
1223 | } | |
1224 | ||
1225 | // Merge by intersecting. We have no notion of BOTTOM, so we use the omission of | |
1226 | // relationships for a pair of nodes to mean TOP. The reason why we don't need BOTTOM | |
1227 | // is (1) we just overapproximate contradictions and (2) a value never having been | |
1228 | // assigned would only happen if we have not processed the node's predecessor. We | |
1229 | // shouldn't process blocks until we have processed the block's predecessor because we | |
1230 | // are using reverse postorder. | |
1231 | Vector<Node*> toRemove; | |
1232 | bool changed = false; | |
1233 | for (auto& entry : m_relationshipsAtHead[target]) { | |
1234 | auto iter = relationshipMap.find(entry.key); | |
1235 | if (iter == relationshipMap.end()) { | |
1236 | toRemove.append(entry.key); | |
1237 | changed = true; | |
1238 | continue; | |
1239 | } | |
1240 | ||
1241 | Vector<Relationship> mergedRelationships; | |
1242 | for (Relationship targetRelationship : entry.value) { | |
1243 | for (Relationship sourceRelationship : iter->value) { | |
1244 | if (verbose) | |
1245 | dataLog(" Merging ", targetRelationship, " and ", sourceRelationship, ":\n"); | |
1246 | Relationship newRelationship = | |
1247 | targetRelationship.merge(sourceRelationship); | |
1248 | ||
1249 | if (verbose) | |
1250 | dataLog(" Got ", newRelationship, "\n"); | |
1251 | ||
1252 | if (!newRelationship) | |
1253 | continue; | |
1254 | ||
1255 | // We need to filter() to avoid exponential explosion of identical | |
1256 | // relationships. We do this here to avoid making setOneSide() do | |
1257 | // more work, since we expect setOneSide() will be called more | |
1258 | // frequently. Here's an example. At some point someone might start | |
1259 | // with two relationships like @a > @b - C and @a < @b + D. Then | |
1260 | // someone does a setRelationship() passing something that turns | |
1261 | // both of these into @a == @b. Now we have @a == @b duplicated. | |
1262 | // Let's say that this duplicate @a == @b ends up at the head of a | |
1263 | // loop. If we didn't have this rule, then the loop would propagate | |
1264 | // duplicate @a == @b's onto the existing duplicate @a == @b's. | |
1265 | // There would be four pairs of @a == @b, each of which would | |
1266 | // create a new @a == @b. Now we'd have four of these duplicates | |
1267 | // and the next time around we'd have 8, then 16, etc. We avoid | |
1268 | // this here by doing this filtration. That might be a bit of | |
1269 | // overkill, since it's probably just the identical duplicate | |
1270 | // relationship case we want' to avoid. But, I'll keep this until | |
1271 | // we have evidence that this is a performance problem. Remember - | |
1272 | // we are already dealing with a list that is pruned down to | |
1273 | // relationships with identical left operand. It shouldn't be a | |
1274 | // large list. | |
1275 | bool found = false; | |
1276 | for (Relationship& existingRelationship : mergedRelationships) { | |
1277 | if (existingRelationship.sameNodesAs(newRelationship)) { | |
1278 | Relationship filtered = | |
1279 | existingRelationship.filter(newRelationship); | |
1280 | if (filtered) { | |
1281 | existingRelationship = filtered; | |
1282 | found = true; | |
1283 | break; | |
1284 | } | |
1285 | } | |
1286 | } | |
1287 | ||
1288 | if (!found) | |
1289 | mergedRelationships.append(newRelationship); | |
1290 | } | |
1291 | } | |
1292 | std::sort(mergedRelationships.begin(), mergedRelationships.end()); | |
1293 | if (entry.value == mergedRelationships) | |
1294 | continue; | |
1295 | ||
1296 | entry.value = mergedRelationships; | |
1297 | changed = true; | |
1298 | } | |
1299 | for (Node* node : toRemove) | |
1300 | m_relationshipsAtHead[target].remove(node); | |
1301 | ||
1302 | return changed; | |
1303 | } | |
1304 | ||
1305 | Vector<Relationship> sortedRelationships(const RelationshipMap& relationships) | |
1306 | { | |
1307 | Vector<Relationship> result; | |
1308 | for (auto& entry : relationships) | |
1309 | result.appendVector(entry.value); | |
1310 | std::sort(result.begin(), result.end()); | |
1311 | return result; | |
1312 | } | |
1313 | ||
1314 | Vector<Relationship> sortedRelationships() | |
1315 | { | |
1316 | return sortedRelationships(m_relationships); | |
1317 | } | |
1318 | ||
1319 | Node* m_zero; | |
1320 | RelationshipMap m_relationships; | |
1321 | BlockSet m_seenBlocks; | |
1322 | BlockMap<RelationshipMap> m_relationshipsAtHead; | |
1323 | InsertionSet m_insertionSet; | |
1324 | }; | |
1325 | ||
1326 | } // anonymous namespace | |
1327 | ||
1328 | bool performIntegerRangeOptimization(Graph& graph) | |
1329 | { | |
1330 | SamplingRegion samplingRegion("DFG Integer Range Optimization Phase"); | |
1331 | return runPhase<IntegerRangeOptimizationPhase>(graph); | |
1332 | } | |
1333 | ||
1334 | } } // namespace JSC::DFG | |
1335 | ||
1336 | #endif // ENABLE(DFG_JIT) | |
1337 |