From 21e2041a79b227bbdb213614c60d3da48c39db48 Mon Sep 17 00:00:00 2001 From: Vincent St-Amour Date: Tue, 4 Dec 2012 15:05:33 -0500 Subject: [PATCH] Don't optimize mixed-mode arithmetic if it would change results. original commit: 93939f45d01206121b5c129ac2c7ba5ed89f7564 --- collects/typed-racket/optimizer/float.rkt | 34 +++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/collects/typed-racket/optimizer/float.rkt b/collects/typed-racket/optimizer/float.rkt index 4db200ee..f3ef404a 100644 --- a/collects/typed-racket/optimizer/float.rkt +++ b/collects/typed-racket/optimizer/float.rkt @@ -106,17 +106,41 @@ (begin (log-optimization "unary float" float-opt-msg this-syntax) #'(op.unsafe f.opt))) (pattern (#%plain-app (~var op (float-op binary-float-ops)) + ;; for now, accept anything that can be coerced to float + ;; finer-grained checking is done below f1:float-arg-expr f2:float-arg-expr fs:float-arg-expr ...) - ;; if the result is a float, we can coerce integers to floats and optimize - #:when (let* ([safe-to-opt? (subtypeof? this-syntax -Flonum)] - ;; if we don't have a return type of float, we missed an optimization - ;; opportunity, report it + #:when (let* ([safe-to-opt? + ;; For it to be safe, we need: + ;; - the result to be a float, in which case coercing args to floats + ;; won't change the result type + ;; - if we're multiplying or dividing, all the args need to be actual + ;; floats, can't coerce anything (o/w can turn division by 0 into a + ;; non-error) + ;; - for other operations, only one argument can be coerced. If more + ;; than one needs coercion, we could end up turning exact (or + ;; single-float) operations into float operations by accident. + ;; (Note: could allow for more args, if not next to each other, but + ;; probably not worth the trouble (most ops have 2 args anyway)) + (and (subtypeof? this-syntax -Flonum) + (cond [(or (free-identifier=? #'op #'*) + (free-identifier=? #'op #'/)) + (for/and ([a (in-list (syntax->list #'(f1 f2 fs ...)))]) + (subtypeof? a -Flonum))] + [else + (>= 1 + (for/sum ([a (in-list (syntax->list #'(f1 f2 fs ...)))] + #:when (not (subtypeof? a -Flonum))) + 1))]))] + ;; if we don't have a return type of float, or if the return type is + ;; float, but we can't optimizer for some other reason, we missed an + ;; optimization opportunity, report it ;; ignore operations that stay within integers or rationals, since ;; these have nothing to do with float optimizations [missed-optimization? (and (not safe-to-opt?) - (in-real-layer? this-syntax))]) + (or (in-real-layer? this-syntax) + (in-float-layer? this-syntax)))]) (when missed-optimization? (log-float-real-missed-opt this-syntax