Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/jit/./../../../../js/src/jit/RangeAnalysis.cpp
Warning:line 476, column 9
Value stored to 'first' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_jit10.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/jit -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src/jit -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D WASM_SUPPORTS_HUGE_MEMORY -D JS_CACHEIR_SPEW -D JS_STRUCTURED_SPEW -D JS_HAS_CTYPES -D FFI_BUILDING -D EXPORT_JS_API -D MOZ_HAS_MOZGLUE -D MOZ_SUPPORT_LEAKCHECKING -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/js/src -I /root/firefox-clang/js/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_js_src_jit10.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "jit/RangeAnalysis.h"
6
7#include "mozilla/CheckedArithmetic.h"
8#include "mozilla/MathAlgorithms.h"
9
10#include <algorithm>
11#include <bit>
12
13#include "builtin/Math.h"
14#include "jit/CompileInfo.h"
15#include "jit/IonAnalysis.h"
16#include "jit/JitSpewer.h"
17#include "jit/MIR-wasm.h"
18#include "jit/MIR.h"
19#include "jit/MIRGenerator.h"
20#include "jit/MIRGraph.h"
21#include "js/Conversions.h"
22#include "js/ScalarType.h" // js::Scalar::Type
23#include "util/Unicode.h"
24#include "vm/ArgumentsObject.h"
25#include "vm/Float16.h"
26#include "vm/TypedArrayObject.h"
27#include "vm/Uint8Clamped.h"
28
29#include "vm/BytecodeUtil-inl.h"
30
31using namespace js;
32using namespace js::jit;
33
34using JS::GenericNaN;
35using JS::ToInt32;
36using mozilla::Abs;
37using mozilla::ExponentComponent;
38using mozilla::FloorLog2;
39using mozilla::IsNegativeZero;
40using mozilla::NegativeInfinity;
41using mozilla::NumberEqualsInt32;
42using mozilla::PositiveInfinity;
43
44// [SMDOC] IonMonkey Range Analysis
45//
46// This algorithm is based on the paper "Eliminating Range Checks Using
47// Static Single Assignment Form" by Gough and Klaren.
48//
49// We associate a range object with each SSA name, and the ranges are consulted
50// in order to determine whether overflow is possible for arithmetic
51// computations.
52//
53// An important source of range information that requires care to take
54// advantage of is conditional control flow. Consider the code below:
55//
56// if (x < 0) {
57// y = x + 2000000000;
58// } else {
59// if (x < 1000000000) {
60// y = x * 2;
61// } else {
62// y = x - 3000000000;
63// }
64// }
65//
66// The arithmetic operations in this code cannot overflow, but it is not
67// sufficient to simply associate each name with a range, since the information
68// differs between basic blocks. The traditional dataflow approach would be
69// associate ranges with (name, basic block) pairs. This solution is not
70// satisfying, since we lose the benefit of SSA form: in SSA form, each
71// definition has a unique name, so there is no need to track information about
72// the control flow of the program.
73//
74// The approach used here is to add a new form of pseudo operation called a
75// beta node, which associates range information with a value. These beta
76// instructions take one argument and additionally have an auxiliary constant
77// range associated with them. Operationally, beta nodes are just copies, but
78// the invariant expressed by beta node copies is that the output will fall
79// inside the range given by the beta node. Gough and Klaeren refer to SSA
80// extended with these beta nodes as XSA form. The following shows the example
81// code transformed into XSA form:
82//
83// if (x < 0) {
84// x1 = Beta(x, [INT_MIN, -1]);
85// y1 = x1 + 2000000000;
86// } else {
87// x2 = Beta(x, [0, INT_MAX]);
88// if (x2 < 1000000000) {
89// x3 = Beta(x2, [INT_MIN, 999999999]);
90// y2 = x3*2;
91// } else {
92// x4 = Beta(x2, [1000000000, INT_MAX]);
93// y3 = x4 - 3000000000;
94// }
95// y4 = Phi(y2, y3);
96// }
97// y = Phi(y1, y4);
98//
99// We insert beta nodes for the purposes of range analysis (they might also be
100// usefully used for other forms of bounds check elimination) and remove them
101// after range analysis is performed. The remaining compiler phases do not ever
102// encounter beta nodes.
103
104static bool IsDominatedUse(const MBasicBlock* block, const MUse* use) {
105 MNode* n = use->consumer();
106 bool isPhi = n->isDefinition() && n->toDefinition()->isPhi();
107
108 if (isPhi) {
109 MPhi* phi = n->toDefinition()->toPhi();
110 return block->dominates(phi->block()->getPredecessor(phi->indexOf(use)));
111 }
112
113 return block->dominates(n->block());
114}
115
116static inline void SpewRange(const MDefinition* def) {
117#ifdef JS_JITSPEW1
118 if (JitSpewEnabled(JitSpew_Range) && def->type() != MIRType::None &&
119 def->range()) {
120 AutoJitSpewMessage msg(JitSpew_Range, " ");
121 def->printName(msg.printer());
122 msg.append(" has range ");
123 def->range()->dump(msg.printer());
124 }
125#endif
126}
127
128#ifdef JS_JITSPEW1
129static const char* TruncateKindString(TruncateKind kind) {
130 switch (kind) {
131 case TruncateKind::NoTruncate:
132 return "NoTruncate";
133 case TruncateKind::TruncateAfterBailouts:
134 return "TruncateAfterBailouts";
135 case TruncateKind::IndirectTruncate:
136 return "IndirectTruncate";
137 case TruncateKind::Truncate:
138 return "Truncate";
139 default:
140 MOZ_CRASH("Unknown truncate kind.")do { do { } while (false); MOZ_ReportCrash("" "Unknown truncate kind."
, "./../../../../js/src/jit/RangeAnalysis.cpp", 140); AnnotateMozCrashReason
("MOZ_CRASH(" "Unknown truncate kind." ")"); do { MOZ_CrashSequence
(__null, 140); __attribute__((nomerge)) ::abort(); } while (false
); } while (false)
;
141 }
142}
143
144static inline void SpewTruncate(const MDefinition* def, TruncateKind kind,
145 bool shouldClone) {
146 if (JitSpewEnabled(JitSpew_Range)) {
147 AutoJitSpewMessage msg(JitSpew_Range, " truncating ");
148 def->printName(msg.printer());
149 msg.append(" (kind: %s, clone: %d)", TruncateKindString(kind), shouldClone);
150 }
151}
152#else
153static inline void SpewTruncate(MDefinition* def, TruncateKind kind,
154 bool shouldClone) {}
155#endif
156
157TempAllocator& RangeAnalysis::alloc() const { return graph_.alloc(); }
158
159static void ReplaceDominatedUsesWith(const MDefinition* orig, MDefinition* dom,
160 const MBasicBlock* block) {
161 for (MUseIterator i(orig->usesBegin()); i != orig->usesEnd();) {
162 MUse* use = *i++;
163 if (use->consumer() != dom && IsDominatedUse(block, use)) {
164 use->replaceProducer(dom);
165 }
166 }
167}
168
169bool RangeAnalysis::addBetaNodes() {
170 JitSpew(JitSpew_Range, "Adding beta nodes");
171
172 for (PostorderIterator i(graph_.poBegin()); i != graph_.poEnd(); i++) {
173 if (mir->shouldCancel("RangeAnalysis addBetaNodes")) {
174 return false;
175 }
176
177 MBasicBlock* block = *i;
178 JitSpew(JitSpew_Range, "Looking at block %u", block->id());
179
180 BranchDirection branch_dir;
181 MTest* test = block->immediateDominatorBranch(&branch_dir);
182
183 if (!test || !test->getOperand(0)->isCompare()) {
184 continue;
185 }
186
187 MCompare* compare = test->getOperand(0)->toCompare();
188
189 if (!compare->isNumericComparison()) {
190 continue;
191 }
192
193 // TODO: support unsigned comparisons
194 if (compare->compareType() == MCompare::Compare_UInt32) {
195 continue;
196 }
197
198 // isNumericComparison should return false for (U)IntPtr.
199 MOZ_ASSERT(compare->compareType() != MCompare::Compare_IntPtr &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compare->compareType() != MCompare::Compare_IntPtr
&& compare->compareType() != MCompare::Compare_UIntPtr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(compare->compareType() != MCompare::Compare_IntPtr
&& compare->compareType() != MCompare::Compare_UIntPtr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"compare->compareType() != MCompare::Compare_IntPtr && compare->compareType() != MCompare::Compare_UIntPtr"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 200); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "compare->compareType() != MCompare::Compare_IntPtr && compare->compareType() != MCompare::Compare_UIntPtr"
")"); do { MOZ_CrashSequence(__null, 200); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
200 compare->compareType() != MCompare::Compare_UIntPtr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compare->compareType() != MCompare::Compare_IntPtr
&& compare->compareType() != MCompare::Compare_UIntPtr
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(compare->compareType() != MCompare::Compare_IntPtr
&& compare->compareType() != MCompare::Compare_UIntPtr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"compare->compareType() != MCompare::Compare_IntPtr && compare->compareType() != MCompare::Compare_UIntPtr"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 200); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "compare->compareType() != MCompare::Compare_IntPtr && compare->compareType() != MCompare::Compare_UIntPtr"
")"); do { MOZ_CrashSequence(__null, 200); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
201
202 MDefinition* left = compare->getOperand(0);
203 MDefinition* right = compare->getOperand(1);
204 double bound;
205 double conservativeLower = NegativeInfinity<double>();
206 double conservativeUpper = PositiveInfinity<double>();
207 MDefinition* val = nullptr;
208
209 JSOp jsop = compare->jsop();
210
211 if (branch_dir == FALSE_BRANCH) {
212 jsop = NegateCompareOp(jsop);
213 conservativeLower = GenericNaN();
214 conservativeUpper = GenericNaN();
215 }
216
217 MConstant* leftConst = left->maybeConstantValue();
218 MConstant* rightConst = right->maybeConstantValue();
219 if (leftConst && leftConst->isTypeRepresentableAsDouble()) {
220 bound = leftConst->numberToDouble();
221 val = right;
222 jsop = ReverseCompareOp(jsop);
223 } else if (rightConst && rightConst->isTypeRepresentableAsDouble()) {
224 bound = rightConst->numberToDouble();
225 val = left;
226 } else if (left->type() == MIRType::Int32 &&
227 right->type() == MIRType::Int32) {
228 MDefinition* smaller = nullptr;
229 MDefinition* greater = nullptr;
230 if (jsop == JSOp::Lt) {
231 smaller = left;
232 greater = right;
233 } else if (jsop == JSOp::Gt) {
234 smaller = right;
235 greater = left;
236 }
237 if (smaller && greater) {
238 if (!alloc().ensureBallast()) {
239 return false;
240 }
241
242 MBeta* beta;
243 beta = MBeta::New(
244 alloc(), smaller,
245 Range::NewInt32Range(alloc(), JSVAL_INT_MIN((int32_t)0x80000000), JSVAL_INT_MAX((int32_t)0x7fffffff) - 1));
246 block->insertBefore(*block->begin(), beta);
247 ReplaceDominatedUsesWith(smaller, beta, block);
248 JitSpew(JitSpew_Range, " Adding beta node for smaller %u",
249 smaller->id());
250 beta = MBeta::New(
251 alloc(), greater,
252 Range::NewInt32Range(alloc(), JSVAL_INT_MIN((int32_t)0x80000000) + 1, JSVAL_INT_MAX((int32_t)0x7fffffff)));
253 block->insertBefore(*block->begin(), beta);
254 ReplaceDominatedUsesWith(greater, beta, block);
255 JitSpew(JitSpew_Range, " Adding beta node for greater %u",
256 greater->id());
257 }
258 continue;
259 } else {
260 continue;
261 }
262
263 // At this point, one of the operands if the compare is a constant, and
264 // val is the other operand.
265 MOZ_ASSERT(val)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(val)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(val))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("val", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 265); AnnotateMozCrashReason("MOZ_ASSERT" "(" "val" ")"); do
{ MOZ_CrashSequence(__null, 265); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
266
267 Range comp;
268 switch (jsop) {
269 case JSOp::Le:
270 comp.setDouble(conservativeLower, bound);
271 break;
272 case JSOp::Lt:
273 // For integers, if x < c, the upper bound of x is c-1.
274 if (val->type() == MIRType::Int32) {
275 int32_t intbound;
276 if (NumberEqualsInt32(bound, &intbound) &&
277 mozilla::SafeSub(intbound, 1, &intbound)) {
278 bound = intbound;
279 }
280 }
281 comp.setDouble(conservativeLower, bound);
282
283 // Negative zero is not less than zero.
284 if (bound == 0) {
285 comp.refineToExcludeNegativeZero();
286 }
287 break;
288 case JSOp::Ge:
289 comp.setDouble(bound, conservativeUpper);
290 break;
291 case JSOp::Gt:
292 // For integers, if x > c, the lower bound of x is c+1.
293 if (val->type() == MIRType::Int32) {
294 int32_t intbound;
295 if (NumberEqualsInt32(bound, &intbound) &&
296 mozilla::SafeAdd(intbound, 1, &intbound)) {
297 bound = intbound;
298 }
299 }
300 comp.setDouble(bound, conservativeUpper);
301
302 // Negative zero is not greater than zero.
303 if (bound == 0) {
304 comp.refineToExcludeNegativeZero();
305 }
306 break;
307 case JSOp::StrictEq:
308 case JSOp::Eq:
309 comp.setDouble(bound, bound);
310 break;
311 case JSOp::StrictNe:
312 case JSOp::Ne:
313 // Negative zero is not not-equal to zero.
314 if (bound == 0) {
315 comp.refineToExcludeNegativeZero();
316 break;
317 }
318 continue; // well, we could have
319 // [-\inf, bound-1] U [bound+1, \inf] but we only use
320 // contiguous ranges.
321 default:
322 continue;
323 }
324
325 if (JitSpewEnabled(JitSpew_Range)) {
326 AutoJitSpewMessage msg(
327 JitSpew_Range, " Adding beta node for %u with range ", val->id());
328 comp.dump(msg.printer());
329 }
330
331 if (!alloc().ensureBallast()) {
332 return false;
333 }
334
335 MBeta* beta = MBeta::New(alloc(), val, new (alloc()) Range(comp));
336 block->insertBefore(*block->begin(), beta);
337 ReplaceDominatedUsesWith(val, beta, block);
338 }
339
340 return true;
341}
342
343bool RangeAnalysis::removeBetaNodes() {
344 JitSpew(JitSpew_Range, "Removing beta nodes");
345
346 for (PostorderIterator i(graph_.poBegin()); i != graph_.poEnd(); i++) {
347 MBasicBlock* block = *i;
348 for (MDefinitionIterator iter(*i); iter;) {
349 MDefinition* def = *iter++;
350 if (def->isBeta()) {
351 auto* beta = def->toBeta();
352 MDefinition* op = beta->input();
353 JitSpew(JitSpew_Range, " Removing beta node %u for %u", beta->id(),
354 op->id());
355 beta->justReplaceAllUsesWith(op);
356 block->discard(beta);
357 } else {
358 // We only place Beta nodes at the beginning of basic
359 // blocks, so if we see something else, we can move on
360 // to the next block.
361 break;
362 }
363 }
364 }
365 return true;
366}
367
368void SymbolicBound::dump(GenericPrinter& out) const {
369 if (loop) {
370 out.printf("[loop] ");
371 }
372 sum.dump(out);
373}
374
375void SymbolicBound::dump() const {
376 Fprinter out(stderrstderr);
377 dump(out);
378 out.printf("\n");
379 out.finish();
380}
381
382// Test whether the given range's exponent tells us anything that its lower
383// and upper bound values don't.
384static bool IsExponentInteresting(const Range* r) {
385 // If it lacks either a lower or upper bound, the exponent is interesting.
386 if (!r->hasInt32Bounds()) {
387 return true;
388 }
389
390 // Otherwise if there's no fractional part, the lower and upper bounds,
391 // which are integers, are perfectly precise.
392 if (!r->canHaveFractionalPart()) {
393 return false;
394 }
395
396 // Otherwise, if the bounds are conservatively rounded across a power-of-two
397 // boundary, the exponent may imply a tighter range.
398 return FloorLog2(std::max(Abs(r->lower()), Abs(r->upper()))) > r->exponent();
399}
400
401void Range::dump(GenericPrinter& out) const {
402 assertInvariants();
403
404 // Floating-point or Integer subset.
405 if (canHaveFractionalPart_) {
406 out.printf("F");
407 } else {
408 out.printf("I");
409 }
410
411 out.printf("[");
412
413 if (!hasInt32LowerBound_) {
414 out.printf("?");
415 } else {
416 out.printf("%d", lower_);
417 }
418 if (symbolicLower_) {
419 out.printf(" {");
420 symbolicLower_->dump(out);
421 out.printf("}");
422 }
423
424 out.printf(", ");
425
426 if (!hasInt32UpperBound_) {
427 out.printf("?");
428 } else {
429 out.printf("%d", upper_);
430 }
431 if (symbolicUpper_) {
432 out.printf(" {");
433 symbolicUpper_->dump(out);
434 out.printf("}");
435 }
436
437 out.printf("]");
438
439 bool includesNaN = max_exponent_ == IncludesInfinityAndNaN;
440 bool includesNegativeInfinity =
441 max_exponent_ >= IncludesInfinity && !hasInt32LowerBound_;
442 bool includesPositiveInfinity =
443 max_exponent_ >= IncludesInfinity && !hasInt32UpperBound_;
444 bool includesNegativeZero = canBeNegativeZero_;
445
446 if (includesNaN || includesNegativeInfinity || includesPositiveInfinity ||
447 includesNegativeZero) {
448 out.printf(" (");
449 bool first = true;
450 if (includesNaN) {
451 if (first) {
452 first = false;
453 } else {
454 out.printf(" ");
455 }
456 out.printf("U NaN");
457 }
458 if (includesNegativeInfinity) {
459 if (first) {
460 first = false;
461 } else {
462 out.printf(" ");
463 }
464 out.printf("U -Infinity");
465 }
466 if (includesPositiveInfinity) {
467 if (first) {
468 first = false;
469 } else {
470 out.printf(" ");
471 }
472 out.printf("U Infinity");
473 }
474 if (includesNegativeZero) {
475 if (first) {
476 first = false;
Value stored to 'first' is never read
477 } else {
478 out.printf(" ");
479 }
480 out.printf("U -0");
481 }
482 out.printf(")");
483 }
484 if (max_exponent_ < IncludesInfinity && IsExponentInteresting(this)) {
485 out.printf(" (< pow(2, %d+1))", max_exponent_);
486 }
487}
488
489void Range::dump() const {
490 Fprinter out(stderrstderr);
491 dump(out);
492 out.printf("\n");
493 out.finish();
494}
495
496Range* Range::intersect(TempAllocator& alloc, const Range* lhs,
497 const Range* rhs, bool* emptyRange) {
498 *emptyRange = false;
499
500 if (!lhs && !rhs) {
501 return nullptr;
502 }
503
504 if (!lhs) {
505 return new (alloc) Range(*rhs);
506 }
507 if (!rhs) {
508 return new (alloc) Range(*lhs);
509 }
510
511 int32_t newLower = std::max(lhs->lower_, rhs->lower_);
512 int32_t newUpper = std::min(lhs->upper_, rhs->upper_);
513
514 // If upper < lower, then we have conflicting constraints. Consider:
515 //
516 // if (x < 0) {
517 // if (x > 0) {
518 // [Some code.]
519 // }
520 // }
521 //
522 // In this case, the block is unreachable.
523 if (newUpper < newLower) {
524 // If both ranges can be NaN, the result can still be NaN.
525 if (!lhs->canBeNaN() || !rhs->canBeNaN()) {
526 *emptyRange = true;
527 }
528 return nullptr;
529 }
530
531 bool newHasInt32LowerBound =
532 lhs->hasInt32LowerBound_ || rhs->hasInt32LowerBound_;
533 bool newHasInt32UpperBound =
534 lhs->hasInt32UpperBound_ || rhs->hasInt32UpperBound_;
535
536 FractionalPartFlag newCanHaveFractionalPart = FractionalPartFlag(
537 lhs->canHaveFractionalPart_ && rhs->canHaveFractionalPart_);
538
539 // As 0.0 == -0.0, the intersection should include negative zero if any of the
540 // operands can be negative zero.
541 NegativeZeroFlag newMayIncludeNegativeZero =
542 NegativeZeroFlag((lhs->canBeNegativeZero_ && rhs->canBeZero()) ||
543 (rhs->canBeNegativeZero_ && lhs->canBeZero()));
544
545 uint16_t newExponent = std::min(lhs->max_exponent_, rhs->max_exponent_);
546
547 // NaN is a special value which is neither greater than infinity or less than
548 // negative infinity. When we intersect two ranges like [?, 0] and [0, ?], we
549 // can end up thinking we have both a lower and upper bound, even though NaN
550 // is still possible. In this case, just be conservative, since any case where
551 // we can have NaN is not especially interesting.
552 if (newHasInt32LowerBound && newHasInt32UpperBound &&
553 newExponent == IncludesInfinityAndNaN) {
554 return nullptr;
555 }
556
557 // If one of the ranges has a fractional part and the other doesn't, it's
558 // possible that we will have computed a newExponent that's more precise
559 // than our newLower and newUpper. This is unusual, so we handle it here
560 // instead of in optimize().
561 //
562 // For example, consider the range F[0,1.5]. Range analysis represents the
563 // lower and upper bound as integers, so we'd actually have
564 // F[0,2] (< pow(2, 0+1)). In this case, the exponent gives us a slightly
565 // more precise upper bound than the integer upper bound.
566 //
567 // When intersecting such a range with an integer range, the fractional part
568 // of the range is dropped. The max exponent of 0 remains valid, so the
569 // upper bound needs to be adjusted to 1.
570 //
571 // When intersecting F[0,2] (< pow(2, 0+1)) with a range like F[2,4],
572 // the naive intersection is I[2,2], but since the max exponent tells us
573 // that the value is always less than 2, the intersection is actually empty.
574 if (lhs->canHaveFractionalPart() != rhs->canHaveFractionalPart() ||
575 (lhs->canHaveFractionalPart() && newHasInt32LowerBound &&
576 newHasInt32UpperBound && newLower == newUpper)) {
577 refineInt32BoundsByExponent(newExponent, &newLower, &newHasInt32LowerBound,
578 &newUpper, &newHasInt32UpperBound);
579
580 // If we're intersecting two ranges that don't overlap, this could also
581 // push the bounds past each other, since the actual intersection is
582 // the empty set.
583 if (newLower > newUpper) {
584 *emptyRange = true;
585 return nullptr;
586 }
587 }
588
589 return new (alloc)
590 Range(newLower, newHasInt32LowerBound, newUpper, newHasInt32UpperBound,
591 newCanHaveFractionalPart, newMayIncludeNegativeZero, newExponent);
592}
593
594void Range::unionWith(const Range* other) {
595 int32_t newLower = std::min(lower_, other->lower_);
596 int32_t newUpper = std::max(upper_, other->upper_);
597
598 bool newHasInt32LowerBound =
599 hasInt32LowerBound_ && other->hasInt32LowerBound_;
600 bool newHasInt32UpperBound =
601 hasInt32UpperBound_ && other->hasInt32UpperBound_;
602
603 FractionalPartFlag newCanHaveFractionalPart = FractionalPartFlag(
604 canHaveFractionalPart_ || other->canHaveFractionalPart_);
605 NegativeZeroFlag newMayIncludeNegativeZero =
606 NegativeZeroFlag(canBeNegativeZero_ || other->canBeNegativeZero_);
607
608 uint16_t newExponent = std::max(max_exponent_, other->max_exponent_);
609
610 rawInitialize(newLower, newHasInt32LowerBound, newUpper,
611 newHasInt32UpperBound, newCanHaveFractionalPart,
612 newMayIncludeNegativeZero, newExponent);
613}
614
615Range::Range(const MDefinition* def)
616 : symbolicLower_(nullptr), symbolicUpper_(nullptr) {
617 if (const Range* other = def->range()) {
618 // The instruction has range information; use it.
619 *this = *other;
620
621 // Simulate the effect of converting the value to its type.
622 // Note: we cannot clamp here, since ranges aren't allowed to shrink
623 // and truncation can increase range again. So doing wrapAround to
624 // mimick a possible truncation.
625 switch (def->type()) {
626 case MIRType::Int32:
627 // MToNumberInt32 cannot truncate. So we can safely clamp.
628 if (def->isToNumberInt32()) {
629 clampToInt32();
630 } else {
631 wrapAroundToInt32();
632 }
633 break;
634 case MIRType::Boolean:
635 wrapAroundToBoolean();
636 break;
637 case MIRType::None:
638 MOZ_CRASH("Asking for the range of an instruction with no value")do { do { } while (false); MOZ_ReportCrash("" "Asking for the range of an instruction with no value"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 638); AnnotateMozCrashReason
("MOZ_CRASH(" "Asking for the range of an instruction with no value"
")"); do { MOZ_CrashSequence(__null, 638); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
639 default:
640 break;
641 }
642 } else {
643 // Otherwise just use type information. We can trust the type here
644 // because we don't care what value the instruction actually produces,
645 // but what value we might get after we get past the bailouts.
646 switch (def->type()) {
647 case MIRType::Int32:
648 setInt32(JSVAL_INT_MIN((int32_t)0x80000000), JSVAL_INT_MAX((int32_t)0x7fffffff));
649 break;
650 case MIRType::Boolean:
651 setInt32(0, 1);
652 break;
653 case MIRType::None:
654 MOZ_CRASH("Asking for the range of an instruction with no value")do { do { } while (false); MOZ_ReportCrash("" "Asking for the range of an instruction with no value"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 654); AnnotateMozCrashReason
("MOZ_CRASH(" "Asking for the range of an instruction with no value"
")"); do { MOZ_CrashSequence(__null, 654); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
655 default:
656 setUnknown();
657 break;
658 }
659 }
660
661 // As a special case, MUrsh is permitted to claim a result type of
662 // MIRType::Int32 while actually returning values in [0,UINT32_MAX] without
663 // bailouts. If range analysis hasn't ruled out values in
664 // (INT32_MAX,UINT32_MAX], set the range to be conservatively correct for
665 // use as either a uint32 or an int32.
666 if (!hasInt32UpperBound() && def->isUrsh() &&
667 def->toUrsh()->bailoutsDisabled() && def->type() != MIRType::Int64) {
668 lower_ = INT32_MIN(-2147483647-1);
669 }
670
671 assertInvariants();
672}
673
674static uint16_t ExponentImpliedByDouble(double d) {
675 // Handle the special values.
676 if (std::isnan(d)) {
677 return Range::IncludesInfinityAndNaN;
678 }
679 if (std::isinf(d)) {
680 return Range::IncludesInfinity;
681 }
682
683 // Otherwise take the exponent part and clamp it at zero, since the Range
684 // class doesn't track fractional ranges.
685 return uint16_t(std::max(int_fast16_t(0), ExponentComponent(d)));
686}
687
688void Range::setDouble(double l, double h) {
689 MOZ_ASSERT(!(l > h))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(l > h))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(l > h)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!(l > h)", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 689); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(l > h)"
")"); do { MOZ_CrashSequence(__null, 689); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
690
691 // Infer lower_, upper_, hasInt32LowerBound_, and hasInt32UpperBound_.
692 if (l >= INT32_MIN(-2147483647-1) && l <= INT32_MAX(2147483647)) {
693 lower_ = int32_t(::floor(l));
694 hasInt32LowerBound_ = true;
695 } else if (l >= INT32_MAX(2147483647)) {
696 lower_ = INT32_MAX(2147483647);
697 hasInt32LowerBound_ = true;
698 } else {
699 lower_ = INT32_MIN(-2147483647-1);
700 hasInt32LowerBound_ = false;
701 }
702 if (h >= INT32_MIN(-2147483647-1) && h <= INT32_MAX(2147483647)) {
703 upper_ = int32_t(::ceil(h));
704 hasInt32UpperBound_ = true;
705 } else if (h <= INT32_MIN(-2147483647-1)) {
706 upper_ = INT32_MIN(-2147483647-1);
707 hasInt32UpperBound_ = true;
708 } else {
709 upper_ = INT32_MAX(2147483647);
710 hasInt32UpperBound_ = false;
711 }
712
713 // Infer max_exponent_.
714 uint16_t lExp = ExponentImpliedByDouble(l);
715 uint16_t hExp = ExponentImpliedByDouble(h);
716 max_exponent_ = std::max(lExp, hExp);
717
718 canHaveFractionalPart_ = ExcludesFractionalParts;
719 canBeNegativeZero_ = ExcludesNegativeZero;
720
721 // If denormals are disabled, any denormal value will be immediately flushed
722 // to 0, so any bit pattern in the denormal range compares equal to zero.
723 //
724 // Check whether the range [l .. h] can cross any of these zeros. We have to
725 // be conservative as the main thread might not interpret floating point
726 // values the same way as the compiler thread.
727 //
728 // This Range may describe a Float32 value, whose denormal range begins at
729 // the smallest normal binary32 (2**-126) rather than the smallest normal
730 // binary64 (2**-1022). Use the (wider) binary32 threshold so we stay
731 // conservative for both float32 and double values.
732 const double doubleMin = double(mozilla::BitwiseCast<float>(
733 mozilla::SpecificFloatingPointBits<float, 0, 1, 0>::value));
734 bool includesNegative = std::isnan(l) || l < doubleMin;
735 bool includesPositive = std::isnan(h) || h > -doubleMin;
736 bool crossesZero = includesNegative && includesPositive;
737
738 // Infer the canHaveFractionalPart_ setting. We can have a
739 // fractional part if the range crosses through the neighborhood of zero. We
740 // won't have a fractional value if the value is always beyond the point at
741 // which double precision can't represent fractional values.
742 uint16_t minExp = std::min(lExp, hExp);
743 if (crossesZero || minExp < MaxTruncatableExponent) {
744 canHaveFractionalPart_ = IncludesFractionalParts;
745 }
746
747 // Infer a conservative value for canBeNegativeZero_ setting. We can have a
748 // negative zero value if the range crosses through the neighborhood of zero
749 // and the lower bound can have a sign bit.
750 if (crossesZero && (std::isnan(l) || mozilla::IsNegative(l))) {
751 canBeNegativeZero_ = IncludesNegativeZero;
752 }
753
754 optimize();
755}
756
757void Range::setDoubleSingleton(double d) {
758 setDouble(d, d);
759 assertInvariants();
760}
761
762static inline bool MissingAnyInt32Bounds(const Range* lhs, const Range* rhs) {
763 return !lhs->hasInt32Bounds() || !rhs->hasInt32Bounds();
764}
765
766Range* Range::add(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
767 int64_t l = (int64_t)lhs->lower_ + (int64_t)rhs->lower_;
768 if (!lhs->hasInt32LowerBound() || !rhs->hasInt32LowerBound()) {
769 l = NoInt32LowerBound;
770 }
771
772 int64_t h = (int64_t)lhs->upper_ + (int64_t)rhs->upper_;
773 if (!lhs->hasInt32UpperBound() || !rhs->hasInt32UpperBound()) {
774 h = NoInt32UpperBound;
775 }
776
777 // The exponent is at most one greater than the greater of the operands'
778 // exponents, except for NaN and infinity cases.
779 uint16_t e = std::max(lhs->max_exponent_, rhs->max_exponent_);
780 if (e <= Range::MaxFiniteExponent) {
781 ++e;
782 }
783
784 // Infinity + -Infinity is NaN.
785 if (lhs->canBeInfiniteOrNaN() && rhs->canBeInfiniteOrNaN()) {
786 e = Range::IncludesInfinityAndNaN;
787 }
788
789 FractionalPartFlag canHaveFractionalPart = FractionalPartFlag(
790 lhs->canHaveFractionalPart() || rhs->canHaveFractionalPart());
791
792 // Handle the case where -0 + -0 == -0.
793 NegativeZeroFlag canBeNegativeZero =
794 NegativeZeroFlag(lhs->canBeNegativeZero() && rhs->canBeNegativeZero());
795
796 // Except for operands which have a fractional part, in the corner case where
797 // denormals are disabled on the execution thread but not on the compiling
798 // thread.
799 //
800 // Example -0 + -1.11e-308 == -0 (denormals disabled)
801 if (l <= 0 && h >= 0 && canHaveFractionalPart) {
802 canBeNegativeZero = IncludesNegativeZero;
803 }
804
805 return new (alloc) Range(l, h, canHaveFractionalPart, canBeNegativeZero, e);
806}
807
808Range* Range::sub(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
809 int64_t l = (int64_t)lhs->lower_ - (int64_t)rhs->upper_;
810 if (!lhs->hasInt32LowerBound() || !rhs->hasInt32UpperBound()) {
811 l = NoInt32LowerBound;
812 }
813
814 int64_t h = (int64_t)lhs->upper_ - (int64_t)rhs->lower_;
815 if (!lhs->hasInt32UpperBound() || !rhs->hasInt32LowerBound()) {
816 h = NoInt32UpperBound;
817 }
818
819 // The exponent is at most one greater than the greater of the operands'
820 // exponents, except for NaN and infinity cases.
821 uint16_t e = std::max(lhs->max_exponent_, rhs->max_exponent_);
822 if (e <= Range::MaxFiniteExponent) {
823 ++e;
824 }
825
826 // Infinity - Infinity is NaN.
827 if (lhs->canBeInfiniteOrNaN() && rhs->canBeInfiniteOrNaN()) {
828 e = Range::IncludesInfinityAndNaN;
829 }
830
831 FractionalPartFlag canHaveFractionalPart = FractionalPartFlag(
832 lhs->canHaveFractionalPart() || rhs->canHaveFractionalPart());
833
834 // Handle the case where -0 - 0 == -0.
835 NegativeZeroFlag canBeNegativeZero =
836 NegativeZeroFlag(lhs->canBeNegativeZero() && rhs->canBeZero());
837
838 // Except for operands which have a fractional part, in the corner case where
839 // denormals are disabled on the execution thread but not on the compiling
840 // thread.
841 if (l <= 0 && h >= 0 && canHaveFractionalPart) {
842 canBeNegativeZero = IncludesNegativeZero;
843 }
844
845 return new (alloc) Range(l, h, canHaveFractionalPart, canBeNegativeZero, e);
846}
847
848Range* Range::and_(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
849 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 849); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 849); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
850 MOZ_ASSERT(rhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("rhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 850); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "rhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 850); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
851
852 // If both numbers can be negative, result can be negative in the whole range
853 if (lhs->lower() < 0 && rhs->lower() < 0) {
854 return Range::NewInt32Range(alloc, INT32_MIN(-2147483647-1),
855 std::max(lhs->upper(), rhs->upper()));
856 }
857
858 // Only one of both numbers can be negative.
859 // - result can't be negative
860 // - Upper bound is minimum of both upper range,
861 int32_t lower = 0;
862 int32_t upper = std::min(lhs->upper(), rhs->upper());
863
864 // EXCEPT when upper bound of non negative number is max value,
865 // because negative value can return the whole max value.
866 // -1 & 5 = 5
867 if (lhs->lower() < 0) {
868 upper = rhs->upper();
869 }
870 if (rhs->lower() < 0) {
871 upper = lhs->upper();
872 }
873
874 return Range::NewInt32Range(alloc, lower, upper);
875}
876
877Range* Range::or_(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
878 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 878); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 878); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
879 MOZ_ASSERT(rhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("rhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 879); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "rhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 879); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
880 // When one operand is always 0 or always -1, it's a special case where we
881 // can compute a fully precise result. Handling these up front also protects
882 // the code below from shifting an int32_t by 32.
883 if (lhs->lower() == lhs->upper()) {
884 if (lhs->lower() == 0) {
885 return new (alloc) Range(*rhs);
886 }
887 if (lhs->lower() == -1) {
888 return new (alloc) Range(*lhs);
889 }
890 }
891 if (rhs->lower() == rhs->upper()) {
892 if (rhs->lower() == 0) {
893 return new (alloc) Range(*lhs);
894 }
895 if (rhs->lower() == -1) {
896 return new (alloc) Range(*rhs);
897 }
898 }
899
900 // The code below uses std::countl_zero, which returns 32 if its operand is 0.
901 // We rely on the code above to protect it.
902 MOZ_ASSERT_IF(lhs->lower() >= 0, lhs->upper() != 0)do { if (lhs->lower() >= 0) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(lhs->upper() !=
0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(lhs->upper() != 0))), 0))) { do { } while (false)
; MOZ_ReportAssertionFailure("lhs->upper() != 0", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 902); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->upper() != 0"
")"); do { MOZ_CrashSequence(__null, 902); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
903 MOZ_ASSERT_IF(rhs->lower() >= 0, rhs->upper() != 0)do { if (rhs->lower() >= 0) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(rhs->upper() !=
0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(rhs->upper() != 0))), 0))) { do { } while (false)
; MOZ_ReportAssertionFailure("rhs->upper() != 0", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 903); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->upper() != 0"
")"); do { MOZ_CrashSequence(__null, 903); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
904 MOZ_ASSERT_IF(lhs->upper() < 0, lhs->lower() != -1)do { if (lhs->upper() < 0) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(lhs->lower() !=
-1)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(lhs->lower() != -1))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("lhs->lower() != -1", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->lower() != -1"
")"); do { MOZ_CrashSequence(__null, 904); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
905 MOZ_ASSERT_IF(rhs->upper() < 0, rhs->lower() != -1)do { if (rhs->upper() < 0) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(rhs->lower() !=
-1)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(rhs->lower() != -1))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("rhs->lower() != -1", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->lower() != -1"
")"); do { MOZ_CrashSequence(__null, 905); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
906
907 int32_t lower = INT32_MIN(-2147483647-1);
908 int32_t upper = INT32_MAX(2147483647);
909
910 if (lhs->lower() >= 0 && rhs->lower() >= 0) {
911 // Both operands are non-negative, so the result won't be less than either.
912 lower = std::max(lhs->lower(), rhs->lower());
913 // The result will have leading zeros where both operands have leading
914 // zeros. std::countl_zero of a non-negative int32 will at least be 1 to
915 // account for the bit of sign.
916 upper = int32_t(UINT32_MAX(4294967295U) >>
917 std::min(std::countl_zero(uint32_t(lhs->upper())),
918 std::countl_zero(uint32_t(rhs->upper()))));
919 } else {
920 // The result will have leading ones where either operand has leading ones.
921 if (lhs->upper() < 0) {
922 unsigned leadingOnes = std::countl_one(uint32_t(lhs->lower()));
923 lower = std::max(lower, ~int32_t(UINT32_MAX(4294967295U) >> leadingOnes));
924 upper = -1;
925 }
926 if (rhs->upper() < 0) {
927 unsigned leadingOnes = std::countl_one(uint32_t(rhs->lower()));
928 lower = std::max(lower, ~int32_t(UINT32_MAX(4294967295U) >> leadingOnes));
929 upper = -1;
930 }
931 }
932
933 return Range::NewInt32Range(alloc, lower, upper);
934}
935
936Range* Range::xor_(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
937 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 937); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 937); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
938 MOZ_ASSERT(rhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("rhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 938); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "rhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 938); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
939 int32_t lhsLower = lhs->lower();
940 int32_t lhsUpper = lhs->upper();
941 int32_t rhsLower = rhs->lower();
942 int32_t rhsUpper = rhs->upper();
943 bool invertAfter = false;
944
945 // If either operand is negative, bitwise-negate it, and arrange to negate
946 // the result; ~((~x)^y) == x^y. If both are negative the negations on the
947 // result cancel each other out; effectively this is (~x)^(~y) == x^y.
948 // These transformations reduce the number of cases we have to handle below.
949 if (lhsUpper < 0) {
950 lhsLower = ~lhsLower;
951 lhsUpper = ~lhsUpper;
952 std::swap(lhsLower, lhsUpper);
953 invertAfter = !invertAfter;
954 }
955 if (rhsUpper < 0) {
956 rhsLower = ~rhsLower;
957 rhsUpper = ~rhsUpper;
958 std::swap(rhsLower, rhsUpper);
959 invertAfter = !invertAfter;
960 }
961
962 // Handle cases where lhs or rhs is always zero specially, because they're
963 // easy cases where we can be perfectly precise, and because it protects the
964 // std::countl_zero calls below from returning 32, which would be undefined
965 // behavior when used as the shift amount.
966 int32_t lower = INT32_MIN(-2147483647-1);
967 int32_t upper = INT32_MAX(2147483647);
968 if (lhsLower == 0 && lhsUpper == 0) {
969 upper = rhsUpper;
970 lower = rhsLower;
971 } else if (rhsLower == 0 && rhsUpper == 0) {
972 upper = lhsUpper;
973 lower = lhsLower;
974 } else if (lhsLower >= 0 && rhsLower >= 0) {
975 // Both operands are non-negative. The result will be non-negative.
976 lower = 0;
977 // To compute the upper value, take each operand's upper value and
978 // set all bits that don't correspond to leading zero bits in the
979 // other to one. For each one, this gives an upper bound for the
980 // result, so we can take the minimum between the two.
981 unsigned lhsLeadingZeros = std::countl_zero(uint32_t(lhsUpper));
982 unsigned rhsLeadingZeros = std::countl_zero(uint32_t(rhsUpper));
983 upper = std::min(rhsUpper | int32_t(UINT32_MAX(4294967295U) >> lhsLeadingZeros),
984 lhsUpper | int32_t(UINT32_MAX(4294967295U) >> rhsLeadingZeros));
985 }
986
987 // If we bitwise-negated one (but not both) of the operands above, apply the
988 // bitwise-negate to the result, completing ~((~x)^y) == x^y.
989 if (invertAfter) {
990 lower = ~lower;
991 upper = ~upper;
992 std::swap(lower, upper);
993 }
994
995 return Range::NewInt32Range(alloc, lower, upper);
996}
997
998Range* Range::not_(TempAllocator& alloc, const Range* op) {
999 MOZ_ASSERT(op->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op->isInt32()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("op->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 999); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "op->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 999); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
1000 return Range::NewInt32Range(alloc, ~op->upper(), ~op->lower());
1001}
1002
1003Range* Range::mul(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
1004 FractionalPartFlag newCanHaveFractionalPart = FractionalPartFlag(
1005 lhs->canHaveFractionalPart_ || rhs->canHaveFractionalPart_);
1006
1007 NegativeZeroFlag newMayIncludeNegativeZero = NegativeZeroFlag(
1008 (lhs->canHaveSignBitSet() && rhs->canBeFiniteNonNegative()) ||
1009 (rhs->canHaveSignBitSet() && lhs->canBeFiniteNonNegative()));
1010
1011 uint16_t exponent;
1012 if (!lhs->canBeInfiniteOrNaN() && !rhs->canBeInfiniteOrNaN()) {
1013 // Two finite values.
1014 exponent = lhs->numBits() + rhs->numBits() - 1;
1015 if (exponent > Range::MaxFiniteExponent) {
1016 exponent = Range::IncludesInfinity;
1017 }
1018 } else if (!lhs->canBeNaN() && !rhs->canBeNaN() &&
1019 !(lhs->canBeZero() && rhs->canBeInfiniteOrNaN()) &&
1020 !(rhs->canBeZero() && lhs->canBeInfiniteOrNaN())) {
1021 // Two values that multiplied together won't produce a NaN.
1022 exponent = Range::IncludesInfinity;
1023 } else {
1024 // Could be anything.
1025 exponent = Range::IncludesInfinityAndNaN;
1026 }
1027
1028 if (MissingAnyInt32Bounds(lhs, rhs)) {
1029 return new (alloc)
1030 Range(NoInt32LowerBound, NoInt32UpperBound, newCanHaveFractionalPart,
1031 newMayIncludeNegativeZero, exponent);
1032 }
1033 int64_t a = (int64_t)lhs->lower() * (int64_t)rhs->lower();
1034 int64_t b = (int64_t)lhs->lower() * (int64_t)rhs->upper();
1035 int64_t c = (int64_t)lhs->upper() * (int64_t)rhs->lower();
1036 int64_t d = (int64_t)lhs->upper() * (int64_t)rhs->upper();
1037 return new (alloc)
1038 Range(std::min(std::min(a, b), std::min(c, d)),
1039 std::max(std::max(a, b), std::max(c, d)), newCanHaveFractionalPart,
1040 newMayIncludeNegativeZero, exponent);
1041}
1042
1043Range* Range::lsh(TempAllocator& alloc, const Range* lhs, int32_t c) {
1044 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1044); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1044); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1045 int32_t shift = c & 0x1f;
1046
1047 // If the shift doesn't loose bits or shift bits into the sign bit, we
1048 // can simply compute the correct range by shifting.
1049 if ((int32_t)((uint32_t)lhs->lower() << shift << 1 >> shift >> 1) ==
1050 lhs->lower() &&
1051 (int32_t)((uint32_t)lhs->upper() << shift << 1 >> shift >> 1) ==
1052 lhs->upper()) {
1053 return Range::NewInt32Range(alloc, uint32_t(lhs->lower()) << shift,
1054 uint32_t(lhs->upper()) << shift);
1055 }
1056
1057 return Range::NewInt32Range(alloc, INT32_MIN(-2147483647-1), INT32_MAX(2147483647));
1058}
1059
1060Range* Range::rsh(TempAllocator& alloc, const Range* lhs, int32_t c) {
1061 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1061); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1061); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1062 int32_t shift = c & 0x1f;
1063 return Range::NewInt32Range(alloc, lhs->lower() >> shift,
1064 lhs->upper() >> shift);
1065}
1066
1067Range* Range::ursh(TempAllocator& alloc, const Range* lhs, int32_t c) {
1068 // ursh's left operand is uint32, not int32, but for range analysis we
1069 // currently approximate it as int32. We assume here that the range has
1070 // already been adjusted accordingly by our callers.
1071 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1071); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1071); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1072
1073 int32_t shift = c & 0x1f;
1074
1075 // If the value is always non-negative or always negative, we can simply
1076 // compute the correct range by shifting.
1077 if (lhs->isFiniteNonNegative() || lhs->isFiniteNegative()) {
1078 return Range::NewUInt32Range(alloc, uint32_t(lhs->lower()) >> shift,
1079 uint32_t(lhs->upper()) >> shift);
1080 }
1081
1082 // Otherwise return the most general range after the shift.
1083 return Range::NewUInt32Range(alloc, 0, UINT32_MAX(4294967295U) >> shift);
1084}
1085
1086Range* Range::lsh(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
1087 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1087); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1087); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1088 MOZ_ASSERT(rhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("rhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1088); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "rhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1088); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1089 return Range::NewInt32Range(alloc, INT32_MIN(-2147483647-1), INT32_MAX(2147483647));
1090}
1091
1092Range* Range::rsh(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
1093 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1093); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1093); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1094 MOZ_ASSERT(rhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("rhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1094); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "rhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1094); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1095
1096 // Canonicalize the shift range to 0 to 31.
1097 int32_t shiftLower = rhs->lower();
1098 int32_t shiftUpper = rhs->upper();
1099 if ((int64_t(shiftUpper) - int64_t(shiftLower)) >= 31) {
1100 shiftLower = 0;
1101 shiftUpper = 31;
1102 } else {
1103 shiftLower &= 0x1f;
1104 shiftUpper &= 0x1f;
1105 if (shiftLower > shiftUpper) {
1106 shiftLower = 0;
1107 shiftUpper = 31;
1108 }
1109 }
1110 MOZ_ASSERT(shiftLower >= 0 && shiftUpper <= 31)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(shiftLower >= 0 && shiftUpper <= 31)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(shiftLower >= 0 && shiftUpper <= 31)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("shiftLower >= 0 && shiftUpper <= 31"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1110); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "shiftLower >= 0 && shiftUpper <= 31"
")"); do { MOZ_CrashSequence(__null, 1110); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1111
1112 // The lhs bounds are signed, thus the minimum is either the lower bound
1113 // shift by the smallest shift if negative or the lower bound shifted by the
1114 // biggest shift otherwise. And the opposite for the maximum.
1115 int32_t lhsLower = lhs->lower();
1116 int32_t min = lhsLower < 0 ? lhsLower >> shiftLower : lhsLower >> shiftUpper;
1117 int32_t lhsUpper = lhs->upper();
1118 int32_t max = lhsUpper >= 0 ? lhsUpper >> shiftLower : lhsUpper >> shiftUpper;
1119
1120 return Range::NewInt32Range(alloc, min, max);
1121}
1122
1123Range* Range::ursh(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
1124 // ursh's left operand is uint32, not int32, but for range analysis we
1125 // currently approximate it as int32. We assume here that the range has
1126 // already been adjusted accordingly by our callers.
1127 MOZ_ASSERT(lhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("lhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1127); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "lhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1127); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1128 MOZ_ASSERT(rhs->isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isInt32()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("rhs->isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1128); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "rhs->isInt32()" ")"); do { MOZ_CrashSequence
(__null, 1128); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1129 return Range::NewUInt32Range(
1130 alloc, 0, lhs->isFiniteNonNegative() ? lhs->upper() : UINT32_MAX(4294967295U));
1131}
1132
1133Range* Range::abs(TempAllocator& alloc, const Range* op) {
1134 int32_t l = op->lower_;
1135 int32_t u = op->upper_;
1136 FractionalPartFlag canHaveFractionalPart = op->canHaveFractionalPart_;
1137
1138 // Abs never produces a negative zero.
1139 NegativeZeroFlag canBeNegativeZero = ExcludesNegativeZero;
1140
1141 return new (alloc) Range(
1142 std::max(std::max(int32_t(0), l), u == INT32_MIN(-2147483647-1) ? INT32_MAX(2147483647) : -u), true,
1143 std::max(std::max(int32_t(0), u), l == INT32_MIN(-2147483647-1) ? INT32_MAX(2147483647) : -l),
1144 op->hasInt32Bounds() && l != INT32_MIN(-2147483647-1), canHaveFractionalPart,
1145 canBeNegativeZero, op->max_exponent_);
1146}
1147
1148Range* Range::min(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
1149 // If either operand is NaN, the result is NaN.
1150 if (lhs->canBeNaN() || rhs->canBeNaN()) {
1151 return nullptr;
1152 }
1153
1154 FractionalPartFlag newCanHaveFractionalPart = FractionalPartFlag(
1155 lhs->canHaveFractionalPart_ || rhs->canHaveFractionalPart_);
1156 NegativeZeroFlag newMayIncludeNegativeZero =
1157 NegativeZeroFlag(lhs->canBeNegativeZero_ || rhs->canBeNegativeZero_);
1158
1159 return new (alloc) Range(std::min(lhs->lower_, rhs->lower_),
1160 lhs->hasInt32LowerBound_ && rhs->hasInt32LowerBound_,
1161 std::min(lhs->upper_, rhs->upper_),
1162 lhs->hasInt32UpperBound_ || rhs->hasInt32UpperBound_,
1163 newCanHaveFractionalPart, newMayIncludeNegativeZero,
1164 std::max(lhs->max_exponent_, rhs->max_exponent_));
1165}
1166
1167Range* Range::max(TempAllocator& alloc, const Range* lhs, const Range* rhs) {
1168 // If either operand is NaN, the result is NaN.
1169 if (lhs->canBeNaN() || rhs->canBeNaN()) {
1170 return nullptr;
1171 }
1172
1173 FractionalPartFlag newCanHaveFractionalPart = FractionalPartFlag(
1174 lhs->canHaveFractionalPart_ || rhs->canHaveFractionalPart_);
1175 NegativeZeroFlag newMayIncludeNegativeZero =
1176 NegativeZeroFlag(lhs->canBeNegativeZero_ || rhs->canBeNegativeZero_);
1177
1178 return new (alloc) Range(std::max(lhs->lower_, rhs->lower_),
1179 lhs->hasInt32LowerBound_ || rhs->hasInt32LowerBound_,
1180 std::max(lhs->upper_, rhs->upper_),
1181 lhs->hasInt32UpperBound_ && rhs->hasInt32UpperBound_,
1182 newCanHaveFractionalPart, newMayIncludeNegativeZero,
1183 std::max(lhs->max_exponent_, rhs->max_exponent_));
1184}
1185
1186Range* Range::floor(TempAllocator& alloc, const Range* op) {
1187 Range* copy = new (alloc) Range(*op);
1188 // Decrement lower bound of copy range if op have a factional part and lower
1189 // bound is Int32 defined. Also we avoid to decrement when op have a
1190 // fractional part but lower_ >= JSVAL_INT_MAX.
1191 if (op->canHaveFractionalPart() && op->hasInt32LowerBound()) {
1192 copy->setLowerInit(int64_t(copy->lower_) - 1);
1193 }
1194
1195 // Also refine max_exponent_ because floor may have decremented int value
1196 // If we've got int32 defined bounds, just deduce it using defined bounds.
1197 // But, if we don't have those, value's max_exponent_ may have changed.
1198 // Because we're looking to maintain an over estimation, if we can,
1199 // we increment it.
1200 if (copy->hasInt32Bounds())
1201 copy->max_exponent_ = copy->exponentImpliedByInt32Bounds();
1202 else if (copy->max_exponent_ < MaxFiniteExponent)
1203 copy->max_exponent_++;
1204
1205 copy->canHaveFractionalPart_ = ExcludesFractionalParts;
1206 copy->assertInvariants();
1207 return copy;
1208}
1209
1210Range* Range::ceil(TempAllocator& alloc, const Range* op) {
1211 Range* copy = new (alloc) Range(*op);
1212
1213 // We need to refine max_exponent_ because ceil may have incremented the int
1214 // value. If we have got int32 bounds defined, just deduce it using the
1215 // defined bounds. Else we can just increment its value, as we are looking to
1216 // maintain an over estimation.
1217 if (copy->hasInt32Bounds()) {
1218 copy->max_exponent_ = copy->exponentImpliedByInt32Bounds();
1219 } else if (copy->max_exponent_ < MaxFiniteExponent) {
1220 copy->max_exponent_++;
1221 }
1222
1223 // If the range is definitely above 0 or below -1, we don't need to include
1224 // -0; otherwise we do.
1225
1226 copy->canBeNegativeZero_ = ((copy->lower_ > 0) || (copy->upper_ <= -1))
1227 ? copy->canBeNegativeZero_
1228 : IncludesNegativeZero;
1229
1230 copy->canHaveFractionalPart_ = ExcludesFractionalParts;
1231 copy->assertInvariants();
1232 return copy;
1233}
1234
1235Range* Range::sign(TempAllocator& alloc, const Range* op) {
1236 if (op->canBeNaN()) {
1237 return nullptr;
1238 }
1239
1240 return new (alloc)
1241 Range(std::clamp(op->lower_, -1, 1), std::clamp(op->upper_, -1, 1),
1242 Range::ExcludesFractionalParts,
1243 NegativeZeroFlag(op->canBeNegativeZero()), 0);
1244}
1245
1246Range* Range::NaNToZero(TempAllocator& alloc, const Range* op) {
1247 Range* copy = new (alloc) Range(*op);
1248 if (copy->canBeNaN()) {
1249 copy->max_exponent_ = Range::IncludesInfinity;
1250 if (!copy->canBeZero()) {
1251 Range zero;
1252 zero.setDoubleSingleton(0);
1253 copy->unionWith(&zero);
1254 }
1255 }
1256 copy->refineToExcludeNegativeZero();
1257 return copy;
1258}
1259
1260bool Range::negativeZeroMul(const Range* lhs, const Range* rhs) {
1261 // The result can only be negative zero if both sides are finite and they
1262 // have differing signs.
1263 return (lhs->canHaveSignBitSet() && rhs->canBeFiniteNonNegative()) ||
1264 (rhs->canHaveSignBitSet() && lhs->canBeFiniteNonNegative());
1265}
1266
1267bool Range::update(const Range* other) {
1268 bool changed = lower_ != other->lower_ ||
1269 hasInt32LowerBound_ != other->hasInt32LowerBound_ ||
1270 upper_ != other->upper_ ||
1271 hasInt32UpperBound_ != other->hasInt32UpperBound_ ||
1272 canHaveFractionalPart_ != other->canHaveFractionalPart_ ||
1273 canBeNegativeZero_ != other->canBeNegativeZero_ ||
1274 max_exponent_ != other->max_exponent_;
1275 if (changed) {
1276 lower_ = other->lower_;
1277 hasInt32LowerBound_ = other->hasInt32LowerBound_;
1278 upper_ = other->upper_;
1279 hasInt32UpperBound_ = other->hasInt32UpperBound_;
1280 canHaveFractionalPart_ = other->canHaveFractionalPart_;
1281 canBeNegativeZero_ = other->canBeNegativeZero_;
1282 max_exponent_ = other->max_exponent_;
1283 assertInvariants();
1284 }
1285
1286 return changed;
1287}
1288
1289///////////////////////////////////////////////////////////////////////////////
1290// Range Computation for MIR Nodes
1291///////////////////////////////////////////////////////////////////////////////
1292
1293void MPhi::computeRange(TempAllocator& alloc) {
1294 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1295 return;
1296 }
1297
1298 Range* range = nullptr;
1299 for (size_t i = 0, e = numOperands(); i < e; i++) {
1300 if (getOperand(i)->block()->unreachable()) {
1301 JitSpew(JitSpew_Range, "Ignoring unreachable input %u",
1302 getOperand(i)->id());
1303 continue;
1304 }
1305
1306 // Peek at the pre-bailout range so we can take a short-cut; if any of
1307 // the operands has an unknown range, this phi has an unknown range.
1308 if (!getOperand(i)->range()) {
1309 return;
1310 }
1311
1312 Range input(getOperand(i));
1313
1314 if (range) {
1315 range->unionWith(&input);
1316 } else {
1317 range = new (alloc) Range(input);
1318 }
1319 }
1320
1321 setRange(range);
1322}
1323
1324void MBeta::computeRange(TempAllocator& alloc) {
1325 bool emptyRange = false;
1326
1327 Range opRange(getOperand(0));
1328 Range* range = Range::intersect(alloc, &opRange, comparison_, &emptyRange);
1329 if (emptyRange) {
1330 JitSpew(JitSpew_Range, "Marking block for inst %u unreachable", id());
1331 block()->setUnreachableUnchecked();
1332 } else {
1333 setRange(range);
1334 }
1335}
1336
1337void MConstant::computeRange(TempAllocator& alloc) {
1338 if (isTypeRepresentableAsDouble()) {
1339 double d = numberToDouble();
1340 setRange(Range::NewDoubleSingletonRange(alloc, d));
1341 } else if (type() == MIRType::Boolean) {
1342 bool b = toBoolean();
1343 setRange(Range::NewInt32Range(alloc, b, b));
1344 }
1345}
1346
1347void MCharCodeAt::computeRange(TempAllocator& alloc) {
1348 // ECMA 262 says that the integer will be non-negative and at most 65535.
1349 setRange(Range::NewInt32Range(alloc, 0, unicode::UTF16Max));
1350}
1351
1352void MCodePointAt::computeRange(TempAllocator& alloc) {
1353 setRange(Range::NewInt32Range(alloc, 0, unicode::NonBMPMax));
1354}
1355
1356void MClampToUint8::computeRange(TempAllocator& alloc) {
1357 setRange(Range::NewUInt32Range(alloc, 0, 255));
1358}
1359
1360void MBitAnd::computeRange(TempAllocator& alloc) {
1361 if (type() != MIRType::Int32) {
1362 return;
1363 }
1364
1365 Range left(getOperand(0));
1366 Range right(getOperand(1));
1367 left.wrapAroundToInt32();
1368 right.wrapAroundToInt32();
1369
1370 setRange(Range::and_(alloc, &left, &right));
1371}
1372
1373void MBitOr::computeRange(TempAllocator& alloc) {
1374 if (type() != MIRType::Int32) {
1375 return;
1376 }
1377
1378 Range left(getOperand(0));
1379 Range right(getOperand(1));
1380 left.wrapAroundToInt32();
1381 right.wrapAroundToInt32();
1382
1383 setRange(Range::or_(alloc, &left, &right));
1384}
1385
1386void MBitXor::computeRange(TempAllocator& alloc) {
1387 if (type() != MIRType::Int32) {
1388 return;
1389 }
1390
1391 Range left(getOperand(0));
1392 Range right(getOperand(1));
1393 left.wrapAroundToInt32();
1394 right.wrapAroundToInt32();
1395
1396 setRange(Range::xor_(alloc, &left, &right));
1397}
1398
1399void MBitNot::computeRange(TempAllocator& alloc) {
1400 if (type() == MIRType::Int64) {
1401 return;
1402 }
1403 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1403); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { MOZ_CrashSequence
(__null, 1403); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1404
1405 Range op(getOperand(0));
1406 op.wrapAroundToInt32();
1407
1408 setRange(Range::not_(alloc, &op));
1409}
1410
1411void MLsh::computeRange(TempAllocator& alloc) {
1412 if (type() != MIRType::Int32) {
1413 return;
1414 }
1415
1416 Range left(getOperand(0));
1417 Range right(getOperand(1));
1418 left.wrapAroundToInt32();
1419
1420 MConstant* rhsConst = getOperand(1)->maybeConstantValue();
1421 if (rhsConst && rhsConst->type() == MIRType::Int32) {
1422 int32_t c = rhsConst->toInt32();
1423 setRange(Range::lsh(alloc, &left, c));
1424 return;
1425 }
1426
1427 right.wrapAroundToShiftCount();
1428 setRange(Range::lsh(alloc, &left, &right));
1429}
1430
1431void MRsh::computeRange(TempAllocator& alloc) {
1432 if (type() != MIRType::Int32) {
1433 return;
1434 }
1435
1436 Range left(getOperand(0));
1437 Range right(getOperand(1));
1438 left.wrapAroundToInt32();
1439
1440 MConstant* rhsConst = getOperand(1)->maybeConstantValue();
1441 if (rhsConst && rhsConst->type() == MIRType::Int32) {
1442 int32_t c = rhsConst->toInt32();
1443 setRange(Range::rsh(alloc, &left, c));
1444 return;
1445 }
1446
1447 right.wrapAroundToShiftCount();
1448 setRange(Range::rsh(alloc, &left, &right));
1449}
1450
1451void MUrsh::computeRange(TempAllocator& alloc) {
1452 if (type() != MIRType::Int32) {
1453 return;
1454 }
1455
1456 Range left(getOperand(0));
1457 Range right(getOperand(1));
1458
1459 // ursh can be thought of as converting its left operand to uint32, or it
1460 // can be thought of as converting its left operand to int32, and then
1461 // reinterpreting the int32 bits as a uint32 value. Both approaches yield
1462 // the same result. Since we lack support for full uint32 ranges, we use
1463 // the second interpretation, though it does cause us to be conservative.
1464 left.wrapAroundToInt32();
1465 right.wrapAroundToShiftCount();
1466
1467 MConstant* rhsConst = getOperand(1)->maybeConstantValue();
1468 if (rhsConst && rhsConst->type() == MIRType::Int32) {
1469 int32_t c = rhsConst->toInt32();
1470 setRange(Range::ursh(alloc, &left, c));
1471 } else {
1472 setRange(Range::ursh(alloc, &left, &right));
1473 }
1474
1475 MOZ_ASSERT(range()->lower() >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(range()->lower() >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(range()->lower() >= 0)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("range()->lower() >= 0"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1475); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "range()->lower() >= 0" ")"); do { MOZ_CrashSequence
(__null, 1475); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1476}
1477
1478void MAbs::computeRange(TempAllocator& alloc) {
1479 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1480 return;
1481 }
1482
1483 Range other(getOperand(0));
1484 Range* next = Range::abs(alloc, &other);
1485 if (implicitTruncate_) {
1486 next->wrapAroundToInt32();
1487 }
1488 setRange(next);
1489}
1490
1491void MFloor::computeRange(TempAllocator& alloc) {
1492 Range other(getOperand(0));
1493 setRange(Range::floor(alloc, &other));
1494}
1495
1496void MCeil::computeRange(TempAllocator& alloc) {
1497 Range other(getOperand(0));
1498 setRange(Range::ceil(alloc, &other));
1499}
1500
1501void MClz::computeRange(TempAllocator& alloc) {
1502 if (type() != MIRType::Int32) {
1503 return;
1504 }
1505 setRange(Range::NewUInt32Range(alloc, 0, 32));
1506}
1507
1508void MCtz::computeRange(TempAllocator& alloc) {
1509 if (type() != MIRType::Int32) {
1510 return;
1511 }
1512 setRange(Range::NewUInt32Range(alloc, 0, 32));
1513}
1514
1515void MPopcnt::computeRange(TempAllocator& alloc) {
1516 if (type() != MIRType::Int32) {
1517 return;
1518 }
1519 setRange(Range::NewUInt32Range(alloc, 0, 32));
1520}
1521
1522void MMinMax::computeRange(TempAllocator& alloc) {
1523 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1524 return;
1525 }
1526
1527 Range left(getOperand(0));
1528 Range right(getOperand(1));
1529 setRange(isMax() ? Range::max(alloc, &left, &right)
1530 : Range::min(alloc, &left, &right));
1531}
1532
1533void MAdd::computeRange(TempAllocator& alloc) {
1534 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1535 return;
1536 }
1537 Range left(getOperand(0));
1538 Range right(getOperand(1));
1539 Range* next = Range::add(alloc, &left, &right);
1540 if (isTruncated()) {
1541 next->wrapAroundToInt32();
1542 }
1543 setRange(next);
1544}
1545
1546void MSub::computeRange(TempAllocator& alloc) {
1547 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1548 return;
1549 }
1550 Range left(getOperand(0));
1551 Range right(getOperand(1));
1552 Range* next = Range::sub(alloc, &left, &right);
1553 if (isTruncated()) {
1554 next->wrapAroundToInt32();
1555 }
1556 setRange(next);
1557}
1558
1559void MMul::computeRange(TempAllocator& alloc) {
1560 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1561 return;
1562 }
1563 Range left(getOperand(0));
1564 Range right(getOperand(1));
1565 if (canBeNegativeZero()) {
1566 canBeNegativeZero_ = Range::negativeZeroMul(&left, &right);
1567 }
1568 Range* next = Range::mul(alloc, &left, &right);
1569 if (!next->canBeNegativeZero()) {
1570 canBeNegativeZero_ = false;
1571 }
1572 // Truncated multiplications could overflow in both directions
1573 if (isTruncated()) {
1574 next->wrapAroundToInt32();
1575 }
1576 setRange(next);
1577}
1578
1579void MMod::computeRange(TempAllocator& alloc) {
1580 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1581 return;
1582 }
1583 Range lhs(getOperand(0));
1584 Range rhs(getOperand(1));
1585
1586 // If either operand is a NaN, the result is NaN. This also conservatively
1587 // handles Infinity cases.
1588 if (!lhs.hasInt32Bounds() || !rhs.hasInt32Bounds()) {
1589 return;
1590 }
1591
1592 // If RHS can be zero, the result can be NaN.
1593 if (rhs.lower() <= 0 && rhs.upper() >= 0) {
1594 return;
1595 }
1596
1597 // If both operands are non-negative integers, we can optimize this to an
1598 // unsigned mod.
1599 if (type() == MIRType::Int32 && rhs.lower() > 0) {
1600 bool hasDoubles = lhs.lower() < 0 || lhs.canHaveFractionalPart() ||
1601 rhs.canHaveFractionalPart();
1602 // It is not possible to check that lhs.lower() >= 0, since the range
1603 // of a ursh with rhs a 0 constant is wrapped around the int32 range in
1604 // Range::Range(). However, IsUint32Type() will only return true for
1605 // nodes that lie in the range [0, UINT32_MAX].
1606 bool hasUint32s =
1607 IsUint32Type(getOperand(0)) &&
1608 getOperand(1)->type() == MIRType::Int32 &&
1609 (IsUint32Type(getOperand(1)) || getOperand(1)->isConstant());
1610 if (!hasDoubles || hasUint32s) {
1611 unsigned_ = true;
1612 }
1613 }
1614
1615 // For unsigned mod, we have to convert both operands to unsigned.
1616 // Note that we handled the case of a zero rhs above.
1617 if (unsigned_) {
1618 // The result of an unsigned mod will never be unsigned-greater than
1619 // either operand.
1620 uint32_t lhsBound = std::max<uint32_t>(lhs.lower(), lhs.upper());
1621 uint32_t rhsBound = std::max<uint32_t>(rhs.lower(), rhs.upper());
1622
1623 // If either range crosses through -1 as a signed value, it could be
1624 // the maximum unsigned value when interpreted as unsigned. If the range
1625 // doesn't include -1, then the simple max value we computed above is
1626 // correct.
1627 if (lhs.lower() <= -1 && lhs.upper() >= -1) {
1628 lhsBound = UINT32_MAX(4294967295U);
1629 }
1630 if (rhs.lower() <= -1 && rhs.upper() >= -1) {
1631 rhsBound = UINT32_MAX(4294967295U);
1632 }
1633
1634 // The result will never be equal to the rhs, and we shouldn't have
1635 // any rounding to worry about.
1636 MOZ_ASSERT(!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1636); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart()"
")"); do { MOZ_CrashSequence(__null, 1636); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1637 --rhsBound;
1638
1639 // This gives us two upper bounds, so we can take the best one.
1640 setRange(Range::NewUInt32Range(alloc, 0, std::min(lhsBound, rhsBound)));
1641 return;
1642 }
1643
1644 // Math.abs(lhs % rhs) == Math.abs(lhs) % Math.abs(rhs).
1645 // First, the absolute value of the result will always be less than the
1646 // absolute value of rhs. (And if rhs is zero, the result is NaN).
1647 int64_t a = Abs<int64_t>(rhs.lower());
1648 int64_t b = Abs<int64_t>(rhs.upper());
1649 if (a == 0 && b == 0) {
1650 return;
1651 }
1652 int64_t rhsAbsBound = std::max(a, b);
1653
1654 // If the value is known to be integer, less-than abs(rhs) is equivalent
1655 // to less-than-or-equal abs(rhs)-1. This is important for being able to
1656 // say that the result of x%256 is an 8-bit unsigned number.
1657 if (!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart()) {
1658 --rhsAbsBound;
1659 }
1660
1661 // Next, the absolute value of the result will never be greater than the
1662 // absolute value of lhs.
1663 int64_t lhsAbsBound =
1664 std::max(Abs<int64_t>(lhs.lower()), Abs<int64_t>(lhs.upper()));
1665
1666 // This gives us two upper bounds, so we can take the best one.
1667 int64_t absBound = std::min(lhsAbsBound, rhsAbsBound);
1668
1669 // Now consider the sign of the result.
1670 // If lhs is non-negative, the result will be non-negative.
1671 // If lhs is non-positive, the result will be non-positive.
1672 int64_t lower = lhs.lower() >= 0 ? 0 : -absBound;
1673 int64_t upper = lhs.upper() <= 0 ? 0 : absBound;
1674
1675 Range::FractionalPartFlag newCanHaveFractionalPart =
1676 Range::FractionalPartFlag(lhs.canHaveFractionalPart() ||
1677 rhs.canHaveFractionalPart());
1678
1679 // If the lhs can have the sign bit set and we can return a zero, it'll be a
1680 // negative zero.
1681 Range::NegativeZeroFlag newMayIncludeNegativeZero =
1682 Range::NegativeZeroFlag(lhs.canHaveSignBitSet());
1683
1684 setRange(new (alloc) Range(lower, upper, newCanHaveFractionalPart,
1685 newMayIncludeNegativeZero,
1686 std::min(lhs.exponent(), rhs.exponent())));
1687}
1688
1689void MDiv::computeRange(TempAllocator& alloc) {
1690 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1691 return;
1692 }
1693 Range lhs(getOperand(0));
1694 Range rhs(getOperand(1));
1695
1696 // If either operand is a NaN, the result is NaN. This also conservatively
1697 // handles Infinity cases.
1698 if (!lhs.hasInt32Bounds() || !rhs.hasInt32Bounds()) {
1699 return;
1700 }
1701
1702 // Something simple for now: When dividing by a positive rhs, the result
1703 // won't be further from zero than lhs.
1704 if (lhs.lower() >= 0 && rhs.lower() >= 1) {
1705 setRange(new (alloc) Range(0, lhs.upper(), Range::IncludesFractionalParts,
1706 Range::IncludesNegativeZero, lhs.exponent()));
1707 } else if (unsigned_ && rhs.lower() >= 1) {
1708 // We shouldn't set the unsigned flag if the inputs can have
1709 // fractional parts.
1710 MOZ_ASSERT(!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1710); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!lhs.canHaveFractionalPart() && !rhs.canHaveFractionalPart()"
")"); do { MOZ_CrashSequence(__null, 1710); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1711 // We shouldn't set the unsigned flag if the inputs can be
1712 // negative zero.
1713 MOZ_ASSERT(!lhs.canBeNegativeZero() && !rhs.canBeNegativeZero())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!lhs.canBeNegativeZero() && !rhs.canBeNegativeZero
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!lhs.canBeNegativeZero() && !rhs.canBeNegativeZero
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!lhs.canBeNegativeZero() && !rhs.canBeNegativeZero()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1713); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!lhs.canBeNegativeZero() && !rhs.canBeNegativeZero()"
")"); do { MOZ_CrashSequence(__null, 1713); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1714 // Unsigned division by a non-zero rhs will return a uint32 value.
1715 setRange(Range::NewUInt32Range(alloc, 0, UINT32_MAX(4294967295U)));
1716 }
1717}
1718
1719void MSqrt::computeRange(TempAllocator& alloc) {
1720 Range input(getOperand(0));
1721
1722 // If either operand is a NaN, the result is NaN. This also conservatively
1723 // handles Infinity cases.
1724 if (!input.hasInt32Bounds()) {
1725 return;
1726 }
1727
1728 // Sqrt of a negative non-zero value is NaN.
1729 if (input.lower() < 0) {
1730 return;
1731 }
1732
1733 // Something simple for now: When taking the sqrt of a positive value, the
1734 // result won't be further from zero than the input.
1735 // And, sqrt of an integer may have a fractional part.
1736 setRange(new (alloc) Range(0, input.upper(), Range::IncludesFractionalParts,
1737 input.canBeNegativeZero(), input.exponent()));
1738}
1739
1740void MToDouble::computeRange(TempAllocator& alloc) {
1741 setRange(new (alloc) Range(getOperand(0)));
1742}
1743
1744void MToFloat32::computeRange(TempAllocator& alloc) {}
1745
1746void MTruncateToInt32::computeRange(TempAllocator& alloc) {
1747 Range* output = new (alloc) Range(getOperand(0));
1748 output->wrapAroundToInt32();
1749 setRange(output);
1750}
1751
1752void MToNumberInt32::computeRange(TempAllocator& alloc) {
1753 // No clamping since this computes the range *before* bailouts.
1754 setRange(new (alloc) Range(getOperand(0)));
1755}
1756
1757void MBooleanToInt32::computeRange(TempAllocator& alloc) {
1758 setRange(Range::NewUInt32Range(alloc, 0, 1));
1759}
1760
1761void MLimitedTruncate::computeRange(TempAllocator& alloc) {
1762 Range* output = new (alloc) Range(input());
1763 setRange(output);
1764}
1765
1766static Range* GetArrayBufferViewRange(TempAllocator& alloc, Scalar::Type type) {
1767 switch (type) {
1768 case Scalar::Uint8Clamped:
1769 case Scalar::Uint8:
1770 return Range::NewUInt32Range(alloc, 0, UINT8_MAX(255));
1771 case Scalar::Uint16:
1772 return Range::NewUInt32Range(alloc, 0, UINT16_MAX(65535));
1773 case Scalar::Uint32:
1774 return Range::NewUInt32Range(alloc, 0, UINT32_MAX(4294967295U));
1775
1776 case Scalar::Int8:
1777 return Range::NewInt32Range(alloc, INT8_MIN(-128), INT8_MAX(127));
1778 case Scalar::Int16:
1779 return Range::NewInt32Range(alloc, INT16_MIN(-32767-1), INT16_MAX(32767));
1780 case Scalar::Int32:
1781 return Range::NewInt32Range(alloc, INT32_MIN(-2147483647-1), INT32_MAX(2147483647));
1782
1783 case Scalar::BigInt64:
1784 case Scalar::BigUint64:
1785 case Scalar::Int64:
1786 case Scalar::Simd128:
1787 case Scalar::Float16:
1788 case Scalar::Float32:
1789 case Scalar::Float64:
1790 case Scalar::MaxTypedArrayViewType:
1791 break;
1792 }
1793 return nullptr;
1794}
1795
1796void MLoadUnboxedScalar::computeRange(TempAllocator& alloc) {
1797 // We have an Int32 type and if this is a UInt32 load it may produce a value
1798 // outside of our range, but we have a bailout to handle those cases.
1799 setRange(GetArrayBufferViewRange(alloc, storageType()));
1800}
1801
1802void MLoadDataViewElement::computeRange(TempAllocator& alloc) {
1803 // We have an Int32 type and if this is a UInt32 load it may produce a value
1804 // outside of our range, but we have a bailout to handle those cases.
1805 setRange(GetArrayBufferViewRange(alloc, storageType()));
1806}
1807
1808void MArrayLength::computeRange(TempAllocator& alloc) {
1809 // Array lengths can go up to UINT32_MAX. We will bail out if the array
1810 // length > INT32_MAX.
1811 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1811); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { MOZ_CrashSequence
(__null, 1811); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1812 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1813}
1814
1815void MInitializedLength::computeRange(TempAllocator& alloc) {
1816 setRange(
1817 Range::NewUInt32Range(alloc, 0, NativeObject::MAX_DENSE_ELEMENTS_COUNT));
1818}
1819
1820void MArrayBufferViewLength::computeRange(TempAllocator& alloc) {
1821 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1822 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1823 }
1824}
1825
1826void MArrayBufferViewByteOffset::computeRange(TempAllocator& alloc) {
1827 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1828 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1829 }
1830}
1831
1832void MResizableTypedArrayLength::computeRange(TempAllocator& alloc) {
1833 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1834 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1835 }
1836}
1837
1838void MResizableDataViewByteLength::computeRange(TempAllocator& alloc) {
1839 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1840 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1841 }
1842}
1843
1844void MTypedArrayElementSize::computeRange(TempAllocator& alloc) {
1845 constexpr auto MaxTypedArraySize = sizeof(double);
1846
1847#define ASSERT_MAX_SIZE(_, T, N) \
1848 static_assert(sizeof(T) <= MaxTypedArraySize, \
1849 "unexpected typed array type exceeding 64-bits storage");
1850 JS_FOR_EACH_TYPED_ARRAY(ASSERT_MAX_SIZE)ASSERT_MAX_SIZE(int8_t, int8_t, Int8) ASSERT_MAX_SIZE(uint8_t
, uint8_t, Uint8) ASSERT_MAX_SIZE(int16_t, int16_t, Int16) ASSERT_MAX_SIZE
(uint16_t, uint16_t, Uint16) ASSERT_MAX_SIZE(int32_t, int32_t
, Int32) ASSERT_MAX_SIZE(uint32_t, uint32_t, Uint32) ASSERT_MAX_SIZE
(float, float, Float32) ASSERT_MAX_SIZE(double, double, Float64
) ASSERT_MAX_SIZE(uint8_t, js::uint8_clamped, Uint8Clamped) ASSERT_MAX_SIZE
(int64_t, int64_t, BigInt64) ASSERT_MAX_SIZE(uint64_t, uint64_t
, BigUint64) ASSERT_MAX_SIZE(uint16_t, js::float16, Float16)
1851#undef ASSERT_MAX_SIZE
1852
1853 setRange(Range::NewUInt32Range(alloc, 0, MaxTypedArraySize));
1854}
1855
1856void MStringLength::computeRange(TempAllocator& alloc) {
1857 static_assert(JSString::MAX_LENGTH <= UINT32_MAX(4294967295U),
1858 "NewUInt32Range requires a uint32 value");
1859 setRange(Range::NewUInt32Range(alloc, 0, JSString::MAX_LENGTH));
1860}
1861
1862void MArgumentsLength::computeRange(TempAllocator& alloc) {
1863 // This is is a conservative upper bound on what |TooManyActualArguments|
1864 // checks. If exceeded, Ion will not be entered in the first place.
1865 static_assert(ARGS_LENGTH_MAX <= UINT32_MAX(4294967295U),
1866 "NewUInt32Range requires a uint32 value");
1867 setRange(Range::NewUInt32Range(alloc, 0, ARGS_LENGTH_MAX));
1868}
1869
1870void MBoundsCheck::computeRange(TempAllocator& alloc) {
1871 // Just transfer the incoming index range to the output. The length() is
1872 // also interesting, but it is handled as a bailout check, and we're
1873 // computing a pre-bailout range here.
1874 setRange(new (alloc) Range(index()));
1875}
1876
1877void MSpectreMaskIndex::computeRange(TempAllocator& alloc) {
1878 // Just transfer the incoming index range to the output for now.
1879 setRange(new (alloc) Range(index()));
1880}
1881
1882void MInt32ToIntPtr::computeRange(TempAllocator& alloc) {
1883 setRange(new (alloc) Range(input()));
1884}
1885
1886void MNonNegativeIntPtrToInt32::computeRange(TempAllocator& alloc) {
1887 // We will bail out if the IntPtr value > INT32_MAX.
1888 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1889}
1890
1891void MArrayPush::computeRange(TempAllocator& alloc) {
1892 // MArrayPush returns the new array length. It bails out if the new length
1893 // doesn't fit in an Int32.
1894 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 1894); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { MOZ_CrashSequence
(__null, 1894); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1895 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1896}
1897
1898void MMathFunction::computeRange(TempAllocator& alloc) {
1899 Range opRange(getOperand(0));
1900 switch (function()) {
1901 case UnaryMathFunction::SinNative:
1902 case UnaryMathFunction::SinFdlibm:
1903 case UnaryMathFunction::CosNative:
1904 case UnaryMathFunction::CosFdlibm:
1905 if (!opRange.canBeInfiniteOrNaN()) {
1906 setRange(Range::NewDoubleRange(alloc, -1.0, 1.0));
1907 }
1908 break;
1909 default:
1910 break;
1911 }
1912}
1913
1914void MSign::computeRange(TempAllocator& alloc) {
1915 Range opRange(getOperand(0));
1916 setRange(Range::sign(alloc, &opRange));
1917}
1918
1919void MRandom::computeRange(TempAllocator& alloc) {
1920 Range* r = Range::NewDoubleRange(alloc, 0.0, 1.0);
1921
1922 // Random never returns negative zero.
1923 r->refineToExcludeNegativeZero();
1924
1925 setRange(r);
1926}
1927
1928void MNaNToZero::computeRange(TempAllocator& alloc) {
1929 Range other(input());
1930 setRange(Range::NaNToZero(alloc, &other));
1931}
1932
1933///////////////////////////////////////////////////////////////////////////////
1934// Range Analysis
1935///////////////////////////////////////////////////////////////////////////////
1936
1937static BranchDirection NegateBranchDirection(BranchDirection dir) {
1938 return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
1939}
1940
1941bool RangeAnalysis::analyzeLoop(const MBasicBlock* header) {
1942 MOZ_ASSERT(header->hasUniqueBackedge())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(header->hasUniqueBackedge())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(header->hasUniqueBackedge
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("header->hasUniqueBackedge()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 1942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "header->hasUniqueBackedge()"
")"); do { MOZ_CrashSequence(__null, 1942); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1943
1944 // Try to compute an upper bound on the number of times the loop backedge
1945 // will be taken. Look for tests that dominate the backedge and which have
1946 // an edge leaving the loop body.
1947 MBasicBlock* backedge = header->backedge();
1948
1949 // Ignore trivial infinite loops.
1950 if (backedge == header) {
1951 return true;
1952 }
1953
1954 bool canOsr;
1955 size_t numBlocks = MarkLoopBlocks(graph_, header, &canOsr);
1956
1957 // Ignore broken loops.
1958 if (numBlocks == 0) {
1959 return true;
1960 }
1961
1962 LoopIterationBound* iterationBound = nullptr;
1963
1964 MBasicBlock* block = backedge;
1965 do {
1966 BranchDirection direction;
1967 MTest* branch = block->immediateDominatorBranch(&direction);
1968
1969 if (block == block->immediateDominator()) {
1970 break;
1971 }
1972
1973 block = block->immediateDominator();
1974
1975 if (branch) {
1976 direction = NegateBranchDirection(direction);
1977 MBasicBlock* otherBlock = branch->branchSuccessor(direction);
1978 if (!otherBlock->isMarked()) {
1979 if (!alloc().ensureBallast()) {
1980 return false;
1981 }
1982 iterationBound = analyzeLoopIterationCount(header, branch, direction);
1983 if (iterationBound) {
1984 break;
1985 }
1986 }
1987 }
1988 } while (block != header);
1989
1990 if (!iterationBound) {
1991 UnmarkLoopBlocks(graph_, header);
1992 return true;
1993 }
1994
1995 if (!loopIterationBounds.append(iterationBound)) {
1996 return false;
1997 }
1998
1999#ifdef DEBUG1
2000 if (JitSpewEnabled(JitSpew_Range)) {
2001 Sprinter sp(GetJitContext()->cx);
2002 if (!sp.init()) {
2003 return false;
2004 }
2005 iterationBound->boundSum.dump(sp);
2006 JS::UniqueChars str = sp.release();
2007 if (!str) {
2008 return false;
2009 }
2010 JitSpew(JitSpew_Range, "computed symbolic bound on backedges: %s",
2011 str.get());
2012 }
2013#endif
2014
2015 // Try to compute symbolic bounds for the phi nodes at the head of this
2016 // loop, expressed in terms of the iteration bound just computed.
2017
2018 for (MPhiIterator iter(header->phisBegin()); iter != header->phisEnd();
2019 iter++) {
2020 analyzeLoopPhi(iterationBound, *iter);
2021 }
2022
2023 if (!mir->compilingWasm() && !mir->outerInfo().hadBoundsCheckBailout()) {
2024 // Try to hoist any bounds checks from the loop using symbolic bounds.
2025
2026 Vector<MBoundsCheck*, 0, JitAllocPolicy> hoistedChecks(alloc());
2027
2028 for (ReversePostorderIterator iter(graph_.rpoBegin(header));
2029 iter != graph_.rpoEnd(); iter++) {
2030 if (mir->shouldCancel("RangeAnalysis analyzeLoop")) {
2031 return false;
2032 }
2033
2034 MBasicBlock* block = *iter;
2035 if (!block->isMarked()) {
2036 continue;
2037 }
2038
2039 for (MDefinitionIterator iter(block); iter; iter++) {
2040 MDefinition* def = *iter;
2041 if (def->isBoundsCheck() && def->isMovable()) {
2042 if (!alloc().ensureBallast()) {
2043 return false;
2044 }
2045 if (tryHoistBoundsCheck(header, def->toBoundsCheck())) {
2046 if (!hoistedChecks.append(def->toBoundsCheck())) {
2047 return false;
2048 }
2049 }
2050 }
2051 }
2052 }
2053
2054 // Note: replace all uses of the original bounds check with the
2055 // actual index. This is usually done during bounds check elimination,
2056 // but in this case it's safe to do it here since the load/store is
2057 // definitely not loop-invariant, so we will never move it before
2058 // one of the bounds checks we just added.
2059 for (size_t i = 0; i < hoistedChecks.length(); i++) {
2060 MBoundsCheck* ins = hoistedChecks[i];
2061 ins->replaceAllUsesWith(ins->index());
2062 ins->block()->discard(ins);
2063 }
2064 }
2065
2066 UnmarkLoopBlocks(graph_, header);
2067 return true;
2068}
2069
2070// Unbox beta nodes in order to hoist instruction properly, and not be limited
2071// by the beta nodes which are added after each branch.
2072static inline MDefinition* DefinitionOrBetaInputDefinition(MDefinition* ins) {
2073 while (ins->isBeta()) {
2074 ins = ins->toBeta()->input();
2075 }
2076 return ins;
2077}
2078
2079LoopIterationBound* RangeAnalysis::analyzeLoopIterationCount(
2080 const MBasicBlock* header, const MTest* test, BranchDirection direction) {
2081 SimpleLinearSum lhs(nullptr, 0);
2082 MDefinition* rhs;
2083 bool lessEqual;
2084 if (!ExtractLinearInequality(test, direction, &lhs, &rhs, &lessEqual)) {
2085 return nullptr;
2086 }
2087
2088 // Ensure the rhs is a loop invariant term.
2089 if (rhs && rhs->block()->isMarked()) {
2090 if (lhs.term && lhs.term->block()->isMarked()) {
2091 return nullptr;
2092 }
2093 MDefinition* temp = lhs.term;
2094 lhs.term = rhs;
2095 rhs = temp;
2096 if (!mozilla::SafeSub(0, lhs.constant, &lhs.constant)) {
2097 return nullptr;
2098 }
2099 lessEqual = !lessEqual;
2100 }
2101
2102 MOZ_ASSERT_IF(rhs, !rhs->block()->isMarked())do { if (rhs) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!rhs->block()->isMarked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!rhs->block()->isMarked
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!rhs->block()->isMarked()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rhs->block()->isMarked()"
")"); do { MOZ_CrashSequence(__null, 2102); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2103
2104 // Ensure the lhs is a phi node from the start of the loop body.
2105 if (!lhs.term || !lhs.term->isPhi() || lhs.term->block() != header) {
2106 return nullptr;
2107 }
2108
2109 // Check that the value of the lhs changes by a constant amount with each
2110 // loop iteration. This requires that the lhs be written in every loop
2111 // iteration with a value that is a constant difference from its value at
2112 // the start of the iteration.
2113
2114 if (lhs.term->toPhi()->numOperands() != 2) {
2115 return nullptr;
2116 }
2117
2118 // The first operand of the phi should be the lhs' value at the start of
2119 // the first executed iteration, and not a value written which could
2120 // replace the second operand below during the middle of execution.
2121 MDefinition* lhsInitial = lhs.term->toPhi()->getLoopPredecessorOperand();
2122 if (lhsInitial->block()->isMarked()) {
2123 return nullptr;
2124 }
2125
2126 // The second operand of the phi should be a value written by an add/sub
2127 // in every loop iteration, i.e. in a block which dominates the backedge.
2128 MDefinition* lhsWrite = DefinitionOrBetaInputDefinition(
2129 lhs.term->toPhi()->getLoopBackedgeOperand());
2130 if (!lhsWrite->isAdd() && !lhsWrite->isSub()) {
2131 return nullptr;
2132 }
2133 if (!lhsWrite->block()->isMarked()) {
2134 return nullptr;
2135 }
2136 MBasicBlock* bb = header->backedge();
2137 for (; bb != lhsWrite->block() && bb != header;
2138 bb = bb->immediateDominator()) {
2139 }
2140 if (bb != lhsWrite->block()) {
2141 return nullptr;
2142 }
2143
2144 SimpleLinearSum lhsModified = ExtractLinearSum(lhsWrite);
2145
2146 // Check that the value of the lhs at the backedge is of the form
2147 // 'old(lhs) + N'. We can be sure that old(lhs) is the value at the start
2148 // of the iteration, and not that written to lhs in a previous iteration,
2149 // as such a previous value could not appear directly in the addition:
2150 // it could not be stored in lhs as the lhs add/sub executes in every
2151 // iteration, and if it were stored in another variable its use here would
2152 // be as an operand to a phi node for that variable.
2153 if (lhsModified.term != lhs.term) {
2154 return nullptr;
2155 }
2156
2157 LinearSum iterationBound(alloc());
2158
2159 if (lhsModified.constant == 1 && !lessEqual) {
2160 // The value of lhs is 'initial(lhs) + iterCount' and this will end
2161 // execution of the loop if 'lhs + lhsN >= rhs'. Thus, an upper bound
2162 // on the number of backedges executed is:
2163 //
2164 // initial(lhs) + iterCount + lhsN == rhs
2165 // iterCount == rhsN - initial(lhs) - lhsN
2166
2167 if (rhs) {
2168 if (!iterationBound.add(rhs, 1)) {
2169 return nullptr;
2170 }
2171 }
2172 if (!iterationBound.add(lhsInitial, -1)) {
2173 return nullptr;
2174 }
2175
2176 int32_t lhsConstant;
2177 if (!mozilla::SafeSub(0, lhs.constant, &lhsConstant)) {
2178 return nullptr;
2179 }
2180 if (!iterationBound.add(lhsConstant)) {
2181 return nullptr;
2182 }
2183 } else if (lhsModified.constant == -1 && lessEqual) {
2184 // The value of lhs is 'initial(lhs) - iterCount'. Similar to the above
2185 // case, an upper bound on the number of backedges executed is:
2186 //
2187 // initial(lhs) - iterCount + lhsN == rhs
2188 // iterCount == initial(lhs) - rhs + lhsN
2189
2190 if (!iterationBound.add(lhsInitial, 1)) {
2191 return nullptr;
2192 }
2193 if (rhs) {
2194 if (!iterationBound.add(rhs, -1)) {
2195 return nullptr;
2196 }
2197 }
2198 if (!iterationBound.add(lhs.constant)) {
2199 return nullptr;
2200 }
2201 } else {
2202 return nullptr;
2203 }
2204
2205 return new (alloc()) LoopIterationBound(test, iterationBound);
2206}
2207
2208void RangeAnalysis::analyzeLoopPhi(const LoopIterationBound* loopBound,
2209 MPhi* phi) {
2210 // Given a bound on the number of backedges taken, compute an upper and
2211 // lower bound for a phi node that may change by a constant amount each
2212 // iteration. Unlike for the case when computing the iteration bound
2213 // itself, the phi does not need to change the same amount every iteration,
2214 // but is required to change at most N and be either nondecreasing or
2215 // nonincreasing.
2216
2217 MOZ_ASSERT(phi->numOperands() == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(phi->numOperands() == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(phi->numOperands() == 2))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("phi->numOperands() == 2"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2217); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "phi->numOperands() == 2" ")"); do { MOZ_CrashSequence
(__null, 2217); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2218
2219 MDefinition* initial = phi->getLoopPredecessorOperand();
2220 if (initial->block()->isMarked()) {
2221 return;
2222 }
2223
2224 SimpleLinearSum modified =
2225 ExtractLinearSum(phi->getLoopBackedgeOperand(), MathSpace::Infinite);
2226
2227 if (modified.term != phi || modified.constant == 0) {
2228 return;
2229 }
2230
2231 if (!phi->range()) {
2232 phi->setRange(new (alloc()) Range(phi));
2233 }
2234
2235 LinearSum initialSum(alloc());
2236 if (!initialSum.add(initial, 1)) {
2237 return;
2238 }
2239
2240 // The phi may change by N each iteration, and is either nondecreasing or
2241 // nonincreasing. initial(phi) is either a lower or upper bound for the
2242 // phi, and initial(phi) + loopBound * N is either an upper or lower bound,
2243 // at all points within the loop, provided that loopBound >= 0.
2244 //
2245 // We are more interested, however, in the bound for phi at points
2246 // dominated by the loop bound's test; if the test dominates e.g. a bounds
2247 // check we want to hoist from the loop, using the value of the phi at the
2248 // head of the loop for this will usually be too imprecise to hoist the
2249 // check. These points will execute only if the backedge executes at least
2250 // one more time (as the test passed and the test dominates the backedge),
2251 // so we know both that loopBound >= 1 and that the phi's value has changed
2252 // at most loopBound - 1 times. Thus, another upper or lower bound for the
2253 // phi is initial(phi) + (loopBound - 1) * N, without requiring us to
2254 // ensure that loopBound >= 0.
2255
2256 LinearSum limitSum(loopBound->boundSum);
2257 if (!limitSum.multiply(modified.constant) || !limitSum.add(initialSum)) {
2258 return;
2259 }
2260
2261 int32_t negativeConstant;
2262 if (!mozilla::SafeSub(0, modified.constant, &negativeConstant) ||
2263 !limitSum.add(negativeConstant)) {
2264 return;
2265 }
2266
2267 Range* initRange = initial->range();
2268 if (modified.constant > 0) {
2269 if (initRange && initRange->hasInt32LowerBound()) {
2270 phi->range()->refineLower(initRange->lower());
2271 }
2272 phi->range()->setSymbolicLower(
2273 SymbolicBound::New(alloc(), nullptr, initialSum));
2274 phi->range()->setSymbolicUpper(
2275 SymbolicBound::New(alloc(), loopBound, limitSum));
2276 } else {
2277 if (initRange && initRange->hasInt32UpperBound()) {
2278 phi->range()->refineUpper(initRange->upper());
2279 }
2280 phi->range()->setSymbolicUpper(
2281 SymbolicBound::New(alloc(), nullptr, initialSum));
2282 phi->range()->setSymbolicLower(
2283 SymbolicBound::New(alloc(), loopBound, limitSum));
2284 }
2285
2286 JitSpew(JitSpew_Range, "added symbolic range on %u", phi->id());
2287 SpewRange(phi);
2288}
2289
2290// Whether bound is valid at the specified bounds check instruction in a loop,
2291// and may be used to hoist ins.
2292static inline bool SymbolicBoundIsValid(const MBasicBlock* header,
2293 const MBoundsCheck* ins,
2294 const SymbolicBound* bound) {
2295 if (!bound->loop) {
2296 return true;
2297 }
2298 if (ins->block() == header) {
2299 return false;
2300 }
2301 MBasicBlock* bb = ins->block()->immediateDominator();
2302 while (bb != header && bb != bound->loop->test->block()) {
2303 bb = bb->immediateDominator();
2304 }
2305 return bb == bound->loop->test->block();
2306}
2307
2308bool RangeAnalysis::tryHoistBoundsCheck(const MBasicBlock* header,
2309 const MBoundsCheck* ins) {
2310 // The bounds check's length must be loop invariant or a constant.
2311 MDefinition* length = DefinitionOrBetaInputDefinition(ins->length());
2312 if (length->block()->isMarked() && !length->isConstant()) {
2313 return false;
2314 }
2315
2316 // The bounds check's index should not be loop invariant (else we would
2317 // already have hoisted it during LICM).
2318 SimpleLinearSum index = ExtractLinearSum(ins->index());
2319 if (!index.term || !index.term->block()->isMarked()) {
2320 return false;
2321 }
2322
2323 // Check for a symbolic lower and upper bound on the index. If either
2324 // condition depends on an iteration bound for the loop, only hoist if
2325 // the bounds check is dominated by the iteration bound's test.
2326 if (!index.term->range()) {
2327 return false;
2328 }
2329 const SymbolicBound* lower = index.term->range()->symbolicLower();
2330 if (!lower || !SymbolicBoundIsValid(header, ins, lower)) {
2331 return false;
2332 }
2333 const SymbolicBound* upper = index.term->range()->symbolicUpper();
2334 if (!upper || !SymbolicBoundIsValid(header, ins, upper)) {
2335 return false;
2336 }
2337
2338 MBasicBlock* preLoop = header->loopPredecessor();
2339 MOZ_ASSERT(!preLoop->isMarked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!preLoop->isMarked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!preLoop->isMarked()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!preLoop->isMarked()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2339); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!preLoop->isMarked()" ")"); do { MOZ_CrashSequence
(__null, 2339); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2340
2341 MDefinition* lowerTerm = ConvertLinearSum(alloc(), preLoop, lower->sum,
2342 BailoutKind::HoistBoundsCheck);
2343 if (!lowerTerm) {
2344 return false;
2345 }
2346
2347 MDefinition* upperTerm = ConvertLinearSum(alloc(), preLoop, upper->sum,
2348 BailoutKind::HoistBoundsCheck);
2349 if (!upperTerm) {
2350 return false;
2351 }
2352
2353 // We are checking that index + indexConstant >= 0, and know that
2354 // index >= lowerTerm + lowerConstant. Thus, check that:
2355 //
2356 // lowerTerm + lowerConstant + indexConstant >= 0
2357 // lowerTerm >= -lowerConstant - indexConstant
2358
2359 int32_t lowerConstant = 0;
2360 if (!mozilla::SafeSub(lowerConstant, index.constant, &lowerConstant)) {
2361 return false;
2362 }
2363 if (!mozilla::SafeSub(lowerConstant, lower->sum.constant(), &lowerConstant)) {
2364 return false;
2365 }
2366
2367 // We are checking that index < boundsLength, and know that
2368 // index <= upperTerm + upperConstant. Thus, check that:
2369 //
2370 // upperTerm + upperConstant < boundsLength
2371
2372 int32_t upperConstant = index.constant;
2373 if (!mozilla::SafeAdd(upper->sum.constant(), upperConstant, &upperConstant)) {
2374 return false;
2375 }
2376
2377 // Hoist the loop invariant lower bounds checks.
2378 MBoundsCheckLower* lowerCheck = MBoundsCheckLower::New(alloc(), lowerTerm);
2379 lowerCheck->setMinimum(lowerConstant);
2380 lowerCheck->computeRange(alloc());
2381 lowerCheck->collectRangeInfoPreTrunc();
2382 lowerCheck->setBailoutKind(BailoutKind::HoistBoundsCheck);
2383 preLoop->insertBefore(preLoop->lastIns(), lowerCheck);
2384
2385 // A common pattern for iterating over typed arrays is this:
2386 //
2387 // for (var i = 0; i < ta.length; i++) {
2388 // use ta[i];
2389 // }
2390 //
2391 // Here |upperTerm| (= ta.length) is a NonNegativeIntPtrToInt32 instruction.
2392 // Unwrap this if |length| is also an IntPtr so that we don't add an
2393 // unnecessary bounds check and Int32ToIntPtr below.
2394 if (upperTerm->isNonNegativeIntPtrToInt32() &&
2395 length->type() == MIRType::IntPtr) {
2396 upperTerm = upperTerm->toNonNegativeIntPtrToInt32()->input();
2397 }
2398
2399 // Hoist the loop invariant upper bounds checks.
2400 if (upperTerm != length || upperConstant >= 0) {
2401 // Hoist the bound check's length if it isn't already loop invariant.
2402 if (length->block()->isMarked()) {
2403 MOZ_ASSERT(length->isConstant())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length->isConstant())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length->isConstant()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("length->isConstant()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2403); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "length->isConstant()" ")"); do { MOZ_CrashSequence
(__null, 2403); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2404 MInstruction* lengthIns = length->toInstruction();
2405 lengthIns->block()->moveBefore(preLoop->lastIns(), lengthIns);
2406 }
2407
2408 // If the length is IntPtr, convert the upperTerm to that as well for the
2409 // bounds check.
2410 if (length->type() == MIRType::IntPtr &&
2411 upperTerm->type() == MIRType::Int32) {
2412 upperTerm = MInt32ToIntPtr::New(alloc(), upperTerm);
2413 upperTerm->computeRange(alloc());
2414 upperTerm->collectRangeInfoPreTrunc();
2415 preLoop->insertBefore(preLoop->lastIns(), upperTerm->toInstruction());
2416 }
2417
2418 MBoundsCheck* upperCheck = MBoundsCheck::New(alloc(), upperTerm, length);
2419 upperCheck->setMinimum(upperConstant);
2420 upperCheck->setMaximum(upperConstant);
2421 upperCheck->computeRange(alloc());
2422 upperCheck->collectRangeInfoPreTrunc();
2423 upperCheck->setBailoutKind(BailoutKind::HoistBoundsCheck);
2424 preLoop->insertBefore(preLoop->lastIns(), upperCheck);
2425 }
2426
2427 return true;
2428}
2429
2430bool RangeAnalysis::analyze() {
2431 JitSpew(JitSpew_Range, "Doing range propagation");
2432
2433 for (ReversePostorderIterator iter(graph_.rpoBegin());
2434 iter != graph_.rpoEnd(); iter++) {
2435 if (mir->shouldCancel("RangeAnalysis analyze")) {
2436 return false;
2437 }
2438
2439 MBasicBlock* block = *iter;
2440 // No blocks are supposed to be unreachable, except when we have an OSR
2441 // block, in which case the Value Numbering phase add fixup blocks which
2442 // are unreachable.
2443 MOZ_ASSERT(!block->unreachable() || graph_.osrBlock())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!block->unreachable() || graph_.osrBlock())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!block->unreachable() || graph_.osrBlock()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!block->unreachable() || graph_.osrBlock()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2443); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!block->unreachable() || graph_.osrBlock()"
")"); do { MOZ_CrashSequence(__null, 2443); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2444
2445 // If the block's immediate dominator is unreachable, the block is
2446 // unreachable. Iterating in RPO, we'll always see the immediate
2447 // dominator before the block.
2448 if (block->immediateDominator()->unreachable()) {
2449 block->setUnreachableUnchecked();
2450 continue;
2451 }
2452
2453 for (MDefinitionIterator iter(block); iter; iter++) {
2454 MDefinition* def = *iter;
2455 if (!alloc().ensureBallast()) {
2456 return false;
2457 }
2458
2459 def->computeRange(alloc());
2460 JitSpew(JitSpew_Range, "computing range on %u", def->id());
2461 SpewRange(def);
2462 }
2463
2464 // Beta node range analysis may have marked this block unreachable. If
2465 // so, it's no longer interesting to continue processing it.
2466 if (block->unreachable()) {
2467 continue;
2468 }
2469
2470 if (block->isLoopHeader()) {
2471 if (!analyzeLoop(block)) {
2472 return false;
2473 }
2474 }
2475
2476 // First pass at collecting range info - while the beta nodes are still
2477 // around and before truncation.
2478 for (MInstructionIterator iter(block->begin()); iter != block->end();
2479 iter++) {
2480 iter->collectRangeInfoPreTrunc();
2481 }
2482 }
2483
2484 return true;
2485}
2486
2487bool RangeAnalysis::addRangeAssertions() {
2488 if (!JitOptions.checkRangeAnalysis) {
2489 return true;
2490 }
2491
2492 // Check the computed range for this instruction, if the option is set. Note
2493 // that this code is quite invasive; it adds numerous additional
2494 // instructions for each MInstruction with a computed range, and it uses
2495 // registers, so it also affects register allocation.
2496 for (ReversePostorderIterator iter(graph_.rpoBegin());
2497 iter != graph_.rpoEnd(); iter++) {
2498 MBasicBlock* block = *iter;
2499
2500 // Do not add assertions in unreachable blocks.
2501 if (block->unreachable()) {
2502 continue;
2503 }
2504
2505 for (MDefinitionIterator iter(block); iter; iter++) {
2506 MDefinition* ins = *iter;
2507
2508 // Perform range checking for all numeric and numeric-like types.
2509 if (!IsNumberType(ins->type()) && ins->type() != MIRType::Boolean &&
2510 ins->type() != MIRType::Value) {
2511 continue;
2512 }
2513
2514 // MIsNoIter is fused with the MTest that follows it and emitted as
2515 // LIsNoIterAndBranch. Similarly, MIteratorHasIndices is fused to
2516 // become LIteratorHasIndicesAndBranch and IteratorsMatchAndHaveIndices
2517 // becomes LIteratorsMatchAndHaveIndicesAndBranch. Skip them to avoid
2518 // complicating lowering.
2519 if (ins->isIsNoIter() || ins->isIteratorHasIndices() ||
2520 ins->isIteratorsMatchAndHaveIndices()) {
2521 MOZ_ASSERT(ins->hasOneUse())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->hasOneUse())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->hasOneUse()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("ins->hasOneUse()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2521); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ins->hasOneUse()" ")"); do { MOZ_CrashSequence
(__null, 2521); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2522 continue;
2523 }
2524
2525 Range r(ins);
2526
2527 MOZ_ASSERT_IF(ins->type() == MIRType::Int64, r.isUnknown())do { if (ins->type() == MIRType::Int64) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(r.isUnknown
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(r.isUnknown()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("r.isUnknown()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r.isUnknown()"
")"); do { MOZ_CrashSequence(__null, 2527); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2528
2529 // Don't insert assertions if there's nothing interesting to assert.
2530 if (r.isUnknown() ||
2531 (ins->type() == MIRType::Int32 && r.isUnknownInt32())) {
2532 continue;
2533 }
2534
2535 // Don't add a use to an instruction that is recovered on bailout.
2536 if (ins->isRecoveredOnBailout()) {
2537 continue;
2538 }
2539
2540 if (!alloc().ensureBallast()) {
2541 return false;
2542 }
2543 MAssertRange* guard =
2544 MAssertRange::New(alloc(), ins, new (alloc()) Range(r));
2545
2546 // Beta nodes and interrupt checks are required to be located at the
2547 // beginnings of basic blocks, so we must insert range assertions
2548 // after any such instructions.
2549 MInstruction* insertAt = nullptr;
2550 if (block->graph().osrBlock() == block) {
2551 insertAt = ins->toInstruction();
2552 } else {
2553 insertAt = block->safeInsertTop(ins);
2554 }
2555
2556 if (insertAt == *iter) {
2557 block->insertAfter(insertAt, guard);
2558 } else {
2559 block->insertBefore(insertAt, guard);
2560 }
2561 }
2562 }
2563
2564 return true;
2565}
2566
2567///////////////////////////////////////////////////////////////////////////////
2568// Range based Truncation
2569///////////////////////////////////////////////////////////////////////////////
2570
2571void Range::clampToInt32() {
2572 if (isInt32()) {
2573 return;
2574 }
2575 int32_t l = hasInt32LowerBound() ? lower() : JSVAL_INT_MIN((int32_t)0x80000000);
2576 int32_t h = hasInt32UpperBound() ? upper() : JSVAL_INT_MAX((int32_t)0x7fffffff);
2577 setInt32(l, h);
2578}
2579
2580void Range::wrapAroundToInt32() {
2581 if (!hasInt32Bounds()) {
2582 setInt32(JSVAL_INT_MIN((int32_t)0x80000000), JSVAL_INT_MAX((int32_t)0x7fffffff));
2583 } else if (canHaveFractionalPart()) {
2584 // Clearing the fractional field may provide an opportunity to refine
2585 // lower_ or upper_.
2586 canHaveFractionalPart_ = ExcludesFractionalParts;
2587 canBeNegativeZero_ = ExcludesNegativeZero;
2588 refineInt32BoundsByExponent(max_exponent_, &lower_, &hasInt32LowerBound_,
2589 &upper_, &hasInt32UpperBound_);
2590
2591 assertInvariants();
2592 } else {
2593 // If nothing else, we can clear the negative zero flag.
2594 canBeNegativeZero_ = ExcludesNegativeZero;
2595 }
2596 MOZ_ASSERT(isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isInt32()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isInt32()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2596); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInt32()" ")"
); do { MOZ_CrashSequence(__null, 2596); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2597}
2598
2599void Range::wrapAroundToShiftCount() {
2600 wrapAroundToInt32();
2601 if (lower() < 0 || upper() >= 32) {
2602 setInt32(0, 31);
2603 }
2604}
2605
2606void Range::wrapAroundToBoolean() {
2607 wrapAroundToInt32();
2608 if (!isBoolean()) {
2609 setInt32(0, 1);
2610 }
2611 MOZ_ASSERT(isBoolean())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isBoolean())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isBoolean()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("isBoolean()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2611); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isBoolean()"
")"); do { MOZ_CrashSequence(__null, 2611); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2612}
2613
2614bool MDefinition::canTruncate() const {
2615 // No procedure defined for truncating this instruction.
2616 return false;
2617}
2618
2619void MDefinition::truncate(TruncateKind kind) {
2620 MOZ_CRASH("No procedure defined for truncating this instruction.")do { do { } while (false); MOZ_ReportCrash("" "No procedure defined for truncating this instruction."
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2620); AnnotateMozCrashReason
("MOZ_CRASH(" "No procedure defined for truncating this instruction."
")"); do { MOZ_CrashSequence(__null, 2620); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2621}
2622
2623bool MConstant::canTruncate() const { return IsFloatingPointType(type()); }
2624
2625void MConstant::truncate(TruncateKind kind) {
2626 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2626); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2626); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2627
2628 // Truncate the double to int, since all uses truncates it.
2629 int32_t res = ToInt32(numberToDouble());
2630 payload_.asBits = 0;
2631 payload_.i32 = res;
2632 setResultType(MIRType::Int32);
2633 if (range()) {
2634 range()->setInt32(res, res);
2635 }
2636}
2637
2638bool MPhi::canTruncate() const {
2639 return type() == MIRType::Double || type() == MIRType::Int32;
2640}
2641
2642void MPhi::truncate(TruncateKind kind) {
2643 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2643); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2643); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2644 truncateKind_ = kind;
2645 setResultType(MIRType::Int32);
2646 if (kind >= TruncateKind::IndirectTruncate && range()) {
2647 range()->wrapAroundToInt32();
2648 }
2649}
2650
2651bool MAdd::canTruncate() const {
2652 return type() == MIRType::Double || type() == MIRType::Int32;
2653}
2654
2655void MAdd::truncate(TruncateKind kind) {
2656 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2656); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2656); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2657
2658 // Remember analysis, needed for fallible checks.
2659 setTruncateKind(kind);
2660
2661 setSpecialization(MIRType::Int32);
2662 if (truncateKind() >= TruncateKind::IndirectTruncate && range()) {
2663 range()->wrapAroundToInt32();
2664 }
2665}
2666
2667bool MSub::canTruncate() const {
2668 return type() == MIRType::Double || type() == MIRType::Int32;
2669}
2670
2671void MSub::truncate(TruncateKind kind) {
2672 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2672); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2672); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2673
2674 // Remember analysis, needed for fallible checks.
2675 setTruncateKind(kind);
2676 setSpecialization(MIRType::Int32);
2677 if (truncateKind() >= TruncateKind::IndirectTruncate && range()) {
2678 range()->wrapAroundToInt32();
2679 }
2680}
2681
2682bool MMul::canTruncate() const {
2683 return type() == MIRType::Double || type() == MIRType::Int32;
2684}
2685
2686void MMul::truncate(TruncateKind kind) {
2687 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2687); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2687); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2688
2689 // Remember analysis, needed for fallible checks.
2690 setTruncateKind(kind);
2691 setSpecialization(MIRType::Int32);
2692 if (truncateKind() >= TruncateKind::IndirectTruncate) {
2693 setCanBeNegativeZero(false);
2694 if (range()) {
2695 range()->wrapAroundToInt32();
2696 }
2697 }
2698}
2699
2700bool MDiv::canTruncate() const {
2701 return type() == MIRType::Double || type() == MIRType::Int32;
2702}
2703
2704void MDiv::truncate(TruncateKind kind) {
2705 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2705); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2705); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2706
2707 // Remember analysis, needed for fallible checks.
2708 setTruncateKind(kind);
2709 setSpecialization(MIRType::Int32);
2710
2711 // Divisions where the lhs and rhs are unsigned and the result is
2712 // truncated can be lowered more efficiently.
2713 if (unsignedOperands()) {
2714 replaceWithUnsignedOperands();
2715 unsigned_ = true;
2716 }
2717}
2718
2719bool MMod::canTruncate() const {
2720 return type() == MIRType::Double || type() == MIRType::Int32;
2721}
2722
2723void MMod::truncate(TruncateKind kind) {
2724 // As for division, handle unsigned modulus with a truncated result.
2725 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2725); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2725); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2726
2727 // Remember analysis, needed for fallible checks.
2728 setTruncateKind(kind);
2729 setSpecialization(MIRType::Int32);
2730
2731 if (unsignedOperands()) {
2732 replaceWithUnsignedOperands();
2733 unsigned_ = true;
2734 }
2735}
2736
2737bool MToDouble::canTruncate() const {
2738 MOZ_ASSERT(type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Double)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Double)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Double"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2738); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { MOZ_CrashSequence
(__null, 2738); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2739 return true;
2740}
2741
2742void MToDouble::truncate(TruncateKind kind) {
2743 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2743); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2743); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2744 setTruncateKind(kind);
2745
2746 // We use the return type to flag that this MToDouble should be replaced by
2747 // a MTruncateToInt32 when modifying the graph.
2748 setResultType(MIRType::Int32);
2749 if (truncateKind() >= TruncateKind::IndirectTruncate) {
2750 if (range()) {
2751 range()->wrapAroundToInt32();
2752 }
2753 }
2754}
2755
2756bool MLimitedTruncate::canTruncate() const { return true; }
2757
2758void MLimitedTruncate::truncate(TruncateKind kind) {
2759 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2759); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2759); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2760 setTruncateKind(kind);
2761 setResultType(MIRType::Int32);
2762 if (kind >= TruncateKind::IndirectTruncate && range()) {
2763 range()->wrapAroundToInt32();
2764 }
2765}
2766
2767bool MCompare::canTruncate() const {
2768 if (!isDoubleComparison()) {
2769 return false;
2770 }
2771
2772 // If both operands are naturally in the int32 range, we can convert from
2773 // a double comparison to being an int32 comparison.
2774 if (!Range(lhs()).isInt32() || !Range(rhs()).isInt32()) {
2775 return false;
2776 }
2777
2778 return true;
2779}
2780
2781void MCompare::truncate(TruncateKind kind) {
2782 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 2782); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2782); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2783 compareType_ = Compare_Int32;
2784
2785 // Truncating the operands won't change their value because we don't force a
2786 // truncation, but it will change their type, which we need because we
2787 // now expect integer inputs.
2788 truncateOperands_ = true;
2789}
2790
2791TruncateKind MDefinition::operandTruncateKind(size_t index) const {
2792 // Generic routine: We don't know anything.
2793 return TruncateKind::NoTruncate;
2794}
2795
2796TruncateKind MPhi::operandTruncateKind(size_t index) const {
2797 // The truncation applied to a phi is effectively applied to the phi's
2798 // operands.
2799 return truncateKind_;
2800}
2801
2802TruncateKind MTruncateToInt32::operandTruncateKind(size_t index) const {
2803 // This operator is an explicit truncate to int32.
2804 return TruncateKind::Truncate;
2805}
2806
2807TruncateKind MBinaryBitwiseInstruction::operandTruncateKind(
2808 size_t index) const {
2809 // The bitwise operators truncate to int32.
2810 return TruncateKind::Truncate;
2811}
2812
2813TruncateKind MLimitedTruncate::operandTruncateKind(size_t index) const {
2814 return std::min(truncateKind(), truncateLimit_);
2815}
2816
2817TruncateKind MAdd::operandTruncateKind(size_t index) const {
2818 // This operator is doing some arithmetic. If its result is truncated,
2819 // it's an indirect truncate for its operands.
2820 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2821}
2822
2823TruncateKind MSub::operandTruncateKind(size_t index) const {
2824 // See the comment in MAdd::operandTruncateKind.
2825 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2826}
2827
2828TruncateKind MMul::operandTruncateKind(size_t index) const {
2829 // See the comment in MAdd::operandTruncateKind.
2830 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2831}
2832
2833TruncateKind MToDouble::operandTruncateKind(size_t index) const {
2834 // MToDouble propagates its truncate kind to its operand.
2835 return truncateKind();
2836}
2837
2838TruncateKind MStoreUnboxedScalar::operandTruncateKind(size_t index) const {
2839 // An integer store truncates the stored value.
2840 return (index == 2 && isIntegerWrite()) ? TruncateKind::Truncate
2841 : TruncateKind::NoTruncate;
2842}
2843
2844TruncateKind MStoreDataViewElement::operandTruncateKind(size_t index) const {
2845 // An integer store truncates the stored value.
2846 return (index == 2 && isIntegerWrite()) ? TruncateKind::Truncate
2847 : TruncateKind::NoTruncate;
2848}
2849
2850TruncateKind MStoreTypedArrayElementHole::operandTruncateKind(
2851 size_t index) const {
2852 // An integer store truncates the stored value.
2853 return (index == 3 && isIntegerWrite()) ? TruncateKind::Truncate
2854 : TruncateKind::NoTruncate;
2855}
2856
2857TruncateKind MTypedArrayFill::operandTruncateKind(size_t index) const {
2858 // An integer store truncates the stored value.
2859 return (index == 1 && isIntegerWrite()) ? TruncateKind::Truncate
2860 : TruncateKind::NoTruncate;
2861}
2862
2863TruncateKind MDiv::operandTruncateKind(size_t index) const {
2864 return std::min(truncateKind(), TruncateKind::TruncateAfterBailouts);
2865}
2866
2867TruncateKind MMod::operandTruncateKind(size_t index) const {
2868 return std::min(truncateKind(), TruncateKind::TruncateAfterBailouts);
2869}
2870
2871TruncateKind MCompare::operandTruncateKind(size_t index) const {
2872 // If we're doing an int32 comparison on operands which were previously
2873 // floating-point, convert them!
2874 MOZ_ASSERT_IF(truncateOperands_, isInt32Comparison())do { if (truncateOperands_) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(isInt32Comparison())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(isInt32Comparison()))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("isInt32Comparison()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInt32Comparison()"
")"); do { MOZ_CrashSequence(__null, 2874); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2875 return truncateOperands_ ? TruncateKind::TruncateAfterBailouts
2876 : TruncateKind::NoTruncate;
2877}
2878
2879static bool TruncateTest(TempAllocator& alloc, const MTest* test) {
2880 // If all possible inputs to the test are either int32 or boolean,
2881 // convert those inputs to int32 so that an int32 test can be performed.
2882
2883 if (test->input()->type() != MIRType::Value) {
2884 return true;
2885 }
2886
2887 if (!test->input()->isPhi() || !test->input()->hasOneDefUse() ||
2888 test->input()->isImplicitlyUsed()) {
2889 return true;
2890 }
2891
2892 MPhi* phi = test->input()->toPhi();
2893 for (size_t i = 0; i < phi->numOperands(); i++) {
2894 MDefinition* def = phi->getOperand(i);
2895 if (!def->isBox()) {
2896 return true;
2897 }
2898 MDefinition* inner = def->getOperand(0);
2899 if (inner->type() != MIRType::Boolean && inner->type() != MIRType::Int32) {
2900 return true;
2901 }
2902 }
2903
2904 for (size_t i = 0; i < phi->numOperands(); i++) {
2905 MDefinition* inner = phi->getOperand(i)->getOperand(0);
2906 if (inner->type() != MIRType::Int32) {
2907 if (!alloc.ensureBallast()) {
2908 return false;
2909 }
2910 MBasicBlock* block = inner->block();
2911 inner = MToNumberInt32::New(alloc, inner);
2912 block->insertBefore(block->lastIns(), inner->toInstruction());
2913 }
2914 MOZ_ASSERT(inner->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inner->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(inner->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("inner->type() == MIRType::Int32", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inner->type() == MIRType::Int32"
")"); do { MOZ_CrashSequence(__null, 2914); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2915 phi->replaceOperand(i, inner);
2916 }
2917
2918 phi->setResultType(MIRType::Int32);
2919 return true;
2920}
2921
2922// Truncating instruction result is an optimization which implies
2923// knowing all uses of an instruction. This implies that if one of
2924// the uses got removed, then Range Analysis is not be allowed to do
2925// any modification which can change the result, especially if the
2926// result can be observed.
2927//
2928// This corner can easily be understood with UCE examples, but it
2929// might also happen with type inference assumptions. Note: Type
2930// inference is implicitly branches where other types might be
2931// flowing into.
2932static bool CloneForDeadBranches(TempAllocator& alloc,
2933 MInstruction* candidate) {
2934 // Compare returns a boolean so it doesn't have to be recovered on bailout
2935 // because the output would remain correct.
2936 if (candidate->isCompare()) {
2937 return true;
2938 }
2939
2940 MOZ_ASSERT(candidate->canClone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(candidate->canClone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(candidate->canClone()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("candidate->canClone()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2940); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "candidate->canClone()" ")"); do { MOZ_CrashSequence
(__null, 2940); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2941 if (!alloc.ensureBallast()) {
2942 return false;
2943 }
2944
2945 MDefinitionVector operands(alloc);
2946 size_t end = candidate->numOperands();
2947 if (!operands.reserve(end)) {
2948 return false;
2949 }
2950 for (size_t i = 0; i < end; ++i) {
2951 operands.infallibleAppend(candidate->getOperand(i));
2952 }
2953
2954 MInstruction* clone = candidate->clone(alloc, operands);
2955 if (!clone) {
2956 return false;
2957 }
2958 clone->setRange(nullptr);
2959
2960 // Set ImplicitlyUsed flag on the cloned instruction in order to chain recover
2961 // instruction for the bailout path.
2962 clone->setImplicitlyUsedUnchecked();
2963
2964 candidate->block()->insertBefore(candidate, clone);
2965
2966 if (!candidate->maybeConstantValue()) {
2967 MOZ_ASSERT(clone->canRecoverOnBailout())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(clone->canRecoverOnBailout())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(clone->canRecoverOnBailout
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("clone->canRecoverOnBailout()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 2967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clone->canRecoverOnBailout()"
")"); do { MOZ_CrashSequence(__null, 2967); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2968 clone->setRecoveredOnBailout();
2969 }
2970
2971 // Replace the candidate by its recovered on bailout clone within recovered
2972 // instructions and resume points operands.
2973 for (MUseIterator i(candidate->usesBegin()); i != candidate->usesEnd();) {
2974 MUse* use = *i++;
2975 MNode* ins = use->consumer();
2976 if (ins->isDefinition() && !ins->toDefinition()->isRecoveredOnBailout()) {
2977 continue;
2978 }
2979
2980 use->replaceProducer(clone);
2981 }
2982
2983 return true;
2984}
2985
2986struct ComputedTruncateKind {
2987 TruncateKind kind = TruncateKind::NoTruncate;
2988 bool shouldClone = false;
2989};
2990
2991// Examine all the users of |candidate| and determine the most aggressive
2992// truncate kind that satisfies all of them.
2993static ComputedTruncateKind ComputeRequestedTruncateKind(
2994 const MDefinition* candidate) {
2995 // Don't call this method when truncation isn't supported, because the result
2996 // isn't used anyway.
2997 MOZ_ASSERT(candidate->canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(candidate->canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(candidate->canTruncate())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("candidate->canTruncate()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 2997); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "candidate->canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2997); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2998
2999 bool isCapturedResult =
3000 false; // Check if used by a recovered instruction or a resume point.
3001 bool isObservableResult =
3002 false; // Check if it can be read from another frame.
3003 bool isRecoverableResult = true; // Check if it can safely be reconstructed.
3004 bool isImplicitlyUsed = candidate->isImplicitlyUsed();
3005 bool hasTryBlock = candidate->block()->graph().hasTryBlock();
3006
3007 TruncateKind kind = TruncateKind::Truncate;
3008 for (MUseIterator use(candidate->usesBegin()); use != candidate->usesEnd();
3009 use++) {
3010 if (use->consumer()->isResumePoint()) {
3011 // Truncation is a destructive optimization, as such, we need to pay
3012 // attention to removed branches and prevent optimization
3013 // destructive optimizations if we have no alternative. (see
3014 // ImplicitlyUsed flag)
3015 isCapturedResult = true;
3016 isObservableResult =
3017 isObservableResult ||
3018 use->consumer()->toResumePoint()->isObservableOperand(*use);
3019 isRecoverableResult =
3020 isRecoverableResult &&
3021 use->consumer()->toResumePoint()->isRecoverableOperand(*use);
3022 continue;
3023 }
3024
3025 MDefinition* consumer = use->consumer()->toDefinition();
3026 if (consumer->isRecoveredOnBailout()) {
3027 isCapturedResult = true;
3028 isImplicitlyUsed = isImplicitlyUsed || consumer->isImplicitlyUsed();
3029 continue;
3030 }
3031
3032 TruncateKind consumerKind =
3033 consumer->operandTruncateKind(consumer->indexOf(*use));
3034 kind = std::min(kind, consumerKind);
3035 if (kind == TruncateKind::NoTruncate) {
3036 break;
3037 }
3038 }
3039
3040 // We cannot do full truncation on guarded instructions.
3041 if (candidate->isGuard() || candidate->isGuardRangeBailouts()) {
3042 kind = std::min(kind, TruncateKind::TruncateAfterBailouts);
3043 }
3044
3045 // If the value naturally produces an int32 value (before bailout checks)
3046 // that needs no conversion, we don't have to worry about resume points
3047 // seeing truncated values.
3048 bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
3049
3050 // If the instruction is explicitly truncated (not indirectly) by all its
3051 // uses and if it is not implicitly used, then we can safely encode its
3052 // truncated result as part of the resume point operands. This is safe,
3053 // because even if we resume with a truncated double, the next baseline
3054 // instruction operating on this instruction is going to be a no-op.
3055 //
3056 // Note, that if the result can be observed from another frame, then this
3057 // optimization is not safe. Similarly, if this function contains a try
3058 // block, the result could be observed from a catch block, which we do
3059 // not compile.
3060 bool safeToConvert = kind == TruncateKind::Truncate && !isImplicitlyUsed &&
3061 !isObservableResult && !hasTryBlock;
3062
3063 // If the candidate instruction appears as operand of a resume point or a
3064 // recover instruction, and we have to truncate its result, then we might
3065 // have to either recover the result during the bailout, or avoid the
3066 // truncation.
3067 bool shouldClone = false;
3068 if (isCapturedResult && needsConversion && !safeToConvert) {
3069 // If the result can be recovered from all the resume points (not needed
3070 // for iterating over the inlined frames), and this instruction can be
3071 // recovered on bailout, then we can clone it and use the cloned
3072 // instruction to encode the recover instruction. Otherwise, we should
3073 // keep the original result and bailout if the value is not in the int32
3074 // range.
3075 if (!JitOptions.disableRecoverIns && isRecoverableResult &&
3076 candidate->canRecoverOnBailout()) {
3077 shouldClone = true;
3078 } else {
3079 kind = std::min(kind, TruncateKind::TruncateAfterBailouts);
3080 }
3081 }
3082
3083 return {kind, shouldClone};
3084}
3085
3086static ComputedTruncateKind ComputeTruncateKind(const MDefinition* candidate) {
3087 // Don't call this method when truncation isn't supported, because the result
3088 // isn't used anyway.
3089 MOZ_ASSERT(candidate->canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(candidate->canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(candidate->canTruncate())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("candidate->canTruncate()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3089); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "candidate->canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 3089); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3090
3091 // Compare operations might coerce its inputs to int32 if the ranges are
3092 // correct. So we do not need to check if all uses are coerced.
3093 if (candidate->isCompare()) {
3094 return {TruncateKind::TruncateAfterBailouts};
3095 }
3096
3097 // Set truncated flag if range analysis ensure that it has no
3098 // rounding errors and no fractional part. Note that we can't use
3099 // the MDefinition Range constructor, because we need to know if
3100 // the value will have rounding errors before any bailout checks.
3101 const Range* r = candidate->range();
3102 bool canHaveRoundingErrors = !r || r->canHaveRoundingErrors();
3103
3104 // Special case integer division and modulo: a/b can be infinite, and a%b
3105 // can be NaN but cannot actually have rounding errors induced by truncation.
3106 if ((candidate->isDiv() || candidate->isMod()) &&
3107 candidate->type() == MIRType::Int32) {
3108 canHaveRoundingErrors = false;
3109 }
3110
3111 if (canHaveRoundingErrors) {
3112 return {TruncateKind::NoTruncate};
3113 }
3114
3115 // Ensure all observable uses are truncated.
3116 return ComputeRequestedTruncateKind(candidate);
3117}
3118
3119static void RemoveTruncatesOnOutput(MDefinition* truncated) {
3120 // Compare returns a boolean so it doesn't have any output truncates.
3121 if (truncated->isCompare()) {
3122 return;
3123 }
3124
3125 MOZ_ASSERT(truncated->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(truncated->type() == MIRType::Int32)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(truncated->type() == MIRType::Int32))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("truncated->type() == MIRType::Int32"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3125); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "truncated->type() == MIRType::Int32" ")"
); do { MOZ_CrashSequence(__null, 3125); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3126 MOZ_ASSERT(Range(truncated).isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(Range(truncated).isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(Range(truncated).isInt32()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("Range(truncated).isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3126); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "Range(truncated).isInt32()" ")"); do { MOZ_CrashSequence
(__null, 3126); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3127
3128 for (MUseDefIterator use(truncated); use; use++) {
3129 MDefinition* def = use.def();
3130 if (!def->isTruncateToInt32() && !def->isToNumberInt32()) {
3131 continue;
3132 }
3133
3134 def->replaceAllUsesWith(truncated);
3135 }
3136}
3137
3138void RangeAnalysis::adjustTruncatedInputs(MDefinition* truncated) {
3139 MBasicBlock* block = truncated->block();
3140 for (size_t i = 0, e = truncated->numOperands(); i < e; i++) {
3141 TruncateKind kind = truncated->operandTruncateKind(i);
3142 if (kind == TruncateKind::NoTruncate) {
3143 continue;
3144 }
3145
3146 MDefinition* input = truncated->getOperand(i);
3147 if (input->type() == MIRType::Int32) {
3148 continue;
3149 }
3150
3151 if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) {
3152 truncated->replaceOperand(i, input->getOperand(0));
3153 } else {
3154 MInstruction* op;
3155 if (kind == TruncateKind::TruncateAfterBailouts) {
3156 MOZ_ASSERT(!mir->outerInfo().hadEagerTruncationBailout())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mir->outerInfo().hadEagerTruncationBailout())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mir->outerInfo().hadEagerTruncationBailout()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!mir->outerInfo().hadEagerTruncationBailout()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3156); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mir->outerInfo().hadEagerTruncationBailout()"
")"); do { MOZ_CrashSequence(__null, 3156); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3157 op = MToNumberInt32::New(alloc(), truncated->getOperand(i));
3158 op->setBailoutKind(BailoutKind::EagerTruncation);
3159 } else {
3160 op = MTruncateToInt32::New(alloc(), truncated->getOperand(i));
3161 }
3162
3163 if (truncated->isPhi()) {
3164 MBasicBlock* pred = block->getPredecessor(i);
3165 pred->insertBefore(pred->lastIns(), op);
3166 } else {
3167 block->insertBefore(truncated->toInstruction(), op);
3168 }
3169 truncated->replaceOperand(i, op);
3170 }
3171 }
3172
3173 if (truncated->isToDouble()) {
3174 truncated->replaceAllUsesWith(truncated->toToDouble()->getOperand(0));
3175 block->discard(truncated->toToDouble());
3176 }
3177}
3178
3179bool RangeAnalysis::canTruncate(const MDefinition* def,
3180 TruncateKind kind) const {
3181 // Don't call this method when truncation isn't supported, because the result
3182 // isn't used anyway.
3183 MOZ_ASSERT(def->canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(def->canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(def->canTruncate()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("def->canTruncate()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3183); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "def->canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 3183); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3184
3185 if (kind == TruncateKind::NoTruncate) {
3186 return false;
3187 }
3188
3189 // Range Analysis is sometimes eager to do optimizations, even if we
3190 // are not able to truncate an instruction. In such case, we
3191 // speculatively compile the instruction to an int32 instruction
3192 // while adding a guard. This is what is implied by
3193 // TruncateAfterBailout.
3194 //
3195 // If a previous compilation was invalidated because a speculative
3196 // truncation bailed out, we no longer attempt to make this kind of
3197 // eager optimization.
3198 if (mir->outerInfo().hadEagerTruncationBailout()) {
3199 if (kind == TruncateKind::TruncateAfterBailouts) {
3200 return false;
3201 }
3202 // MDiv and MMod always require TruncateAfterBailout for their operands.
3203 // See MDiv::operandTruncateKind and MMod::operandTruncateKind.
3204 if (def->isDiv() || def->isMod()) {
3205 return false;
3206 }
3207 }
3208
3209 return true;
3210}
3211
3212// Iterate backward on all instruction and attempt to truncate operations for
3213// each instruction which respect the following list of predicates: Has been
3214// analyzed by range analysis, the range has no rounding errors, all uses cases
3215// are truncating the result.
3216//
3217// If the truncation of the operation is successful, then the instruction is
3218// queue for later updating the graph to restore the type correctness by
3219// converting the operands that need to be truncated.
3220//
3221// We iterate backward because it is likely that a truncated operation truncates
3222// some of its operands.
3223bool RangeAnalysis::truncate() {
3224 JitSpew(JitSpew_Range, "Do range-base truncation (backward loop)");
3225
3226 // Automatic truncation is disabled for wasm because the truncation logic
3227 // is based on IonMonkey which assumes that we can bailout if the truncation
3228 // logic fails. As wasm code has no bailout mechanism, it is safer to avoid
3229 // any automatic truncations.
3230 MOZ_ASSERT(!mir->compilingWasm())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mir->compilingWasm())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mir->compilingWasm()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!mir->compilingWasm()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3230); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mir->compilingWasm()" ")"); do { MOZ_CrashSequence
(__null, 3230); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3231
3232 Vector<MDefinition*, 16, SystemAllocPolicy> worklist;
3233
3234 for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd();
3235 block++) {
3236 if (mir->shouldCancel("RangeAnalysis truncate")) {
3237 return false;
3238 }
3239
3240 for (MInstructionReverseIterator iter(block->rbegin());
3241 iter != block->rend(); iter++) {
3242 if (iter->isRecoveredOnBailout()) {
3243 continue;
3244 }
3245
3246 if (iter->type() == MIRType::None) {
3247 if (iter->isTest()) {
3248 if (!TruncateTest(alloc(), iter->toTest())) {
3249 return false;
3250 }
3251 }
3252 continue;
3253 }
3254
3255 // Remember all bitop instructions for folding after range analysis.
3256 switch (iter->op()) {
3257 case MDefinition::Opcode::BitAnd:
3258 case MDefinition::Opcode::BitOr:
3259 case MDefinition::Opcode::BitXor:
3260 case MDefinition::Opcode::Lsh:
3261 case MDefinition::Opcode::Rsh:
3262 case MDefinition::Opcode::Ursh:
3263 if (!bitops.append(static_cast<MBinaryBitwiseInstruction*>(*iter))) {
3264 return false;
3265 }
3266 break;
3267 default:;
3268 }
3269
3270 // Skip instructions which can't be truncated.
3271 if (!iter->canTruncate()) {
3272 continue;
3273 }
3274
3275 auto [kind, shouldClone] = ComputeTruncateKind(*iter);
3276
3277 // Truncate this instruction if possible.
3278 if (!canTruncate(*iter, kind)) {
3279 continue;
3280 }
3281
3282 SpewTruncate(*iter, kind, shouldClone);
3283
3284 // If needed, clone the current instruction for keeping it for the
3285 // bailout path. This give us the ability to truncate instructions
3286 // even after the removal of branches.
3287 if (shouldClone && !CloneForDeadBranches(alloc(), *iter)) {
3288 return false;
3289 }
3290
3291 // TruncateAfterBailouts keeps the bailout code as-is and
3292 // continues with truncated operations, with the expectation
3293 // that we are unlikely to bail out. If we do bail out, then we
3294 // will set a flag in FinishBailoutToBaseline to prevent eager
3295 // truncation when we recompile, to avoid bailout loops.
3296 if (kind == TruncateKind::TruncateAfterBailouts) {
3297 iter->setBailoutKind(BailoutKind::EagerTruncation);
3298 }
3299
3300 iter->truncate(kind);
3301
3302 // Delay updates of inputs/outputs to avoid creating node which
3303 // would be removed by the truncation of the next operations.
3304 iter->setInWorklist();
3305 if (!worklist.append(*iter)) {
3306 return false;
3307 }
3308 }
3309 for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd());
3310 iter != end; ++iter) {
3311 // Skip phis which can't be truncated.
3312 if (!iter->canTruncate()) {
3313 continue;
3314 }
3315
3316 auto [kind, shouldClone] = ComputeTruncateKind(*iter);
3317
3318 // Truncate this phi if possible.
3319 if (shouldClone || !canTruncate(*iter, kind)) {
3320 continue;
3321 }
3322
3323 SpewTruncate(*iter, kind, shouldClone);
3324
3325 iter->truncate(kind);
3326
3327 // Delay updates of inputs/outputs to avoid creating node which
3328 // would be removed by the truncation of the next operations.
3329 iter->setInWorklist();
3330 if (!worklist.append(*iter)) {
3331 return false;
3332 }
3333 }
3334 }
3335
3336 // Update inputs/outputs of truncated instructions.
3337 JitSpew(JitSpew_Range, "Do graph type fixup (dequeue)");
3338 while (!worklist.empty()) {
3339 if (!alloc().ensureBallast()) {
3340 return false;
3341 }
3342 MDefinition* def = worklist.popCopy();
3343 def->setNotInWorklist();
3344 RemoveTruncatesOnOutput(def);
3345 adjustTruncatedInputs(def);
3346 }
3347
3348 return true;
3349}
3350
3351bool RangeAnalysis::removeUnnecessaryBitops() {
3352 JitSpew(JitSpew_Range, "Begin (removeUnnecessaryBitops)");
3353 // Note: This operation change the semantic of the program in a way which
3354 // uniquely works with Int32, Recover Instructions added by the Sink phase
3355 // expects the MIR Graph to still have a valid flow as-if they were double
3356 // operations instead of Int32 operations. Thus, this phase should be
3357 // executed after the Sink phase, and before DCE.
3358
3359 // Fold any unnecessary bitops in the graph, such as (x | 0) on an integer
3360 // input. This is done after range analysis rather than during GVN as the
3361 // presence of the bitop can change which instructions are truncated.
3362 for (size_t i = 0; i < bitops.length(); i++) {
3363 MBinaryBitwiseInstruction* ins = bitops[i];
3364 if (ins->isRecoveredOnBailout()) {
3365 continue;
3366 }
3367
3368 MDefinition* folded = ins->foldUnnecessaryBitop();
3369 if (folded != ins) {
3370 ins->replaceAllLiveUsesWith(folded);
3371 ins->setRecoveredOnBailout();
3372 }
3373 }
3374
3375 bitops.clear();
3376 return true;
3377}
3378
3379///////////////////////////////////////////////////////////////////////////////
3380// Collect Range information of operands
3381///////////////////////////////////////////////////////////////////////////////
3382
3383void MInArray::collectRangeInfoPreTrunc() {
3384 Range indexRange(index());
3385 if (indexRange.isFiniteNonNegative()) {
3386 needsNegativeIntCheck_ = false;
3387 setNotGuard();
3388 }
3389}
3390
3391void MLoadElementHole::collectRangeInfoPreTrunc() {
3392 Range indexRange(index());
3393 if (indexRange.isFiniteNonNegative()) {
3394 needsNegativeIntCheck_ = false;
3395 setNotGuard();
3396 }
3397}
3398
3399void MInt32ToIntPtr::collectRangeInfoPreTrunc() {
3400 Range inputRange(input());
3401 if (inputRange.isFiniteNonNegative()) {
3402 canBeNegative_ = false;
3403 }
3404}
3405
3406void MClz::collectRangeInfoPreTrunc() {
3407 Range inputRange(input());
3408 if (!inputRange.canBeZero()) {
3409 operandIsNeverZero_ = true;
3410 }
3411}
3412
3413void MCtz::collectRangeInfoPreTrunc() {
3414 Range inputRange(input());
3415 if (!inputRange.canBeZero()) {
3416 operandIsNeverZero_ = true;
3417 }
3418}
3419
3420void MDiv::collectRangeInfoPreTrunc() {
3421 Range lhsRange(lhs());
3422 Range rhsRange(rhs());
3423
3424 // Test if Dividend is non-negative.
3425 if (lhsRange.isFiniteNonNegative()) {
3426 canBeNegativeDividend_ = false;
3427 }
3428
3429 // Try removing divide by zero check.
3430 if (!rhsRange.canBeZero()) {
3431 canBeDivideByZero_ = false;
3432 }
3433
3434 // If lhsRange does not contain INT32_MIN in its range,
3435 // negative overflow check can be skipped.
3436 if (!lhsRange.contains(INT32_MIN(-2147483647-1))) {
3437 canBeNegativeOverflow_ = false;
3438 }
3439
3440 // If rhsRange does not contain -1 likewise.
3441 if (!rhsRange.contains(-1)) {
3442 canBeNegativeOverflow_ = false;
3443 }
3444
3445 // If lhsRange does not contain a zero,
3446 // negative zero check can be skipped.
3447 if (!lhsRange.canBeZero()) {
3448 canBeNegativeZero_ = false;
3449 }
3450
3451 // If rhsRange >= 0 negative zero check can be skipped.
3452 if (rhsRange.isFiniteNonNegative()) {
3453 canBeNegativeZero_ = false;
3454 }
3455
3456 if (type() == MIRType::Int32 && fallible()) {
3457 setGuardRangeBailoutsUnchecked();
3458 }
3459}
3460
3461void MMul::collectRangeInfoPreTrunc() {
3462 Range lhsRange(lhs());
3463 Range rhsRange(rhs());
3464
3465 // If lhsRange contains only positive then we can skip negative zero check.
3466 if (lhsRange.isFiniteNonNegative() && !lhsRange.canBeZero()) {
3467 setCanBeNegativeZero(false);
3468 }
3469
3470 // Likewise rhsRange.
3471 if (rhsRange.isFiniteNonNegative() && !rhsRange.canBeZero()) {
3472 setCanBeNegativeZero(false);
3473 }
3474
3475 // If rhsRange and lhsRange contain Non-negative integers only,
3476 // We skip negative zero check.
3477 if (rhsRange.isFiniteNonNegative() && lhsRange.isFiniteNonNegative()) {
3478 setCanBeNegativeZero(false);
3479 }
3480
3481 // If rhsRange and lhsRange < 0. Then we skip negative zero check.
3482 if (rhsRange.isFiniteNegative() && lhsRange.isFiniteNegative()) {
3483 setCanBeNegativeZero(false);
3484 }
3485}
3486
3487void MMod::collectRangeInfoPreTrunc() {
3488 Range lhsRange(lhs());
3489 Range rhsRange(rhs());
3490 if (lhsRange.isFiniteNonNegative()) {
3491 canBeNegativeDividend_ = false;
3492 }
3493 if (!rhsRange.canBeZero()) {
3494 canBeDivideByZero_ = false;
3495 }
3496 if (type() == MIRType::Int32 && fallible()) {
3497 setGuardRangeBailoutsUnchecked();
3498 }
3499}
3500
3501void MToNumberInt32::collectRangeInfoPreTrunc() {
3502 Range inputRange(input());
3503 if (!inputRange.canBeNegativeZero()) {
3504 needsNegativeZeroCheck_ = false;
3505 }
3506}
3507
3508void MBoundsCheck::collectRangeInfoPreTrunc() {
3509 Range indexRange(index());
3510 Range lengthRange(length());
3511 if (!indexRange.hasInt32LowerBound() || !indexRange.hasInt32UpperBound()) {
3512 return;
3513 }
3514 if (!lengthRange.hasInt32LowerBound() || lengthRange.canBeNaN()) {
3515 return;
3516 }
3517
3518 int64_t indexLower = indexRange.lower();
3519 int64_t indexUpper = indexRange.upper();
3520 int64_t lengthLower = lengthRange.lower();
3521 int64_t min = minimum();
3522 int64_t max = maximum();
3523
3524 if (indexLower + min >= 0 && indexUpper + max < lengthLower) {
3525 fallible_ = false;
3526 }
3527}
3528
3529void MBoundsCheckLower::collectRangeInfoPreTrunc() {
3530 Range indexRange(index());
3531 if (indexRange.hasInt32LowerBound() && indexRange.lower() >= minimum_) {
3532 fallible_ = false;
3533 }
3534}
3535
3536void MCompare::collectRangeInfoPreTrunc() {
3537 if (!Range(lhs()).canBeNaN() && !Range(rhs()).canBeNaN()) {
3538 operandsAreNeverNaN_ = true;
3539 }
3540}
3541
3542void MNot::collectRangeInfoPreTrunc() {
3543 if (!Range(input()).canBeNaN()) {
3544 operandIsNeverNaN_ = true;
3545 }
3546}
3547
3548void MPowHalf::collectRangeInfoPreTrunc() {
3549 Range inputRange(input());
3550 if (!inputRange.canBeInfiniteOrNaN() || inputRange.hasInt32LowerBound()) {
3551 operandIsNeverNegativeInfinity_ = true;
3552 }
3553 if (!inputRange.canBeNegativeZero()) {
3554 operandIsNeverNegativeZero_ = true;
3555 }
3556 if (!inputRange.canBeNaN()) {
3557 operandIsNeverNaN_ = true;
3558 }
3559}
3560
3561void MUrsh::collectRangeInfoPreTrunc() {
3562 if (type() == MIRType::Int64) {
3563 return;
3564 }
3565
3566 Range lhsRange(lhs()), rhsRange(rhs());
3567
3568 // As in MUrsh::computeRange(), convert the inputs.
3569 lhsRange.wrapAroundToInt32();
3570 rhsRange.wrapAroundToShiftCount();
3571
3572 // If the most significant bit of our result is always going to be zero,
3573 // we can optimize by disabling bailout checks for enforcing an int32 range.
3574 if (lhsRange.lower() >= 0 || rhsRange.lower() >= 1) {
3575 bailoutsDisabled_ = true;
3576 }
3577}
3578
3579static bool DoesMaskMatchRange(int32_t mask, const Range& range) {
3580 // Check if range is positive, because the bitand operator in `(-3) & 0xff`
3581 // can't be eliminated.
3582 if (range.lower() >= 0) {
3583 MOZ_ASSERT(range.isInt32())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(range.isInt32())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(range.isInt32()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("range.isInt32()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3583); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "range.isInt32()" ")"); do { MOZ_CrashSequence
(__null, 3583); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3584 // Check that the mask value has all bits set given the range upper bound.
3585 // Note that the upper bound does not have to be exactly the mask value. For
3586 // example, consider `x & 0xfff` where `x` is a uint8. That expression can
3587 // still be optimized to `x`.
3588 int bits = 1 + FloorLog2(uint32_t(range.upper()));
3589 uint32_t maskNeeded = (bits == 32) ? 0xffffffff : (uint32_t(1) << bits) - 1;
3590 if ((mask & maskNeeded) == maskNeeded) {
3591 return true;
3592 }
3593 }
3594
3595 return false;
3596}
3597
3598void MBinaryBitwiseInstruction::collectRangeInfoPreTrunc() {
3599 Range lhsRange(lhs());
3600 Range rhsRange(rhs());
3601
3602 if (lhs()->isConstant() && lhs()->type() == MIRType::Int32 &&
3603 DoesMaskMatchRange(lhs()->toConstant()->toInt32(), rhsRange)) {
3604 maskMatchesRightRange = true;
3605 }
3606
3607 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32 &&
3608 DoesMaskMatchRange(rhs()->toConstant()->toInt32(), lhsRange)) {
3609 maskMatchesLeftRange = true;
3610 }
3611}
3612
3613void MNaNToZero::collectRangeInfoPreTrunc() {
3614 Range inputRange(input());
3615
3616 if (!inputRange.canBeNaN()) {
3617 operandIsNeverNaN_ = true;
3618 }
3619 if (!inputRange.canBeNegativeZero()) {
3620 operandIsNeverNegativeZero_ = true;
3621 }
3622}
3623
3624bool RangeAnalysis::prepareForUCE(bool* shouldRemoveDeadCode) {
3625 *shouldRemoveDeadCode = false;
3626
3627 for (ReversePostorderIterator iter(graph_.rpoBegin());
3628 iter != graph_.rpoEnd(); iter++) {
3629 MBasicBlock* block = *iter;
3630
3631 if (!block->unreachable()) {
3632 continue;
3633 }
3634
3635 // Filter out unreachable fake entries.
3636 if (block->numPredecessors() == 0) {
3637 // Ignore fixup blocks added by the Value Numbering phase, in order
3638 // to keep the dominator tree as-is when we have OSR Block which are
3639 // no longer reachable from the main entry point of the graph.
3640 MOZ_ASSERT(graph_.osrBlock())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(graph_.osrBlock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(graph_.osrBlock()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("graph_.osrBlock()"
, "./../../../../js/src/jit/RangeAnalysis.cpp", 3640); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "graph_.osrBlock()" ")"); do { MOZ_CrashSequence
(__null, 3640); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3641 continue;
3642 }
3643
3644 MControlInstruction* cond = block->getPredecessor(0)->lastIns();
3645 if (!cond->isTest()) {
3646 continue;
3647 }
3648
3649 // Replace the condition of the test control instruction by a constant
3650 // chosen based which of the successors has the unreachable flag which is
3651 // added by MBeta::computeRange on its own block.
3652 MTest* test = cond->toTest();
3653 MDefinition* condition = test->input();
3654
3655 // If the false-branch is unreachable, then the test condition must be true.
3656 // If the true-branch is unreachable, then the test condition must be false.
3657 MOZ_ASSERT(block == test->ifTrue() || block == test->ifFalse())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(block == test->ifTrue() || block == test->ifFalse
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(block == test->ifTrue() || block == test->ifFalse
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("block == test->ifTrue() || block == test->ifFalse()",
"./../../../../js/src/jit/RangeAnalysis.cpp", 3657); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "block == test->ifTrue() || block == test->ifFalse()"
")"); do { MOZ_CrashSequence(__null, 3657); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3658 bool value = block == test->ifFalse();
3659 MConstant* constant =
3660 MConstant::New(alloc().fallible(), BooleanValue(value));
3661 if (!constant) {
3662 return false;
3663 }
3664
3665 condition->setGuardRangeBailoutsUnchecked();
3666
3667 test->block()->insertBefore(test, constant);
3668
3669 test->replaceOperand(0, constant);
3670 JitSpew(JitSpew_Range,
3671 "Update condition of %u to reflect unreachable branches.",
3672 test->id());
3673
3674 *shouldRemoveDeadCode = true;
3675 }
3676
3677 return tryRemovingGuards();
3678}
3679
3680bool RangeAnalysis::tryRemovingGuards() {
3681 MDefinitionVector guards(alloc());
3682
3683 for (ReversePostorderIterator block = graph_.rpoBegin();
3684 block != graph_.rpoEnd(); block++) {
3685 if (mir->shouldCancel("RangeAnalysis tryRemovingGuards (block loop)")) {
3686 return false;
3687 }
3688
3689 for (MDefinitionIterator iter(*block); iter; iter++) {
3690 if (!iter->isGuardRangeBailouts()) {
3691 continue;
3692 }
3693
3694 iter->setInWorklist();
3695 if (!guards.append(*iter)) {
3696 return false;
3697 }
3698 }
3699 }
3700
3701 // Flag all fallible instructions which were indirectly used in the
3702 // computation of the condition, such that we do not ignore
3703 // bailout-paths which are used to shrink the input range of the
3704 // operands of the condition.
3705 for (size_t i = 0; i < guards.length(); i++) {
3706 if (mir->shouldCancel("RangeAnalysis tryRemovingGuards (guards loop)")) {
3707 return false;
3708 }
3709
3710 MDefinition* guard = guards[i];
3711
3712 // If this ins is a guard even without guardRangeBailouts,
3713 // there is no reason in trying to hoist the guardRangeBailouts check.
3714 guard->setNotGuardRangeBailouts();
3715 if (!DeadIfUnused(guard)) {
3716 guard->setGuardRangeBailouts();
3717 continue;
3718 }
3719 guard->setGuardRangeBailouts();
3720
3721 if (!guard->isPhi()) {
3722 if (!guard->range()) {
3723 continue;
3724 }
3725
3726 // Filter the range of the instruction based on its MIRType.
3727 Range typeFilteredRange(guard);
3728
3729 // If the output range is updated by adding the inner range,
3730 // then the MIRType act as an effectful filter. As we do not know if
3731 // this filtered Range might change or not the result of the
3732 // previous comparison, we have to keep this instruction as a guard
3733 // because it has to bailout in order to restrict the Range to its
3734 // MIRType.
3735 if (typeFilteredRange.update(guard->range())) {
3736 continue;
3737 }
3738 }
3739
3740 guard->setNotGuardRangeBailouts();
3741
3742 // Propagate the guard to its operands.
3743 for (size_t op = 0, e = guard->numOperands(); op < e; op++) {
3744 MDefinition* operand = guard->getOperand(op);
3745
3746 // Already marked.
3747 if (operand->isInWorklist()) {
3748 continue;
3749 }
3750
3751 MOZ_ASSERT(!operand->isGuardRangeBailouts())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!operand->isGuardRangeBailouts())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!operand->isGuardRangeBailouts
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!operand->isGuardRangeBailouts()", "./../../../../js/src/jit/RangeAnalysis.cpp"
, 3751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!operand->isGuardRangeBailouts()"
")"); do { MOZ_CrashSequence(__null, 3751); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3752
3753 operand->setInWorklist();
3754 operand->setGuardRangeBailouts();
3755 if (!guards.append(operand)) {
3756 return false;
3757 }
3758 }
3759 }
3760
3761 for (size_t i = 0; i < guards.length(); i++) {
3762 MDefinition* guard = guards[i];
3763 guard->setNotInWorklist();
3764 }
3765
3766 return true;
3767}