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-10-17-231001-351276-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 // Disallow hoisting for loops that have a generator resume dispatch. This
2024 // matches jit::LICM.
2025 if (!mir->compilingWasm() && !mir->outerInfo().hadBoundsCheckBailout() &&
2026 !header->hasGeneratorResumeEntry()) {
2027 // Try to hoist any bounds checks from the loop using symbolic bounds.
2028
2029 Vector<MBoundsCheck*, 0, JitAllocPolicy> hoistedChecks(alloc());
2030
2031 for (ReversePostorderIterator iter(graph_.rpoBegin(header));
2032 iter != graph_.rpoEnd(); iter++) {
2033 if (mir->shouldCancel("RangeAnalysis analyzeLoop")) {
2034 return false;
2035 }
2036
2037 MBasicBlock* block = *iter;
2038 if (!block->isMarked()) {
2039 continue;
2040 }
2041
2042 for (MDefinitionIterator iter(block); iter; iter++) {
2043 MDefinition* def = *iter;
2044 if (def->isBoundsCheck() && def->isMovable()) {
2045 if (!alloc().ensureBallast()) {
2046 return false;
2047 }
2048 if (tryHoistBoundsCheck(header, def->toBoundsCheck())) {
2049 if (!hoistedChecks.append(def->toBoundsCheck())) {
2050 return false;
2051 }
2052 }
2053 }
2054 }
2055 }
2056
2057 // Note: replace all uses of the original bounds check with the
2058 // actual index. This is usually done during bounds check elimination,
2059 // but in this case it's safe to do it here since the load/store is
2060 // definitely not loop-invariant, so we will never move it before
2061 // one of the bounds checks we just added.
2062 for (size_t i = 0; i < hoistedChecks.length(); i++) {
2063 MBoundsCheck* ins = hoistedChecks[i];
2064 ins->replaceAllUsesWith(ins->index());
2065 ins->block()->discard(ins);
2066 }
2067 }
2068
2069 UnmarkLoopBlocks(graph_, header);
2070 return true;
2071}
2072
2073// Unbox beta nodes in order to hoist instruction properly, and not be limited
2074// by the beta nodes which are added after each branch.
2075static inline MDefinition* DefinitionOrBetaInputDefinition(MDefinition* ins) {
2076 while (ins->isBeta()) {
2077 ins = ins->toBeta()->input();
2078 }
2079 return ins;
2080}
2081
2082LoopIterationBound* RangeAnalysis::analyzeLoopIterationCount(
2083 const MBasicBlock* header, const MTest* test, BranchDirection direction) {
2084 SimpleLinearSum lhs(nullptr, 0);
2085 MDefinition* rhs;
2086 bool lessEqual;
2087 if (!ExtractLinearInequality(test, direction, &lhs, &rhs, &lessEqual)) {
2088 return nullptr;
2089 }
2090
2091 // Ensure the rhs is a loop invariant term.
2092 if (rhs && rhs->block()->isMarked()) {
2093 if (lhs.term && lhs.term->block()->isMarked()) {
2094 return nullptr;
2095 }
2096 MDefinition* temp = lhs.term;
2097 lhs.term = rhs;
2098 rhs = temp;
2099 if (!mozilla::SafeSub(0, lhs.constant, &lhs.constant)) {
2100 return nullptr;
2101 }
2102 lessEqual = !lessEqual;
2103 }
2104
2105 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"
, 2105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rhs->block()->isMarked()"
")"); do { MOZ_CrashSequence(__null, 2105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2106
2107 // Ensure the lhs is a phi node from the start of the loop body.
2108 if (!lhs.term || !lhs.term->isPhi() || lhs.term->block() != header) {
2109 return nullptr;
2110 }
2111
2112 // Check that the value of the lhs changes by a constant amount with each
2113 // loop iteration. This requires that the lhs be written in every loop
2114 // iteration with a value that is a constant difference from its value at
2115 // the start of the iteration.
2116
2117 if (lhs.term->toPhi()->numOperands() != 2) {
2118 return nullptr;
2119 }
2120
2121 // The first operand of the phi should be the lhs' value at the start of
2122 // the first executed iteration, and not a value written which could
2123 // replace the second operand below during the middle of execution.
2124 MDefinition* lhsInitial = lhs.term->toPhi()->getLoopPredecessorOperand();
2125 if (lhsInitial->block()->isMarked()) {
2126 return nullptr;
2127 }
2128
2129 // The second operand of the phi should be a value written by an add/sub
2130 // in every loop iteration, i.e. in a block which dominates the backedge.
2131 MDefinition* lhsWrite = DefinitionOrBetaInputDefinition(
2132 lhs.term->toPhi()->getLoopBackedgeOperand());
2133 if (!lhsWrite->isAdd() && !lhsWrite->isSub()) {
2134 return nullptr;
2135 }
2136 if (!lhsWrite->block()->isMarked()) {
2137 return nullptr;
2138 }
2139 MBasicBlock* bb = header->backedge();
2140 for (; bb != lhsWrite->block() && bb != header;
2141 bb = bb->immediateDominator()) {
2142 }
2143 if (bb != lhsWrite->block()) {
2144 return nullptr;
2145 }
2146
2147 SimpleLinearSum lhsModified = ExtractLinearSum(lhsWrite);
2148
2149 // Check that the value of the lhs at the backedge is of the form
2150 // 'old(lhs) + N'. We can be sure that old(lhs) is the value at the start
2151 // of the iteration, and not that written to lhs in a previous iteration,
2152 // as such a previous value could not appear directly in the addition:
2153 // it could not be stored in lhs as the lhs add/sub executes in every
2154 // iteration, and if it were stored in another variable its use here would
2155 // be as an operand to a phi node for that variable.
2156 if (lhsModified.term != lhs.term) {
2157 return nullptr;
2158 }
2159
2160 LinearSum iterationBound(alloc());
2161
2162 if (lhsModified.constant == 1 && !lessEqual) {
2163 // The value of lhs is 'initial(lhs) + iterCount' and this will end
2164 // execution of the loop if 'lhs + lhsN >= rhs'. Thus, an upper bound
2165 // on the number of backedges executed is:
2166 //
2167 // initial(lhs) + iterCount + lhsN == rhs
2168 // iterCount == rhsN - initial(lhs) - lhsN
2169
2170 if (rhs) {
2171 if (!iterationBound.add(rhs, 1)) {
2172 return nullptr;
2173 }
2174 }
2175 if (!iterationBound.add(lhsInitial, -1)) {
2176 return nullptr;
2177 }
2178
2179 int32_t lhsConstant;
2180 if (!mozilla::SafeSub(0, lhs.constant, &lhsConstant)) {
2181 return nullptr;
2182 }
2183 if (!iterationBound.add(lhsConstant)) {
2184 return nullptr;
2185 }
2186 } else if (lhsModified.constant == -1 && lessEqual) {
2187 // The value of lhs is 'initial(lhs) - iterCount'. Similar to the above
2188 // case, an upper bound on the number of backedges executed is:
2189 //
2190 // initial(lhs) - iterCount + lhsN == rhs
2191 // iterCount == initial(lhs) - rhs + lhsN
2192
2193 if (!iterationBound.add(lhsInitial, 1)) {
2194 return nullptr;
2195 }
2196 if (rhs) {
2197 if (!iterationBound.add(rhs, -1)) {
2198 return nullptr;
2199 }
2200 }
2201 if (!iterationBound.add(lhs.constant)) {
2202 return nullptr;
2203 }
2204 } else {
2205 return nullptr;
2206 }
2207
2208 return new (alloc()) LoopIterationBound(test, iterationBound);
2209}
2210
2211void RangeAnalysis::analyzeLoopPhi(const LoopIterationBound* loopBound,
2212 MPhi* phi) {
2213 // Given a bound on the number of backedges taken, compute an upper and
2214 // lower bound for a phi node that may change by a constant amount each
2215 // iteration. Unlike for the case when computing the iteration bound
2216 // itself, the phi does not need to change the same amount every iteration,
2217 // but is required to change at most N and be either nondecreasing or
2218 // nonincreasing.
2219
2220 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", 2220); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "phi->numOperands() == 2" ")"); do { MOZ_CrashSequence
(__null, 2220); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2221
2222 MDefinition* initial = phi->getLoopPredecessorOperand();
2223 if (initial->block()->isMarked()) {
2224 return;
2225 }
2226
2227 SimpleLinearSum modified =
2228 ExtractLinearSum(phi->getLoopBackedgeOperand(), MathSpace::Infinite);
2229
2230 if (modified.term != phi || modified.constant == 0) {
2231 return;
2232 }
2233
2234 if (!phi->range()) {
2235 phi->setRange(new (alloc()) Range(phi));
2236 }
2237
2238 LinearSum initialSum(alloc());
2239 if (!initialSum.add(initial, 1)) {
2240 return;
2241 }
2242
2243 // The phi may change by N each iteration, and is either nondecreasing or
2244 // nonincreasing. initial(phi) is either a lower or upper bound for the
2245 // phi, and initial(phi) + loopBound * N is either an upper or lower bound,
2246 // at all points within the loop, provided that loopBound >= 0.
2247 //
2248 // We are more interested, however, in the bound for phi at points
2249 // dominated by the loop bound's test; if the test dominates e.g. a bounds
2250 // check we want to hoist from the loop, using the value of the phi at the
2251 // head of the loop for this will usually be too imprecise to hoist the
2252 // check. These points will execute only if the backedge executes at least
2253 // one more time (as the test passed and the test dominates the backedge),
2254 // so we know both that loopBound >= 1 and that the phi's value has changed
2255 // at most loopBound - 1 times. Thus, another upper or lower bound for the
2256 // phi is initial(phi) + (loopBound - 1) * N, without requiring us to
2257 // ensure that loopBound >= 0.
2258
2259 LinearSum limitSum(loopBound->boundSum);
2260 if (!limitSum.multiply(modified.constant) || !limitSum.add(initialSum)) {
2261 return;
2262 }
2263
2264 int32_t negativeConstant;
2265 if (!mozilla::SafeSub(0, modified.constant, &negativeConstant) ||
2266 !limitSum.add(negativeConstant)) {
2267 return;
2268 }
2269
2270 Range initRange(initial);
2271 if (modified.constant > 0) {
2272 if (initRange.hasInt32LowerBound()) {
2273 phi->range()->refineLower(initRange.lower());
2274 }
2275 phi->range()->setSymbolicLower(
2276 SymbolicBound::New(alloc(), nullptr, initialSum));
2277 phi->range()->setSymbolicUpper(
2278 SymbolicBound::New(alloc(), loopBound, limitSum));
2279 } else {
2280 if (initRange.hasInt32UpperBound()) {
2281 phi->range()->refineUpper(initRange.upper());
2282 }
2283 phi->range()->setSymbolicUpper(
2284 SymbolicBound::New(alloc(), nullptr, initialSum));
2285 phi->range()->setSymbolicLower(
2286 SymbolicBound::New(alloc(), loopBound, limitSum));
2287 }
2288
2289 JitSpew(JitSpew_Range, "added symbolic range on %u", phi->id());
2290 SpewRange(phi);
2291}
2292
2293// Whether bound is valid at the specified bounds check instruction in a loop,
2294// and may be used to hoist ins.
2295static inline bool SymbolicBoundIsValid(const MBasicBlock* header,
2296 const MBoundsCheck* ins,
2297 const SymbolicBound* bound) {
2298 if (!bound->loop) {
2299 return true;
2300 }
2301 if (ins->block() == header) {
2302 return false;
2303 }
2304 MBasicBlock* bb = ins->block()->immediateDominator();
2305 while (bb != header && bb != bound->loop->test->block()) {
2306 bb = bb->immediateDominator();
2307 }
2308 return bb == bound->loop->test->block();
2309}
2310
2311bool RangeAnalysis::tryHoistBoundsCheck(const MBasicBlock* header,
2312 const MBoundsCheck* ins) {
2313 // The bounds check's length must be loop invariant or a constant.
2314 MDefinition* length = DefinitionOrBetaInputDefinition(ins->length());
2315 if (length->block()->isMarked() && !length->isConstant()) {
2316 return false;
2317 }
2318
2319 // The bounds check's index should not be loop invariant (else we would
2320 // already have hoisted it during LICM).
2321 SimpleLinearSum index = ExtractLinearSum(ins->index());
2322 if (!index.term || !index.term->block()->isMarked()) {
2323 return false;
2324 }
2325
2326 // Check for a symbolic lower and upper bound on the index. If either
2327 // condition depends on an iteration bound for the loop, only hoist if
2328 // the bounds check is dominated by the iteration bound's test.
2329 if (!index.term->range()) {
2330 return false;
2331 }
2332 const SymbolicBound* lower = index.term->range()->symbolicLower();
2333 if (!lower || !SymbolicBoundIsValid(header, ins, lower)) {
2334 return false;
2335 }
2336 const SymbolicBound* upper = index.term->range()->symbolicUpper();
2337 if (!upper || !SymbolicBoundIsValid(header, ins, upper)) {
2338 return false;
2339 }
2340
2341 MBasicBlock* preLoop = header->loopPredecessor();
2342 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", 2342); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!preLoop->isMarked()" ")"); do { MOZ_CrashSequence
(__null, 2342); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2343
2344 MDefinition* lowerTerm = ConvertLinearSum(alloc(), preLoop, lower->sum,
2345 BailoutKind::HoistBoundsCheck);
2346 if (!lowerTerm) {
2347 return false;
2348 }
2349
2350 MDefinition* upperTerm = ConvertLinearSum(alloc(), preLoop, upper->sum,
2351 BailoutKind::HoistBoundsCheck);
2352 if (!upperTerm) {
2353 return false;
2354 }
2355
2356 // We are checking that index + indexConstant >= 0, and know that
2357 // index >= lowerTerm + lowerConstant. Thus, check that:
2358 //
2359 // lowerTerm + lowerConstant + indexConstant >= 0
2360 // lowerTerm >= -lowerConstant - indexConstant
2361
2362 int32_t lowerConstant = 0;
2363 if (!mozilla::SafeSub(lowerConstant, index.constant, &lowerConstant)) {
2364 return false;
2365 }
2366 if (!mozilla::SafeSub(lowerConstant, lower->sum.constant(), &lowerConstant)) {
2367 return false;
2368 }
2369
2370 // We are checking that index < boundsLength, and know that
2371 // index <= upperTerm + upperConstant. Thus, check that:
2372 //
2373 // upperTerm + upperConstant < boundsLength
2374
2375 int32_t upperConstant = index.constant;
2376 if (!mozilla::SafeAdd(upper->sum.constant(), upperConstant, &upperConstant)) {
2377 return false;
2378 }
2379
2380 // Hoist the loop invariant lower bounds checks.
2381 MBoundsCheckLower* lowerCheck = MBoundsCheckLower::New(alloc(), lowerTerm);
2382 lowerCheck->setMinimum(lowerConstant);
2383 lowerCheck->computeRange(alloc());
2384 lowerCheck->collectRangeInfoPreTrunc();
2385 lowerCheck->setBailoutKind(BailoutKind::HoistBoundsCheck);
2386 preLoop->insertBefore(preLoop->lastIns(), lowerCheck);
2387
2388 // A common pattern for iterating over typed arrays is this:
2389 //
2390 // for (var i = 0; i < ta.length; i++) {
2391 // use ta[i];
2392 // }
2393 //
2394 // Here |upperTerm| (= ta.length) is a NonNegativeIntPtrToInt32 instruction.
2395 // Unwrap this if |length| is also an IntPtr so that we don't add an
2396 // unnecessary bounds check and Int32ToIntPtr below.
2397 if (upperTerm->isNonNegativeIntPtrToInt32() &&
2398 length->type() == MIRType::IntPtr) {
2399 upperTerm = upperTerm->toNonNegativeIntPtrToInt32()->input();
2400 }
2401
2402 // Hoist the loop invariant upper bounds checks.
2403 if (upperTerm != length || upperConstant >= 0) {
2404 // Hoist the bound check's length if it isn't already loop invariant.
2405 if (length->block()->isMarked()) {
2406 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", 2406); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "length->isConstant()" ")"); do { MOZ_CrashSequence
(__null, 2406); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2407 MInstruction* lengthIns = length->toInstruction();
2408 lengthIns->block()->moveBefore(preLoop->lastIns(), lengthIns);
2409 }
2410
2411 // If the length is IntPtr, convert the upperTerm to that as well for the
2412 // bounds check.
2413 if (length->type() == MIRType::IntPtr &&
2414 upperTerm->type() == MIRType::Int32) {
2415 upperTerm = MInt32ToIntPtr::New(alloc(), upperTerm);
2416 upperTerm->computeRange(alloc());
2417 upperTerm->collectRangeInfoPreTrunc();
2418 preLoop->insertBefore(preLoop->lastIns(), upperTerm->toInstruction());
2419 }
2420
2421 MBoundsCheck* upperCheck = MBoundsCheck::New(alloc(), upperTerm, length);
2422 upperCheck->setMinimum(upperConstant);
2423 upperCheck->setMaximum(upperConstant);
2424 upperCheck->computeRange(alloc());
2425 upperCheck->collectRangeInfoPreTrunc();
2426 upperCheck->setBailoutKind(BailoutKind::HoistBoundsCheck);
2427 preLoop->insertBefore(preLoop->lastIns(), upperCheck);
2428 }
2429
2430 return true;
2431}
2432
2433bool RangeAnalysis::analyze() {
2434 JitSpew(JitSpew_Range, "Doing range propagation");
2435
2436 for (ReversePostorderIterator iter(graph_.rpoBegin());
2437 iter != graph_.rpoEnd(); iter++) {
2438 if (mir->shouldCancel("RangeAnalysis analyze")) {
2439 return false;
2440 }
2441
2442 MBasicBlock* block = *iter;
2443 // No blocks are supposed to be unreachable, except when we have an OSR
2444 // block, in which case the Value Numbering phase add fixup blocks which
2445 // are unreachable.
2446 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", 2446); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!block->unreachable() || graph_.osrBlock()"
")"); do { MOZ_CrashSequence(__null, 2446); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2447
2448 // If the block's immediate dominator is unreachable, the block is
2449 // unreachable. Iterating in RPO, we'll always see the immediate
2450 // dominator before the block.
2451 if (block->immediateDominator()->unreachable()) {
2452 block->setUnreachableUnchecked();
2453 continue;
2454 }
2455
2456 for (MDefinitionIterator iter(block); iter; iter++) {
2457 MDefinition* def = *iter;
2458 if (!alloc().ensureBallast()) {
2459 return false;
2460 }
2461
2462 def->computeRange(alloc());
2463 JitSpew(JitSpew_Range, "computing range on %u", def->id());
2464 SpewRange(def);
2465 }
2466
2467 // Beta node range analysis may have marked this block unreachable. If
2468 // so, it's no longer interesting to continue processing it.
2469 if (block->unreachable()) {
2470 continue;
2471 }
2472
2473 if (block->isLoopHeader()) {
2474 if (!analyzeLoop(block)) {
2475 return false;
2476 }
2477 }
2478
2479 // First pass at collecting range info - while the beta nodes are still
2480 // around and before truncation.
2481 for (MInstructionIterator iter(block->begin()); iter != block->end();
2482 iter++) {
2483 iter->collectRangeInfoPreTrunc();
2484 }
2485 }
2486
2487 return true;
2488}
2489
2490bool RangeAnalysis::addRangeAssertions() {
2491 if (!JitOptions.checkRangeAnalysis) {
2492 return true;
2493 }
2494
2495 // Check the computed range for this instruction, if the option is set. Note
2496 // that this code is quite invasive; it adds numerous additional
2497 // instructions for each MInstruction with a computed range, and it uses
2498 // registers, so it also affects register allocation.
2499 for (ReversePostorderIterator iter(graph_.rpoBegin());
2500 iter != graph_.rpoEnd(); iter++) {
2501 MBasicBlock* block = *iter;
2502
2503 // Do not add assertions in unreachable blocks.
2504 if (block->unreachable()) {
2505 continue;
2506 }
2507
2508 for (MDefinitionIterator iter(block); iter; iter++) {
2509 MDefinition* ins = *iter;
2510
2511 // Perform range checking for all numeric and numeric-like types.
2512 if (!IsNumberType(ins->type()) && ins->type() != MIRType::Boolean &&
2513 ins->type() != MIRType::Value) {
2514 continue;
2515 }
2516
2517 // MIsNoIter is fused with the MTest that follows it and emitted as
2518 // LIsNoIterAndBranch. Similarly, MIteratorHasIndices is fused to
2519 // become LIteratorHasIndicesAndBranch and IteratorsMatchAndHaveIndices
2520 // becomes LIteratorsMatchAndHaveIndicesAndBranch. Skip them to avoid
2521 // complicating lowering.
2522 if (ins->isIsNoIter() || ins->isIteratorHasIndices() ||
2523 ins->isIteratorsMatchAndHaveIndices()) {
2524 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", 2524); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "ins->hasOneUse()" ")"); do { MOZ_CrashSequence
(__null, 2524); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2525 continue;
2526 }
2527
2528 Range r(ins);
2529
2530 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"
, 2530); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r.isUnknown()"
")"); do { MOZ_CrashSequence(__null, 2530); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2531
2532 // Don't insert assertions if there's nothing interesting to assert.
2533 if (r.isUnknown() ||
2534 (ins->type() == MIRType::Int32 && r.isUnknownInt32())) {
2535 continue;
2536 }
2537
2538 // Don't add a use to an instruction that is recovered on bailout.
2539 if (ins->isRecoveredOnBailout()) {
2540 continue;
2541 }
2542
2543 if (!alloc().ensureBallast()) {
2544 return false;
2545 }
2546 MAssertRange* guard =
2547 MAssertRange::New(alloc(), ins, new (alloc()) Range(r));
2548
2549 // Beta nodes and interrupt checks are required to be located at the
2550 // beginnings of basic blocks, so we must insert range assertions
2551 // after any such instructions.
2552 MInstruction* insertAt = nullptr;
2553 if (block->graph().osrBlock() == block) {
2554 insertAt = ins->toInstruction();
2555 } else {
2556 insertAt = block->safeInsertTop(ins);
2557 }
2558
2559 if (insertAt == *iter) {
2560 block->insertAfter(insertAt, guard);
2561 } else {
2562 block->insertBefore(insertAt, guard);
2563 }
2564 }
2565 }
2566
2567 return true;
2568}
2569
2570///////////////////////////////////////////////////////////////////////////////
2571// Range based Truncation
2572///////////////////////////////////////////////////////////////////////////////
2573
2574void Range::clampToInt32() {
2575 if (isInt32()) {
2576 return;
2577 }
2578 int32_t l = hasInt32LowerBound() ? lower() : JSVAL_INT_MIN((int32_t)0x80000000);
2579 int32_t h = hasInt32UpperBound() ? upper() : JSVAL_INT_MAX((int32_t)0x7fffffff);
2580 setInt32(l, h);
2581}
2582
2583void Range::wrapAroundToInt32() {
2584 if (!hasInt32Bounds()) {
2585 setInt32(JSVAL_INT_MIN((int32_t)0x80000000), JSVAL_INT_MAX((int32_t)0x7fffffff));
2586 } else if (canHaveFractionalPart()) {
2587 // Clearing the fractional field may provide an opportunity to refine
2588 // lower_ or upper_.
2589 canHaveFractionalPart_ = ExcludesFractionalParts;
2590 canBeNegativeZero_ = ExcludesNegativeZero;
2591 refineInt32BoundsByExponent(max_exponent_, &lower_, &hasInt32LowerBound_,
2592 &upper_, &hasInt32UpperBound_);
2593
2594 assertInvariants();
2595 } else {
2596 // If nothing else, we can clear the negative zero flag.
2597 canBeNegativeZero_ = ExcludesNegativeZero;
2598 }
2599 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"
, 2599); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInt32()" ")"
); do { MOZ_CrashSequence(__null, 2599); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2600}
2601
2602void Range::wrapAroundToShiftCount() {
2603 wrapAroundToInt32();
2604 if (lower() < 0 || upper() >= 32) {
2605 setInt32(0, 31);
2606 }
2607}
2608
2609void Range::wrapAroundToBoolean() {
2610 wrapAroundToInt32();
2611 if (!isBoolean()) {
2612 setInt32(0, 1);
2613 }
2614 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"
, 2614); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isBoolean()"
")"); do { MOZ_CrashSequence(__null, 2614); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2615}
2616
2617bool MDefinition::canTruncate() const {
2618 // No procedure defined for truncating this instruction.
2619 return false;
2620}
2621
2622void MDefinition::truncate(TruncateKind kind) {
2623 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", 2623); AnnotateMozCrashReason
("MOZ_CRASH(" "No procedure defined for truncating this instruction."
")"); do { MOZ_CrashSequence(__null, 2623); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2624}
2625
2626bool MConstant::canTruncate() const { return IsFloatingPointType(type()); }
2627
2628void MConstant::truncate(TruncateKind kind) {
2629 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", 2629); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2629); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2630
2631 // Truncate the double to int, since all uses truncates it.
2632 int32_t res = ToInt32(numberToDouble());
2633 payload_.asBits = 0;
2634 payload_.i32 = res;
2635 setResultType(MIRType::Int32);
2636 if (range()) {
2637 range()->setInt32(res, res);
2638 }
2639}
2640
2641bool MPhi::canTruncate() const {
2642 return type() == MIRType::Double || type() == MIRType::Int32;
2643}
2644
2645void MPhi::truncate(TruncateKind kind) {
2646 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", 2646); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2646); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2647 truncateKind_ = kind;
2648 setResultType(MIRType::Int32);
2649 if (kind >= TruncateKind::IndirectTruncate && range()) {
2650 range()->wrapAroundToInt32();
2651 }
2652}
2653
2654bool MAdd::canTruncate() const {
2655 return type() == MIRType::Double || type() == MIRType::Int32;
2656}
2657
2658void MAdd::truncate(TruncateKind kind) {
2659 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", 2659); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2659); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2660
2661 // Remember analysis, needed for fallible checks.
2662 setTruncateKind(kind);
2663
2664 setSpecialization(MIRType::Int32);
2665 if (truncateKind() >= TruncateKind::IndirectTruncate && range()) {
2666 range()->wrapAroundToInt32();
2667 }
2668}
2669
2670bool MSub::canTruncate() const {
2671 return type() == MIRType::Double || type() == MIRType::Int32;
2672}
2673
2674void MSub::truncate(TruncateKind kind) {
2675 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", 2675); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2675); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2676
2677 // Remember analysis, needed for fallible checks.
2678 setTruncateKind(kind);
2679 setSpecialization(MIRType::Int32);
2680 if (truncateKind() >= TruncateKind::IndirectTruncate && range()) {
2681 range()->wrapAroundToInt32();
2682 }
2683}
2684
2685bool MMul::canTruncate() const {
2686 return type() == MIRType::Double || type() == MIRType::Int32;
2687}
2688
2689void MMul::truncate(TruncateKind kind) {
2690 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", 2690); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2690); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2691
2692 // Remember analysis, needed for fallible checks.
2693 setTruncateKind(kind);
2694 setSpecialization(MIRType::Int32);
2695 if (truncateKind() >= TruncateKind::IndirectTruncate) {
2696 setCanBeNegativeZero(false);
2697 if (range()) {
2698 range()->wrapAroundToInt32();
2699 }
2700 }
2701}
2702
2703bool MDiv::canTruncate() const {
2704 return type() == MIRType::Double || type() == MIRType::Int32;
2705}
2706
2707void MDiv::truncate(TruncateKind kind) {
2708 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", 2708); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2708); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2709
2710 // Remember analysis, needed for fallible checks.
2711 setTruncateKind(kind);
2712 setSpecialization(MIRType::Int32);
2713
2714 // Divisions where the lhs and rhs are unsigned and the result is
2715 // truncated can be lowered more efficiently.
2716 if (unsignedOperands()) {
2717 replaceWithUnsignedOperands();
2718 unsigned_ = true;
2719 }
2720}
2721
2722bool MMod::canTruncate() const {
2723 return type() == MIRType::Double || type() == MIRType::Int32;
2724}
2725
2726void MMod::truncate(TruncateKind kind) {
2727 // As for division, handle unsigned modulus with a truncated result.
2728 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", 2728); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2728); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2729
2730 // Remember analysis, needed for fallible checks.
2731 setTruncateKind(kind);
2732 setSpecialization(MIRType::Int32);
2733
2734 if (unsignedOperands()) {
2735 replaceWithUnsignedOperands();
2736 unsigned_ = true;
2737 }
2738}
2739
2740bool MToDouble::canTruncate() const {
2741 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", 2741); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { MOZ_CrashSequence
(__null, 2741); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2742 return true;
2743}
2744
2745void MToDouble::truncate(TruncateKind kind) {
2746 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", 2746); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2746); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2747 setTruncateKind(kind);
2748
2749 // We use the return type to flag that this MToDouble should be replaced by
2750 // a MTruncateToInt32 when modifying the graph.
2751 setResultType(MIRType::Int32);
2752 if (truncateKind() >= TruncateKind::IndirectTruncate) {
2753 if (range()) {
2754 range()->wrapAroundToInt32();
2755 }
2756 }
2757}
2758
2759bool MLimitedTruncate::canTruncate() const { return true; }
2760
2761void MLimitedTruncate::truncate(TruncateKind kind) {
2762 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", 2762); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2762); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2763 setTruncateKind(kind);
2764 setResultType(MIRType::Int32);
2765 if (kind >= TruncateKind::IndirectTruncate && range()) {
2766 range()->wrapAroundToInt32();
2767 }
2768}
2769
2770bool MCompare::canTruncate() const {
2771 if (!isDoubleComparison()) {
2772 return false;
2773 }
2774
2775 // If both operands are naturally in the int32 range, we can convert from
2776 // a double comparison to being an int32 comparison.
2777 if (!Range(lhs()).isInt32() || !Range(rhs()).isInt32()) {
2778 return false;
2779 }
2780
2781 return true;
2782}
2783
2784void MCompare::truncate(TruncateKind kind) {
2785 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", 2785); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 2785); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2786 compareType_ = Compare_Int32;
2787
2788 // Truncating the operands won't change their value because we don't force a
2789 // truncation, but it will change their type, which we need because we
2790 // now expect integer inputs.
2791 truncateOperands_ = true;
2792}
2793
2794TruncateKind MDefinition::operandTruncateKind(size_t index) const {
2795 // Generic routine: We don't know anything.
2796 return TruncateKind::NoTruncate;
2797}
2798
2799TruncateKind MPhi::operandTruncateKind(size_t index) const {
2800 // The truncation applied to a phi is effectively applied to the phi's
2801 // operands.
2802 return truncateKind_;
2803}
2804
2805TruncateKind MTruncateToInt32::operandTruncateKind(size_t index) const {
2806 // This operator is an explicit truncate to int32.
2807 return TruncateKind::Truncate;
2808}
2809
2810TruncateKind MBinaryBitwiseInstruction::operandTruncateKind(
2811 size_t index) const {
2812 // The bitwise operators truncate to int32.
2813 return TruncateKind::Truncate;
2814}
2815
2816TruncateKind MLimitedTruncate::operandTruncateKind(size_t index) const {
2817 return std::min(truncateKind(), truncateLimit_);
2818}
2819
2820TruncateKind MAdd::operandTruncateKind(size_t index) const {
2821 // This operator is doing some arithmetic. If its result is truncated,
2822 // it's an indirect truncate for its operands.
2823 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2824}
2825
2826TruncateKind MSub::operandTruncateKind(size_t index) const {
2827 // See the comment in MAdd::operandTruncateKind.
2828 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2829}
2830
2831TruncateKind MMul::operandTruncateKind(size_t index) const {
2832 // See the comment in MAdd::operandTruncateKind.
2833 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2834}
2835
2836TruncateKind MToDouble::operandTruncateKind(size_t index) const {
2837 // MToDouble propagates its truncate kind to its operand.
2838 return truncateKind();
2839}
2840
2841TruncateKind MStoreUnboxedScalar::operandTruncateKind(size_t index) const {
2842 // An integer store truncates the stored value.
2843 return (index == 2 && isIntegerWrite()) ? TruncateKind::Truncate
2844 : TruncateKind::NoTruncate;
2845}
2846
2847TruncateKind MStoreDataViewElement::operandTruncateKind(size_t index) const {
2848 // An integer store truncates the stored value.
2849 return (index == 2 && isIntegerWrite()) ? TruncateKind::Truncate
2850 : TruncateKind::NoTruncate;
2851}
2852
2853TruncateKind MStoreTypedArrayElementHole::operandTruncateKind(
2854 size_t index) const {
2855 // An integer store truncates the stored value.
2856 return (index == 3 && isIntegerWrite()) ? TruncateKind::Truncate
2857 : TruncateKind::NoTruncate;
2858}
2859
2860TruncateKind MTypedArrayFill::operandTruncateKind(size_t index) const {
2861 // An integer store truncates the stored value.
2862 return (index == 1 && isIntegerWrite()) ? TruncateKind::Truncate
2863 : TruncateKind::NoTruncate;
2864}
2865
2866TruncateKind MDiv::operandTruncateKind(size_t index) const {
2867 return std::min(truncateKind(), TruncateKind::TruncateAfterBailouts);
2868}
2869
2870TruncateKind MMod::operandTruncateKind(size_t index) const {
2871 return std::min(truncateKind(), TruncateKind::TruncateAfterBailouts);
2872}
2873
2874TruncateKind MCompare::operandTruncateKind(size_t index) const {
2875 // If we're doing an int32 comparison on operands which were previously
2876 // floating-point, convert them!
2877 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"
, 2877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInt32Comparison()"
")"); do { MOZ_CrashSequence(__null, 2877); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2878 return truncateOperands_ ? TruncateKind::TruncateAfterBailouts
2879 : TruncateKind::NoTruncate;
2880}
2881
2882static bool TruncateTest(TempAllocator& alloc, const MTest* test) {
2883 // If all possible inputs to the test are either int32 or boolean,
2884 // convert those inputs to int32 so that an int32 test can be performed.
2885
2886 if (test->input()->type() != MIRType::Value) {
2887 return true;
2888 }
2889
2890 if (!test->input()->isPhi() || !test->input()->hasOneDefUse() ||
2891 test->input()->isImplicitlyUsed()) {
2892 return true;
2893 }
2894
2895 MPhi* phi = test->input()->toPhi();
2896 for (size_t i = 0; i < phi->numOperands(); i++) {
2897 MDefinition* def = phi->getOperand(i);
2898 if (!def->isBox()) {
2899 return true;
2900 }
2901 MDefinition* inner = def->getOperand(0);
2902 if (inner->type() != MIRType::Boolean && inner->type() != MIRType::Int32) {
2903 return true;
2904 }
2905 }
2906
2907 for (size_t i = 0; i < phi->numOperands(); i++) {
2908 MDefinition* inner = phi->getOperand(i)->getOperand(0);
2909 if (inner->type() != MIRType::Int32) {
2910 if (!alloc.ensureBallast()) {
2911 return false;
2912 }
2913 MBasicBlock* block = inner->block();
2914 inner = MToNumberInt32::New(alloc, inner);
2915 block->insertBefore(block->lastIns(), inner->toInstruction());
2916 }
2917 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"
, 2917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inner->type() == MIRType::Int32"
")"); do { MOZ_CrashSequence(__null, 2917); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2918 phi->replaceOperand(i, inner);
2919 }
2920
2921 phi->setResultType(MIRType::Int32);
2922 return true;
2923}
2924
2925// Truncating instruction result is an optimization which implies
2926// knowing all uses of an instruction. This implies that if one of
2927// the uses got removed, then Range Analysis is not be allowed to do
2928// any modification which can change the result, especially if the
2929// result can be observed.
2930//
2931// This corner can easily be understood with UCE examples, but it
2932// might also happen with type inference assumptions. Note: Type
2933// inference is implicitly branches where other types might be
2934// flowing into.
2935static bool CloneForDeadBranches(TempAllocator& alloc,
2936 MInstruction* candidate) {
2937 // Compare returns a boolean so it doesn't have to be recovered on bailout
2938 // because the output would remain correct.
2939 if (candidate->isCompare()) {
2940 return true;
2941 }
2942
2943 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", 2943); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "candidate->canClone()" ")"); do { MOZ_CrashSequence
(__null, 2943); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2944 if (!alloc.ensureBallast()) {
2945 return false;
2946 }
2947
2948 MDefinitionVector operands(alloc);
2949 size_t end = candidate->numOperands();
2950 if (!operands.reserve(end)) {
2951 return false;
2952 }
2953 for (size_t i = 0; i < end; ++i) {
2954 operands.infallibleAppend(candidate->getOperand(i));
2955 }
2956
2957 MInstruction* clone = candidate->clone(alloc, operands);
2958 if (!clone) {
2959 return false;
2960 }
2961 clone->setRange(nullptr);
2962
2963 // Set ImplicitlyUsed flag on the cloned instruction in order to chain recover
2964 // instruction for the bailout path.
2965 clone->setImplicitlyUsedUnchecked();
2966
2967 candidate->block()->insertBefore(candidate, clone);
2968
2969 if (!candidate->maybeConstantValue()) {
2970 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"
, 2970); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clone->canRecoverOnBailout()"
")"); do { MOZ_CrashSequence(__null, 2970); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2971 clone->setRecoveredOnBailout();
2972 }
2973
2974 // Replace the candidate by its recovered on bailout clone within recovered
2975 // instructions and resume points operands.
2976 for (MUseIterator i(candidate->usesBegin()); i != candidate->usesEnd();) {
2977 MUse* use = *i++;
2978 MNode* ins = use->consumer();
2979 if (ins->isDefinition() && !ins->toDefinition()->isRecoveredOnBailout()) {
2980 continue;
2981 }
2982
2983 use->replaceProducer(clone);
2984 }
2985
2986 return true;
2987}
2988
2989struct ComputedTruncateKind {
2990 TruncateKind kind = TruncateKind::NoTruncate;
2991 bool shouldClone = false;
2992};
2993
2994// Examine all the users of |candidate| and determine the most aggressive
2995// truncate kind that satisfies all of them.
2996static ComputedTruncateKind ComputeRequestedTruncateKind(
2997 const MDefinition* candidate) {
2998 // Don't call this method when truncation isn't supported, because the result
2999 // isn't used anyway.
3000 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", 3000); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "candidate->canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 3000); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3001
3002 bool isCapturedResult =
3003 false; // Check if used by a recovered instruction or a resume point.
3004 bool isObservableResult =
3005 false; // Check if it can be read from another frame.
3006 bool isRecoverableResult = true; // Check if it can safely be reconstructed.
3007 bool isImplicitlyUsed = candidate->isImplicitlyUsed();
3008 bool hasTryBlock = candidate->block()->graph().hasTryBlock();
3009
3010 TruncateKind kind = TruncateKind::Truncate;
3011 for (MUseIterator use(candidate->usesBegin()); use != candidate->usesEnd();
3012 use++) {
3013 if (use->consumer()->isResumePoint()) {
3014 // Truncation is a destructive optimization, as such, we need to pay
3015 // attention to removed branches and prevent optimization
3016 // destructive optimizations if we have no alternative. (see
3017 // ImplicitlyUsed flag)
3018 isCapturedResult = true;
3019 isObservableResult =
3020 isObservableResult ||
3021 use->consumer()->toResumePoint()->isObservableOperand(*use);
3022 isRecoverableResult =
3023 isRecoverableResult &&
3024 use->consumer()->toResumePoint()->isRecoverableOperand(*use);
3025 continue;
3026 }
3027
3028 MDefinition* consumer = use->consumer()->toDefinition();
3029 if (consumer->isRecoveredOnBailout()) {
3030 isCapturedResult = true;
3031 isImplicitlyUsed = isImplicitlyUsed || consumer->isImplicitlyUsed();
3032 continue;
3033 }
3034
3035 TruncateKind consumerKind =
3036 consumer->operandTruncateKind(consumer->indexOf(*use));
3037 kind = std::min(kind, consumerKind);
3038 if (kind == TruncateKind::NoTruncate) {
3039 break;
3040 }
3041 }
3042
3043 // We cannot do full truncation on guarded instructions.
3044 if (candidate->isGuard() || candidate->isGuardRangeBailouts()) {
3045 kind = std::min(kind, TruncateKind::TruncateAfterBailouts);
3046 }
3047
3048 // If the value naturally produces an int32 value (before bailout checks)
3049 // that needs no conversion, we don't have to worry about resume points
3050 // seeing truncated values.
3051 bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
3052
3053 // If the instruction is explicitly truncated (not indirectly) by all its
3054 // uses and if it is not implicitly used, then we can safely encode its
3055 // truncated result as part of the resume point operands. This is safe,
3056 // because even if we resume with a truncated double, the next baseline
3057 // instruction operating on this instruction is going to be a no-op.
3058 //
3059 // Note, that if the result can be observed from another frame, then this
3060 // optimization is not safe. Similarly, if this function contains a try
3061 // block, the result could be observed from a catch block, which we do
3062 // not compile.
3063 bool safeToConvert = kind == TruncateKind::Truncate && !isImplicitlyUsed &&
3064 !isObservableResult && !hasTryBlock;
3065
3066 // If the candidate instruction appears as operand of a resume point or a
3067 // recover instruction, and we have to truncate its result, then we might
3068 // have to either recover the result during the bailout, or avoid the
3069 // truncation.
3070 bool shouldClone = false;
3071 if (isCapturedResult && needsConversion && !safeToConvert) {
3072 // If the result can be recovered from all the resume points (not needed
3073 // for iterating over the inlined frames), and this instruction can be
3074 // recovered on bailout, then we can clone it and use the cloned
3075 // instruction to encode the recover instruction. Otherwise, we should
3076 // keep the original result and bailout if the value is not in the int32
3077 // range.
3078 if (!JitOptions.disableRecoverIns && isRecoverableResult &&
3079 candidate->canRecoverOnBailout()) {
3080 shouldClone = true;
3081 } else {
3082 kind = std::min(kind, TruncateKind::TruncateAfterBailouts);
3083 }
3084 }
3085
3086 return {kind, shouldClone};
3087}
3088
3089static ComputedTruncateKind ComputeTruncateKind(const MDefinition* candidate) {
3090 // Don't call this method when truncation isn't supported, because the result
3091 // isn't used anyway.
3092 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", 3092); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "candidate->canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 3092); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3093
3094 // Compare operations might coerce its inputs to int32 if the ranges are
3095 // correct. So we do not need to check if all uses are coerced.
3096 if (candidate->isCompare()) {
3097 return {TruncateKind::TruncateAfterBailouts};
3098 }
3099
3100 // Set truncated flag if range analysis ensure that it has no
3101 // rounding errors and no fractional part. Note that we can't use
3102 // the MDefinition Range constructor, because we need to know if
3103 // the value will have rounding errors before any bailout checks.
3104 const Range* r = candidate->range();
3105 bool canHaveRoundingErrors = !r || r->canHaveRoundingErrors();
3106
3107 // Special case integer division and modulo: a/b can be infinite, and a%b
3108 // can be NaN but cannot actually have rounding errors induced by truncation.
3109 if ((candidate->isDiv() || candidate->isMod()) &&
3110 candidate->type() == MIRType::Int32) {
3111 canHaveRoundingErrors = false;
3112 }
3113
3114 if (canHaveRoundingErrors) {
3115 return {TruncateKind::NoTruncate};
3116 }
3117
3118 // Ensure all observable uses are truncated.
3119 return ComputeRequestedTruncateKind(candidate);
3120}
3121
3122static void RemoveTruncatesOnOutput(MDefinition* truncated) {
3123 // Compare returns a boolean so it doesn't have any output truncates.
3124 if (truncated->isCompare()) {
3125 return;
3126 }
3127
3128 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", 3128); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "truncated->type() == MIRType::Int32" ")"
); do { MOZ_CrashSequence(__null, 3128); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3129 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", 3129); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "Range(truncated).isInt32()" ")"); do { MOZ_CrashSequence
(__null, 3129); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3130
3131 for (MUseDefIterator use(truncated); use; use++) {
3132 MDefinition* def = use.def();
3133 if (!def->isTruncateToInt32() && !def->isToNumberInt32()) {
3134 continue;
3135 }
3136
3137 def->replaceAllUsesWith(truncated);
3138 }
3139}
3140
3141void RangeAnalysis::adjustTruncatedInputs(MDefinition* truncated) {
3142 MBasicBlock* block = truncated->block();
3143 for (size_t i = 0, e = truncated->numOperands(); i < e; i++) {
3144 TruncateKind kind = truncated->operandTruncateKind(i);
3145 if (kind == TruncateKind::NoTruncate) {
3146 continue;
3147 }
3148
3149 MDefinition* input = truncated->getOperand(i);
3150 if (input->type() == MIRType::Int32) {
3151 continue;
3152 }
3153
3154 if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) {
3155 truncated->replaceOperand(i, input->getOperand(0));
3156 } else {
3157 MInstruction* op;
3158 if (kind == TruncateKind::TruncateAfterBailouts) {
3159 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", 3159); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mir->outerInfo().hadEagerTruncationBailout()"
")"); do { MOZ_CrashSequence(__null, 3159); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3160 op = MToNumberInt32::New(alloc(), truncated->getOperand(i));
3161 op->setBailoutKind(BailoutKind::EagerTruncation);
3162 } else {
3163 op = MTruncateToInt32::New(alloc(), truncated->getOperand(i));
3164 }
3165
3166 if (truncated->isPhi()) {
3167 MBasicBlock* pred = block->getPredecessor(i);
3168 pred->insertBefore(pred->lastIns(), op);
3169 } else {
3170 block->insertBefore(truncated->toInstruction(), op);
3171 }
3172 truncated->replaceOperand(i, op);
3173 }
3174 }
3175
3176 if (truncated->isToDouble()) {
3177 truncated->replaceAllUsesWith(truncated->toToDouble()->getOperand(0));
3178 block->discard(truncated->toToDouble());
3179 }
3180}
3181
3182bool RangeAnalysis::canTruncate(const MDefinition* def,
3183 TruncateKind kind) const {
3184 // Don't call this method when truncation isn't supported, because the result
3185 // isn't used anyway.
3186 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", 3186); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "def->canTruncate()" ")"); do { MOZ_CrashSequence
(__null, 3186); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3187
3188 if (kind == TruncateKind::NoTruncate) {
3189 return false;
3190 }
3191
3192 // Range Analysis is sometimes eager to do optimizations, even if we
3193 // are not able to truncate an instruction. In such case, we
3194 // speculatively compile the instruction to an int32 instruction
3195 // while adding a guard. This is what is implied by
3196 // TruncateAfterBailout.
3197 //
3198 // If a previous compilation was invalidated because a speculative
3199 // truncation bailed out, we no longer attempt to make this kind of
3200 // eager optimization.
3201 if (mir->outerInfo().hadEagerTruncationBailout()) {
3202 if (kind == TruncateKind::TruncateAfterBailouts) {
3203 return false;
3204 }
3205 // MDiv and MMod always require TruncateAfterBailout for their operands.
3206 // See MDiv::operandTruncateKind and MMod::operandTruncateKind.
3207 if (def->isDiv() || def->isMod()) {
3208 return false;
3209 }
3210 }
3211
3212 return true;
3213}
3214
3215// Iterate backward on all instruction and attempt to truncate operations for
3216// each instruction which respect the following list of predicates: Has been
3217// analyzed by range analysis, the range has no rounding errors, all uses cases
3218// are truncating the result.
3219//
3220// If the truncation of the operation is successful, then the instruction is
3221// queue for later updating the graph to restore the type correctness by
3222// converting the operands that need to be truncated.
3223//
3224// We iterate backward because it is likely that a truncated operation truncates
3225// some of its operands.
3226bool RangeAnalysis::truncate() {
3227 JitSpew(JitSpew_Range, "Do range-base truncation (backward loop)");
3228
3229 // Automatic truncation is disabled for wasm because the truncation logic
3230 // is based on IonMonkey which assumes that we can bailout if the truncation
3231 // logic fails. As wasm code has no bailout mechanism, it is safer to avoid
3232 // any automatic truncations.
3233 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", 3233); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mir->compilingWasm()" ")"); do { MOZ_CrashSequence
(__null, 3233); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3234
3235 Vector<MDefinition*, 16, SystemAllocPolicy> worklist;
3236
3237 for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd();
3238 block++) {
3239 if (mir->shouldCancel("RangeAnalysis truncate")) {
3240 return false;
3241 }
3242
3243 for (MInstructionReverseIterator iter(block->rbegin());
3244 iter != block->rend(); iter++) {
3245 if (iter->isRecoveredOnBailout()) {
3246 continue;
3247 }
3248
3249 if (iter->type() == MIRType::None) {
3250 if (iter->isTest()) {
3251 if (!TruncateTest(alloc(), iter->toTest())) {
3252 return false;
3253 }
3254 }
3255 continue;
3256 }
3257
3258 // Remember all bitop instructions for folding after range analysis.
3259 switch (iter->op()) {
3260 case MDefinition::Opcode::BitAnd:
3261 case MDefinition::Opcode::BitOr:
3262 case MDefinition::Opcode::BitXor:
3263 case MDefinition::Opcode::Lsh:
3264 case MDefinition::Opcode::Rsh:
3265 case MDefinition::Opcode::Ursh:
3266 if (!bitops.append(static_cast<MBinaryBitwiseInstruction*>(*iter))) {
3267 return false;
3268 }
3269 break;
3270 default:;
3271 }
3272
3273 // Skip instructions which can't be truncated.
3274 if (!iter->canTruncate()) {
3275 continue;
3276 }
3277
3278 auto [kind, shouldClone] = ComputeTruncateKind(*iter);
3279
3280 // Truncate this instruction if possible.
3281 if (!canTruncate(*iter, kind)) {
3282 continue;
3283 }
3284
3285 SpewTruncate(*iter, kind, shouldClone);
3286
3287 // If needed, clone the current instruction for keeping it for the
3288 // bailout path. This give us the ability to truncate instructions
3289 // even after the removal of branches.
3290 if (shouldClone && !CloneForDeadBranches(alloc(), *iter)) {
3291 return false;
3292 }
3293
3294 // TruncateAfterBailouts keeps the bailout code as-is and
3295 // continues with truncated operations, with the expectation
3296 // that we are unlikely to bail out. If we do bail out, then we
3297 // will set a flag in FinishBailoutToBaseline to prevent eager
3298 // truncation when we recompile, to avoid bailout loops.
3299 if (kind == TruncateKind::TruncateAfterBailouts) {
3300 iter->setBailoutKind(BailoutKind::EagerTruncation);
3301 }
3302
3303 iter->truncate(kind);
3304
3305 // Delay updates of inputs/outputs to avoid creating node which
3306 // would be removed by the truncation of the next operations.
3307 iter->setInWorklist();
3308 if (!worklist.append(*iter)) {
3309 return false;
3310 }
3311 }
3312 for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd());
3313 iter != end; ++iter) {
3314 // Skip phis which can't be truncated.
3315 if (!iter->canTruncate()) {
3316 continue;
3317 }
3318
3319 auto [kind, shouldClone] = ComputeTruncateKind(*iter);
3320
3321 // Truncate this phi if possible.
3322 if (shouldClone || !canTruncate(*iter, kind)) {
3323 continue;
3324 }
3325
3326 SpewTruncate(*iter, kind, shouldClone);
3327
3328 iter->truncate(kind);
3329
3330 // Delay updates of inputs/outputs to avoid creating node which
3331 // would be removed by the truncation of the next operations.
3332 iter->setInWorklist();
3333 if (!worklist.append(*iter)) {
3334 return false;
3335 }
3336 }
3337 }
3338
3339 // Update inputs/outputs of truncated instructions.
3340 JitSpew(JitSpew_Range, "Do graph type fixup (dequeue)");
3341 while (!worklist.empty()) {
3342 if (!alloc().ensureBallast()) {
3343 return false;
3344 }
3345 MDefinition* def = worklist.popCopy();
3346 def->setNotInWorklist();
3347 RemoveTruncatesOnOutput(def);
3348 adjustTruncatedInputs(def);
3349 }
3350
3351 return true;
3352}
3353
3354bool RangeAnalysis::removeUnnecessaryBitops() {
3355 JitSpew(JitSpew_Range, "Begin (removeUnnecessaryBitops)");
3356 // Note: This operation change the semantic of the program in a way which
3357 // uniquely works with Int32, Recover Instructions added by the Sink phase
3358 // expects the MIR Graph to still have a valid flow as-if they were double
3359 // operations instead of Int32 operations. Thus, this phase should be
3360 // executed after the Sink phase, and before DCE.
3361
3362 // Fold any unnecessary bitops in the graph, such as (x | 0) on an integer
3363 // input. This is done after range analysis rather than during GVN as the
3364 // presence of the bitop can change which instructions are truncated.
3365 for (size_t i = 0; i < bitops.length(); i++) {
3366 MBinaryBitwiseInstruction* ins = bitops[i];
3367 if (ins->isRecoveredOnBailout()) {
3368 continue;
3369 }
3370
3371 MDefinition* folded = ins->foldUnnecessaryBitop();
3372 if (folded != ins) {
3373 ins->replaceAllLiveUsesWith(folded);
3374 ins->setRecoveredOnBailout();
3375 }
3376 }
3377
3378 bitops.clear();
3379 return true;
3380}
3381
3382///////////////////////////////////////////////////////////////////////////////
3383// Collect Range information of operands
3384///////////////////////////////////////////////////////////////////////////////
3385
3386void MInArray::collectRangeInfoPreTrunc() {
3387 Range indexRange(index());
3388 if (indexRange.isFiniteNonNegative()) {
3389 needsNegativeIntCheck_ = false;
3390 setNotGuard();
3391 }
3392}
3393
3394void MLoadElementHole::collectRangeInfoPreTrunc() {
3395 Range indexRange(index());
3396 if (indexRange.isFiniteNonNegative()) {
3397 needsNegativeIntCheck_ = false;
3398 setNotGuard();
3399 }
3400}
3401
3402void MInt32ToIntPtr::collectRangeInfoPreTrunc() {
3403 Range inputRange(input());
3404 if (inputRange.isFiniteNonNegative()) {
3405 canBeNegative_ = false;
3406 }
3407}
3408
3409void MClz::collectRangeInfoPreTrunc() {
3410 Range inputRange(input());
3411 if (!inputRange.canBeZero()) {
3412 operandIsNeverZero_ = true;
3413 }
3414}
3415
3416void MCtz::collectRangeInfoPreTrunc() {
3417 Range inputRange(input());
3418 if (!inputRange.canBeZero()) {
3419 operandIsNeverZero_ = true;
3420 }
3421}
3422
3423void MDiv::collectRangeInfoPreTrunc() {
3424 Range lhsRange(lhs());
3425 Range rhsRange(rhs());
3426
3427 // Test if Dividend is non-negative.
3428 if (lhsRange.isFiniteNonNegative()) {
3429 canBeNegativeDividend_ = false;
3430 }
3431
3432 // Try removing divide by zero check.
3433 if (!rhsRange.canBeZero()) {
3434 canBeDivideByZero_ = false;
3435 }
3436
3437 // If lhsRange does not contain INT32_MIN in its range,
3438 // negative overflow check can be skipped.
3439 if (!lhsRange.contains(INT32_MIN(-2147483647-1))) {
3440 canBeNegativeOverflow_ = false;
3441 }
3442
3443 // If rhsRange does not contain -1 likewise.
3444 if (!rhsRange.contains(-1)) {
3445 canBeNegativeOverflow_ = false;
3446 }
3447
3448 // If lhsRange does not contain a zero,
3449 // negative zero check can be skipped.
3450 if (!lhsRange.canBeZero()) {
3451 canBeNegativeZero_ = false;
3452 }
3453
3454 // If rhsRange >= 0 negative zero check can be skipped.
3455 if (rhsRange.isFiniteNonNegative()) {
3456 canBeNegativeZero_ = false;
3457 }
3458
3459 if (type() == MIRType::Int32 && fallible()) {
3460 setGuardRangeBailoutsUnchecked();
3461 }
3462}
3463
3464void MMul::collectRangeInfoPreTrunc() {
3465 Range lhsRange(lhs());
3466 Range rhsRange(rhs());
3467
3468 // If lhsRange contains only positive then we can skip negative zero check.
3469 if (lhsRange.isFiniteNonNegative() && !lhsRange.canBeZero()) {
3470 setCanBeNegativeZero(false);
3471 }
3472
3473 // Likewise rhsRange.
3474 if (rhsRange.isFiniteNonNegative() && !rhsRange.canBeZero()) {
3475 setCanBeNegativeZero(false);
3476 }
3477
3478 // If rhsRange and lhsRange contain Non-negative integers only,
3479 // We skip negative zero check.
3480 if (rhsRange.isFiniteNonNegative() && lhsRange.isFiniteNonNegative()) {
3481 setCanBeNegativeZero(false);
3482 }
3483
3484 // If rhsRange and lhsRange < 0. Then we skip negative zero check.
3485 if (rhsRange.isFiniteNegative() && lhsRange.isFiniteNegative()) {
3486 setCanBeNegativeZero(false);
3487 }
3488}
3489
3490void MMod::collectRangeInfoPreTrunc() {
3491 Range lhsRange(lhs());
3492 Range rhsRange(rhs());
3493 if (lhsRange.isFiniteNonNegative()) {
3494 canBeNegativeDividend_ = false;
3495 }
3496 if (!rhsRange.canBeZero()) {
3497 canBeDivideByZero_ = false;
3498 }
3499 if (type() == MIRType::Int32 && fallible()) {
3500 setGuardRangeBailoutsUnchecked();
3501 }
3502}
3503
3504void MToNumberInt32::collectRangeInfoPreTrunc() {
3505 Range inputRange(input());
3506 if (!inputRange.canBeNegativeZero()) {
3507 needsNegativeZeroCheck_ = false;
3508 }
3509}
3510
3511void MBoundsCheck::collectRangeInfoPreTrunc() {
3512 Range indexRange(index());
3513 Range lengthRange(length());
3514 if (!indexRange.hasInt32LowerBound() || !indexRange.hasInt32UpperBound()) {
3515 return;
3516 }
3517 if (!lengthRange.hasInt32LowerBound() || lengthRange.canBeNaN()) {
3518 return;
3519 }
3520
3521 int64_t indexLower = indexRange.lower();
3522 int64_t indexUpper = indexRange.upper();
3523 int64_t lengthLower = lengthRange.lower();
3524 int64_t min = minimum();
3525 int64_t max = maximum();
3526
3527 if (indexLower + min >= 0 && indexUpper + max < lengthLower) {
3528 fallible_ = false;
3529 }
3530}
3531
3532void MBoundsCheckLower::collectRangeInfoPreTrunc() {
3533 Range indexRange(index());
3534 if (indexRange.hasInt32LowerBound() && indexRange.lower() >= minimum_) {
3535 fallible_ = false;
3536 }
3537}
3538
3539void MCompare::collectRangeInfoPreTrunc() {
3540 if (!Range(lhs()).canBeNaN() && !Range(rhs()).canBeNaN()) {
3541 operandsAreNeverNaN_ = true;
3542 }
3543}
3544
3545void MNot::collectRangeInfoPreTrunc() {
3546 if (!Range(input()).canBeNaN()) {
3547 operandIsNeverNaN_ = true;
3548 }
3549}
3550
3551void MPowHalf::collectRangeInfoPreTrunc() {
3552 Range inputRange(input());
3553 if (!inputRange.canBeInfiniteOrNaN() || inputRange.hasInt32LowerBound()) {
3554 operandIsNeverNegativeInfinity_ = true;
3555 }
3556 if (!inputRange.canBeNegativeZero()) {
3557 operandIsNeverNegativeZero_ = true;
3558 }
3559 if (!inputRange.canBeNaN()) {
3560 operandIsNeverNaN_ = true;
3561 }
3562}
3563
3564void MUrsh::collectRangeInfoPreTrunc() {
3565 if (type() == MIRType::Int64) {
3566 return;
3567 }
3568
3569 Range lhsRange(lhs()), rhsRange(rhs());
3570
3571 // As in MUrsh::computeRange(), convert the inputs.
3572 lhsRange.wrapAroundToInt32();
3573 rhsRange.wrapAroundToShiftCount();
3574
3575 // If the most significant bit of our result is always going to be zero,
3576 // we can optimize by disabling bailout checks for enforcing an int32 range.
3577 if (lhsRange.lower() >= 0 || rhsRange.lower() >= 1) {
3578 bailoutsDisabled_ = true;
3579 }
3580}
3581
3582static bool DoesMaskMatchRange(int32_t mask, const Range& range) {
3583 // Check if range is positive, because the bitand operator in `(-3) & 0xff`
3584 // can't be eliminated.
3585 if (range.lower() >= 0) {
3586 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", 3586); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "range.isInt32()" ")"); do { MOZ_CrashSequence
(__null, 3586); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3587 // Check that the mask value has all bits set given the range upper bound.
3588 // Note that the upper bound does not have to be exactly the mask value. For
3589 // example, consider `x & 0xfff` where `x` is a uint8. That expression can
3590 // still be optimized to `x`.
3591 int bits = 1 + FloorLog2(uint32_t(range.upper()));
3592 uint32_t maskNeeded = (bits == 32) ? 0xffffffff : (uint32_t(1) << bits) - 1;
3593 if ((mask & maskNeeded) == maskNeeded) {
3594 return true;
3595 }
3596 }
3597
3598 return false;
3599}
3600
3601void MBinaryBitwiseInstruction::collectRangeInfoPreTrunc() {
3602 Range lhsRange(lhs());
3603 Range rhsRange(rhs());
3604
3605 if (lhs()->isConstant() && lhs()->type() == MIRType::Int32 &&
3606 DoesMaskMatchRange(lhs()->toConstant()->toInt32(), rhsRange)) {
3607 maskMatchesRightRange = true;
3608 }
3609
3610 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32 &&
3611 DoesMaskMatchRange(rhs()->toConstant()->toInt32(), lhsRange)) {
3612 maskMatchesLeftRange = true;
3613 }
3614}
3615
3616void MNaNToZero::collectRangeInfoPreTrunc() {
3617 Range inputRange(input());
3618
3619 if (!inputRange.canBeNaN()) {
3620 operandIsNeverNaN_ = true;
3621 }
3622 if (!inputRange.canBeNegativeZero()) {
3623 operandIsNeverNegativeZero_ = true;
3624 }
3625}
3626
3627bool RangeAnalysis::prepareForUCE(bool* shouldRemoveDeadCode) {
3628 *shouldRemoveDeadCode = false;
3629
3630 for (ReversePostorderIterator iter(graph_.rpoBegin());
3631 iter != graph_.rpoEnd(); iter++) {
3632 MBasicBlock* block = *iter;
3633
3634 if (!block->unreachable()) {
3635 continue;
3636 }
3637
3638 // Filter out unreachable fake entries.
3639 if (block->numPredecessors() == 0) {
3640 // Ignore fixup blocks added by the Value Numbering phase, in order
3641 // to keep the dominator tree as-is when we have OSR Block which are
3642 // no longer reachable from the main entry point of the graph.
3643 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", 3643); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "graph_.osrBlock()" ")"); do { MOZ_CrashSequence
(__null, 3643); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3644 continue;
3645 }
3646
3647 MControlInstruction* cond = block->getPredecessor(0)->lastIns();
3648 if (!cond->isTest()) {
3649 continue;
3650 }
3651
3652 // Replace the condition of the test control instruction by a constant
3653 // chosen based which of the successors has the unreachable flag which is
3654 // added by MBeta::computeRange on its own block.
3655 MTest* test = cond->toTest();
3656 MDefinition* condition = test->input();
3657
3658 // If the false-branch is unreachable, then the test condition must be true.
3659 // If the true-branch is unreachable, then the test condition must be false.
3660 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", 3660); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "block == test->ifTrue() || block == test->ifFalse()"
")"); do { MOZ_CrashSequence(__null, 3660); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3661 bool value = block == test->ifFalse();
3662 MConstant* constant =
3663 MConstant::New(alloc().fallible(), BooleanValue(value));
3664 if (!constant) {
3665 return false;
3666 }
3667
3668 condition->setGuardRangeBailoutsUnchecked();
3669
3670 test->block()->insertBefore(test, constant);
3671
3672 test->replaceOperand(0, constant);
3673 JitSpew(JitSpew_Range,
3674 "Update condition of %u to reflect unreachable branches.",
3675 test->id());
3676
3677 *shouldRemoveDeadCode = true;
3678 }
3679
3680 return tryRemovingGuards();
3681}
3682
3683bool RangeAnalysis::tryRemovingGuards() {
3684 MDefinitionVector guards(alloc());
3685
3686 for (ReversePostorderIterator block = graph_.rpoBegin();
3687 block != graph_.rpoEnd(); block++) {
3688 if (mir->shouldCancel("RangeAnalysis tryRemovingGuards (block loop)")) {
3689 return false;
3690 }
3691
3692 for (MDefinitionIterator iter(*block); iter; iter++) {
3693 if (!iter->isGuardRangeBailouts()) {
3694 continue;
3695 }
3696
3697 iter->setInWorklist();
3698 if (!guards.append(*iter)) {
3699 return false;
3700 }
3701 }
3702 }
3703
3704 // Flag all fallible instructions which were indirectly used in the
3705 // computation of the condition, such that we do not ignore
3706 // bailout-paths which are used to shrink the input range of the
3707 // operands of the condition.
3708 for (size_t i = 0; i < guards.length(); i++) {
3709 if (mir->shouldCancel("RangeAnalysis tryRemovingGuards (guards loop)")) {
3710 return false;
3711 }
3712
3713 MDefinition* guard = guards[i];
3714
3715 // If this ins is a guard even without guardRangeBailouts,
3716 // there is no reason in trying to hoist the guardRangeBailouts check.
3717 guard->setNotGuardRangeBailouts();
3718 if (!DeadIfUnused(guard)) {
3719 guard->setGuardRangeBailouts();
3720 continue;
3721 }
3722 guard->setGuardRangeBailouts();
3723
3724 if (!guard->isPhi()) {
3725 if (!guard->range()) {
3726 continue;
3727 }
3728
3729 // Filter the range of the instruction based on its MIRType.
3730 Range typeFilteredRange(guard);
3731
3732 // If the output range is updated by adding the inner range,
3733 // then the MIRType act as an effectful filter. As we do not know if
3734 // this filtered Range might change or not the result of the
3735 // previous comparison, we have to keep this instruction as a guard
3736 // because it has to bailout in order to restrict the Range to its
3737 // MIRType.
3738 if (typeFilteredRange.update(guard->range())) {
3739 continue;
3740 }
3741 }
3742
3743 guard->setNotGuardRangeBailouts();
3744
3745 // Propagate the guard to its operands.
3746 for (size_t op = 0, e = guard->numOperands(); op < e; op++) {
3747 MDefinition* operand = guard->getOperand(op);
3748
3749 // Already marked.
3750 if (operand->isInWorklist()) {
3751 continue;
3752 }
3753
3754 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"
, 3754); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!operand->isGuardRangeBailouts()"
")"); do { MOZ_CrashSequence(__null, 3754); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3755
3756 operand->setInWorklist();
3757 operand->setGuardRangeBailouts();
3758 if (!guards.append(operand)) {
3759 return false;
3760 }
3761 }
3762 }
3763
3764 for (size_t i = 0; i < guards.length(); i++) {
3765 MDefinition* guard = guards[i];
3766 guard->setNotInWorklist();
3767 }
3768
3769 return true;
3770}