Bug Summary

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