2 * Copyright (C) 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGIntegerRangeOptimizationPhase.h"
31 #include "DFGBlockMapInlines.h"
33 #include "DFGInsertionSet.h"
35 #include "DFGPredictionPropagationPhase.h"
36 #include "DFGVariableAccessDataDump.h"
37 #include "JSCInlines.h"
39 namespace JSC
{ namespace DFG
{
43 const bool verbose
= false;
45 int64_t clampedSumImpl() { return 0; }
47 template<typename
... Args
>
48 int64_t clampedSumImpl(int left
, Args
... args
)
50 return static_cast<int64_t>(left
) + clampedSumImpl(args
...);
53 template<typename
... Args
>
54 int clampedSum(Args
... args
)
56 int64_t result
= clampedSumImpl(args
...);
57 return static_cast<int>(std::min(
58 static_cast<int64_t>(std::numeric_limits
<int>::max()),
60 static_cast<int64_t>(std::numeric_limits
<int>::min()),
73 static Kind
flipped(Kind kind
)
85 RELEASE_ASSERT_NOT_REACHED();
97 Relationship(Node
* left
, Node
* right
, Kind kind
, int offset
= 0)
103 RELEASE_ASSERT(m_left
);
104 RELEASE_ASSERT(m_right
);
105 RELEASE_ASSERT(m_left
!= m_right
);
108 static Relationship
safeCreate(Node
* left
, Node
* right
, Kind kind
, int offset
= 0)
110 if (!left
|| !right
|| left
== right
)
111 return Relationship();
112 return Relationship(left
, right
, kind
, offset
);
115 typedef void* (Relationship::*UnspecifiedBoolType
);
117 explicit operator bool() const { return m_left
; }
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
; }
124 Relationship
flipped() const
127 return Relationship();
129 // This should return Relationship() if -m_offset overflows. For example:
133 // If we flip it we get:
137 // Except that the sign gets flipped since it's INT_MIN:
141 // And that makes no sense. To see how little sense it makes, consider:
143 // @a > @zero - 2**31
145 // We would flip it to mean:
147 // @zero < @a - 2**31
151 if (m_offset
== std::numeric_limits
<int>::min())
152 return Relationship();
154 return Relationship(m_right
, m_left
, flipped(m_kind
), -m_offset
);
157 Relationship
inverse() const
164 return Relationship(m_left
, m_right
, NotEqual
, m_offset
);
166 return Relationship(m_left
, m_right
, Equal
, m_offset
);
168 if (sumOverflows
<int>(m_offset
, -1))
169 return Relationship();
170 return Relationship(m_left
, m_right
, GreaterThan
, m_offset
- 1);
172 if (sumOverflows
<int>(m_offset
, 1))
173 return Relationship();
174 return Relationship(m_left
, m_right
, LessThan
, m_offset
+ 1);
177 RELEASE_ASSERT_NOT_REACHED();
180 bool isCanonical() const { return m_left
< m_right
; }
182 Relationship
canonical() const
189 bool sameNodesAs(const Relationship
& other
) const
191 return m_left
== other
.m_left
192 && m_right
== other
.m_right
;
195 bool operator==(const Relationship
& other
) const
197 return sameNodesAs(other
)
198 && m_kind
== other
.m_kind
199 && m_offset
== other
.m_offset
;
202 bool operator!=(const Relationship
& other
) const
204 return !(*this == other
);
207 bool operator<(const Relationship
& other
) const
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
;
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
221 Relationship
forNode(Node
* node
) const
227 return Relationship();
230 void setLeft(Node
* left
)
232 RELEASE_ASSERT(left
!= m_right
);
235 bool addToOffset(int offset
)
237 if (sumOverflows
<int>(m_offset
, offset
))
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.
251 // If *this and other are identical, we just return it.
253 // If they are different, we pick from a finite set of "general" relationships:
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.
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:
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.
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.
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.
290 // Here's an example of this in action:
292 // for (var i = a; ; ++i) { }
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
302 if (!sameNodesAs(other
))
303 return Relationship();
305 // Handle the super obvious case first.
309 // This does some interesting permutations to reduce the amount of duplicate code. For
312 // initially: @a != @b, @a > @b
315 // finally: @b != a, @b < @a
319 // initially: @a < @b, @a != @b
320 // finally: @a != @b, @a < @b
322 Relationship a
= *this;
323 Relationship b
= other
;
324 bool needFlip
= false;
326 // Get rid of GreaterThan.
327 if (a
.m_kind
== GreaterThan
|| b
.m_kind
== GreaterThan
) {
331 // In rare cases, we might not be able to flip. Just give up on life in those
334 return Relationship();
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();
345 // Make sure that if we have a LessThan, then it's first.
346 if (b
.m_kind
== LessThan
)
349 // Make sure that if we have a NotEqual, then it's first.
350 if (b
.m_kind
== NotEqual
)
353 Relationship result
= a
.mergeImpl(b
);
356 return result
.flipped();
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
372 // We are only interested in merging relationships over the same nodes.
373 ASSERT(sameNodesAs(other
));
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
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.
387 if (other
.m_kind
== Equal
)
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();
397 Relationship result
= a
.filter(b
);
399 return Relationship();
400 result
= result
.flipped();
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.
414 if (other
.m_kind
== GreaterThan
) {
415 // Implement this in terms of NotEqual.filter(LessThan).
416 return filterFlipped();
419 ASSERT(other
.m_kind
== LessThan
);
420 // We have two claims:
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:
430 // Note that C == this.m_offset, D == other.m_offset.
432 if (m_offset
== other
.m_offset
- 1)
433 return Relationship(m_left
, m_right
, LessThan
, m_offset
);
438 if (other
.m_kind
== NotEqual
)
439 return other
.filter(*this);
441 if (m_kind
== LessThan
) {
442 if (other
.m_kind
== LessThan
) {
444 m_left
, m_right
, LessThan
, std::min(m_offset
, other
.m_offset
));
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);
455 return Relationship();
458 ASSERT(m_kind
== GreaterThan
);
459 return filterFlipped();
462 int minValueOfLeft() const
464 if (m_left
->isInt32Constant())
465 return m_left
->asInt32();
467 if (m_kind
== LessThan
|| m_kind
== NotEqual
)
468 return std::numeric_limits
<int>::min();
470 int minRightValue
= std::numeric_limits
<int>::min();
471 if (m_right
->isInt32Constant())
472 minRightValue
= m_right
->asInt32();
474 if (m_kind
== GreaterThan
)
475 return clampedSum(minRightValue
, m_offset
, 1);
476 ASSERT(m_kind
== Equal
);
477 return clampedSum(minRightValue
, m_offset
);
480 int maxValueOfLeft() const
482 if (m_left
->isInt32Constant())
483 return m_left
->asInt32();
485 if (m_kind
== GreaterThan
|| m_kind
== NotEqual
)
486 return std::numeric_limits
<int>::max();
488 int maxRightValue
= std::numeric_limits
<int>::max();
489 if (m_right
->isInt32Constant())
490 maxRightValue
= m_right
->asInt32();
492 if (m_kind
== LessThan
)
493 return clampedSum(maxRightValue
, m_offset
, -1);
494 ASSERT(m_kind
== Equal
);
495 return clampedSum(maxRightValue
, m_offset
);
498 void dump(PrintStream
& out
) const
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
527 out
.print("+", m_offset
);
528 else if (m_offset
< 0)
529 out
.print("-", -static_cast<int64_t>(m_offset
));
533 Relationship
mergeImpl(const Relationship
& other
) const
535 ASSERT(sameNodesAs(other
));
536 ASSERT(m_kind
!= GreaterThan
);
537 ASSERT(other
.m_kind
!= GreaterThan
);
538 ASSERT(*this != other
);
540 // The purpose of this method is to guarantee that:
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.
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 >=.
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
554 if (m_kind
== NotEqual
) {
555 if (other
.m_kind
== NotEqual
)
556 return Relationship(); // Different offsets, so tautology.
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
566 // Otherwise, same offsets: we're saying that you're either A or you're not
569 return Relationship();
572 RELEASE_ASSERT(other
.m_kind
== LessThan
);
573 // We have these claims, and we're merging them:
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.
582 if (m_offset
< other
.m_offset
)
583 return Relationship();
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
593 // First figure out what offset we'd like to use.
594 int bestOffset
= std::max(m_offset
, other
.m_offset
);
596 // We have something like @a < @b + 2. We can't represent this under the
599 return Relationship(m_left
, m_right
, LessThan
, std::max(bestOffset
, -1));
601 return Relationship();
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
);
608 // This is the really interesting case. We have:
616 // Therefore we'd like to return:
618 // @a < @b + max(C, D + 1)
620 int bestOffset
= std::max(m_offset
, other
.m_offset
+ 1);
622 // We have something like @a < @b + 2. We can't do it.
624 return Relationship(m_left
, m_right
, LessThan
, std::max(bestOffset
, -1));
626 return Relationship();
629 // The only thing left is Equal, since we would have gotten rid of the GreaterThan's.
630 RELEASE_ASSERT(m_kind
== Equal
);
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.
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
643 Relationship lessThan
;
644 Relationship greaterThan
;
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);
651 ASSERT(lessThan
.offset() >= -1 && lessThan
.offset() <= 1);
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);
659 ASSERT(greaterThan
.offset() >= -1 && greaterThan
.offset() <= 1);
663 // Both relationships cannot be valid; see above.
664 RELEASE_ASSERT(!greaterThan
);
675 int m_offset
; // This offset can be arbitrarily large.
678 typedef HashMap
<Node
*, Vector
<Relationship
>> RelationshipMap
;
680 class IntegerRangeOptimizationPhase
: public Phase
{
682 IntegerRangeOptimizationPhase(Graph
& graph
)
683 : Phase(graph
, "integer range optimization")
685 , m_relationshipsAtHead(graph
)
686 , m_insertionSet(graph
)
692 ASSERT(m_graph
.m_form
== SSA
);
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()) {
702 m_zero
= m_insertionSet
.insertConstant(0, NodeOrigin(), jsNumber(0));
703 m_insertionSet
.execute(m_graph
.block(0));
707 dataLog("Graph before integer range optimization:\n");
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
716 // TOP && rel1 && rel2 && ... && relN
718 // This allows us to express things like:
720 // @a > @b - 42 && @a < @b + 25
722 // But not things like:
724 // @a < @b - 42 || @a > @b + 25
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
732 // (A && B && C) || (D && E && F)
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:
737 // (A || D) && (A || E) && (A || F) && (B || D) && (B || E) && (B || F) &&
738 // (C || D) && (C || E) && (C || F)
740 // If A && B && C is true, then this returns true. If D && E && F is true, this also
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.
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.
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.
762 BlockList postOrder
= m_graph
.blocksInPostOrder();
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.
775 for (unsigned postOrderIndex
= postOrder
.size(); postOrderIndex
--;) {
776 BasicBlock
* block
= postOrder
[postOrderIndex
];
779 block
== m_graph
.block(0) || m_seenBlocks
.contains(block
));
781 m_relationships
= m_relationshipsAtHead
[block
];
783 for (unsigned nodeIndex
= 0; nodeIndex
< block
->size(); ++nodeIndex
) {
784 Node
* node
= block
->at(nodeIndex
);
786 dataLog("Analysis: at ", node
, ": ", listDump(sortedRelationships()), "\n");
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();
804 if (terminal
->child1()->op() == LogicalNot
) {
805 terminal
= terminal
->child1().node();
809 if (terminal
->child1().useKind() == Int32Use
) {
810 relationshipForTrue
= Relationship::safeCreate(
811 terminal
->child1().node(), m_zero
, Relationship::NotEqual
, 0);
813 Node
* compare
= terminal
->child1().node();
814 switch (compare
->op()) {
816 case CompareStrictEq
:
820 case CompareGreaterEq
: {
821 if (!compare
->isBinaryUseKind(Int32Use
))
824 switch (compare
->op()) {
826 case CompareStrictEq
:
827 relationshipForTrue
= Relationship::safeCreate(
828 compare
->child1().node(), compare
->child2().node(),
829 Relationship::Equal
, 0);
832 relationshipForTrue
= Relationship::safeCreate(
833 compare
->child1().node(), compare
->child2().node(),
834 Relationship::LessThan
, 0);
837 relationshipForTrue
= Relationship::safeCreate(
838 compare
->child1().node(), compare
->child2().node(),
839 Relationship::LessThan
, 1);
842 relationshipForTrue
= Relationship::safeCreate(
843 compare
->child1().node(), compare
->child2().node(),
844 Relationship::GreaterThan
, 0);
846 case CompareGreaterEq
:
847 relationshipForTrue
= Relationship::safeCreate(
848 compare
->child1().node(), compare
->child2().node(),
849 Relationship::GreaterThan
, -1);
852 DFG_CRASH(m_graph
, compare
, "Invalid comparison node type");
864 relationshipForTrue
= relationshipForTrue
.inverse();
866 if (relationshipForTrue
) {
867 RelationshipMap forTrue
= m_relationships
;
868 RelationshipMap forFalse
= m_relationships
;
871 dataLog("Dealing with true:\n");
872 setRelationship(forTrue
, relationshipForTrue
);
873 if (Relationship relationshipForFalse
= relationshipForTrue
.inverse()) {
875 dataLog("Dealing with false:\n");
876 setRelationship(forFalse
, relationshipForFalse
);
879 changed
|= mergeTo(forTrue
, branchData
->taken
.block
);
880 changed
|= mergeTo(forFalse
, branchData
->notTaken
.block
);
881 alreadyMerged
= true;
885 if (!alreadyMerged
) {
886 for (BasicBlock
* successor
: block
->successors())
887 changed
|= mergeTo(m_relationships
, successor
);
892 // Now we transform the code based on the results computed in the previous loop.
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
);
899 dataLog("Transformation: at ", node
, ": ", listDump(sortedRelationships()), "\n");
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()) {
906 if (!node
->isBinaryUseKind(Int32Use
))
908 if (node
->arithMode() != Arith::CheckOverflow
)
910 if (!node
->child2()->isInt32Constant())
913 auto iter
= m_relationships
.find(node
->child1().node());
914 if (iter
== m_relationships
.end())
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());
924 if (sumOverflows
<int>(minValue
, node
->child2()->asInt32()) ||
925 sumOverflows
<int>(maxValue
, node
->child2()->asInt32()))
928 executeNode(block
->at(nodeIndex
));
929 node
->setArithMode(Arith::Unchecked
);
934 case CheckInBounds
: {
935 auto iter
= m_relationships
.find(node
->child1().node());
936 if (iter
== m_relationships
.end())
939 bool nonNegative
= false;
940 bool lessThanLength
= false;
941 for (Relationship relationship
: iter
->value
) {
942 if (relationship
.minValueOfLeft() >= 0)
945 if (relationship
.right() == node
->child2()) {
946 if (relationship
.kind() == Relationship::Equal
947 && relationship
.offset() < 0)
948 lessThanLength
= true;
950 if (relationship
.kind() == Relationship::LessThan
951 && relationship
.offset() <= 0)
952 lessThanLength
= true;
956 if (nonNegative
&& lessThanLength
) {
957 executeNode(block
->at(nodeIndex
));
968 executeNode(block
->at(nodeIndex
));
976 void executeNode(Node
* node
)
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));
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
))
991 // FIXME: We could handle the unchecked arithmetic case. We just do it don't right
993 if (node
->arithMode() != Arith::CheckOverflow
)
996 // Handle add: @value + constant.
997 if (!node
->child2()->isInt32Constant())
1000 int offset
= node
->child2()->asInt32();
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().
1007 Relationship(node
, node
->child1().node(), Relationship::Equal
, offset
));
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
) {
1014 // add: ArithAdd(@x, C)
1017 // The following certainly holds:
1020 // Which allows us to substitute:
1021 // @add - C op @y + D
1023 // And then carry the C over:
1024 // @add op @y + D + C
1026 Relationship newRelationship
= relationship
;
1027 ASSERT(newRelationship
.left() == node
->child1().node());
1029 if (newRelationship
.right() == node
)
1031 newRelationship
.setLeft(node
);
1032 if (newRelationship
.addToOffset(offset
))
1033 toAdd
.append(newRelationship
);
1035 for (Relationship relationship
: toAdd
)
1036 setRelationship(relationship
, 0);
1039 // Now we want to establish that both the input and the output of the addition are
1040 // within a particular range of integers.
1043 // If we have "add: @value + 1" then we know that @value <= max - 1, i.e. that
1045 if (!sumOverflows
<int>(std::numeric_limits
<int>::max(), -offset
, 1)) {
1047 Relationship::safeCreate(
1048 node
->child1().node(), m_zero
, Relationship::LessThan
,
1049 std::numeric_limits
<int>::max() - offset
+ 1),
1053 // If we have "add: @value + 1" then we know that @add >= min + 1, i.e. that
1055 if (!sumOverflows
<int>(std::numeric_limits
<int>::min(), offset
, -1)) {
1058 node
, m_zero
, Relationship::GreaterThan
,
1059 std::numeric_limits
<int>::min() + offset
- 1),
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
1067 if (!sumOverflows
<int>(std::numeric_limits
<int>::min(), offset
, -1)) {
1069 Relationship::safeCreate(
1070 node
->child1().node(), m_zero
, Relationship::GreaterThan
,
1071 std::numeric_limits
<int>::min() + offset
- 1),
1075 // If we have "add: @value + 1" then we know that @add <= max - 1, i.e. that
1077 if (!sumOverflows
<int>(std::numeric_limits
<int>::max(), -offset
, 1)) {
1080 node
, m_zero
, Relationship::LessThan
,
1081 std::numeric_limits
<int>::max() - offset
+ 1),
1088 case GetArrayLength
: {
1089 setRelationship(Relationship(node
, m_zero
, Relationship::GreaterThan
, -1));
1095 Relationship::safeCreate(
1096 node
->child1().node(), node
->phi(), Relationship::Equal
, 0));
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())
1105 newRelationship
.setLeft(node
->phi());
1106 toAdd
.append(newRelationship
);
1108 for (Relationship relationship
: toAdd
)
1109 setRelationship(relationship
);
1119 void setRelationship(Relationship relationship
, unsigned timeToLive
= 1)
1121 setRelationship(m_relationships
, relationship
, timeToLive
);
1124 void setRelationship(
1125 RelationshipMap
& relationshipMap
, Relationship relationship
, unsigned timeToLive
= 1)
1127 setOneSide(relationshipMap
, relationship
, timeToLive
);
1128 setOneSide(relationshipMap
, relationship
.flipped(), timeToLive
);
1132 RelationshipMap
& relationshipMap
, Relationship relationship
, unsigned timeToLive
= 1)
1138 dataLog(" Setting: ", relationship
, " (ttl = ", timeToLive
, ")\n");
1140 auto result
= relationshipMap
.add(
1141 relationship
.left(), Vector
<Relationship
>());
1142 Vector
<Relationship
>& relationships
= result
.iterator
->value
;
1143 Vector
<Relationship
> toAdd
;
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
;
1154 if (timeToLive
&& otherRelationship
.kind() == Relationship::Equal
) {
1156 dataLog(" Considering: ", otherRelationship
, "\n");
1166 // Where: @a == relationship.left(), @b == relationship.right(),
1167 // @a == otherRelationship.left(), @c == otherRelationship.right().
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
);
1181 relationships
.append(relationship
);
1183 for (Relationship anotherRelationship
: toAdd
) {
1185 setOneSide(relationshipMap
, anotherRelationship
, timeToLive
- 1);
1189 bool mergeTo(RelationshipMap
& relationshipMap
, BasicBlock
* target
)
1192 dataLog("Merging to ", pointerDump(target
), ":\n");
1193 dataLog(" Incoming: ", listDump(sortedRelationships(relationshipMap
)), "\n");
1194 dataLog(" At head: ", listDump(sortedRelationships(m_relationshipsAtHead
[target
])), "\n");
1197 if (m_seenBlocks
.add(target
)) {
1198 // This is a new block. We copy subject to liveness pruning.
1199 auto isLive
= [&] (Node
* node
) {
1202 return target
->ssa
->liveAtHead
.contains(node
);
1205 for (auto& entry
: relationshipMap
) {
1206 if (!isLive(entry
.key
))
1209 Vector
<Relationship
> values
;
1210 for (Relationship relationship
: entry
.value
) {
1211 ASSERT(relationship
.left() == entry
.key
);
1212 if (isLive(relationship
.right())) {
1214 dataLog(" Propagating ", relationship
, "\n");
1215 values
.append(relationship
);
1219 std::sort(values
.begin(), values
.end());
1220 m_relationshipsAtHead
[target
].add(entry
.key
, values
);
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
);
1241 Vector
<Relationship
> mergedRelationships
;
1242 for (Relationship targetRelationship
: entry
.value
) {
1243 for (Relationship sourceRelationship
: iter
->value
) {
1245 dataLog(" Merging ", targetRelationship
, " and ", sourceRelationship
, ":\n");
1246 Relationship newRelationship
=
1247 targetRelationship
.merge(sourceRelationship
);
1250 dataLog(" Got ", newRelationship
, "\n");
1252 if (!newRelationship
)
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
1276 for (Relationship
& existingRelationship
: mergedRelationships
) {
1277 if (existingRelationship
.sameNodesAs(newRelationship
)) {
1278 Relationship filtered
=
1279 existingRelationship
.filter(newRelationship
);
1281 existingRelationship
= filtered
;
1289 mergedRelationships
.append(newRelationship
);
1292 std::sort(mergedRelationships
.begin(), mergedRelationships
.end());
1293 if (entry
.value
== mergedRelationships
)
1296 entry
.value
= mergedRelationships
;
1299 for (Node
* node
: toRemove
)
1300 m_relationshipsAtHead
[target
].remove(node
);
1305 Vector
<Relationship
> sortedRelationships(const RelationshipMap
& relationships
)
1307 Vector
<Relationship
> result
;
1308 for (auto& entry
: relationships
)
1309 result
.appendVector(entry
.value
);
1310 std::sort(result
.begin(), result
.end());
1314 Vector
<Relationship
> sortedRelationships()
1316 return sortedRelationships(m_relationships
);
1320 RelationshipMap m_relationships
;
1321 BlockSet m_seenBlocks
;
1322 BlockMap
<RelationshipMap
> m_relationshipsAtHead
;
1323 InsertionSet m_insertionSet
;
1326 } // anonymous namespace
1328 bool performIntegerRangeOptimization(Graph
& graph
)
1330 SamplingRegion
samplingRegion("DFG Integer Range Optimization Phase");
1331 return runPhase
<IntegerRangeOptimizationPhase
>(graph
);
1334 } } // namespace JSC::DFG
1336 #endif // ENABLE(DFG_JIT)