1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-12 23:00:22 +02:00

Fix range analysis for mul and div

* module/language/cps/types.scm (mul): Avoid producing nans in the
  resulting range.
  (div): Fix range analysis.
This commit is contained in:
Andy Wingo 2014-07-04 11:14:16 +02:00
parent 384d1ec3b2
commit 42b544ebbc

View file

@ -799,13 +799,30 @@ minimum, and maximum."
(define-type-inferrer (mul a b result) (define-type-inferrer (mul a b result)
(let ((min-a (&min a)) (max-a (&max a)) (let ((min-a (&min a)) (max-a (&max a))
(min-b (&min b)) (max-b (&max b))) (min-b (&min b)) (max-b (&max b)))
(let ((-- (* min-a min-b)) (define (nan* a b)
(-+ (* min-a max-b)) ;; We only really get +inf.0 at runtime for flonums and compnums.
(++ (* max-a max-b)) ;; If we have inferred that the arguments are not flonums and not
(+- (* max-a min-b))) ;; compnums, then the result of (* +inf.0 0) at range inference
(define-binary-result! a b result #t ;; time is 0 and not +nan.0.
(if (eqv? a b) 0 (min -- -+ ++ +-)) (if (or (and (inf? a) (zero? b))
(max -- -+ ++ +-))))) (and (zero? a) (inf? b))
(not (logtest (logior (&type a) (&type b))
(logior &flonum &complex))))
0
(* a b)))
(let ((-- (nan* min-a min-b))
(-+ (nan* min-a max-b))
(++ (nan* max-a max-b))
(+- (nan* max-a min-b)))
(let ((has-nan? (or (nan? --) (nan? -+) (nan? ++) (nan? +-))))
(define-binary-result! a b result #t
(cond
((eqv? a b) 0)
(has-nan? -inf.0)
(else (min -- -+ ++ +-)))
(if has-nan?
+inf.0
(max -- -+ ++ +-)))))))
(define-type-checker (div a b) (define-type-checker (div a b)
(and (check-type a &number -inf.0 +inf.0) (and (check-type a &number -inf.0 +inf.0)
@ -824,12 +841,18 @@ minimum, and maximum."
(values -inf.0 +inf.0) (values -inf.0 +inf.0)
;; Otherwise min-b and max-b have the same sign, and cannot both ;; Otherwise min-b and max-b have the same sign, and cannot both
;; be infinity. ;; be infinity.
(let ((-- (if (inf? min-b) 0 (* min-a min-b))) (let ((--- (if (inf? min-b) 0 (floor/ min-a min-b)))
(-+ (if (inf? max-b) 0 (* min-a max-b))) (-+- (if (inf? max-b) 0 (floor/ min-a max-b)))
(++ (if (inf? max-b) 0 (* max-a max-b))) (++- (if (inf? max-b) 0 (floor/ max-a max-b)))
(+- (if (inf? min-b) 0 (* max-a min-b)))) (+-- (if (inf? min-b) 0 (floor/ max-a min-b)))
(values (min -- -+ ++ +-) (--+ (if (inf? min-b) 0 (ceiling/ min-a min-b)))
(max -- -+ ++ +-))))) (-++ (if (inf? max-b) 0 (ceiling/ min-a max-b)))
(+++ (if (inf? max-b) 0 (ceiling/ max-a max-b)))
(+-+ (if (inf? min-b) 0 (ceiling/ max-a min-b))))
(values (min (min --- -+- ++- +--)
(min --+ -++ +++ +-+))
(max (max --- -+- ++- +--)
(max --+ -++ +++ +-+))))))
(lambda (min max) (lambda (min max)
(define-binary-result! a b result #f min max))))) (define-binary-result! a b result #f min max)))))