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 -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -resource-dir /usr/lib/llvm-18/lib/clang/18 -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/stl_wrappers -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/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../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-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -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-2024-05-16-034744-15991-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 "util/Unicode.h"
25#include "vm/ArgumentsObject.h"
26#include "vm/Float16.h"
27#include "vm/TypedArrayObject.h"
28#include "vm/Uint8Clamped.h"
29
30#include "vm/BytecodeUtil-inl.h"
31
32using namespace js;
33using namespace js::jit;
34
35using JS::GenericNaN;
36using JS::ToInt32;
37using mozilla::Abs;
38using mozilla::CountLeadingZeroes32;
39using mozilla::ExponentComponent;
40using mozilla::FloorLog2;
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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge)) ::
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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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 (std::isnan(d)) {
680 return Range::IncludesInfinityAndNaN;
681 }
682 if (std::isinf(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; __attribute__((nomerge
)) ::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 = std::isnan(l) || l < 0;
730 bool includesPositive = std::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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
1235bool Range::negativeZeroMul(const Range* lhs, const Range* rhs) {
1236 // The result can only be negative zero if both sides are finite and they
1237 // have differing signs.
1238 return (lhs->canHaveSignBitSet() && rhs->canBeFiniteNonNegative()) ||
1239 (rhs->canHaveSignBitSet() && lhs->canBeFiniteNonNegative());
1240}
1241
1242bool Range::update(const Range* other) {
1243 bool changed = lower_ != other->lower_ ||
1244 hasInt32LowerBound_ != other->hasInt32LowerBound_ ||
1245 upper_ != other->upper_ ||
1246 hasInt32UpperBound_ != other->hasInt32UpperBound_ ||
1247 canHaveFractionalPart_ != other->canHaveFractionalPart_ ||
1248 canBeNegativeZero_ != other->canBeNegativeZero_ ||
1249 max_exponent_ != other->max_exponent_;
1250 if (changed) {
1251 lower_ = other->lower_;
1252 hasInt32LowerBound_ = other->hasInt32LowerBound_;
1253 upper_ = other->upper_;
1254 hasInt32UpperBound_ = other->hasInt32UpperBound_;
1255 canHaveFractionalPart_ = other->canHaveFractionalPart_;
1256 canBeNegativeZero_ = other->canBeNegativeZero_;
1257 max_exponent_ = other->max_exponent_;
1258 assertInvariants();
1259 }
1260
1261 return changed;
1262}
1263
1264///////////////////////////////////////////////////////////////////////////////
1265// Range Computation for MIR Nodes
1266///////////////////////////////////////////////////////////////////////////////
1267
1268void MPhi::computeRange(TempAllocator& alloc) {
1269 if (type() != MIRType::Int32 && type() != MIRType::Double) {
1270 return;
1271 }
1272
1273 Range* range = nullptr;
1274 for (size_t i = 0, e = numOperands(); i < e; i++) {
1275 if (getOperand(i)->block()->unreachable()) {
1276 JitSpew(JitSpew_Range, "Ignoring unreachable input %u",
1277 getOperand(i)->id());
1278 continue;
1279 }
1280
1281 // Peek at the pre-bailout range so we can take a short-cut; if any of
1282 // the operands has an unknown range, this phi has an unknown range.
1283 if (!getOperand(i)->range()) {
1284 return;
1285 }
1286
1287 Range input(getOperand(i));
1288
1289 if (range) {
1290 range->unionWith(&input);
1291 } else {
1292 range = new (alloc) Range(input);
1293 }
1294 }
1295
1296 setRange(range);
1297}
1298
1299void MBeta::computeRange(TempAllocator& alloc) {
1300 bool emptyRange = false;
1301
1302 Range opRange(getOperand(0));
1303 Range* range = Range::intersect(alloc, &opRange, comparison_, &emptyRange);
1304 if (emptyRange) {
1305 JitSpew(JitSpew_Range, "Marking block for inst %u unreachable", id());
1306 block()->setUnreachableUnchecked();
1307 } else {
1308 setRange(range);
1309 }
1310}
1311
1312void MConstant::computeRange(TempAllocator& alloc) {
1313 if (isTypeRepresentableAsDouble()) {
1314 double d = numberToDouble();
1315 setRange(Range::NewDoubleSingletonRange(alloc, d));
1316 } else if (type() == MIRType::Boolean) {
1317 bool b = toBoolean();
1318 setRange(Range::NewInt32Range(alloc, b, b));
1319 }
1320}
1321
1322void MCharCodeAt::computeRange(TempAllocator& alloc) {
1323 // ECMA 262 says that the integer will be non-negative and at most 65535.
1324 setRange(Range::NewInt32Range(alloc, 0, unicode::UTF16Max));
1325}
1326
1327void MCodePointAt::computeRange(TempAllocator& alloc) {
1328 setRange(Range::NewInt32Range(alloc, 0, unicode::NonBMPMax));
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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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; __attribute__((nomerge
)) ::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 MBooleanToInt32::computeRange(TempAllocator& alloc) {
1733 setRange(Range::NewUInt32Range(alloc, 0, 1));
1734}
1735
1736void MLimitedTruncate::computeRange(TempAllocator& alloc) {
1737 Range* output = new (alloc) Range(input());
1738 setRange(output);
1739}
1740
1741static Range* GetArrayBufferViewRange(TempAllocator& alloc, Scalar::Type type) {
1742 switch (type) {
1743 case Scalar::Uint8Clamped:
1744 case Scalar::Uint8:
1745 return Range::NewUInt32Range(alloc, 0, UINT8_MAX(255));
1746 case Scalar::Uint16:
1747 return Range::NewUInt32Range(alloc, 0, UINT16_MAX(65535));
1748 case Scalar::Uint32:
1749 return Range::NewUInt32Range(alloc, 0, UINT32_MAX(4294967295U));
1750
1751 case Scalar::Int8:
1752 return Range::NewInt32Range(alloc, INT8_MIN(-128), INT8_MAX(127));
1753 case Scalar::Int16:
1754 return Range::NewInt32Range(alloc, INT16_MIN(-32767-1), INT16_MAX(32767));
1755 case Scalar::Int32:
1756 return Range::NewInt32Range(alloc, INT32_MIN(-2147483647-1), INT32_MAX(2147483647));
1757
1758 case Scalar::BigInt64:
1759 case Scalar::BigUint64:
1760 case Scalar::Int64:
1761 case Scalar::Simd128:
1762 case Scalar::Float16:
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; __attribute__((nomerge
)) ::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 constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1797 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1798 }
1799}
1800
1801void MArrayBufferViewByteOffset::computeRange(TempAllocator& alloc) {
1802 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1803 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1804 }
1805}
1806
1807void MResizableTypedArrayByteOffsetMaybeOutOfBounds::computeRange(
1808 TempAllocator& alloc) {
1809 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1810 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1811 }
1812}
1813
1814void MResizableTypedArrayLength::computeRange(TempAllocator& alloc) {
1815 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1816 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1817 }
1818}
1819
1820void MResizableDataViewByteLength::computeRange(TempAllocator& alloc) {
1821 if constexpr (ArrayBufferObject::ByteLengthLimit <= INT32_MAX(2147483647)) {
1822 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1823 }
1824}
1825
1826void MTypedArrayElementSize::computeRange(TempAllocator& alloc) {
1827 constexpr auto MaxTypedArraySize = sizeof(double);
1828
1829#define ASSERT_MAX_SIZE(_, T, N) \
1830 static_assert(sizeof(T) <= MaxTypedArraySize, \
1831 "unexpected typed array type exceeding 64-bits storage");
1832 JS_FOR_EACH_TYPED_ARRAY(ASSERT_MAX_SIZE)ASSERT_MAX_SIZE(int8_t, int8_t, Int8) ASSERT_MAX_SIZE(uint8_t
, uint8_t, Uint8) ASSERT_MAX_SIZE(int16_t, int16_t, Int16) ASSERT_MAX_SIZE
(uint16_t, uint16_t, Uint16) ASSERT_MAX_SIZE(int32_t, int32_t
, Int32) ASSERT_MAX_SIZE(uint32_t, uint32_t, Uint32) ASSERT_MAX_SIZE
(float, float, Float32) ASSERT_MAX_SIZE(double, double, Float64
) ASSERT_MAX_SIZE(uint8_t, js::uint8_clamped, Uint8Clamped) ASSERT_MAX_SIZE
(int64_t, int64_t, BigInt64) ASSERT_MAX_SIZE(uint64_t, uint64_t
, BigUint64) ASSERT_MAX_SIZE(uint16_t, js::float16, Float16)
1833#undef ASSERT_MAX_SIZE
1834
1835 setRange(Range::NewUInt32Range(alloc, 0, MaxTypedArraySize));
1836}
1837
1838void MStringLength::computeRange(TempAllocator& alloc) {
1839 static_assert(JSString::MAX_LENGTH <= UINT32_MAX(4294967295U),
1840 "NewUInt32Range requires a uint32 value");
1841 setRange(Range::NewUInt32Range(alloc, 0, JSString::MAX_LENGTH));
1842}
1843
1844void MArgumentsLength::computeRange(TempAllocator& alloc) {
1845 // This is is a conservative upper bound on what |TooManyActualArguments|
1846 // checks. If exceeded, Ion will not be entered in the first place.
1847 static_assert(ARGS_LENGTH_MAX <= UINT32_MAX(4294967295U),
1848 "NewUInt32Range requires a uint32 value");
1849 setRange(Range::NewUInt32Range(alloc, 0, ARGS_LENGTH_MAX));
1850}
1851
1852void MBoundsCheck::computeRange(TempAllocator& alloc) {
1853 // Just transfer the incoming index range to the output. The length() is
1854 // also interesting, but it is handled as a bailout check, and we're
1855 // computing a pre-bailout range here.
1856 setRange(new (alloc) Range(index()));
1857}
1858
1859void MSpectreMaskIndex::computeRange(TempAllocator& alloc) {
1860 // Just transfer the incoming index range to the output for now.
1861 setRange(new (alloc) Range(index()));
1862}
1863
1864void MInt32ToIntPtr::computeRange(TempAllocator& alloc) {
1865 setRange(new (alloc) Range(input()));
1866}
1867
1868void MNonNegativeIntPtrToInt32::computeRange(TempAllocator& alloc) {
1869 // We will bail out if the IntPtr value > INT32_MAX.
1870 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1871}
1872
1873void MArrayPush::computeRange(TempAllocator& alloc) {
1874 // MArrayPush returns the new array length. It bails out if the new length
1875 // doesn't fit in an Int32.
1876 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"
, 1876); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 1876; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1877 setRange(Range::NewUInt32Range(alloc, 0, INT32_MAX(2147483647)));
1878}
1879
1880void MMathFunction::computeRange(TempAllocator& alloc) {
1881 Range opRange(getOperand(0));
1882 switch (function()) {
1883 case UnaryMathFunction::SinNative:
1884 case UnaryMathFunction::SinFdlibm:
1885 case UnaryMathFunction::CosNative:
1886 case UnaryMathFunction::CosFdlibm:
1887 if (!opRange.canBeInfiniteOrNaN()) {
1888 setRange(Range::NewDoubleRange(alloc, -1.0, 1.0));
1889 }
1890 break;
1891 default:
1892 break;
1893 }
1894}
1895
1896void MSign::computeRange(TempAllocator& alloc) {
1897 Range opRange(getOperand(0));
1898 setRange(Range::sign(alloc, &opRange));
1899}
1900
1901void MRandom::computeRange(TempAllocator& alloc) {
1902 Range* r = Range::NewDoubleRange(alloc, 0.0, 1.0);
1903
1904 // Random never returns negative zero.
1905 r->refineToExcludeNegativeZero();
1906
1907 setRange(r);
1908}
1909
1910void MNaNToZero::computeRange(TempAllocator& alloc) {
1911 Range other(input());
1912 setRange(Range::NaNToZero(alloc, &other));
1913}
1914
1915///////////////////////////////////////////////////////////////////////////////
1916// Range Analysis
1917///////////////////////////////////////////////////////////////////////////////
1918
1919static BranchDirection NegateBranchDirection(BranchDirection dir) {
1920 return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
1921}
1922
1923bool RangeAnalysis::analyzeLoop(MBasicBlock* header) {
1924 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"
, 1924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "header->hasUniqueBackedge()"
")"); do { *((volatile int*)__null) = 1924; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1925
1926 // Try to compute an upper bound on the number of times the loop backedge
1927 // will be taken. Look for tests that dominate the backedge and which have
1928 // an edge leaving the loop body.
1929 MBasicBlock* backedge = header->backedge();
1930
1931 // Ignore trivial infinite loops.
1932 if (backedge == header) {
1933 return true;
1934 }
1935
1936 bool canOsr;
1937 size_t numBlocks = MarkLoopBlocks(graph_, header, &canOsr);
1938
1939 // Ignore broken loops.
1940 if (numBlocks == 0) {
1941 return true;
1942 }
1943
1944 LoopIterationBound* iterationBound = nullptr;
1945
1946 MBasicBlock* block = backedge;
1947 do {
1948 BranchDirection direction;
1949 MTest* branch = block->immediateDominatorBranch(&direction);
1950
1951 if (block == block->immediateDominator()) {
1952 break;
1953 }
1954
1955 block = block->immediateDominator();
1956
1957 if (branch) {
1958 direction = NegateBranchDirection(direction);
1959 MBasicBlock* otherBlock = branch->branchSuccessor(direction);
1960 if (!otherBlock->isMarked()) {
1961 if (!alloc().ensureBallast()) {
1962 return false;
1963 }
1964 iterationBound = analyzeLoopIterationCount(header, branch, direction);
1965 if (iterationBound) {
1966 break;
1967 }
1968 }
1969 }
1970 } while (block != header);
1971
1972 if (!iterationBound) {
1973 UnmarkLoopBlocks(graph_, header);
1974 return true;
1975 }
1976
1977 if (!loopIterationBounds.append(iterationBound)) {
1978 return false;
1979 }
1980
1981#ifdef DEBUG1
1982 if (JitSpewEnabled(JitSpew_Range)) {
1983 Sprinter sp(GetJitContext()->cx);
1984 if (!sp.init()) {
1985 return false;
1986 }
1987 iterationBound->boundSum.dump(sp);
1988 JS::UniqueChars str = sp.release();
1989 if (!str) {
1990 return false;
1991 }
1992 JitSpew(JitSpew_Range, "computed symbolic bound on backedges: %s",
1993 str.get());
1994 }
1995#endif
1996
1997 // Try to compute symbolic bounds for the phi nodes at the head of this
1998 // loop, expressed in terms of the iteration bound just computed.
1999
2000 for (MPhiIterator iter(header->phisBegin()); iter != header->phisEnd();
2001 iter++) {
2002 analyzeLoopPhi(iterationBound, *iter);
2003 }
2004
2005 if (!mir->compilingWasm() && !mir->outerInfo().hadBoundsCheckBailout()) {
2006 // Try to hoist any bounds checks from the loop using symbolic bounds.
2007
2008 Vector<MBoundsCheck*, 0, JitAllocPolicy> hoistedChecks(alloc());
2009
2010 for (ReversePostorderIterator iter(graph_.rpoBegin(header));
2011 iter != graph_.rpoEnd(); iter++) {
2012 MBasicBlock* block = *iter;
2013 if (!block->isMarked()) {
2014 continue;
2015 }
2016
2017 for (MDefinitionIterator iter(block); iter; iter++) {
2018 MDefinition* def = *iter;
2019 if (def->isBoundsCheck() && def->isMovable()) {
2020 if (!alloc().ensureBallast()) {
2021 return false;
2022 }
2023 if (tryHoistBoundsCheck(header, def->toBoundsCheck())) {
2024 if (!hoistedChecks.append(def->toBoundsCheck())) {
2025 return false;
2026 }
2027 }
2028 }
2029 }
2030 }
2031
2032 // Note: replace all uses of the original bounds check with the
2033 // actual index. This is usually done during bounds check elimination,
2034 // but in this case it's safe to do it here since the load/store is
2035 // definitely not loop-invariant, so we will never move it before
2036 // one of the bounds checks we just added.
2037 for (size_t i = 0; i < hoistedChecks.length(); i++) {
2038 MBoundsCheck* ins = hoistedChecks[i];
2039 ins->replaceAllUsesWith(ins->index());
2040 ins->block()->discard(ins);
2041 }
2042 }
2043
2044 UnmarkLoopBlocks(graph_, header);
2045 return true;
2046}
2047
2048// Unbox beta nodes in order to hoist instruction properly, and not be limited
2049// by the beta nodes which are added after each branch.
2050static inline MDefinition* DefinitionOrBetaInputDefinition(MDefinition* ins) {
2051 while (ins->isBeta()) {
2052 ins = ins->toBeta()->input();
2053 }
2054 return ins;
2055}
2056
2057LoopIterationBound* RangeAnalysis::analyzeLoopIterationCount(
2058 MBasicBlock* header, MTest* test, BranchDirection direction) {
2059 SimpleLinearSum lhs(nullptr, 0);
2060 MDefinition* rhs;
2061 bool lessEqual;
2062 if (!ExtractLinearInequality(test, direction, &lhs, &rhs, &lessEqual)) {
2063 return nullptr;
2064 }
2065
2066 // Ensure the rhs is a loop invariant term.
2067 if (rhs && rhs->block()->isMarked()) {
2068 if (lhs.term && lhs.term->block()->isMarked()) {
2069 return nullptr;
2070 }
2071 MDefinition* temp = lhs.term;
2072 lhs.term = rhs;
2073 rhs = temp;
2074 if (!SafeSub(0, lhs.constant, &lhs.constant)) {
2075 return nullptr;
2076 }
2077 lessEqual = !lessEqual;
2078 }
2079
2080 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"
, 2080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!rhs->block()->isMarked()"
")"); do { *((volatile int*)__null) = 2080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2081
2082 // Ensure the lhs is a phi node from the start of the loop body.
2083 if (!lhs.term || !lhs.term->isPhi() || lhs.term->block() != header) {
2084 return nullptr;
2085 }
2086
2087 // Check that the value of the lhs changes by a constant amount with each
2088 // loop iteration. This requires that the lhs be written in every loop
2089 // iteration with a value that is a constant difference from its value at
2090 // the start of the iteration.
2091
2092 if (lhs.term->toPhi()->numOperands() != 2) {
2093 return nullptr;
2094 }
2095
2096 // The first operand of the phi should be the lhs' value at the start of
2097 // the first executed iteration, and not a value written which could
2098 // replace the second operand below during the middle of execution.
2099 MDefinition* lhsInitial = lhs.term->toPhi()->getLoopPredecessorOperand();
2100 if (lhsInitial->block()->isMarked()) {
2101 return nullptr;
2102 }
2103
2104 // The second operand of the phi should be a value written by an add/sub
2105 // in every loop iteration, i.e. in a block which dominates the backedge.
2106 MDefinition* lhsWrite = DefinitionOrBetaInputDefinition(
2107 lhs.term->toPhi()->getLoopBackedgeOperand());
2108 if (!lhsWrite->isAdd() && !lhsWrite->isSub()) {
2109 return nullptr;
2110 }
2111 if (!lhsWrite->block()->isMarked()) {
2112 return nullptr;
2113 }
2114 MBasicBlock* bb = header->backedge();
2115 for (; bb != lhsWrite->block() && bb != header;
2116 bb = bb->immediateDominator()) {
2117 }
2118 if (bb != lhsWrite->block()) {
2119 return nullptr;
2120 }
2121
2122 SimpleLinearSum lhsModified = ExtractLinearSum(lhsWrite);
2123
2124 // Check that the value of the lhs at the backedge is of the form
2125 // 'old(lhs) + N'. We can be sure that old(lhs) is the value at the start
2126 // of the iteration, and not that written to lhs in a previous iteration,
2127 // as such a previous value could not appear directly in the addition:
2128 // it could not be stored in lhs as the lhs add/sub executes in every
2129 // iteration, and if it were stored in another variable its use here would
2130 // be as an operand to a phi node for that variable.
2131 if (lhsModified.term != lhs.term) {
2132 return nullptr;
2133 }
2134
2135 LinearSum iterationBound(alloc());
2136 LinearSum currentIteration(alloc());
2137
2138 if (lhsModified.constant == 1 && !lessEqual) {
2139 // The value of lhs is 'initial(lhs) + iterCount' and this will end
2140 // execution of the loop if 'lhs + lhsN >= rhs'. Thus, an upper bound
2141 // on the number of backedges executed is:
2142 //
2143 // initial(lhs) + iterCount + lhsN == rhs
2144 // iterCount == rhsN - initial(lhs) - lhsN
2145
2146 if (rhs) {
2147 if (!iterationBound.add(rhs, 1)) {
2148 return nullptr;
2149 }
2150 }
2151 if (!iterationBound.add(lhsInitial, -1)) {
2152 return nullptr;
2153 }
2154
2155 int32_t lhsConstant;
2156 if (!SafeSub(0, lhs.constant, &lhsConstant)) {
2157 return nullptr;
2158 }
2159 if (!iterationBound.add(lhsConstant)) {
2160 return nullptr;
2161 }
2162
2163 if (!currentIteration.add(lhs.term, 1)) {
2164 return nullptr;
2165 }
2166 if (!currentIteration.add(lhsInitial, -1)) {
2167 return nullptr;
2168 }
2169 } else if (lhsModified.constant == -1 && lessEqual) {
2170 // The value of lhs is 'initial(lhs) - iterCount'. Similar to the above
2171 // case, an upper bound on the number of backedges executed is:
2172 //
2173 // initial(lhs) - iterCount + lhsN == rhs
2174 // iterCount == initial(lhs) - rhs + lhsN
2175
2176 if (!iterationBound.add(lhsInitial, 1)) {
2177 return nullptr;
2178 }
2179 if (rhs) {
2180 if (!iterationBound.add(rhs, -1)) {
2181 return nullptr;
2182 }
2183 }
2184 if (!iterationBound.add(lhs.constant)) {
2185 return nullptr;
2186 }
2187
2188 if (!currentIteration.add(lhsInitial, 1)) {
2189 return nullptr;
2190 }
2191 if (!currentIteration.add(lhs.term, -1)) {
2192 return nullptr;
2193 }
2194 } else {
2195 return nullptr;
2196 }
2197
2198 return new (alloc())
2199 LoopIterationBound(header, test, iterationBound, currentIteration);
2200}
2201
2202void RangeAnalysis::analyzeLoopPhi(LoopIterationBound* loopBound, MPhi* phi) {
2203 // Given a bound on the number of backedges taken, compute an upper and
2204 // lower bound for a phi node that may change by a constant amount each
2205 // iteration. Unlike for the case when computing the iteration bound
2206 // itself, the phi does not need to change the same amount every iteration,
2207 // but is required to change at most N and be either nondecreasing or
2208 // nonincreasing.
2209
2210 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"
, 2210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "phi->numOperands() == 2"
")"); do { *((volatile int*)__null) = 2210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2211
2212 MDefinition* initial = phi->getLoopPredecessorOperand();
2213 if (initial->block()->isMarked()) {
2214 return;
2215 }
2216
2217 SimpleLinearSum modified =
2218 ExtractLinearSum(phi->getLoopBackedgeOperand(), MathSpace::Infinite);
2219
2220 if (modified.term != phi || modified.constant == 0) {
2221 return;
2222 }
2223
2224 if (!phi->range()) {
2225 phi->setRange(new (alloc()) Range(phi));
2226 }
2227
2228 LinearSum initialSum(alloc());
2229 if (!initialSum.add(initial, 1)) {
2230 return;
2231 }
2232
2233 // The phi may change by N each iteration, and is either nondecreasing or
2234 // nonincreasing. initial(phi) is either a lower or upper bound for the
2235 // phi, and initial(phi) + loopBound * N is either an upper or lower bound,
2236 // at all points within the loop, provided that loopBound >= 0.
2237 //
2238 // We are more interested, however, in the bound for phi at points
2239 // dominated by the loop bound's test; if the test dominates e.g. a bounds
2240 // check we want to hoist from the loop, using the value of the phi at the
2241 // head of the loop for this will usually be too imprecise to hoist the
2242 // check. These points will execute only if the backedge executes at least
2243 // one more time (as the test passed and the test dominates the backedge),
2244 // so we know both that loopBound >= 1 and that the phi's value has changed
2245 // at most loopBound - 1 times. Thus, another upper or lower bound for the
2246 // phi is initial(phi) + (loopBound - 1) * N, without requiring us to
2247 // ensure that loopBound >= 0.
2248
2249 LinearSum limitSum(loopBound->boundSum);
2250 if (!limitSum.multiply(modified.constant) || !limitSum.add(initialSum)) {
2251 return;
2252 }
2253
2254 int32_t negativeConstant;
2255 if (!SafeSub(0, modified.constant, &negativeConstant) ||
2256 !limitSum.add(negativeConstant)) {
2257 return;
2258 }
2259
2260 Range* initRange = initial->range();
2261 if (modified.constant > 0) {
2262 if (initRange && initRange->hasInt32LowerBound()) {
2263 phi->range()->refineLower(initRange->lower());
2264 }
2265 phi->range()->setSymbolicLower(
2266 SymbolicBound::New(alloc(), nullptr, initialSum));
2267 phi->range()->setSymbolicUpper(
2268 SymbolicBound::New(alloc(), loopBound, limitSum));
2269 } else {
2270 if (initRange && initRange->hasInt32UpperBound()) {
2271 phi->range()->refineUpper(initRange->upper());
2272 }
2273 phi->range()->setSymbolicUpper(
2274 SymbolicBound::New(alloc(), nullptr, initialSum));
2275 phi->range()->setSymbolicLower(
2276 SymbolicBound::New(alloc(), loopBound, limitSum));
2277 }
2278
2279 JitSpew(JitSpew_Range, "added symbolic range on %u", phi->id());
2280 SpewRange(phi);
2281}
2282
2283// Whether bound is valid at the specified bounds check instruction in a loop,
2284// and may be used to hoist ins.
2285static inline bool SymbolicBoundIsValid(MBasicBlock* header, MBoundsCheck* ins,
2286 const SymbolicBound* bound) {
2287 if (!bound->loop) {
2288 return true;
2289 }
2290 if (ins->block() == header) {
2291 return false;
2292 }
2293 MBasicBlock* bb = ins->block()->immediateDominator();
2294 while (bb != header && bb != bound->loop->test->block()) {
2295 bb = bb->immediateDominator();
2296 }
2297 return bb == bound->loop->test->block();
2298}
2299
2300bool RangeAnalysis::tryHoistBoundsCheck(MBasicBlock* header,
2301 MBoundsCheck* ins) {
2302 // The bounds check's length must be loop invariant or a constant.
2303 MDefinition* length = DefinitionOrBetaInputDefinition(ins->length());
2304 if (length->block()->isMarked() && !length->isConstant()) {
2305 return false;
2306 }
2307
2308 // The bounds check's index should not be loop invariant (else we would
2309 // already have hoisted it during LICM).
2310 SimpleLinearSum index = ExtractLinearSum(ins->index());
2311 if (!index.term || !index.term->block()->isMarked()) {
2312 return false;
2313 }
2314
2315 // Check for a symbolic lower and upper bound on the index. If either
2316 // condition depends on an iteration bound for the loop, only hoist if
2317 // the bounds check is dominated by the iteration bound's test.
2318 if (!index.term->range()) {
2319 return false;
2320 }
2321 const SymbolicBound* lower = index.term->range()->symbolicLower();
2322 if (!lower || !SymbolicBoundIsValid(header, ins, lower)) {
2323 return false;
2324 }
2325 const SymbolicBound* upper = index.term->range()->symbolicUpper();
2326 if (!upper || !SymbolicBoundIsValid(header, ins, upper)) {
2327 return false;
2328 }
2329
2330 MBasicBlock* preLoop = header->loopPredecessor();
2331 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"
, 2331); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!preLoop->isMarked()"
")"); do { *((volatile int*)__null) = 2331; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2332
2333 MDefinition* lowerTerm = ConvertLinearSum(alloc(), preLoop, lower->sum,
2334 BailoutKind::HoistBoundsCheck);
2335 if (!lowerTerm) {
2336 return false;
2337 }
2338
2339 MDefinition* upperTerm = ConvertLinearSum(alloc(), preLoop, upper->sum,
2340 BailoutKind::HoistBoundsCheck);
2341 if (!upperTerm) {
2342 return false;
2343 }
2344
2345 // We are checking that index + indexConstant >= 0, and know that
2346 // index >= lowerTerm + lowerConstant. Thus, check that:
2347 //
2348 // lowerTerm + lowerConstant + indexConstant >= 0
2349 // lowerTerm >= -lowerConstant - indexConstant
2350
2351 int32_t lowerConstant = 0;
2352 if (!SafeSub(lowerConstant, index.constant, &lowerConstant)) {
2353 return false;
2354 }
2355 if (!SafeSub(lowerConstant, lower->sum.constant(), &lowerConstant)) {
2356 return false;
2357 }
2358
2359 // We are checking that index < boundsLength, and know that
2360 // index <= upperTerm + upperConstant. Thus, check that:
2361 //
2362 // upperTerm + upperConstant < boundsLength
2363
2364 int32_t upperConstant = index.constant;
2365 if (!SafeAdd(upper->sum.constant(), upperConstant, &upperConstant)) {
2366 return false;
2367 }
2368
2369 // Hoist the loop invariant lower bounds checks.
2370 MBoundsCheckLower* lowerCheck = MBoundsCheckLower::New(alloc(), lowerTerm);
2371 lowerCheck->setMinimum(lowerConstant);
2372 lowerCheck->computeRange(alloc());
2373 lowerCheck->collectRangeInfoPreTrunc();
2374 lowerCheck->setBailoutKind(BailoutKind::HoistBoundsCheck);
2375 preLoop->insertBefore(preLoop->lastIns(), lowerCheck);
2376
2377 // A common pattern for iterating over typed arrays is this:
2378 //
2379 // for (var i = 0; i < ta.length; i++) {
2380 // use ta[i];
2381 // }
2382 //
2383 // Here |upperTerm| (= ta.length) is a NonNegativeIntPtrToInt32 instruction.
2384 // Unwrap this if |length| is also an IntPtr so that we don't add an
2385 // unnecessary bounds check and Int32ToIntPtr below.
2386 if (upperTerm->isNonNegativeIntPtrToInt32() &&
2387 length->type() == MIRType::IntPtr) {
2388 upperTerm = upperTerm->toNonNegativeIntPtrToInt32()->input();
2389 }
2390
2391 // Hoist the loop invariant upper bounds checks.
2392 if (upperTerm != length || upperConstant >= 0) {
2393 // Hoist the bound check's length if it isn't already loop invariant.
2394 if (length->block()->isMarked()) {
2395 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"
, 2395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->isConstant()"
")"); do { *((volatile int*)__null) = 2395; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2396 MInstruction* lengthIns = length->toInstruction();
2397 lengthIns->block()->moveBefore(preLoop->lastIns(), lengthIns);
2398 }
2399
2400 // If the length is IntPtr, convert the upperTerm to that as well for the
2401 // bounds check.
2402 if (length->type() == MIRType::IntPtr &&
2403 upperTerm->type() == MIRType::Int32) {
2404 upperTerm = MInt32ToIntPtr::New(alloc(), upperTerm);
2405 upperTerm->computeRange(alloc());
2406 upperTerm->collectRangeInfoPreTrunc();
2407 preLoop->insertBefore(preLoop->lastIns(), upperTerm->toInstruction());
2408 }
2409
2410 MBoundsCheck* upperCheck = MBoundsCheck::New(alloc(), upperTerm, length);
2411 upperCheck->setMinimum(upperConstant);
2412 upperCheck->setMaximum(upperConstant);
2413 upperCheck->computeRange(alloc());
2414 upperCheck->collectRangeInfoPreTrunc();
2415 upperCheck->setBailoutKind(BailoutKind::HoistBoundsCheck);
2416 preLoop->insertBefore(preLoop->lastIns(), upperCheck);
2417 }
2418
2419 return true;
2420}
2421
2422bool RangeAnalysis::analyze() {
2423 JitSpew(JitSpew_Range, "Doing range propagation");
2424
2425 for (ReversePostorderIterator iter(graph_.rpoBegin());
2426 iter != graph_.rpoEnd(); iter++) {
2427 MBasicBlock* block = *iter;
2428 // No blocks are supposed to be unreachable, except when we have an OSR
2429 // block, in which case the Value Numbering phase add fixup blocks which
2430 // are unreachable.
2431 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"
, 2431); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!block->unreachable() || graph_.osrBlock()"
")"); do { *((volatile int*)__null) = 2431; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2432
2433 // If the block's immediate dominator is unreachable, the block is
2434 // unreachable. Iterating in RPO, we'll always see the immediate
2435 // dominator before the block.
2436 if (block->immediateDominator()->unreachable()) {
2437 block->setUnreachableUnchecked();
2438 continue;
2439 }
2440
2441 for (MDefinitionIterator iter(block); iter; iter++) {
2442 MDefinition* def = *iter;
2443 if (!alloc().ensureBallast()) {
2444 return false;
2445 }
2446
2447 def->computeRange(alloc());
2448 JitSpew(JitSpew_Range, "computing range on %u", def->id());
2449 SpewRange(def);
2450 }
2451
2452 // Beta node range analysis may have marked this block unreachable. If
2453 // so, it's no longer interesting to continue processing it.
2454 if (block->unreachable()) {
2455 continue;
2456 }
2457
2458 if (block->isLoopHeader()) {
2459 if (!analyzeLoop(block)) {
2460 return false;
2461 }
2462 }
2463
2464 // First pass at collecting range info - while the beta nodes are still
2465 // around and before truncation.
2466 for (MInstructionIterator iter(block->begin()); iter != block->end();
2467 iter++) {
2468 iter->collectRangeInfoPreTrunc();
2469 }
2470 }
2471
2472 return true;
2473}
2474
2475bool RangeAnalysis::addRangeAssertions() {
2476 if (!JitOptions.checkRangeAnalysis) {
2477 return true;
2478 }
2479
2480 // Check the computed range for this instruction, if the option is set. Note
2481 // that this code is quite invasive; it adds numerous additional
2482 // instructions for each MInstruction with a computed range, and it uses
2483 // registers, so it also affects register allocation.
2484 for (ReversePostorderIterator iter(graph_.rpoBegin());
2485 iter != graph_.rpoEnd(); iter++) {
2486 MBasicBlock* block = *iter;
2487
2488 // Do not add assertions in unreachable blocks.
2489 if (block->unreachable()) {
2490 continue;
2491 }
2492
2493 for (MDefinitionIterator iter(block); iter; iter++) {
2494 MDefinition* ins = *iter;
2495
2496 // Perform range checking for all numeric and numeric-like types.
2497 if (!IsNumberType(ins->type()) && ins->type() != MIRType::Boolean &&
2498 ins->type() != MIRType::Value && ins->type() != MIRType::IntPtr) {
2499 continue;
2500 }
2501
2502 // MIsNoIter is fused with the MTest that follows it and emitted as
2503 // LIsNoIterAndBranch. Similarly, MIteratorHasIndices is fused to
2504 // become LIteratorHasIndicesAndBranch. Skip them to avoid complicating
2505 // lowering.
2506 if (ins->isIsNoIter() || ins->isIteratorHasIndices()) {
2507 MOZ_ASSERT(ins->hasOneUse())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->hasOneUse())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->hasOneUse()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("ins->hasOneUse()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->hasOneUse()"
")"); do { *((volatile int*)__null) = 2507; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2508 continue;
2509 }
2510
2511 Range r(ins);
2512
2513 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"
, 2513); AnnotateMozCrashReason("MOZ_ASSERT" "(" "r.isUnknown()"
")"); do { *((volatile int*)__null) = 2513; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2514
2515 // Don't insert assertions if there's nothing interesting to assert.
2516 if (r.isUnknown() ||
2517 (ins->type() == MIRType::Int32 && r.isUnknownInt32())) {
2518 continue;
2519 }
2520
2521 // Don't add a use to an instruction that is recovered on bailout.
2522 if (ins->isRecoveredOnBailout()) {
2523 continue;
2524 }
2525
2526 if (!alloc().ensureBallast()) {
2527 return false;
2528 }
2529 MAssertRange* guard =
2530 MAssertRange::New(alloc(), ins, new (alloc()) Range(r));
2531
2532 // Beta nodes and interrupt checks are required to be located at the
2533 // beginnings of basic blocks, so we must insert range assertions
2534 // after any such instructions.
2535 MInstruction* insertAt = nullptr;
2536 if (block->graph().osrBlock() == block) {
2537 insertAt = ins->toInstruction();
2538 } else {
2539 insertAt = block->safeInsertTop(ins);
2540 }
2541
2542 if (insertAt == *iter) {
2543 block->insertAfter(insertAt, guard);
2544 } else {
2545 block->insertBefore(insertAt, guard);
2546 }
2547 }
2548 }
2549
2550 return true;
2551}
2552
2553///////////////////////////////////////////////////////////////////////////////
2554// Range based Truncation
2555///////////////////////////////////////////////////////////////////////////////
2556
2557void Range::clampToInt32() {
2558 if (isInt32()) {
2559 return;
2560 }
2561 int32_t l = hasInt32LowerBound() ? lower() : JSVAL_INT_MIN((int32_t)0x80000000);
2562 int32_t h = hasInt32UpperBound() ? upper() : JSVAL_INT_MAX((int32_t)0x7fffffff);
2563 setInt32(l, h);
2564}
2565
2566void Range::wrapAroundToInt32() {
2567 if (!hasInt32Bounds()) {
2568 setInt32(JSVAL_INT_MIN((int32_t)0x80000000), JSVAL_INT_MAX((int32_t)0x7fffffff));
2569 } else if (canHaveFractionalPart()) {
2570 // Clearing the fractional field may provide an opportunity to refine
2571 // lower_ or upper_.
2572 canHaveFractionalPart_ = ExcludesFractionalParts;
2573 canBeNegativeZero_ = ExcludesNegativeZero;
2574 refineInt32BoundsByExponent(max_exponent_, &lower_, &hasInt32LowerBound_,
2575 &upper_, &hasInt32UpperBound_);
2576
2577 assertInvariants();
2578 } else {
2579 // If nothing else, we can clear the negative zero flag.
2580 canBeNegativeZero_ = ExcludesNegativeZero;
2581 }
2582 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"
, 2582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInt32()" ")"
); do { *((volatile int*)__null) = 2582; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2583}
2584
2585void Range::wrapAroundToShiftCount() {
2586 wrapAroundToInt32();
2587 if (lower() < 0 || upper() >= 32) {
2588 setInt32(0, 31);
2589 }
2590}
2591
2592void Range::wrapAroundToBoolean() {
2593 wrapAroundToInt32();
2594 if (!isBoolean()) {
2595 setInt32(0, 1);
2596 }
2597 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"
, 2597); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isBoolean()"
")"); do { *((volatile int*)__null) = 2597; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2598}
2599
2600bool MDefinition::canTruncate() const {
2601 // No procedure defined for truncating this instruction.
2602 return false;
2603}
2604
2605void MDefinition::truncate(TruncateKind kind) {
2606 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"
, 2606); AnnotateMozCrashReason("MOZ_CRASH(" "No procedure defined for truncating this instruction."
")"); do { *((volatile int*)__null) = 2606; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2607}
2608
2609bool MConstant::canTruncate() const { return IsFloatingPointType(type()); }
2610
2611void MConstant::truncate(TruncateKind kind) {
2612 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2612); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2612; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2613
2614 // Truncate the double to int, since all uses truncates it.
2615 int32_t res = ToInt32(numberToDouble());
2616 payload_.asBits = 0;
2617 payload_.i32 = res;
2618 setResultType(MIRType::Int32);
2619 if (range()) {
2620 range()->setInt32(res, res);
2621 }
2622}
2623
2624bool MPhi::canTruncate() const {
2625 return type() == MIRType::Double || type() == MIRType::Int32;
2626}
2627
2628void MPhi::truncate(TruncateKind kind) {
2629 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2629; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2630 truncateKind_ = kind;
2631 setResultType(MIRType::Int32);
2632 if (kind >= TruncateKind::IndirectTruncate && range()) {
2633 range()->wrapAroundToInt32();
2634 }
2635}
2636
2637bool MAdd::canTruncate() const {
2638 return type() == MIRType::Double || type() == MIRType::Int32;
2639}
2640
2641void MAdd::truncate(TruncateKind kind) {
2642 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2642); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2642; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2643
2644 // Remember analysis, needed for fallible checks.
2645 setTruncateKind(kind);
2646
2647 setSpecialization(MIRType::Int32);
2648 if (truncateKind() >= TruncateKind::IndirectTruncate && range()) {
2649 range()->wrapAroundToInt32();
2650 }
2651}
2652
2653bool MSub::canTruncate() const {
2654 return type() == MIRType::Double || type() == MIRType::Int32;
2655}
2656
2657void MSub::truncate(TruncateKind kind) {
2658 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2658; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2659
2660 // Remember analysis, needed for fallible checks.
2661 setTruncateKind(kind);
2662 setSpecialization(MIRType::Int32);
2663 if (truncateKind() >= TruncateKind::IndirectTruncate && range()) {
2664 range()->wrapAroundToInt32();
2665 }
2666}
2667
2668bool MMul::canTruncate() const {
2669 return type() == MIRType::Double || type() == MIRType::Int32;
2670}
2671
2672void MMul::truncate(TruncateKind kind) {
2673 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2673; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2674
2675 // Remember analysis, needed for fallible checks.
2676 setTruncateKind(kind);
2677 setSpecialization(MIRType::Int32);
2678 if (truncateKind() >= TruncateKind::IndirectTruncate) {
2679 setCanBeNegativeZero(false);
2680 if (range()) {
2681 range()->wrapAroundToInt32();
2682 }
2683 }
2684}
2685
2686bool MDiv::canTruncate() const {
2687 return type() == MIRType::Double || type() == MIRType::Int32;
2688}
2689
2690void MDiv::truncate(TruncateKind kind) {
2691 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2691; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2692
2693 // Remember analysis, needed for fallible checks.
2694 setTruncateKind(kind);
2695 setSpecialization(MIRType::Int32);
2696
2697 // Divisions where the lhs and rhs are unsigned and the result is
2698 // truncated can be lowered more efficiently.
2699 if (unsignedOperands()) {
2700 replaceWithUnsignedOperands();
2701 unsigned_ = true;
2702 }
2703}
2704
2705bool MMod::canTruncate() const {
2706 return type() == MIRType::Double || type() == MIRType::Int32;
2707}
2708
2709void MMod::truncate(TruncateKind kind) {
2710 // As for division, handle unsigned modulus with a truncated result.
2711 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2711; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2712
2713 // Remember analysis, needed for fallible checks.
2714 setTruncateKind(kind);
2715 setSpecialization(MIRType::Int32);
2716
2717 if (unsignedOperands()) {
2718 replaceWithUnsignedOperands();
2719 unsigned_ = true;
2720 }
2721}
2722
2723bool MToDouble::canTruncate() const {
2724 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"
, 2724); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 2724; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2725 return true;
2726}
2727
2728void MToDouble::truncate(TruncateKind kind) {
2729 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2729); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2729; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2730 setTruncateKind(kind);
2731
2732 // We use the return type to flag that this MToDouble should be replaced by
2733 // a MTruncateToInt32 when modifying the graph.
2734 setResultType(MIRType::Int32);
2735 if (truncateKind() >= TruncateKind::IndirectTruncate) {
2736 if (range()) {
2737 range()->wrapAroundToInt32();
2738 }
2739 }
2740}
2741
2742bool MLimitedTruncate::canTruncate() const { return true; }
2743
2744void MLimitedTruncate::truncate(TruncateKind kind) {
2745 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2745); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2745; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2746 setTruncateKind(kind);
2747 setResultType(MIRType::Int32);
2748 if (kind >= TruncateKind::IndirectTruncate && range()) {
2749 range()->wrapAroundToInt32();
2750 }
2751}
2752
2753bool MCompare::canTruncate() const {
2754 if (!isDoubleComparison()) {
2755 return false;
2756 }
2757
2758 // If both operands are naturally in the int32 range, we can convert from
2759 // a double comparison to being an int32 comparison.
2760 if (!Range(lhs()).isInt32() || !Range(rhs()).isInt32()) {
2761 return false;
2762 }
2763
2764 return true;
2765}
2766
2767void MCompare::truncate(TruncateKind kind) {
2768 MOZ_ASSERT(canTruncate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canTruncate())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canTruncate()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canTruncate()",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/RangeAnalysis.cpp"
, 2768); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canTruncate()"
")"); do { *((volatile int*)__null) = 2768; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2769 compareType_ = Compare_Int32;
2770
2771 // Truncating the operands won't change their value because we don't force a
2772 // truncation, but it will change their type, which we need because we
2773 // now expect integer inputs.
2774 truncateOperands_ = true;
2775}
2776
2777TruncateKind MDefinition::operandTruncateKind(size_t index) const {
2778 // Generic routine: We don't know anything.
2779 return TruncateKind::NoTruncate;
2780}
2781
2782TruncateKind MPhi::operandTruncateKind(size_t index) const {
2783 // The truncation applied to a phi is effectively applied to the phi's
2784 // operands.
2785 return truncateKind_;
2786}
2787
2788TruncateKind MTruncateToInt32::operandTruncateKind(size_t index) const {
2789 // This operator is an explicit truncate to int32.
2790 return TruncateKind::Truncate;
2791}
2792
2793TruncateKind MBinaryBitwiseInstruction::operandTruncateKind(
2794 size_t index) const {
2795 // The bitwise operators truncate to int32.
2796 return TruncateKind::Truncate;
2797}
2798
2799TruncateKind MLimitedTruncate::operandTruncateKind(size_t index) const {
2800 return std::min(truncateKind(), truncateLimit_);
2801}
2802
2803TruncateKind MAdd::operandTruncateKind(size_t index) const {
2804 // This operator is doing some arithmetic. If its result is truncated,
2805 // it's an indirect truncate for its operands.
2806 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2807}
2808
2809TruncateKind MSub::operandTruncateKind(size_t index) const {
2810 // See the comment in MAdd::operandTruncateKind.
2811 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2812}
2813
2814TruncateKind MMul::operandTruncateKind(size_t index) const {
2815 // See the comment in MAdd::operandTruncateKind.
2816 return std::min(truncateKind(), TruncateKind::IndirectTruncate);
2817}
2818
2819TruncateKind MToDouble::operandTruncateKind(size_t index) const {
2820 // MToDouble propagates its truncate kind to its operand.
2821 return truncateKind();
2822}
2823
2824TruncateKind MStoreUnboxedScalar::operandTruncateKind(size_t index) const {
2825 // An integer store truncates the stored value.
2826 return (index == 2 && isIntegerWrite()) ? TruncateKind::Truncate
2827 : TruncateKind::NoTruncate;
2828}
2829
2830TruncateKind MStoreDataViewElement::operandTruncateKind(size_t index) const {
2831 // An integer store truncates the stored value.
2832 return (index == 2 && isIntegerWrite()) ? TruncateKind::Truncate
2833 : TruncateKind::NoTruncate;
2834}
2835
2836TruncateKind MStoreTypedArrayElementHole::operandTruncateKind(
2837 size_t index) const {
2838 // An integer store truncates the stored value.
2839 return (index == 3 && isIntegerWrite()) ? TruncateKind::Truncate
2840 : TruncateKind::NoTruncate;
2841}
2842
2843TruncateKind MDiv::operandTruncateKind(size_t index) const {
2844 return std::min(truncateKind(), TruncateKind::TruncateAfterBailouts);
2845}
2846
2847TruncateKind MMod::operandTruncateKind(size_t index) const {
2848 return std::min(truncateKind(), TruncateKind::TruncateAfterBailouts);
2849}
2850
2851TruncateKind MCompare::operandTruncateKind(size_t index) const {
2852 // If we're doing an int32 comparison on operands which were previously
2853 // floating-point, convert them!
2854 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"
, 2854); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInt32Comparison()"
")"); do { *((volatile int*)__null) = 2854; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2855 return truncateOperands_ ? TruncateKind::TruncateAfterBailouts
2856 : TruncateKind::NoTruncate;
2857}
2858
2859static bool TruncateTest(TempAllocator& alloc, MTest* test) {
2860 // If all possible inputs to the test are either int32 or boolean,
2861 // convert those inputs to int32 so that an int32 test can be performed.
2862
2863 if (test->input()->type() != MIRType::Value) {
2864 return true;
2865 }
2866
2867 if (!test->input()->isPhi() || !test->input()->hasOneDefUse() ||
2868 test->input()->isImplicitlyUsed()) {
2869 return true;
2870 }
2871
2872 MPhi* phi = test->input()->toPhi();
2873 for (size_t i = 0; i < phi->numOperands(); i++) {
2874 MDefinition* def = phi->getOperand(i);
2875 if (!def->isBox()) {
2876 return true;
2877 }
2878 MDefinition* inner = def->getOperand(0);
2879 if (inner->type() != MIRType::Boolean && inner->type() != MIRType::Int32) {
2880 return true;
2881 }
2882 }
2883
2884 for (size_t i = 0; i < phi->numOperands(); i++) {
2885 MDefinition* inner = phi->getOperand(i)->getOperand(0);
2886 if (inner->type() != MIRType::Int32) {
2887 if (!alloc.ensureBallast()) {
2888 return false;
2889 }
2890 MBasicBlock* block = inner->block();
2891 inner = MToNumberInt32::New(alloc, inner);
2892 block->insertBefore(block->lastIns(), inner->toInstruction());
2893 }
2894 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"
, 2894); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inner->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2894; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2895 phi->replaceOperand(i, inner);
2896 }
2897
2898 phi->setResultType(MIRType::Int32);
2899 return true;
2900}
2901
2902// Truncating instruction result is an optimization which implies
2903// knowing all uses of an instruction. This implies that if one of
2904// the uses got removed, then Range Analysis is not be allowed to do
2905// any modification which can change the result, especially if the
2906// result can be observed.
2907//
2908// This corner can easily be understood with UCE examples, but it
2909// might also happen with type inference assumptions. Note: Type
2910// inference is implicitly branches where other types might be
2911// flowing into.
2912static bool CloneForDeadBranches(TempAllocator& alloc,
2913 MInstruction* candidate) {
2914 // Compare returns a boolean so it doesn't have to be recovered on bailout
2915 // because the output would remain correct.
2916 if (candidate->isCompare()) {
2917 return true;
2918 }
2919
2920 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"
, 2920); AnnotateMozCrashReason("MOZ_ASSERT" "(" "candidate->canClone()"
")"); do { *((volatile int*)__null) = 2920; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2921 if (!alloc.ensureBallast()) {
2922 return false;
2923 }
2924
2925 MDefinitionVector operands(alloc);
2926 size_t end = candidate->numOperands();
2927 if (!operands.reserve(end)) {
2928 return false;
2929 }
2930 for (size_t i = 0; i < end; ++i) {
2931 operands.infallibleAppend(candidate->getOperand(i));
2932 }
2933
2934 MInstruction* clone = candidate->clone(alloc, operands);
2935 if (!clone) {
2936 return false;
2937 }
2938 clone->setRange(nullptr);
2939
2940 // Set ImplicitlyUsed flag on the cloned instruction in order to chain recover
2941 // instruction for the bailout path.
2942 clone->setImplicitlyUsedUnchecked();
2943
2944 candidate->block()->insertBefore(candidate, clone);
2945
2946 if (!candidate->maybeConstantValue()) {
2947 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"
, 2947); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clone->canRecoverOnBailout()"
")"); do { *((volatile int*)__null) = 2947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2948 clone->setRecoveredOnBailout();
2949 }
2950
2951 // Replace the candidate by its recovered on bailout clone within recovered
2952 // instructions and resume points operands.
2953 for (MUseIterator i(candidate->usesBegin()); i != candidate->usesEnd();) {
2954 MUse* use = *i++;
2955 MNode* ins = use->consumer();
2956 if (ins->isDefinition() && !ins->toDefinition()->isRecoveredOnBailout()) {
2957 continue;
2958 }
2959
2960 use->replaceProducer(clone);
2961 }
2962
2963 return true;
2964}
2965
2966// Examine all the users of |candidate| and determine the most aggressive
2967// truncate kind that satisfies all of them.
2968static TruncateKind ComputeRequestedTruncateKind(MDefinition* candidate,
2969 bool* shouldClone) {
2970 bool isCapturedResult =
2971 false; // Check if used by a recovered instruction or a resume point.
2972 bool isObservableResult =
2973 false; // Check if it can be read from another frame.
2974 bool isRecoverableResult = true; // Check if it can safely be reconstructed.
2975 bool isImplicitlyUsed = candidate->isImplicitlyUsed();
2976 bool hasTryBlock = candidate->block()->graph().hasTryBlock();
2977
2978 TruncateKind kind = TruncateKind::Truncate;
2979 for (MUseIterator use(candidate->usesBegin()); use != candidate->usesEnd();
2980 use++) {
2981 if (use->consumer()->isResumePoint()) {
2982 // Truncation is a destructive optimization, as such, we need to pay
2983 // attention to removed branches and prevent optimization
2984 // destructive optimizations if we have no alternative. (see
2985 // ImplicitlyUsed flag)
2986 isCapturedResult = true;
2987 isObservableResult =
2988 isObservableResult ||
2989 use->consumer()->toResumePoint()->isObservableOperand(*use);
2990 isRecoverableResult =
2991 isRecoverableResult &&
2992 use->consumer()->toResumePoint()->isRecoverableOperand(*use);
2993 continue;
2994 }
2995
2996 MDefinition* consumer = use->consumer()->toDefinition();
2997 if (consumer->isRecoveredOnBailout()) {
2998 isCapturedResult = true;
2999 isImplicitlyUsed = isImplicitlyUsed || consumer->isImplicitlyUsed();
3000 continue;
3001 }
3002
3003 TruncateKind consumerKind =
3004 consumer->operandTruncateKind(consumer->indexOf(*use));
3005 kind = std::min(kind, consumerKind);
3006 if (kind == TruncateKind::NoTruncate) {
3007 break;
3008 }
3009 }
3010
3011 // We cannot do full trunction on guarded instructions.
3012 if (candidate->isGuard() || candidate->isGuardRangeBailouts()) {
3013 kind = std::min(kind, TruncateKind::TruncateAfterBailouts);
3014 }
3015
3016 // If the value naturally produces an int32 value (before bailout checks)
3017 // that needs no conversion, we don't have to worry about resume points
3018 // seeing truncated values.
3019 bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
3020
3021 // If the instruction is explicitly truncated (not indirectly) by all its
3022 // uses and if it is not implicitly used, then we can safely encode its
3023 // truncated result as part of the resume point operands. This is safe,
3024 // because even if we resume with a truncated double, the next baseline
3025 // instruction operating on this instruction is going to be a no-op.
3026 //
3027 // Note, that if the result can be observed from another frame, then this
3028 // optimization is not safe. Similarly, if this function contains a try
3029 // block, the result could be observed from a catch block, which we do
3030 // not compile.
3031 bool safeToConvert = kind == TruncateKind::Truncate && !isImplicitlyUsed &&
3032 !isObservableResult && !hasTryBlock;
3033
3034 // If the candidate instruction appears as operand of a resume point or a
3035 // recover instruction, and we have to truncate its result, then we might
3036 // have to either recover the result during the bailout, or avoid the
3037 // truncation.
3038 if (isCapturedResult && needsConversion && !safeToConvert) {
3039 // If the result can be recovered from all the resume points (not needed
3040 // for iterating over the inlined frames), and this instruction can be
3041 // recovered on bailout, then we can clone it and use the cloned
3042 // instruction to encode the recover instruction. Otherwise, we should
3043 // keep the original result and bailout if the value is not in the int32
3044 // range.
3045 if (!JitOptions.disableRecoverIns && isRecoverableResult &&
3046 candidate->canRecoverOnBailout()) {
3047 *shouldClone = true;
3048 } else {
3049 kind = std::min(kind, TruncateKind::TruncateAfterBailouts);
3050 }
3051 }
3052
3053 return kind;
3054}
3055
3056static TruncateKind ComputeTruncateKind(MDefinition* candidate,
3057 bool* shouldClone) {
3058 // Compare operations might coerce its inputs to int32 if the ranges are
3059 // correct. So we do not need to check if all uses are coerced.
3060 if (candidate->isCompare()) {
3061 return TruncateKind::TruncateAfterBailouts;
3062 }
3063
3064 // Set truncated flag if range analysis ensure that it has no
3065 // rounding errors and no fractional part. Note that we can't use
3066 // the MDefinition Range constructor, because we need to know if
3067 // the value will have rounding errors before any bailout checks.
3068 const Range* r = candidate->range();
3069 bool canHaveRoundingErrors = !r || r->canHaveRoundingErrors();
3070
3071 // Special case integer division and modulo: a/b can be infinite, and a%b
3072 // can be NaN but cannot actually have rounding errors induced by truncation.
3073 if ((candidate->isDiv() || candidate->isMod()) &&
3074 candidate->type() == MIRType::Int32) {
3075 canHaveRoundingErrors = false;
3076 }
3077
3078 if (canHaveRoundingErrors) {
3079 return TruncateKind::NoTruncate;
3080 }
3081
3082 // Ensure all observable uses are truncated.
3083 return ComputeRequestedTruncateKind(candidate, shouldClone);
3084}
3085
3086static void RemoveTruncatesOnOutput(MDefinition* truncated) {
3087 // Compare returns a boolean so it doen't have any output truncates.
3088 if (truncated->isCompare()) {
3089 return;
3090 }
3091
3092 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"
, 3092); AnnotateMozCrashReason("MOZ_ASSERT" "(" "truncated->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3092; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3093 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"
, 3093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "Range(truncated).isInt32()"
")"); do { *((volatile int*)__null) = 3093; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3094
3095 for (MUseDefIterator use(truncated); use; use++) {
3096 MDefinition* def = use.def();
3097 if (!def->isTruncateToInt32() || !def->isToNumberInt32()) {
3098 continue;
3099 }
3100
3101 def->replaceAllUsesWith(truncated);
3102 }
3103}
3104
3105void RangeAnalysis::adjustTruncatedInputs(MDefinition* truncated) {
3106 MBasicBlock* block = truncated->block();
3107 for (size_t i = 0, e = truncated->numOperands(); i < e; i++) {
3108 TruncateKind kind = truncated->operandTruncateKind(i);
3109 if (kind == TruncateKind::NoTruncate) {
3110 continue;
3111 }
3112
3113 MDefinition* input = truncated->getOperand(i);
3114 if (input->type() == MIRType::Int32) {
3115 continue;
3116 }
3117
3118 if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) {
3119 truncated->replaceOperand(i, input->getOperand(0));
3120 } else {
3121 MInstruction* op;
3122 if (kind == TruncateKind::TruncateAfterBailouts) {
3123 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"
, 3123); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mir->outerInfo().hadEagerTruncationBailout()"
")"); do { *((volatile int*)__null) = 3123; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3124 op = MToNumberInt32::New(alloc(), truncated->getOperand(i));
3125 op->setBailoutKind(BailoutKind::EagerTruncation);
3126 } else {
3127 op = MTruncateToInt32::New(alloc(), truncated->getOperand(i));
3128 }
3129
3130 if (truncated->isPhi()) {
3131 MBasicBlock* pred = block->getPredecessor(i);
3132 pred->insertBefore(pred->lastIns(), op);
3133 } else {
3134 block->insertBefore(truncated->toInstruction(), op);
3135 }
3136 truncated->replaceOperand(i, op);
3137 }
3138 }
3139
3140 if (truncated->isToDouble()) {
3141 truncated->replaceAllUsesWith(truncated->toToDouble()->getOperand(0));
3142 block->discard(truncated->toToDouble());
3143 }
3144}
3145
3146bool RangeAnalysis::canTruncate(MDefinition* def, TruncateKind kind) const {
3147 if (kind == TruncateKind::NoTruncate) {
3148 return false;
3149 }
3150
3151 // Range Analysis is sometimes eager to do optimizations, even if we
3152 // are not able to truncate an instruction. In such case, we
3153 // speculatively compile the instruction to an int32 instruction
3154 // while adding a guard. This is what is implied by
3155 // TruncateAfterBailout.
3156 //
3157 // If a previous compilation was invalidated because a speculative
3158 // truncation bailed out, we no longer attempt to make this kind of
3159 // eager optimization.
3160 if (mir->outerInfo().hadEagerTruncationBailout()) {
3161 if (kind == TruncateKind::TruncateAfterBailouts) {
3162 return false;
3163 }
3164 // MDiv and MMod always require TruncateAfterBailout for their operands.
3165 // See MDiv::operandTruncateKind and MMod::operandTruncateKind.
3166 if (def->isDiv() || def->isMod()) {
3167 return false;
3168 }
3169 }
3170
3171 return true;
3172}
3173
3174// Iterate backward on all instruction and attempt to truncate operations for
3175// each instruction which respect the following list of predicates: Has been
3176// analyzed by range analysis, the range has no rounding errors, all uses cases
3177// are truncating the result.
3178//
3179// If the truncation of the operation is successful, then the instruction is
3180// queue for later updating the graph to restore the type correctness by
3181// converting the operands that need to be truncated.
3182//
3183// We iterate backward because it is likely that a truncated operation truncates
3184// some of its operands.
3185bool RangeAnalysis::truncate() {
3186 JitSpew(JitSpew_Range, "Do range-base truncation (backward loop)");
3187
3188 // Automatic truncation is disabled for wasm because the truncation logic
3189 // is based on IonMonkey which assumes that we can bailout if the truncation
3190 // logic fails. As wasm code has no bailout mechanism, it is safer to avoid
3191 // any automatic truncations.
3192 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"
, 3192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mir->compilingWasm()"
")"); do { *((volatile int*)__null) = 3192; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3193
3194 Vector<MDefinition*, 16, SystemAllocPolicy> worklist;
3195
3196 for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd();
3197 block++) {
3198 for (MInstructionReverseIterator iter(block->rbegin());
3199 iter != block->rend(); iter++) {
3200 if (iter->isRecoveredOnBailout()) {
3201 continue;
3202 }
3203
3204 if (iter->type() == MIRType::None) {
3205 if (iter->isTest()) {
3206 if (!TruncateTest(alloc(), iter->toTest())) {
3207 return false;
3208 }
3209 }
3210 continue;
3211 }
3212
3213 // Remember all bitop instructions for folding after range analysis.
3214 switch (iter->op()) {
3215 case MDefinition::Opcode::BitAnd:
3216 case MDefinition::Opcode::BitOr:
3217 case MDefinition::Opcode::BitXor:
3218 case MDefinition::Opcode::Lsh:
3219 case MDefinition::Opcode::Rsh:
3220 case MDefinition::Opcode::Ursh:
3221 if (!bitops.append(static_cast<MBinaryBitwiseInstruction*>(*iter))) {
3222 return false;
3223 }
3224 break;
3225 default:;
3226 }
3227
3228 bool shouldClone = false;
3229 TruncateKind kind = ComputeTruncateKind(*iter, &shouldClone);
3230
3231 // Truncate this instruction if possible.
3232 if (!canTruncate(*iter, kind) || !iter->canTruncate()) {
3233 continue;
3234 }
3235
3236 SpewTruncate(*iter, kind, shouldClone);
3237
3238 // If needed, clone the current instruction for keeping it for the
3239 // bailout path. This give us the ability to truncate instructions
3240 // even after the removal of branches.
3241 if (shouldClone && !CloneForDeadBranches(alloc(), *iter)) {
3242 return false;
3243 }
3244
3245 // TruncateAfterBailouts keeps the bailout code as-is and
3246 // continues with truncated operations, with the expectation
3247 // that we are unlikely to bail out. If we do bail out, then we
3248 // will set a flag in FinishBailoutToBaseline to prevent eager
3249 // truncation when we recompile, to avoid bailout loops.
3250 if (kind == TruncateKind::TruncateAfterBailouts) {
3251 iter->setBailoutKind(BailoutKind::EagerTruncation);
3252 }
3253
3254 iter->truncate(kind);
3255
3256 // Delay updates of inputs/outputs to avoid creating node which
3257 // would be removed by the truncation of the next operations.
3258 iter->setInWorklist();
3259 if (!worklist.append(*iter)) {
3260 return false;
3261 }
3262 }
3263 for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd());
3264 iter != end; ++iter) {
3265 bool shouldClone = false;
3266 TruncateKind kind = ComputeTruncateKind(*iter, &shouldClone);
3267
3268 // Truncate this phi if possible.
3269 if (shouldClone || !canTruncate(*iter, kind) || !iter->canTruncate()) {
3270 continue;
3271 }
3272
3273 SpewTruncate(*iter, kind, shouldClone);
3274
3275 iter->truncate(kind);
3276
3277 // Delay updates of inputs/outputs to avoid creating node which
3278 // would be removed by the truncation of the next operations.
3279 iter->setInWorklist();
3280 if (!worklist.append(*iter)) {
3281 return false;
3282 }
3283 }
3284 }
3285
3286 // Update inputs/outputs of truncated instructions.
3287 JitSpew(JitSpew_Range, "Do graph type fixup (dequeue)");
3288 while (!worklist.empty()) {
3289 if (!alloc().ensureBallast()) {
3290 return false;
3291 }
3292 MDefinition* def = worklist.popCopy();
3293 def->setNotInWorklist();
3294 RemoveTruncatesOnOutput(def);
3295 adjustTruncatedInputs(def);
3296 }
3297
3298 return true;
3299}
3300
3301bool RangeAnalysis::removeUnnecessaryBitops() {
3302 JitSpew(JitSpew_Range, "Begin (removeUnnecessaryBitops)");
3303 // Note: This operation change the semantic of the program in a way which
3304 // uniquely works with Int32, Recover Instructions added by the Sink phase
3305 // expects the MIR Graph to still have a valid flow as-if they were double
3306 // operations instead of Int32 operations. Thus, this phase should be
3307 // executed after the Sink phase, and before DCE.
3308
3309 // Fold any unnecessary bitops in the graph, such as (x | 0) on an integer
3310 // input. This is done after range analysis rather than during GVN as the
3311 // presence of the bitop can change which instructions are truncated.
3312 for (size_t i = 0; i < bitops.length(); i++) {
3313 MBinaryBitwiseInstruction* ins = bitops[i];
3314 if (ins->isRecoveredOnBailout()) {
3315 continue;
3316 }
3317
3318 MDefinition* folded = ins->foldUnnecessaryBitop();
3319 if (folded != ins) {
3320 ins->replaceAllLiveUsesWith(folded);
3321 ins->setRecoveredOnBailout();
3322 }
3323 }
3324
3325 bitops.clear();
3326 return true;
3327}
3328
3329///////////////////////////////////////////////////////////////////////////////
3330// Collect Range information of operands
3331///////////////////////////////////////////////////////////////////////////////
3332
3333void MInArray::collectRangeInfoPreTrunc() {
3334 Range indexRange(index());
3335 if (indexRange.isFiniteNonNegative()) {
3336 needsNegativeIntCheck_ = false;
3337 setNotGuard();
3338 }
3339}
3340
3341void MLoadElementHole::collectRangeInfoPreTrunc() {
3342 Range indexRange(index());
3343 if (indexRange.isFiniteNonNegative()) {
3344 needsNegativeIntCheck_ = false;
3345 setNotGuard();
3346 }
3347}
3348
3349void MInt32ToIntPtr::collectRangeInfoPreTrunc() {
3350 Range inputRange(input());
3351 if (inputRange.isFiniteNonNegative()) {
3352 canBeNegative_ = false;
3353 }
3354}
3355
3356void MClz::collectRangeInfoPreTrunc() {
3357 Range inputRange(input());
3358 if (!inputRange.canBeZero()) {
3359 operandIsNeverZero_ = true;
3360 }
3361}
3362
3363void MCtz::collectRangeInfoPreTrunc() {
3364 Range inputRange(input());
3365 if (!inputRange.canBeZero()) {
3366 operandIsNeverZero_ = true;
3367 }
3368}
3369
3370void MDiv::collectRangeInfoPreTrunc() {
3371 Range lhsRange(lhs());
3372 Range rhsRange(rhs());
3373
3374 // Test if Dividend is non-negative.
3375 if (lhsRange.isFiniteNonNegative()) {
3376 canBeNegativeDividend_ = false;
3377 }
3378
3379 // Try removing divide by zero check.
3380 if (!rhsRange.canBeZero()) {
3381 canBeDivideByZero_ = false;
3382 }
3383
3384 // If lhsRange does not contain INT32_MIN in its range,
3385 // negative overflow check can be skipped.
3386 if (!lhsRange.contains(INT32_MIN(-2147483647-1))) {
3387 canBeNegativeOverflow_ = false;
3388 }
3389
3390 // If rhsRange does not contain -1 likewise.
3391 if (!rhsRange.contains(-1)) {
3392 canBeNegativeOverflow_ = false;
3393 }
3394
3395 // If lhsRange does not contain a zero,
3396 // negative zero check can be skipped.
3397 if (!lhsRange.canBeZero()) {
3398 canBeNegativeZero_ = false;
3399 }
3400
3401 // If rhsRange >= 0 negative zero check can be skipped.
3402 if (rhsRange.isFiniteNonNegative()) {
3403 canBeNegativeZero_ = false;
3404 }
3405
3406 if (fallible()) {
3407 setGuardRangeBailoutsUnchecked();
3408 }
3409}
3410
3411void MMul::collectRangeInfoPreTrunc() {
3412 Range lhsRange(lhs());
3413 Range rhsRange(rhs());
3414
3415 // If lhsRange contains only positive then we can skip negative zero check.
3416 if (lhsRange.isFiniteNonNegative() && !lhsRange.canBeZero()) {
3417 setCanBeNegativeZero(false);
3418 }
3419
3420 // Likewise rhsRange.
3421 if (rhsRange.isFiniteNonNegative() && !rhsRange.canBeZero()) {
3422 setCanBeNegativeZero(false);
3423 }
3424
3425 // If rhsRange and lhsRange contain Non-negative integers only,
3426 // We skip negative zero check.
3427 if (rhsRange.isFiniteNonNegative() && lhsRange.isFiniteNonNegative()) {
3428 setCanBeNegativeZero(false);
3429 }
3430
3431 // If rhsRange and lhsRange < 0. Then we skip negative zero check.
3432 if (rhsRange.isFiniteNegative() && lhsRange.isFiniteNegative()) {
3433 setCanBeNegativeZero(false);
3434 }
3435}
3436
3437void MMod::collectRangeInfoPreTrunc() {
3438 Range lhsRange(lhs());
3439 Range rhsRange(rhs());
3440 if (lhsRange.isFiniteNonNegative()) {
3441 canBeNegativeDividend_ = false;
3442 }
3443 if (!rhsRange.canBeZero()) {
3444 canBeDivideByZero_ = false;
3445 }
3446 if (type() == MIRType::Int32 && fallible()) {
3447 setGuardRangeBailoutsUnchecked();
3448 }
3449}
3450
3451void MToNumberInt32::collectRangeInfoPreTrunc() {
3452 Range inputRange(input());
3453 if (!inputRange.canBeNegativeZero()) {
3454 needsNegativeZeroCheck_ = false;
3455 }
3456}
3457
3458void MBoundsCheck::collectRangeInfoPreTrunc() {
3459 Range indexRange(index());
3460 Range lengthRange(length());
3461 if (!indexRange.hasInt32LowerBound() || !indexRange.hasInt32UpperBound()) {
3462 return;
3463 }
3464 if (!lengthRange.hasInt32LowerBound() || lengthRange.canBeNaN()) {
3465 return;
3466 }
3467
3468 int64_t indexLower = indexRange.lower();
3469 int64_t indexUpper = indexRange.upper();
3470 int64_t lengthLower = lengthRange.lower();
3471 int64_t min = minimum();
3472 int64_t max = maximum();
3473
3474 if (indexLower + min >= 0 && indexUpper + max < lengthLower) {
3475 fallible_ = false;
3476 }
3477}
3478
3479void MBoundsCheckLower::collectRangeInfoPreTrunc() {
3480 Range indexRange(index());
3481 if (indexRange.hasInt32LowerBound() && indexRange.lower() >= minimum_) {
3482 fallible_ = false;
3483 }
3484}
3485
3486void MCompare::collectRangeInfoPreTrunc() {
3487 if (!Range(lhs()).canBeNaN() && !Range(rhs()).canBeNaN()) {
3488 operandsAreNeverNaN_ = true;
3489 }
3490}
3491
3492void MNot::collectRangeInfoPreTrunc() {
3493 if (!Range(input()).canBeNaN()) {
3494 operandIsNeverNaN_ = true;
3495 }
3496}
3497
3498void MPowHalf::collectRangeInfoPreTrunc() {
3499 Range inputRange(input());
3500 if (!inputRange.canBeInfiniteOrNaN() || inputRange.hasInt32LowerBound()) {
3501 operandIsNeverNegativeInfinity_ = true;
3502 }
3503 if (!inputRange.canBeNegativeZero()) {
3504 operandIsNeverNegativeZero_ = true;
3505 }
3506 if (!inputRange.canBeNaN()) {
3507 operandIsNeverNaN_ = true;
3508 }
3509}
3510
3511void MUrsh::collectRangeInfoPreTrunc() {
3512 if (type() == MIRType::Int64) {
3513 return;
3514 }
3515
3516 Range lhsRange(lhs()), rhsRange(rhs());
3517
3518 // As in MUrsh::computeRange(), convert the inputs.
3519 lhsRange.wrapAroundToInt32();
3520 rhsRange.wrapAroundToShiftCount();
3521
3522 // If the most significant bit of our result is always going to be zero,
3523 // we can optimize by disabling bailout checks for enforcing an int32 range.
3524 if (lhsRange.lower() >= 0 || rhsRange.lower() >= 1) {
3525 bailoutsDisabled_ = true;
3526 }
3527}
3528
3529static bool DoesMaskMatchRange(int32_t mask, Range& range) {
3530 // Check if range is positive, because the bitand operator in `(-3) & 0xff`
3531 // can't be eliminated.
3532 if (range.lower() >= 0) {
3533 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"
, 3533); AnnotateMozCrashReason("MOZ_ASSERT" "(" "range.isInt32()"
")"); do { *((volatile int*)__null) = 3533; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3534 // Check that the mask value has all bits set given the range upper bound.
3535 // Note that the upper bound does not have to be exactly the mask value. For
3536 // example, consider `x & 0xfff` where `x` is a uint8. That expression can
3537 // still be optimized to `x`.
3538 int bits = 1 + FloorLog2(range.upper());
3539 uint32_t maskNeeded = (bits == 32) ? 0xffffffff : (uint32_t(1) << bits) - 1;
3540 if ((mask & maskNeeded) == maskNeeded) {
3541 return true;
3542 }
3543 }
3544
3545 return false;
3546}
3547
3548void MBinaryBitwiseInstruction::collectRangeInfoPreTrunc() {
3549 Range lhsRange(lhs());
3550 Range rhsRange(rhs());
3551
3552 if (lhs()->isConstant() && lhs()->type() == MIRType::Int32 &&
3553 DoesMaskMatchRange(lhs()->toConstant()->toInt32(), rhsRange)) {
3554 maskMatchesRightRange = true;
3555 }
3556
3557 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32 &&
3558 DoesMaskMatchRange(rhs()->toConstant()->toInt32(), lhsRange)) {
3559 maskMatchesLeftRange = true;
3560 }
3561}
3562
3563void MNaNToZero::collectRangeInfoPreTrunc() {
3564 Range inputRange(input());
3565
3566 if (!inputRange.canBeNaN()) {
3567 operandIsNeverNaN_ = true;
3568 }
3569 if (!inputRange.canBeNegativeZero()) {
3570 operandIsNeverNegativeZero_ = true;
3571 }
3572}
3573
3574bool RangeAnalysis::prepareForUCE(bool* shouldRemoveDeadCode) {
3575 *shouldRemoveDeadCode = false;
3576
3577 for (ReversePostorderIterator iter(graph_.rpoBegin());
3578 iter != graph_.rpoEnd(); iter++) {
3579 MBasicBlock* block = *iter;
3580
3581 if (!block->unreachable()) {
3582 continue;
3583 }
3584
3585 // Filter out unreachable fake entries.
3586 if (block->numPredecessors() == 0) {
3587 // Ignore fixup blocks added by the Value Numbering phase, in order
3588 // to keep the dominator tree as-is when we have OSR Block which are
3589 // no longer reachable from the main entry point of the graph.
3590 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"
, 3590); AnnotateMozCrashReason("MOZ_ASSERT" "(" "graph_.osrBlock()"
")"); do { *((volatile int*)__null) = 3590; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3591 continue;
3592 }
3593
3594 MControlInstruction* cond = block->getPredecessor(0)->lastIns();
3595 if (!cond->isTest()) {
3596 continue;
3597 }
3598
3599 // Replace the condition of the test control instruction by a constant
3600 // chosen based which of the successors has the unreachable flag which is
3601 // added by MBeta::computeRange on its own block.
3602 MTest* test = cond->toTest();
3603 MDefinition* condition = test->input();
3604
3605 // If the false-branch is unreachable, then the test condition must be true.
3606 // If the true-branch is unreachable, then the test condition must be false.
3607 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"
, 3607); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block == test->ifTrue() || block == test->ifFalse()"
")"); do { *((volatile int*)__null) = 3607; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3608 bool value = block == test->ifFalse();
3609 MConstant* constant =
3610 MConstant::New(alloc().fallible(), BooleanValue(value));
3611 if (!constant) {
3612 return false;
3613 }
3614
3615 condition->setGuardRangeBailoutsUnchecked();
3616
3617 test->block()->insertBefore(test, constant);
3618
3619 test->replaceOperand(0, constant);
3620 JitSpew(JitSpew_Range,
3621 "Update condition of %u to reflect unreachable branches.",
3622 test->id());
3623
3624 *shouldRemoveDeadCode = true;
3625 }
3626
3627 return tryRemovingGuards();
3628}
3629
3630bool RangeAnalysis::tryRemovingGuards() {
3631 MDefinitionVector guards(alloc());
3632
3633 for (ReversePostorderIterator block = graph_.rpoBegin();
3634 block != graph_.rpoEnd(); block++) {
3635 for (MDefinitionIterator iter(*block); iter; iter++) {
3636 if (!iter->isGuardRangeBailouts()) {
3637 continue;
3638 }
3639
3640 iter->setInWorklist();
3641 if (!guards.append(*iter)) {
3642 return false;
3643 }
3644 }
3645 }
3646
3647 // Flag all fallible instructions which were indirectly used in the
3648 // computation of the condition, such that we do not ignore
3649 // bailout-paths which are used to shrink the input range of the
3650 // operands of the condition.
3651 for (size_t i = 0; i < guards.length(); i++) {
3652 MDefinition* guard = guards[i];
3653
3654 // If this ins is a guard even without guardRangeBailouts,
3655 // there is no reason in trying to hoist the guardRangeBailouts check.
3656 guard->setNotGuardRangeBailouts();
3657 if (!DeadIfUnused(guard)) {
3658 guard->setGuardRangeBailouts();
3659 continue;
3660 }
3661 guard->setGuardRangeBailouts();
3662
3663 if (!guard->isPhi()) {
3664 if (!guard->range()) {
3665 continue;
3666 }
3667
3668 // Filter the range of the instruction based on its MIRType.
3669 Range typeFilteredRange(guard);
3670
3671 // If the output range is updated by adding the inner range,
3672 // then the MIRType act as an effectful filter. As we do not know if
3673 // this filtered Range might change or not the result of the
3674 // previous comparison, we have to keep this instruction as a guard
3675 // because it has to bailout in order to restrict the Range to its
3676 // MIRType.
3677 if (typeFilteredRange.update(guard->range())) {
3678 continue;
3679 }
3680 }
3681
3682 guard->setNotGuardRangeBailouts();
3683
3684 // Propagate the guard to its operands.
3685 for (size_t op = 0, e = guard->numOperands(); op < e; op++) {
3686 MDefinition* operand = guard->getOperand(op);
3687
3688 // Already marked.
3689 if (operand->isInWorklist()) {
3690 continue;
3691 }
3692
3693 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"
, 3693); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!operand->isGuardRangeBailouts()"
")"); do { *((volatile int*)__null) = 3693; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3694
3695 operand->setInWorklist();
3696 operand->setGuardRangeBailouts();
3697 if (!guards.append(operand)) {
3698 return false;
3699 }
3700 }
3701 }
3702
3703 for (size_t i = 0; i < guards.length(); i++) {
3704 MDefinition* guard = guards[i];
3705 guard->setNotInWorklist();
3706 }
3707
3708 return true;
3709}