blob: 07b6ac3482fd0e7f32ef84ef82b31151277bd212 [file] [log] [blame]
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001/*
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00002 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00003 *
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"
fpizlo@apple.com92dbc1f2015-11-02 00:48:03 +000032#include "DFGBlockSet.h"
fpizlo@apple.comee3920c2015-06-17 05:31:30 +000033#include "DFGGraph.h"
34#include "DFGInsertionSet.h"
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +000035#include "DFGNodeFlowProjection.h"
fpizlo@apple.comee3920c2015-06-17 05:31:30 +000036#include "DFGPhase.h"
37#include "DFGPredictionPropagationPhase.h"
38#include "DFGVariableAccessDataDump.h"
39#include "JSCInlines.h"
40
41namespace JSC { namespace DFG {
42
43namespace {
44
45const bool verbose = false;
commit-queue@webkit.org07a90bb2016-03-24 09:02:55 +000046const unsigned giveUpThreshold = 50;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +000047
48int64_t clampedSumImpl() { return 0; }
49
50template<typename... Args>
51int64_t clampedSumImpl(int left, Args... args)
52{
53 return static_cast<int64_t>(left) + clampedSumImpl(args...);
54}
55
56template<typename... Args>
57int clampedSum(Args... args)
58{
59 int64_t result = clampedSumImpl(args...);
achristensen@apple.com477be962015-06-17 07:07:42 +000060 return static_cast<int>(std::min(
fpizlo@apple.comee3920c2015-06-17 05:31:30 +000061 static_cast<int64_t>(std::numeric_limits<int>::max()),
62 std::max(
63 static_cast<int64_t>(std::numeric_limits<int>::min()),
achristensen@apple.com477be962015-06-17 07:07:42 +000064 result)));
fpizlo@apple.comee3920c2015-06-17 05:31:30 +000065}
66
fpizlo@apple.com12227fb2015-08-21 00:26:41 +000067bool isGeneralOffset(int offset)
68{
69 return offset >= -1 && offset <= 1;
70}
71
fpizlo@apple.comee3920c2015-06-17 05:31:30 +000072class Relationship {
73public:
74 enum Kind {
75 LessThan,
76 Equal,
77 NotEqual,
78 GreaterThan
79 };
fpizlo@apple.com12227fb2015-08-21 00:26:41 +000080
81 // Some relationships provide more information than others. When a relationship provides more
82 // information, it is less vague.
83 static unsigned vagueness(Kind kind)
84 {
85 switch (kind) {
86 case Equal:
87 return 0;
88 case LessThan:
89 case GreaterThan:
90 return 1;
91 case NotEqual:
92 return 2;
93 }
94 RELEASE_ASSERT_NOT_REACHED();
95 return 0;
96 }
97
98 static const unsigned minVagueness = 0;
99 static const unsigned maxVagueness = 2;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000100
101 static Kind flipped(Kind kind)
102 {
103 switch (kind) {
104 case LessThan:
105 return GreaterThan;
106 case Equal:
107 return Equal;
108 case NotEqual:
109 return NotEqual;
110 case GreaterThan:
111 return LessThan;
112 }
113 RELEASE_ASSERT_NOT_REACHED();
114 return kind;
115 }
116
117 Relationship()
118 : m_left(nullptr)
119 , m_right(nullptr)
120 , m_kind(Equal)
121 , m_offset(0)
122 {
123 }
124
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000125 Relationship(NodeFlowProjection left, NodeFlowProjection right, Kind kind, int offset = 0)
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000126 : m_left(left)
127 , m_right(right)
128 , m_kind(kind)
129 , m_offset(offset)
130 {
131 RELEASE_ASSERT(m_left);
132 RELEASE_ASSERT(m_right);
133 RELEASE_ASSERT(m_left != m_right);
134 }
135
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000136 static Relationship safeCreate(NodeFlowProjection left, NodeFlowProjection right, Kind kind, int offset = 0)
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000137 {
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000138 if (!left.isStillValid() || !right.isStillValid() || left == right)
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000139 return Relationship();
140 return Relationship(left, right, kind, offset);
141 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000142
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000143 explicit operator bool() const { return !!m_left; }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000144
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000145 NodeFlowProjection left() const { return m_left; }
146 NodeFlowProjection right() const { return m_right; }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000147 Kind kind() const { return m_kind; }
148 int offset() const { return m_offset; }
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000149
150 unsigned vagueness() const { return vagueness(kind()); }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000151
152 Relationship flipped() const
153 {
154 if (!*this)
155 return Relationship();
156
157 // This should return Relationship() if -m_offset overflows. For example:
158 //
159 // @a > @b - 2**31
160 //
161 // If we flip it we get:
162 //
163 // @b < @a + 2**31
164 //
165 // Except that the sign gets flipped since it's INT_MIN:
166 //
167 // @b < @a - 2**31
168 //
169 // And that makes no sense. To see how little sense it makes, consider:
170 //
171 // @a > @zero - 2**31
172 //
173 // We would flip it to mean:
174 //
175 // @zero < @a - 2**31
176 //
177 // Which is absurd.
178
179 if (m_offset == std::numeric_limits<int>::min())
180 return Relationship();
181
182 return Relationship(m_right, m_left, flipped(m_kind), -m_offset);
183 }
184
185 Relationship inverse() const
186 {
187 if (!*this)
188 return *this;
189
190 switch (m_kind) {
191 case Equal:
192 return Relationship(m_left, m_right, NotEqual, m_offset);
193 case NotEqual:
194 return Relationship(m_left, m_right, Equal, m_offset);
195 case LessThan:
196 if (sumOverflows<int>(m_offset, -1))
197 return Relationship();
198 return Relationship(m_left, m_right, GreaterThan, m_offset - 1);
199 case GreaterThan:
200 if (sumOverflows<int>(m_offset, 1))
201 return Relationship();
202 return Relationship(m_left, m_right, LessThan, m_offset + 1);
203 }
204
205 RELEASE_ASSERT_NOT_REACHED();
206 }
207
208 bool isCanonical() const { return m_left < m_right; }
209
210 Relationship canonical() const
211 {
212 if (isCanonical())
213 return *this;
214 return flipped();
215 }
216
217 bool sameNodesAs(const Relationship& other) const
218 {
219 return m_left == other.m_left
220 && m_right == other.m_right;
221 }
commit-queue@webkit.org07a90bb2016-03-24 09:02:55 +0000222
223 bool isEquivalentTo(const Relationship& other) const
224 {
225 if (m_left != other.m_left || m_kind != other.m_kind)
226 return false;
227
228 if (*this == other)
229 return true;
230
231 if (m_right->isInt32Constant() && other.m_right->isInt32Constant())
232 return (m_right->asInt32() + m_offset) == (other.m_right->asInt32() + other.m_offset);
233 return false;
234 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000235
236 bool operator==(const Relationship& other) const
237 {
238 return sameNodesAs(other)
239 && m_kind == other.m_kind
240 && m_offset == other.m_offset;
241 }
242
243 bool operator!=(const Relationship& other) const
244 {
245 return !(*this == other);
246 }
247
248 bool operator<(const Relationship& other) const
249 {
250 if (m_left != other.m_left)
251 return m_left < other.m_left;
252 if (m_right != other.m_right)
253 return m_right < other.m_right;
254 if (m_kind != other.m_kind)
255 return m_kind < other.m_kind;
256 return m_offset < other.m_offset;
257 }
258
259 // If possible, returns a form of this relationship where the given node is the left
260 // side. Returns a null relationship if this relationship cannot say anything about this
261 // node.
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000262 Relationship forNode(NodeFlowProjection node) const
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000263 {
264 if (m_left == node)
265 return *this;
266 if (m_right == node)
267 return flipped();
268 return Relationship();
269 }
270
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000271 void setLeft(NodeFlowProjection left)
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000272 {
273 RELEASE_ASSERT(left != m_right);
274 m_left = left;
275 }
276 bool addToOffset(int offset)
277 {
278 if (sumOverflows<int>(m_offset, offset))
279 return false;
280 m_offset += offset;
281 return true;
282 }
283
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000284 // Attempts to create relationships that summarize the union of this relationship and
285 // the other relationship. Relationships are returned by calling the functor with the newly
286 // created relationships. No relationships are created to indicate TOP. This is used
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000287 // for merging the current relationship-at-head for some pair of nodes and a new
288 // relationship-at-head being proposed by a predecessor. We wish to create a new
289 // relationship that is true whenever either of them are true, which ensuring that we don't
290 // do this forever. Anytime we create a relationship that is not equal to either of the
291 // previous ones, we will cause the analysis fixpoint to reexecute.
292 //
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000293 // If *this and other are identical, we just pass it to the functor.
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000294 //
295 // If they are different, we pick from a finite set of "general" relationships:
296 //
297 // Eq: this == other + C, where C is -1, 0, or 1.
298 // Lt: this < other + C, where C is -1, 0, or 1.
299 // Gt: this > other + C, where C is -1, 0, or 1.
300 // Ne: this != other + C, where C is -1, 0, or 1.
301 // TOP: the null relationship.
302 //
303 // Constraining C to -1,0,1 is necessary to ensure that the set of general relationships is
304 // finite. This finite set of relationships forms a pretty simple lattice where a
305 // relA->relB means "relB is more general than relA". For example, this<other+1 is more
306 // general than this==other. I'll leave it as an exercise for the reader to see that a
307 // graph between the 13 general relationships is indeed a lattice. The fact that the set of
308 // general relationships is a finite lattice ensures monotonicity of the fixpoint, since
309 // any merge over not-identical relationships returns a relationship that is closer to the
310 // TOP relationship than either of the original relationships. Here's how convergence is
311 // achieved for any pair of relationships over the same nodes:
312 //
313 // - If they are identical, then returning *this means that we won't be responsible for
314 // causing another fixpoint iteration. Once all merges reach this point, we're done.
315 //
316 // - If they are different, then we pick the most constraining of the 13 general
317 // relationships that is true if either *this or other are true. This means that if the
318 // relationships are not identical, the merged relationship will be closer to TOP than
319 // either of the originals. Returning a different relationship means that we will be
320 // responsible for the fixpoint to reloop, but we can only do this at most 13 times since
321 // that's how "deep" the general relationship lattice is.
322 //
323 // Note that C being constrained to -1,0,1 also ensures that we never have to return a
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000324 // combination of Lt and Gt, as in for example this<other+C && this>other-D. The only possible
325 // values of C and D where this would work are -1 and 1, but in that case we just say
326 // this==other. That said, the logic for merging two == relationships, like this==other+C ||
327 // this==other+D is to attempt to create these two relationships: this>other+min(C,D)-1 &&
328 // this<other+max(C,D)+1. But only one of these relationships will belong to the set of general
329 // relationships.
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000330 //
331 // Here's an example of this in action:
332 //
333 // for (var i = a; ; ++i) { }
334 //
335 // Without C being constrained to -1,0,1, we could end up looping forever: first we'd say
336 // 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
337 // because i<a+2 is not a valid general relationship: so when we merge i==a from the first
338 // iteration and i==a+1 from the second iteration, we create i>a-1 and i<a+2 but then
339 // realize that only i>a-1 is a valid general relationship. This gives us exactly what we
340 // want: a statement that i>=a.
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000341 //
342 // However, this may return a pair of relationships when merging relationships involving
343 // constants. For example, if given:
344 //
345 // @x == @c
346 // @x == @d
347 //
348 // where @c and @d are constants, then this may pass two relationships to the functor:
349 //
350 // @x > min(@c, @d) - 1
351 // @x < max(@c, @d) + 1
352 //
353 // This still allows for convergence, because just as when merging relationships over
354 // variables, this always picks from a set of general relationships. Hence although this may
355 // produce two relationships as a result of the merge, the total number of relationships that
356 // can be present at head of block is limited by O(graph.size^2).
357 template<typename Functor>
358 void merge(const Relationship& other, const Functor& functor) const
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000359 {
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000360 // Handle the super obvious case first.
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000361 if (*this == other) {
362 functor(*this);
363 return;
364 }
365
366 if (m_left != other.m_left)
367 return;
368
369 if (m_right != other.m_right) {
370 mergeConstantsImpl(other, functor);
371 return;
372 }
373
374 ASSERT(sameNodesAs(other));
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000375
376 // This does some interesting permutations to reduce the amount of duplicate code. For
377 // example:
378 //
379 // initially: @a != @b, @a > @b
380 // @b != @a, @b < @a
381 // @b < @a, @b != @a
382 // finally: @b != a, @b < @a
383 //
384 // Another example:
385 //
386 // initially: @a < @b, @a != @b
387 // finally: @a != @b, @a < @b
388
389 Relationship a = *this;
390 Relationship b = other;
391 bool needFlip = false;
392
393 // Get rid of GreaterThan.
394 if (a.m_kind == GreaterThan || b.m_kind == GreaterThan) {
395 a = a.flipped();
396 b = b.flipped();
397
398 // In rare cases, we might not be able to flip. Just give up on life in those
399 // cases.
400 if (!a || !b)
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000401 return;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000402
403 needFlip = true;
404
405 // If we still have GreaterThan, then it means that we started with @a < @b and
406 // @a > @b. That's pretty much always a tautology; we don't attempt to do smart
407 // things for that case for now.
408 if (a.m_kind == GreaterThan || b.m_kind == GreaterThan)
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000409 return;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000410 }
411
412 // Make sure that if we have a LessThan, then it's first.
413 if (b.m_kind == LessThan)
414 std::swap(a, b);
415
416 // Make sure that if we have a NotEqual, then it's first.
417 if (b.m_kind == NotEqual)
418 std::swap(a, b);
419
420 Relationship result = a.mergeImpl(b);
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000421 if (!result)
422 return;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000423
424 if (needFlip)
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000425 result = result.flipped();
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000426
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000427 functor(result);
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000428 }
429
430 // Attempts to construct one Relationship that adequately summarizes the intersection of
431 // this and other. Returns a null relationship if the filtration should be expressed as two
432 // different relationships. Returning null is always safe because relationship lists in
433 // this phase always imply intersection. So, you could soundly skip calling this method and
434 // just put both relationships into the list. But, that could lead the fixpoint to diverge.
435 // Hence this will attempt to combine the two relationships into one as a convergence hack.
436 // In some cases, it will do something conservative. It's always safe for this to return
437 // *this, or to return other. It'll do that sometimes, mainly to accelerate convergence for
438 // things that we don't think are important enough to slow down the analysis.
439 Relationship filter(const Relationship& other) const
440 {
441 // We are only interested in merging relationships over the same nodes.
442 ASSERT(sameNodesAs(other));
443
444 if (*this == other)
445 return *this;
446
447 // From here we can assume that the two relationships are not identical. Usually we use
448 // this to assume that we have different offsets anytime that everything but the offset
449 // is identical.
450
451 // We want equality to take precedent over everything else, and we don't want multiple
452 // independent claims of equality. That would just be a contradiction. When it does
453 // happen, we will be conservative in the sense that we will pick one.
454 if (m_kind == Equal)
455 return *this;
456 if (other.m_kind == Equal)
457 return other;
458
459 // Useful helper for flipping.
460 auto filterFlipped = [&] () -> Relationship {
461 // If we cannot flip, then just conservatively return *this.
462 Relationship a = flipped();
463 Relationship b = other.flipped();
464 if (!a || !b)
465 return *this;
466 Relationship result = a.filter(b);
467 if (!result)
468 return Relationship();
469 result = result.flipped();
470 if (!result)
471 return *this;
472 return result;
473 };
474
475 if (m_kind == NotEqual) {
476 if (other.m_kind == NotEqual) {
477 // We could do something smarter here. We could even keep both NotEqual's. We
478 // would need to make sure that we correctly collapsed them when merging. But
479 // for now, we just pick one of them and hope for the best.
480 return *this;
481 }
482
483 if (other.m_kind == GreaterThan) {
484 // Implement this in terms of NotEqual.filter(LessThan).
485 return filterFlipped();
486 }
487
488 ASSERT(other.m_kind == LessThan);
489 // We have two claims:
490 // @a != @b + C
491 // @a < @b + D
492 //
493 // If C >= D, then the NotEqual is redundant.
494 // If C < D - 1, then we could keep both, but for now we just keep the LessThan.
495 // If C == D - 1, then the LessThan can be turned into:
496 //
497 // @a < @b + C
498 //
499 // Note that C == this.m_offset, D == other.m_offset.
500
501 if (m_offset == other.m_offset - 1)
502 return Relationship(m_left, m_right, LessThan, m_offset);
503
504 return other;
505 }
506
507 if (other.m_kind == NotEqual)
508 return other.filter(*this);
509
510 if (m_kind == LessThan) {
511 if (other.m_kind == LessThan) {
512 return Relationship(
513 m_left, m_right, LessThan, std::min(m_offset, other.m_offset));
514 }
515
516 ASSERT(other.m_kind == GreaterThan);
517 if (sumOverflows<int>(m_offset, -1))
518 return Relationship();
519 if (sumOverflows<int>(other.m_offset, 1))
520 return Relationship();
521 if (m_offset - 1 == other.m_offset + 1)
522 return Relationship(m_left, m_right, Equal, m_offset - 1);
523
524 return Relationship();
525 }
526
527 ASSERT(m_kind == GreaterThan);
528 return filterFlipped();
529 }
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000530
531 // Come up with a relationship that is the best description of this && other, provided that left() is
532 // the same and right() is a constant. Also requires that this is at least as vague as other. It may
533 // return this or it may return something else, but whatever it returns, it will have the same nodes as
534 // this. This is not automatically done by filter() because it currently only makes sense to call this
535 // during a very particular part of setOneSide().
536 Relationship filterConstant(const Relationship& other) const
537 {
538 ASSERT(m_left == other.m_left);
539 ASSERT(m_right->isInt32Constant());
540 ASSERT(other.m_right->isInt32Constant());
541 ASSERT(vagueness() >= other.vagueness());
542
543 if (vagueness() == other.vagueness())
544 return *this;
545
546 int thisRight = m_right->asInt32();
547 int otherRight = other.m_right->asInt32();
548
549 // Ignore funny business.
550 if (sumOverflows<int>(otherRight, other.m_offset))
551 return *this;
552
553 int otherEffectiveRight = otherRight + other.m_offset;
554
555 switch (other.m_kind) {
556 case Equal:
557 // Return a version of *this that is Equal to other's constant.
558 return Relationship(m_left, m_right, Equal, otherEffectiveRight - thisRight);
559
560 case LessThan:
561 case GreaterThan:
562 ASSERT(m_kind == NotEqual);
563 // We could do smart things here. But we don't currently have an example of when it would be
564 // valuable. Note that you have to be careful. We could refine NotEqual to LessThan, but only
565 // if the LessThan subsumes the NotEqual.
566 return *this;
567
568 case NotEqual:
569 RELEASE_ASSERT_NOT_REACHED();
570 return Relationship();
571 }
572
573 RELEASE_ASSERT_NOT_REACHED();
574 return Relationship();
575 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000576
577 int minValueOfLeft() const
578 {
579 if (m_left->isInt32Constant())
580 return m_left->asInt32();
581
582 if (m_kind == LessThan || m_kind == NotEqual)
583 return std::numeric_limits<int>::min();
584
585 int minRightValue = std::numeric_limits<int>::min();
586 if (m_right->isInt32Constant())
587 minRightValue = m_right->asInt32();
588
589 if (m_kind == GreaterThan)
590 return clampedSum(minRightValue, m_offset, 1);
591 ASSERT(m_kind == Equal);
592 return clampedSum(minRightValue, m_offset);
593 }
594
595 int maxValueOfLeft() const
596 {
597 if (m_left->isInt32Constant())
598 return m_left->asInt32();
599
600 if (m_kind == GreaterThan || m_kind == NotEqual)
601 return std::numeric_limits<int>::max();
602
603 int maxRightValue = std::numeric_limits<int>::max();
604 if (m_right->isInt32Constant())
605 maxRightValue = m_right->asInt32();
606
607 if (m_kind == LessThan)
608 return clampedSum(maxRightValue, m_offset, -1);
609 ASSERT(m_kind == Equal);
610 return clampedSum(maxRightValue, m_offset);
611 }
612
613 void dump(PrintStream& out) const
614 {
615 // This prints out the relationship without any whitespace, like @x<@y+42. This
616 // optimizes for the clarity of a list of relationships. It's easier to read something
617 // like [@1<@2+3, @4==@5-6] than it would be if there was whitespace inside the
618 // relationships.
619
620 if (!*this) {
621 out.print("null");
622 return;
623 }
624
625 out.print(m_left);
626 switch (m_kind) {
627 case LessThan:
628 out.print("<");
629 break;
630 case Equal:
631 out.print("==");
632 break;
633 case NotEqual:
634 out.print("!=");
635 break;
636 case GreaterThan:
637 out.print(">");
638 break;
639 }
640 out.print(m_right);
641 if (m_offset > 0)
642 out.print("+", m_offset);
643 else if (m_offset < 0)
644 out.print("-", -static_cast<int64_t>(m_offset));
645 }
646
647private:
648 Relationship mergeImpl(const Relationship& other) const
649 {
650 ASSERT(sameNodesAs(other));
651 ASSERT(m_kind != GreaterThan);
652 ASSERT(other.m_kind != GreaterThan);
653 ASSERT(*this != other);
654
655 // The purpose of this method is to guarantee that:
656 //
657 // - We avoid having more than one Relationship over the same two nodes. Therefore, if
658 // the merge could be expressed as two Relationships, we prefer to instead pick the
659 // less precise single Relationship form even if that means TOP.
660 //
661 // - If the difference between two Relationships is just the m_offset, then we create a
662 // Relationship that has an offset of -1, 0, or 1. This is an essential convergence
663 // hack. We need -1 and 1 to support <= and >=.
664
665 // From here we can assume that the two relationships are not identical. Usually we use
666 // this to assume that we have different offsets anytime that everything but the offset
667 // is identical.
668
669 if (m_kind == NotEqual) {
670 if (other.m_kind == NotEqual)
671 return Relationship(); // Different offsets, so tautology.
672
673 if (other.m_kind == Equal) {
674 if (m_offset != other.m_offset) {
675 // Saying that you might be B when you've already said that you're anything
676 // but A, where A and B are different, is a tautology. You could just say
677 // that you're anything but A. Adding "(a == b + 1)" to "(a != b + 5)" has
678 // no value.
679 return *this;
680 }
681 // Otherwise, same offsets: we're saying that you're either A or you're not
682 // equal to A.
683
684 return Relationship();
685 }
686
687 RELEASE_ASSERT(other.m_kind == LessThan);
688 // We have these claims, and we're merging them:
689 // @a != @b + C
690 // @a < @b + D
691 //
692 // If we have C == D, then the merge is clearly just the NotEqual.
693 // If we have C < D, then the merge is a tautology.
694 // If we have C > D, then we could keep both claims, but we are cheap, so we
695 // don't. We just use the NotEqual.
696
697 if (m_offset < other.m_offset)
698 return Relationship();
699
700 return *this;
701 }
702
703 if (m_kind == LessThan) {
704 if (other.m_kind == LessThan) {
705 // Figure out what offset to select to merge them. The appropriate offsets are
706 // -1, 0, or 1.
707
708 // First figure out what offset we'd like to use.
709 int bestOffset = std::max(m_offset, other.m_offset);
710
711 // We have something like @a < @b + 2. We can't represent this under the
712 // -1,0,1 rule.
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000713 if (isGeneralOffset(bestOffset))
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000714 return Relationship(m_left, m_right, LessThan, std::max(bestOffset, -1));
715
716 return Relationship();
717 }
718
719 // The only thing left is Equal. We would have eliminated the GreaterThan's, and
720 // if we merge LessThan and NotEqual, the NotEqual always comes first.
721 RELEASE_ASSERT(other.m_kind == Equal);
722
723 // This is the really interesting case. We have:
724 //
725 // @a < @b + C
726 //
727 // and:
728 //
729 // @a == @b + D
730 //
731 // Therefore we'd like to return:
732 //
733 // @a < @b + max(C, D + 1)
734
735 int bestOffset = std::max(m_offset, other.m_offset + 1);
736
737 // We have something like @a < @b + 2. We can't do it.
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000738 if (isGeneralOffset(bestOffset))
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000739 return Relationship(m_left, m_right, LessThan, std::max(bestOffset, -1));
740
741 return Relationship();
742 }
743
744 // The only thing left is Equal, since we would have gotten rid of the GreaterThan's.
745 RELEASE_ASSERT(m_kind == Equal);
746
747 // We would never see NotEqual, because those always come first. We would never
748 // see GreaterThan, because we would have eliminated those. We would never see
749 // LessThan, because those always come first.
750
751 RELEASE_ASSERT(other.m_kind == Equal);
752 // We have @a == @b + C and @a == @b + D, where C != D. Turn this into some
753 // inequality that involves a constant that is -1,0,1. Note that we will never have
754 // lessThan and greaterThan because the constants are constrained to -1,0,1. The only
755 // way for both of them to be valid is a<b+1 and a>b-1, but then we would have said
756 // a==b.
757
758 Relationship lessThan;
759 Relationship greaterThan;
760
761 int lessThanEqOffset = std::max(m_offset, other.m_offset);
762 if (lessThanEqOffset >= -2 && lessThanEqOffset <= 0) {
763 lessThan = Relationship(
764 m_left, other.m_right, LessThan, lessThanEqOffset + 1);
765
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000766 ASSERT(isGeneralOffset(lessThan.offset()));
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000767 }
768
769 int greaterThanEqOffset = std::min(m_offset, other.m_offset);
770 if (greaterThanEqOffset >= 0 && greaterThanEqOffset <= 2) {
771 greaterThan = Relationship(
772 m_left, other.m_right, GreaterThan, greaterThanEqOffset - 1);
773
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000774 ASSERT(isGeneralOffset(greaterThan.offset()));
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000775 }
776
777 if (lessThan) {
778 // Both relationships cannot be valid; see above.
779 RELEASE_ASSERT(!greaterThan);
780
781 return lessThan;
782 }
783
784 return greaterThan;
785 }
fpizlo@apple.com12227fb2015-08-21 00:26:41 +0000786
787 template<typename Functor>
788 void mergeConstantsImpl(const Relationship& other, const Functor& functor) const
789 {
790 ASSERT(m_left == other.m_left);
791
792 // Only deal with constant right.
793 if (!m_right->isInt32Constant() || !other.m_right->isInt32Constant())
794 return;
795
796 // What follows is a fairly conservative merge. We could tune this phase to come up with
797 // all possible inequalities between variables and constants, but we focus mainly on cheap
798 // cases for now.
799
800 // Here are some of the the arrangements we can merge usefully assuming @c < @d:
801 //
802 // @x == @c || @x == @d => @x >= c && @x <= @d
803 // @x >= @c || @x <= @d => TOP
804 // @x == @c || @x != @d => @x != @d
805
806 int thisRight = m_right->asInt32();
807 int otherRight = other.m_right->asInt32();
808
809 // Ignore funny business.
810 if (sumOverflows<int>(thisRight, m_offset))
811 return;
812 if (sumOverflows<int>(otherRight, other.m_offset))
813 return;
814
815 int thisEffectiveRight = thisRight + m_offset;
816 int otherEffectiveRight = otherRight + other.m_offset;
817
818 auto makeUpper = [&] (int64_t upper) {
819 if (upper <= thisRight) {
820 // We want m_right + offset to be equal to upper. Hence we want offset to cancel
821 // with m_right. But there's more to it, since we want +1 to turn the LessThan into
822 // a LessThanOrEqual, and we want to make sure we don't end up with non-general
823 // offsets.
824 int offset = static_cast<int>(std::max(
825 static_cast<int64_t>(1) + upper - static_cast<int64_t>(thisRight),
826 static_cast<int64_t>(-1)));
827 functor(Relationship(m_left, m_right, LessThan, offset));
828 }
829 if (upper <= otherRight) {
830 int offset = static_cast<int>(std::max(
831 static_cast<int64_t>(1) + upper - static_cast<int64_t>(otherRight),
832 static_cast<int64_t>(-1)));
833 functor(Relationship(m_left, other.m_right, LessThan, offset));
834 }
835 };
836 auto makeLower = [&] (int64_t lower) {
837 if (lower >= thisRight) {
838 // We want m_right + offset to be equal to lower. Hence we want offset to cancel with
839 // m_right. But there's more to it, since we want -1 to turn the GreaterThan into a
840 // GreaterThanOrEqual, and we want to make sure we don't end up with non-general
841 // offsets.
842 int offset = static_cast<int>(std::min(
843 static_cast<int64_t>(-1) + lower - static_cast<int64_t>(thisRight),
844 static_cast<int64_t>(1)));
845 functor(Relationship(m_left, m_right, GreaterThan, offset));
846 }
847 if (lower >= otherRight) {
848 int offset = static_cast<int>(std::min(
849 static_cast<int64_t>(-1) + lower - static_cast<int64_t>(otherRight),
850 static_cast<int64_t>(1)));
851 functor(Relationship(m_left, other.m_right, GreaterThan, offset));
852 }
853 };
854
855 switch (m_kind) {
856 case Equal: {
857 switch (other.m_kind) {
858 case Equal: {
859 if (thisEffectiveRight == otherEffectiveRight) {
860 // This probably won't arise often. We can keep whichever relationship is general.
861 if (isGeneralOffset(m_offset))
862 functor(*this);
863 if (isGeneralOffset(other.m_offset))
864 functor(other);
865 return;
866 }
867
868 // What follows is the only case where a merge will create more rules than what it
869 // started with. This is fine for convergence because the LessThan/GreaterThan
870 // rules that this creates are general (i.e. have small offsets) and they never
871 // spawn more rules upon subsequent merging.
872
873 makeUpper(std::max(thisEffectiveRight, otherEffectiveRight));
874 makeLower(std::min(thisEffectiveRight, otherEffectiveRight));
875 return;
876 }
877
878 case LessThan: {
879 // Either the LessThan condition subsumes the equality, or the LessThan condition
880 // and equality merge together to create a looser LessThan condition.
881
882 // This is @x == thisEffectiveRight
883 // Other is: @x < otherEffectiveRight
884
885 // We want to create @x <= upper. Figure out the value of upper.
886 makeUpper(std::max(
887 static_cast<int64_t>(thisEffectiveRight),
888 static_cast<int64_t>(otherEffectiveRight) - 1));
889 return;
890 }
891
892 case GreaterThan: {
893 // Opposite of the LessThan case, above.
894
895 // This is: @x == thisEffectiveRight
896 // Other is: @x > otherEffectiveRight
897
898 makeLower(std::min(
899 static_cast<int64_t>(thisEffectiveRight),
900 static_cast<int64_t>(otherEffectiveRight) + 1));
901 return;
902 }
903
904 case NotEqual: {
905 // We keep the NotEqual so long as it doesn't contradict our Equal.
906 if (otherEffectiveRight == thisEffectiveRight)
907 return;
908
909 // But, we only keep the NotEqual if it is general. This simplifies reasoning about
910 // convergence: merging never introduces a new rule unless that rule is general.
911 if (!isGeneralOffset(other.m_offset))
912 return;
913
914 functor(other);
915 return;
916 } }
917
918 RELEASE_ASSERT_NOT_REACHED();
919 return;
920 }
921
922 case LessThan: {
923 switch (other.m_kind) {
924 case Equal: {
925 other.mergeConstantsImpl(*this, functor);
926 return;
927 }
928
929 case LessThan: {
930 makeUpper(std::max(
931 static_cast<int64_t>(thisEffectiveRight) - 1,
932 static_cast<int64_t>(otherEffectiveRight) - 1));
933 return;
934 }
935
936 case GreaterThan: {
937 // We have a claim that @x > @c || @x < @d. If @d > @c, this is the tautology. If
938 // @d <= @c, it's sort of uninteresting. Just ignore this.
939 return;
940 }
941
942 case NotEqual: {
943 // We have a claim that @x < @c || @x != @d. This isn't interesting.
944 return;
945 } }
946
947 RELEASE_ASSERT_NOT_REACHED();
948 return;
949 }
950
951 case GreaterThan: {
952 switch (other.m_kind) {
953 case Equal: {
954 other.mergeConstantsImpl(*this, functor);
955 return;
956 }
957
958 case LessThan: {
959 // Not interesting, see above.
960 return;
961 }
962
963 case GreaterThan: {
964 makeLower(std::min(
965 static_cast<int64_t>(thisEffectiveRight) + 1,
966 static_cast<int64_t>(otherEffectiveRight) + 1));
967 return;
968 }
969
970 case NotEqual: {
971 // Not interesting, see above.
972 return;
973 } }
974
975 RELEASE_ASSERT_NOT_REACHED();
976 return;
977 }
978
979 case NotEqual: {
980 if (other.m_kind == Equal)
981 other.mergeConstantsImpl(*this, functor);
982 return;
983 } }
984
985 RELEASE_ASSERT_NOT_REACHED();
986 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000987
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000988 NodeFlowProjection m_left;
989 NodeFlowProjection m_right;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000990 Kind m_kind;
991 int m_offset; // This offset can be arbitrarily large.
992};
993
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +0000994typedef HashMap<NodeFlowProjection, Vector<Relationship>> RelationshipMap;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +0000995
996class IntegerRangeOptimizationPhase : public Phase {
997public:
998 IntegerRangeOptimizationPhase(Graph& graph)
999 : Phase(graph, "integer range optimization")
1000 , m_zero(nullptr)
1001 , m_relationshipsAtHead(graph)
1002 , m_insertionSet(graph)
1003 {
1004 }
1005
1006 bool run()
1007 {
1008 ASSERT(m_graph.m_form == SSA);
1009
1010 // Before we do anything, make sure that we have a zero constant at the top.
1011 for (Node* node : *m_graph.block(0)) {
1012 if (node->isInt32Constant() && !node->asInt32()) {
1013 m_zero = node;
1014 break;
1015 }
1016 }
1017 if (!m_zero) {
fpizlo@apple.comc9d072f2015-08-27 07:16:07 +00001018 m_zero = m_insertionSet.insertConstant(0, m_graph.block(0)->at(0)->origin, jsNumber(0));
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001019 m_insertionSet.execute(m_graph.block(0));
1020 }
1021
1022 if (verbose) {
1023 dataLog("Graph before integer range optimization:\n");
1024 m_graph.dump();
1025 }
1026
1027 // This performs a fixpoint over the blocks in reverse post-order. Logically, we
1028 // maintain a list of relationships at each point in the program. The list should be
1029 // read as an intersection. For example if we have {rel1, rel2, ..., relN}, you should
1030 // read this as:
1031 //
1032 // TOP && rel1 && rel2 && ... && relN
1033 //
1034 // This allows us to express things like:
1035 //
1036 // @a > @b - 42 && @a < @b + 25
1037 //
1038 // But not things like:
1039 //
1040 // @a < @b - 42 || @a > @b + 25
1041 //
1042 // We merge two lists by merging each relationship in one list with each relationship
1043 // in the other list. Merging two relationships will yield a relationship list; as with
1044 // all such lists it is an intersction. Merging relationships over different variables
1045 // always yields the empty list (i.e. TOP). This merge style is sound because if we
1046 // have:
1047 //
1048 // (A && B && C) || (D && E && F)
1049 //
1050 // Then a valid merge is just one that will return true if A, B, C are all true, or
1051 // that will return true if D, E, F are all true. Our merge style essentially does:
1052 //
1053 // (A || D) && (A || E) && (A || F) && (B || D) && (B || E) && (B || F) &&
1054 // (C || D) && (C || E) && (C || F)
1055 //
1056 // If A && B && C is true, then this returns true. If D && E && F is true, this also
1057 // returns true.
1058 //
1059 // While this appears at first like a kind of expression explosion, in practice it
1060 // isn't. The code that handles this knows that the merge of two relationships over
1061 // different variables is TOP (i.e. the empty list). For example if A above is @a < @b
1062 // and B above is @c > @d, where @a, @b, @c, and @d are different nodes, the merge will
1063 // yield nothing. In fact, the merge algorithm will skip such merges entirely because
1064 // the relationship lists are actually keyed by node.
1065 //
1066 // Note that it's always safe to drop any of relationship from the relationship list.
1067 // This merely increases the likelihood of the "expression" yielding true, i.e. being
1068 // closer to TOP. Optimizations are only performed if we can establish that the
1069 // expression implied by the relationship list is false for all of those cases where
1070 // some check would have failed.
1071 //
1072 // There is no notion of BOTTOM because we treat blocks that haven't had their
1073 // state-at-head set as a special case: we just transfer all live relationships to such
1074 // a block. After the head of a block is set, we perform the merging as above. In all
1075 // other places where we would ordinarily need BOTTOM, we approximate it by having some
1076 // non-BOTTOM relationship.
1077
1078 BlockList postOrder = m_graph.blocksInPostOrder();
1079
1080 // This loop analyzes the IR to give us m_relationshipsAtHead for each block. This
1081 // may reexecute blocks many times, but it is guaranteed to converge. The state of
1082 // the relationshipsAtHead over any pair of nodes converge monotonically towards the
1083 // TOP relationship (i.e. no relationships in the relationship list). The merge rule
1084 // when between the current relationshipsAtHead and the relationships being propagated
1085 // from a predecessor ensures monotonicity by converting disagreements into one of a
1086 // small set of "general" relationships. There are 12 such relationshis, plus TOP. See
1087 // the comment above Relationship::merge() for details.
1088 bool changed = true;
1089 while (changed) {
commit-queue@webkit.org07a90bb2016-03-24 09:02:55 +00001090 ++m_iterations;
1091 if (m_iterations >= giveUpThreshold) {
1092 // This case is not necessarily wrong but it can be a sign that this phase
1093 // does not converge.
1094 // If you hit this assertion for a legitimate case, update the giveUpThreshold
1095 // to the smallest values that converges.
1096 ASSERT_NOT_REACHED();
1097
1098 // In release, do not risk holding the thread for too long since this phase
1099 // is really slow.
1100 return false;
1101 }
1102
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001103 changed = false;
1104 for (unsigned postOrderIndex = postOrder.size(); postOrderIndex--;) {
1105 BasicBlock* block = postOrder[postOrderIndex];
1106 DFG_ASSERT(
1107 m_graph, nullptr,
1108 block == m_graph.block(0) || m_seenBlocks.contains(block));
1109
1110 m_relationships = m_relationshipsAtHead[block];
1111
annulen@yandex.ru23120122016-12-20 18:26:10 +00001112 for (auto* node : *block) {
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001113 if (verbose)
1114 dataLog("Analysis: at ", node, ": ", listDump(sortedRelationships()), "\n");
1115 executeNode(node);
1116 }
1117
1118 // Now comes perhaps the most important piece of cleverness: if we Branch, and
1119 // the predicate involves some relation over integers, we propagate different
1120 // information to the taken and notTaken paths. This handles:
1121 // - Branch on int32.
1122 // - Branch on LogicalNot on int32.
1123 // - Branch on compare on int32's.
1124 // - Branch on LogicalNot of compare on int32's.
1125 Node* terminal = block->terminal();
1126 bool alreadyMerged = false;
1127 if (terminal->op() == Branch) {
1128 Relationship relationshipForTrue;
1129 BranchData* branchData = terminal->branchData();
1130
1131 bool invert = false;
1132 if (terminal->child1()->op() == LogicalNot) {
1133 terminal = terminal->child1().node();
1134 invert = true;
1135 }
1136
1137 if (terminal->child1().useKind() == Int32Use) {
1138 relationshipForTrue = Relationship::safeCreate(
1139 terminal->child1().node(), m_zero, Relationship::NotEqual, 0);
1140 } else {
1141 Node* compare = terminal->child1().node();
1142 switch (compare->op()) {
1143 case CompareEq:
1144 case CompareStrictEq:
1145 case CompareLess:
1146 case CompareLessEq:
1147 case CompareGreater:
1148 case CompareGreaterEq: {
1149 if (!compare->isBinaryUseKind(Int32Use))
1150 break;
1151
1152 switch (compare->op()) {
1153 case CompareEq:
1154 case CompareStrictEq:
1155 relationshipForTrue = Relationship::safeCreate(
1156 compare->child1().node(), compare->child2().node(),
1157 Relationship::Equal, 0);
1158 break;
1159 case CompareLess:
1160 relationshipForTrue = Relationship::safeCreate(
1161 compare->child1().node(), compare->child2().node(),
1162 Relationship::LessThan, 0);
1163 break;
1164 case CompareLessEq:
1165 relationshipForTrue = Relationship::safeCreate(
1166 compare->child1().node(), compare->child2().node(),
1167 Relationship::LessThan, 1);
1168 break;
1169 case CompareGreater:
1170 relationshipForTrue = Relationship::safeCreate(
1171 compare->child1().node(), compare->child2().node(),
1172 Relationship::GreaterThan, 0);
1173 break;
1174 case CompareGreaterEq:
1175 relationshipForTrue = Relationship::safeCreate(
1176 compare->child1().node(), compare->child2().node(),
1177 Relationship::GreaterThan, -1);
1178 break;
1179 default:
1180 DFG_CRASH(m_graph, compare, "Invalid comparison node type");
1181 break;
1182 }
1183 break;
1184 }
1185
1186 default:
1187 break;
1188 }
1189 }
1190
1191 if (invert)
1192 relationshipForTrue = relationshipForTrue.inverse();
1193
1194 if (relationshipForTrue) {
1195 RelationshipMap forTrue = m_relationships;
1196 RelationshipMap forFalse = m_relationships;
1197
1198 if (verbose)
1199 dataLog("Dealing with true:\n");
1200 setRelationship(forTrue, relationshipForTrue);
1201 if (Relationship relationshipForFalse = relationshipForTrue.inverse()) {
1202 if (verbose)
1203 dataLog("Dealing with false:\n");
1204 setRelationship(forFalse, relationshipForFalse);
1205 }
1206
1207 changed |= mergeTo(forTrue, branchData->taken.block);
1208 changed |= mergeTo(forFalse, branchData->notTaken.block);
1209 alreadyMerged = true;
1210 }
1211 }
1212
1213 if (!alreadyMerged) {
1214 for (BasicBlock* successor : block->successors())
1215 changed |= mergeTo(m_relationships, successor);
1216 }
1217 }
1218 }
1219
1220 // Now we transform the code based on the results computed in the previous loop.
1221 changed = false;
1222 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
1223 m_relationships = m_relationshipsAtHead[block];
1224 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
1225 Node* node = block->at(nodeIndex);
1226 if (verbose)
1227 dataLog("Transformation: at ", node, ": ", listDump(sortedRelationships()), "\n");
1228
1229 // This ends up being pretty awkward to write because we need to decide if we
1230 // optimize by using the relationships before the operation, but we need to
1231 // call executeNode() before we optimize.
1232 switch (node->op()) {
commit-queue@webkit.orgf4256ed2016-02-17 23:35:11 +00001233 case ArithAbs: {
1234 if (node->child1().useKind() != Int32Use)
1235 break;
1236
1237 auto iter = m_relationships.find(node->child1().node());
1238 if (iter == m_relationships.end())
1239 break;
1240
1241 int minValue = std::numeric_limits<int>::min();
1242 int maxValue = std::numeric_limits<int>::max();
1243 for (Relationship relationship : iter->value) {
1244 minValue = std::max(minValue, relationship.minValueOfLeft());
1245 maxValue = std::min(maxValue, relationship.maxValueOfLeft());
1246 }
1247
1248 executeNode(block->at(nodeIndex));
1249
1250 if (minValue >= 0) {
1251 node->convertToIdentityOn(node->child1().node());
1252 changed = true;
1253 break;
1254 }
commit-queue@webkit.orgf59f0ed2016-10-15 02:19:16 +00001255 bool absIsUnchecked = !shouldCheckOverflow(node->arithMode());
1256 if (maxValue < 0 || (absIsUnchecked && maxValue <= 0)) {
commit-queue@webkit.orgf4256ed2016-02-17 23:35:11 +00001257 node->convertToArithNegate();
commit-queue@webkit.orgf59f0ed2016-10-15 02:19:16 +00001258 if (absIsUnchecked || minValue > std::numeric_limits<int>::min())
commit-queue@webkit.orgf4256ed2016-02-17 23:35:11 +00001259 node->setArithMode(Arith::Unchecked);
1260 changed = true;
1261 break;
1262 }
1263 if (minValue > std::numeric_limits<int>::min()) {
1264 node->setArithMode(Arith::Unchecked);
1265 changed = true;
1266 break;
1267 }
1268
1269 break;
1270 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001271 case ArithAdd: {
1272 if (!node->isBinaryUseKind(Int32Use))
1273 break;
1274 if (node->arithMode() != Arith::CheckOverflow)
1275 break;
1276 if (!node->child2()->isInt32Constant())
1277 break;
1278
1279 auto iter = m_relationships.find(node->child1().node());
1280 if (iter == m_relationships.end())
1281 break;
1282
1283 int minValue = std::numeric_limits<int>::min();
1284 int maxValue = std::numeric_limits<int>::max();
1285 for (Relationship relationship : iter->value) {
1286 minValue = std::max(minValue, relationship.minValueOfLeft());
1287 maxValue = std::min(maxValue, relationship.maxValueOfLeft());
1288 }
fpizlo@apple.com11aaea92016-01-26 08:17:31 +00001289
1290 if (verbose)
1291 dataLog(" minValue = ", minValue, ", maxValue = ", maxValue, "\n");
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001292
1293 if (sumOverflows<int>(minValue, node->child2()->asInt32()) ||
1294 sumOverflows<int>(maxValue, node->child2()->asInt32()))
1295 break;
fpizlo@apple.com11aaea92016-01-26 08:17:31 +00001296
1297 if (verbose)
1298 dataLog(" It's in bounds.\n");
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001299
1300 executeNode(block->at(nodeIndex));
1301 node->setArithMode(Arith::Unchecked);
1302 changed = true;
1303 break;
1304 }
1305
1306 case CheckInBounds: {
1307 auto iter = m_relationships.find(node->child1().node());
1308 if (iter == m_relationships.end())
1309 break;
1310
1311 bool nonNegative = false;
1312 bool lessThanLength = false;
1313 for (Relationship relationship : iter->value) {
1314 if (relationship.minValueOfLeft() >= 0)
1315 nonNegative = true;
1316
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001317 if (relationship.right() == node->child2().node()) {
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001318 if (relationship.kind() == Relationship::Equal
1319 && relationship.offset() < 0)
1320 lessThanLength = true;
1321
1322 if (relationship.kind() == Relationship::LessThan
1323 && relationship.offset() <= 0)
1324 lessThanLength = true;
1325 }
1326 }
1327
1328 if (nonNegative && lessThanLength) {
1329 executeNode(block->at(nodeIndex));
1330 node->remove();
1331 changed = true;
1332 }
1333 break;
1334 }
benjamin@webkit.org5c3fb3a2015-08-14 03:54:32 +00001335
1336 case GetByVal: {
1337 if (node->arrayMode().type() != Array::Undecided)
1338 break;
1339
1340 auto iter = m_relationships.find(node->child2().node());
1341 if (iter == m_relationships.end())
1342 break;
1343
1344 int minValue = std::numeric_limits<int>::min();
1345 for (Relationship relationship : iter->value)
1346 minValue = std::max(minValue, relationship.minValueOfLeft());
1347
1348 if (minValue < 0)
1349 break;
1350
1351 executeNode(block->at(nodeIndex));
1352 m_graph.convertToConstant(node, jsUndefined());
1353 changed = true;
1354 break;
1355 }
1356
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001357 default:
1358 break;
1359 }
1360
1361 executeNode(block->at(nodeIndex));
1362 }
1363 }
1364
1365 return changed;
1366 }
1367
1368private:
1369 void executeNode(Node* node)
1370 {
1371 switch (node->op()) {
1372 case CheckInBounds: {
1373 setRelationship(Relationship::safeCreate(node->child1().node(), node->child2().node(), Relationship::LessThan));
1374 setRelationship(Relationship::safeCreate(node->child1().node(), m_zero, Relationship::GreaterThan, -1));
1375 break;
1376 }
commit-queue@webkit.orgf4256ed2016-02-17 23:35:11 +00001377
1378 case ArithAbs: {
1379 if (node->child1().useKind() != Int32Use)
1380 break;
1381 setRelationship(Relationship(node, m_zero, Relationship::GreaterThan, -1));
1382 break;
1383 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001384
1385 case ArithAdd: {
1386 // We're only interested in int32 additions and we currently only know how to
1387 // handle the non-wrapping ones.
1388 if (!node->isBinaryUseKind(Int32Use))
1389 break;
1390
1391 // FIXME: We could handle the unchecked arithmetic case. We just do it don't right
1392 // now.
1393 if (node->arithMode() != Arith::CheckOverflow)
1394 break;
1395
1396 // Handle add: @value + constant.
1397 if (!node->child2()->isInt32Constant())
1398 break;
1399
1400 int offset = node->child2()->asInt32();
1401
1402 // We add a relationship for @add == @value + constant, and then we copy the
1403 // relationships for @value. This gives us a one-deep view of @value's existing
1404 // relationships, which matches the one-deep search in setRelationship().
1405
1406 setRelationship(
1407 Relationship(node, node->child1().node(), Relationship::Equal, offset));
1408
1409 auto iter = m_relationships.find(node->child1().node());
1410 if (iter != m_relationships.end()) {
1411 Vector<Relationship> toAdd;
1412 for (Relationship relationship : iter->value) {
1413 // We have:
1414 // add: ArithAdd(@x, C)
1415 // @x op @y + D
1416 //
1417 // The following certainly holds:
1418 // @x == @add - C
1419 //
1420 // Which allows us to substitute:
1421 // @add - C op @y + D
1422 //
1423 // And then carry the C over:
1424 // @add op @y + D + C
1425
1426 Relationship newRelationship = relationship;
1427 ASSERT(newRelationship.left() == node->child1().node());
1428
1429 if (newRelationship.right() == node)
1430 continue;
1431 newRelationship.setLeft(node);
1432 if (newRelationship.addToOffset(offset))
1433 toAdd.append(newRelationship);
1434 }
1435 for (Relationship relationship : toAdd)
1436 setRelationship(relationship, 0);
1437 }
1438
1439 // Now we want to establish that both the input and the output of the addition are
1440 // within a particular range of integers.
1441
1442 if (offset > 0) {
1443 // If we have "add: @value + 1" then we know that @value <= max - 1, i.e. that
1444 // @value < max.
1445 if (!sumOverflows<int>(std::numeric_limits<int>::max(), -offset, 1)) {
1446 setRelationship(
1447 Relationship::safeCreate(
1448 node->child1().node(), m_zero, Relationship::LessThan,
1449 std::numeric_limits<int>::max() - offset + 1),
1450 0);
1451 }
1452
1453 // If we have "add: @value + 1" then we know that @add >= min + 1, i.e. that
1454 // @add > min.
1455 if (!sumOverflows<int>(std::numeric_limits<int>::min(), offset, -1)) {
1456 setRelationship(
1457 Relationship(
1458 node, m_zero, Relationship::GreaterThan,
1459 std::numeric_limits<int>::min() + offset - 1),
1460 0);
1461 }
1462 }
1463
1464 if (offset < 0 && offset != std::numeric_limits<int>::min()) {
1465 // If we have "add: @value - 1" then we know that @value >= min + 1, i.e. that
1466 // @value > min.
1467 if (!sumOverflows<int>(std::numeric_limits<int>::min(), offset, -1)) {
1468 setRelationship(
1469 Relationship::safeCreate(
1470 node->child1().node(), m_zero, Relationship::GreaterThan,
1471 std::numeric_limits<int>::min() + offset - 1),
1472 0);
1473 }
1474
1475 // If we have "add: @value + 1" then we know that @add <= max - 1, i.e. that
1476 // @add < max.
1477 if (!sumOverflows<int>(std::numeric_limits<int>::max(), -offset, 1)) {
1478 setRelationship(
1479 Relationship(
1480 node, m_zero, Relationship::LessThan,
1481 std::numeric_limits<int>::max() - offset + 1),
1482 0);
1483 }
1484 }
1485 break;
1486 }
1487
utatane.tea@gmail.com95eee7b2017-05-22 06:24:44 +00001488 case GetArrayLength:
1489 case GetVectorLength: {
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001490 setRelationship(Relationship(node, m_zero, Relationship::GreaterThan, -1));
1491 break;
1492 }
1493
1494 case Upsilon: {
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001495 setEquivalence(
1496 node->child1().node(),
1497 NodeFlowProjection(node->phi(), NodeFlowProjection::Shadow));
1498 break;
1499 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001500
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001501 case Phi: {
1502 setEquivalence(
1503 NodeFlowProjection(node, NodeFlowProjection::Shadow),
1504 node);
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001505 break;
1506 }
1507
1508 default:
1509 break;
1510 }
1511 }
1512
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001513 void setEquivalence(NodeFlowProjection oldNode, NodeFlowProjection newNode)
1514 {
1515 setRelationship(Relationship::safeCreate(oldNode, newNode, Relationship::Equal, 0));
1516
1517 auto iter = m_relationships.find(oldNode);
1518 if (iter != m_relationships.end()) {
1519 Vector<Relationship> toAdd;
1520 for (Relationship relationship : iter->value) {
1521 Relationship newRelationship = relationship;
1522 // Avoid creating any kind of self-relationship.
1523 if (newNode.node() == newRelationship.right().node())
1524 continue;
1525 newRelationship.setLeft(newNode);
1526 toAdd.append(newRelationship);
1527 }
1528 for (Relationship relationship : toAdd)
1529 setRelationship(relationship);
1530 }
1531 }
1532
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001533 void setRelationship(Relationship relationship, unsigned timeToLive = 1)
1534 {
1535 setRelationship(m_relationships, relationship, timeToLive);
1536 }
1537
1538 void setRelationship(
1539 RelationshipMap& relationshipMap, Relationship relationship, unsigned timeToLive = 1)
1540 {
1541 setOneSide(relationshipMap, relationship, timeToLive);
1542 setOneSide(relationshipMap, relationship.flipped(), timeToLive);
1543 }
1544
1545 void setOneSide(
1546 RelationshipMap& relationshipMap, Relationship relationship, unsigned timeToLive = 1)
1547 {
1548 if (!relationship)
1549 return;
1550
1551 if (verbose)
1552 dataLog(" Setting: ", relationship, " (ttl = ", timeToLive, ")\n");
1553
1554 auto result = relationshipMap.add(
1555 relationship.left(), Vector<Relationship>());
1556 Vector<Relationship>& relationships = result.iterator->value;
fpizlo@apple.com12227fb2015-08-21 00:26:41 +00001557
1558 if (relationship.right()->isInt32Constant()) {
1559 // We want to do some work to refine relationships over constants. This is necessary because
1560 // when we introduce a constant into the IR, we don't automatically create relationships
1561 // between that constant and the other constants. That means that when we do introduce
1562 // relationships between a non-constant and a constant, we need to check the other
1563 // relationships between that non-constant and other constants to see if we can make some
1564 // refinements. Possible constant statement filtrations:
1565 //
1566 // - @x == @c and @x != @d, where @c > @d:
1567 // @x == @c and @x > @d
1568 //
1569 // but actually we are more aggressive:
1570 //
1571 // - @x == @c and @x op @d where @c == @d + k
1572 // @x == @c and @x == @d + k
1573 //
1574 // And this is also possible:
1575 //
1576 // - @x > @c and @x != @d where @c == @d + k and k >= 0
1577 //
1578 // @x > @c and @x > @d + k
1579 //
1580 // So, here's what we should do depending on the kind of relationship we're introducing:
1581 //
1582 // Equal constant: Find all LessThan, NotEqual, and GreaterThan constant operations and refine
1583 // them to be Equal constant. Don't worry about contradictions.
1584 //
1585 // LessThan, GreaterThan constant: See if there is any Equal constant, and if so, refine to
1586 // that. Otherwise, find all NotEqual constant operations and refine them to be LessThan or
1587 // GreaterThan constant if possible.
1588 //
1589 // NotEqual constant: See if there is any Equal constant, and if so, refine to that. Otherwise,
1590 // see if there is any LessThan or GreaterThan constant operation, and if so, attempt to
1591 // refine to that.
1592 //
1593 // Seems that the key thing is to have a filterConstant() operation that returns a refined
1594 // version of *this based on other. The code here accomplishes this by using the vagueness
1595 // index (Relationship::vagueness()) to first find less vague relationships and refine this one
1596 // using them, and then find more vague relationships and refine those to this.
1597
1598 if (relationship.vagueness() != Relationship::minVagueness) {
1599 // We're not minimally vague (maximally specific), so try to refine ourselves based on what
1600 // we already know.
1601 for (Relationship& otherRelationship : relationships) {
1602 if (otherRelationship.vagueness() < relationship.vagueness()
1603 && otherRelationship.right()->isInt32Constant()) {
1604 Relationship newRelationship = relationship.filterConstant(otherRelationship);
1605 if (verbose && newRelationship != relationship)
1606 dataLog(" Refined to: ", newRelationship, " based on ", otherRelationship, "\n");
1607 relationship = newRelationship;
1608 }
1609 }
1610 }
1611
1612 if (relationship.vagueness() != Relationship::maxVagueness) {
1613 // We're not maximally value (minimally specific), so try to refine other relationships
1614 // based on this one.
1615 for (Relationship& otherRelationship : relationships) {
1616 if (otherRelationship.vagueness() > relationship.vagueness()
1617 && otherRelationship.right()->isInt32Constant()) {
1618 Relationship newRelationship = otherRelationship.filterConstant(relationship);
1619 if (verbose && newRelationship != otherRelationship)
1620 dataLog(" Refined ", otherRelationship, " to: ", newRelationship, "\n");
1621 otherRelationship = newRelationship;
1622 }
1623 }
1624 }
1625 }
1626
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001627 Vector<Relationship> toAdd;
1628 bool found = false;
1629 for (Relationship& otherRelationship : relationships) {
1630 if (otherRelationship.sameNodesAs(relationship)) {
1631 if (Relationship filtered = otherRelationship.filter(relationship)) {
1632 ASSERT(filtered.left() == relationship.left());
1633 otherRelationship = filtered;
1634 found = true;
1635 }
1636 }
fpizlo@apple.com12227fb2015-08-21 00:26:41 +00001637
1638 // FIXME: Also add filtration over statements about constants. For example, if we have
1639 // @x == @c and @x != @d, where @d > @c, then we want to turn @x != @d into @x < @d.
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001640
1641 if (timeToLive && otherRelationship.kind() == Relationship::Equal) {
1642 if (verbose)
1643 dataLog(" Considering: ", otherRelationship, "\n");
1644
1645 // We have:
1646 // @a op @b + C
1647 // @a == @c + D
1648 //
1649 // This implies:
1650 // @c + D op @b + C
1651 // @c op @b + C - D
1652 //
1653 // Where: @a == relationship.left(), @b == relationship.right(),
1654 // @a == otherRelationship.left(), @c == otherRelationship.right().
1655
1656 if (otherRelationship.offset() != std::numeric_limits<int>::min()) {
1657 Relationship newRelationship = relationship;
1658 if (newRelationship.right() != otherRelationship.right()) {
1659 newRelationship.setLeft(otherRelationship.right());
1660 if (newRelationship.addToOffset(-otherRelationship.offset()))
1661 toAdd.append(newRelationship);
1662 }
1663 }
1664 }
1665 }
1666
1667 if (!found)
1668 relationships.append(relationship);
1669
1670 for (Relationship anotherRelationship : toAdd) {
1671 ASSERT(timeToLive);
1672 setOneSide(relationshipMap, anotherRelationship, timeToLive - 1);
1673 }
1674 }
1675
1676 bool mergeTo(RelationshipMap& relationshipMap, BasicBlock* target)
1677 {
1678 if (verbose) {
1679 dataLog("Merging to ", pointerDump(target), ":\n");
1680 dataLog(" Incoming: ", listDump(sortedRelationships(relationshipMap)), "\n");
1681 dataLog(" At head: ", listDump(sortedRelationships(m_relationshipsAtHead[target])), "\n");
1682 }
1683
1684 if (m_seenBlocks.add(target)) {
1685 // This is a new block. We copy subject to liveness pruning.
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001686 auto isLive = [&] (NodeFlowProjection node) {
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001687 if (node == m_zero)
1688 return true;
1689 return target->ssa->liveAtHead.contains(node);
1690 };
1691
1692 for (auto& entry : relationshipMap) {
1693 if (!isLive(entry.key))
1694 continue;
1695
1696 Vector<Relationship> values;
1697 for (Relationship relationship : entry.value) {
1698 ASSERT(relationship.left() == entry.key);
1699 if (isLive(relationship.right())) {
1700 if (verbose)
1701 dataLog(" Propagating ", relationship, "\n");
1702 values.append(relationship);
1703 }
1704 }
1705
1706 std::sort(values.begin(), values.end());
1707 m_relationshipsAtHead[target].add(entry.key, values);
1708 }
1709 return true;
1710 }
1711
1712 // Merge by intersecting. We have no notion of BOTTOM, so we use the omission of
1713 // relationships for a pair of nodes to mean TOP. The reason why we don't need BOTTOM
1714 // is (1) we just overapproximate contradictions and (2) a value never having been
1715 // assigned would only happen if we have not processed the node's predecessor. We
1716 // shouldn't process blocks until we have processed the block's predecessor because we
1717 // are using reverse postorder.
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001718 Vector<NodeFlowProjection> toRemove;
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001719 bool changed = false;
1720 for (auto& entry : m_relationshipsAtHead[target]) {
1721 auto iter = relationshipMap.find(entry.key);
1722 if (iter == relationshipMap.end()) {
1723 toRemove.append(entry.key);
1724 changed = true;
1725 continue;
1726 }
commit-queue@webkit.org07a90bb2016-03-24 09:02:55 +00001727
1728 Vector<Relationship> constantRelationshipsAtHead;
1729 for (Relationship& relationshipAtHead : entry.value) {
1730 if (relationshipAtHead.right()->isInt32Constant())
1731 constantRelationshipsAtHead.append(relationshipAtHead);
1732 }
1733
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001734 Vector<Relationship> mergedRelationships;
1735 for (Relationship targetRelationship : entry.value) {
1736 for (Relationship sourceRelationship : iter->value) {
1737 if (verbose)
1738 dataLog(" Merging ", targetRelationship, " and ", sourceRelationship, ":\n");
fpizlo@apple.com12227fb2015-08-21 00:26:41 +00001739 targetRelationship.merge(
1740 sourceRelationship,
1741 [&] (Relationship newRelationship) {
1742 if (verbose)
1743 dataLog(" Got ", newRelationship, "\n");
commit-queue@webkit.org07a90bb2016-03-24 09:02:55 +00001744
1745 if (newRelationship.right()->isInt32Constant()) {
1746 // We can produce a relationship with a constant equivalent to
1747 // an existing relationship yet of a different form. For example:
1748 //
1749 // @a == @b(42) + 0
1750 // @a == @c(41) + 1
1751 //
1752 // We do not want to perpetually switch between those two forms,
1753 // so we always prefer the one already at head.
1754
1755 for (Relationship& existingRelationshipAtHead : constantRelationshipsAtHead) {
1756 if (existingRelationshipAtHead.isEquivalentTo(newRelationship)) {
1757 newRelationship = existingRelationshipAtHead;
1758 break;
1759 }
1760 }
1761 }
fpizlo@apple.com12227fb2015-08-21 00:26:41 +00001762
1763 // We need to filter() to avoid exponential explosion of identical
1764 // relationships. We do this here to avoid making setOneSide() do
1765 // more work, since we expect setOneSide() will be called more
1766 // frequently. Here's an example. At some point someone might start
1767 // with two relationships like @a > @b - C and @a < @b + D. Then
1768 // someone does a setRelationship() passing something that turns
1769 // both of these into @a == @b. Now we have @a == @b duplicated.
1770 // Let's say that this duplicate @a == @b ends up at the head of a
1771 // loop. If we didn't have this rule, then the loop would propagate
1772 // duplicate @a == @b's onto the existing duplicate @a == @b's.
1773 // There would be four pairs of @a == @b, each of which would
1774 // create a new @a == @b. Now we'd have four of these duplicates
1775 // and the next time around we'd have 8, then 16, etc. We avoid
1776 // this here by doing this filtration. That might be a bit of
1777 // overkill, since it's probably just the identical duplicate
1778 // relationship case we want' to avoid. But, I'll keep this until
1779 // we have evidence that this is a performance problem. Remember -
1780 // we are already dealing with a list that is pruned down to
1781 // relationships with identical left operand. It shouldn't be a
1782 // large list.
1783 bool found = false;
1784 for (Relationship& existingRelationship : mergedRelationships) {
1785 if (existingRelationship.sameNodesAs(newRelationship)) {
1786 Relationship filtered =
1787 existingRelationship.filter(newRelationship);
1788 if (filtered) {
1789 existingRelationship = filtered;
1790 found = true;
1791 break;
1792 }
1793 }
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001794 }
fpizlo@apple.com12227fb2015-08-21 00:26:41 +00001795
1796 if (!found)
1797 mergedRelationships.append(newRelationship);
1798 });
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001799 }
1800 }
1801 std::sort(mergedRelationships.begin(), mergedRelationships.end());
1802 if (entry.value == mergedRelationships)
1803 continue;
1804
1805 entry.value = mergedRelationships;
1806 changed = true;
1807 }
fpizlo@apple.com8ff2aef2016-11-04 05:28:35 +00001808 for (NodeFlowProjection node : toRemove)
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001809 m_relationshipsAtHead[target].remove(node);
1810
1811 return changed;
1812 }
1813
1814 Vector<Relationship> sortedRelationships(const RelationshipMap& relationships)
1815 {
1816 Vector<Relationship> result;
1817 for (auto& entry : relationships)
1818 result.appendVector(entry.value);
1819 std::sort(result.begin(), result.end());
1820 return result;
1821 }
1822
1823 Vector<Relationship> sortedRelationships()
1824 {
1825 return sortedRelationships(m_relationships);
1826 }
1827
1828 Node* m_zero;
1829 RelationshipMap m_relationships;
1830 BlockSet m_seenBlocks;
1831 BlockMap<RelationshipMap> m_relationshipsAtHead;
1832 InsertionSet m_insertionSet;
commit-queue@webkit.org07a90bb2016-03-24 09:02:55 +00001833
1834 unsigned m_iterations { 0 };
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001835};
1836
1837} // anonymous namespace
1838
1839bool performIntegerRangeOptimization(Graph& graph)
1840{
fpizlo@apple.comee3920c2015-06-17 05:31:30 +00001841 return runPhase<IntegerRangeOptimizationPhase>(graph);
1842}
1843
1844} } // namespace JSC::DFG
1845
1846#endif // ENABLE(DFG_JIT)
1847