]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGIntegerRangeOptimizationPhase.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGIntegerRangeOptimizationPhase.cpp
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