Fix range inference on division in unreachable code
authorAndy Wingo <wingo@pobox.com>
Wed, 27 Nov 2019 15:00:43 +0000 (16:00 +0100)
committerAndy Wingo <wingo@pobox.com>
Wed, 27 Nov 2019 15:03:59 +0000 (16:03 +0100)
* module/language/cps/types.scm (div-result-range): It is possible for a
  max value to be less than a minimum.  In this bug from zig:

    (define (benchmark x)
      (let loop ((count 0)
                 (sum 0))
        (if (= count 10)
            (exact->inexact (/ sum 10)))
        (loop (+ count 1) x)))

  Here the first iteration gets peeled, and thus the first "if" can't be
  true, because "count" is zero.  However on the true branch of the if,
  range inference produces bogus ranges -- notably, the variable bound
  to 10 is inferred to have a min of 10 and a max of 0.  This is fine,
  because it's unreachable; but that then infects the division, because
  the same variable bound to 10 is used there, resulting in division by
  zero.

module/language/cps/types.scm

index d224f0c1e7713bd7d83b0184653dfd4bcd51fb27..a0d58fd0dc27c7c54a92b813e68763b22039cfe6 100644 (file)
@@ -1241,9 +1241,10 @@ minimum, and maximum."
        (not (<= (&min b) 0 (&max b)))))
 (define-type-checker (fdiv a b) #t)
 (define (div-result-range min-a max-a min-b max-b)
-  (if (<= min-b 0 max-b)
-      ;; If the range of the divisor crosses 0, the result spans
-      ;; the whole range.
+  (if (or (<= min-b 0 max-b)
+          (< max-b min-b))
+      ;; If the range of the divisor crosses 0, or if we are in
+      ;; unreachable code, the result spans the whole range.
       (values -inf.0 +inf.0)
       ;; Otherwise min-b and max-b have the same sign, and cannot both
       ;; be infinity.