Bug Summary

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