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