diff --git a/collects/tests/typed-scheme/optimizer/generic/unboxed-let3.rkt b/collects/tests/typed-scheme/optimizer/generic/unboxed-let3.rkt new file mode 100644 index 0000000000..b52e893c8e --- /dev/null +++ b/collects/tests/typed-scheme/optimizer/generic/unboxed-let3.rkt @@ -0,0 +1,15 @@ +#lang typed/scheme #:optimize + +(require racket/unsafe/ops) + +;; both boxed and unboxed uses, we unbox anyway +;; causes unnecessary boxing/unboxing if we take a boxed path when +;; unboxing a complex literal or variable, but I expect this case +;; to be uncommon +;; by comparison, cases where we leave a result unboxed and box it +;; if needed (like here) or cases where this would unbox loop variables +;; are likely to be more common, and more interesting +(let ((x (+ 1.0+2.0i 2.0+4.0i))) + (if (even? 2) + x + (+ x 2.0+4.0i))) diff --git a/collects/tests/typed-scheme/optimizer/hand-optimized/unboxed-let3.rkt b/collects/tests/typed-scheme/optimizer/hand-optimized/unboxed-let3.rkt new file mode 100644 index 0000000000..844ba57554 --- /dev/null +++ b/collects/tests/typed-scheme/optimizer/hand-optimized/unboxed-let3.rkt @@ -0,0 +1,28 @@ +#lang racket + +(require racket/unsafe/ops) + +;; both boxed and unboxed uses, we unbox anyway +;; causes unnecessary boxing/unboxing if we take a boxed path when +;; unboxing a complex literal or variable, but I expect this case +;; to be uncommon +;; by comparison, cases where we leave a result unboxed and box it +;; if needed (like here) or cases where this would unbox loop variables +;; are likely to be more common, and more interesting +(let*-values (((unboxed-gensym-1) 1.0+2.0i) + ((unboxed-gensym-2) (unsafe-flreal-part unboxed-gensym-1)) + ((unboxed-gensym-3) (unsafe-flimag-part unboxed-gensym-1)) + ((unboxed-gensym-4) 2.0+4.0i) + ((unboxed-gensym-5) (unsafe-flreal-part unboxed-gensym-4)) + ((unboxed-gensym-6) (unsafe-flimag-part unboxed-gensym-4)) + ((unboxed-gensym-7) (unsafe-fl+ unboxed-gensym-2 unboxed-gensym-5)) + ((unboxed-gensym-8) (unsafe-fl+ unboxed-gensym-3 unboxed-gensym-6))) + (if (even? 2) + (unsafe-make-flrectangular unboxed-gensym-7 unboxed-gensym-8) + (let*-values (((unboxed-gensym-9) 2.0+4.0i) + ((unboxed-gensym-10) (unsafe-flreal-part unboxed-gensym-9)) + ((unboxed-gensym-11) (unsafe-flimag-part unboxed-gensym-9)) + ((unboxed-gensym-12) (unsafe-fl+ unboxed-gensym-7 unboxed-gensym-10)) + ((unboxed-gensym-13) (unsafe-fl+ unboxed-gensym-8 unboxed-gensym-11))) + (unsafe-make-flrectangular unboxed-gensym-12 unboxed-gensym-13)))) +(void) diff --git a/collects/tests/typed-scheme/optimizer/non-optimized/unboxed-let3.rkt b/collects/tests/typed-scheme/optimizer/non-optimized/unboxed-let3.rkt new file mode 100644 index 0000000000..5c9577f4ab --- /dev/null +++ b/collects/tests/typed-scheme/optimizer/non-optimized/unboxed-let3.rkt @@ -0,0 +1,15 @@ +#lang typed/scheme + +(require racket/unsafe/ops) + +;; both boxed and unboxed uses, we unbox anyway +;; causes unnecessary boxing/unboxing if we take a boxed path when +;; unboxing a complex literal or variable, but I expect this case +;; to be uncommon +;; by comparison, cases where we leave a result unboxed and box it +;; if needed (like here) or cases where this would unbox loop variables +;; are likely to be more common, and more interesting +(let ((x (+ 1.0+2.0i 2.0+4.0i))) + (if (even? 2) + x + (+ x 2.0+4.0i))) diff --git a/collects/typed-scheme/optimizer/inexact-complex.rkt b/collects/typed-scheme/optimizer/inexact-complex.rkt index def4dde921..95be46370b 100644 --- a/collects/typed-scheme/optimizer/inexact-complex.rkt +++ b/collects/typed-scheme/optimizer/inexact-complex.rkt @@ -332,6 +332,16 @@ e.imag-binding ... #,@(map (lambda (i) ((optimize) (get-arg i))) boxed)))]))) ; boxed params + + ;; unboxed variable used in a boxed fashion, we have to box + (pattern v:id + #:with unboxed-info (dict-ref unboxed-vars-table #'v #f) + #:when (syntax->datum #'unboxed-info) + #:with real-binding (car (syntax->list #'unboxed-info)) + #:with imag-binding (cadr (syntax->list #'unboxed-info)) + #:with opt + (begin (log-optimization "boxing of an unboxed variable" #'v) + #'(unsafe-make-flrectangular real-binding imag-binding))) (pattern e:inexact-complex-arith-opt-expr #:with opt diff --git a/collects/typed-scheme/optimizer/unboxed-let.rkt b/collects/typed-scheme/optimizer/unboxed-let.rkt index f4f7948d80..a5a0369bcc 100644 --- a/collects/typed-scheme/optimizer/unboxed-let.rkt +++ b/collects/typed-scheme/optimizer/unboxed-let.rkt @@ -109,16 +109,15 @@ (ormap (lambda (x) (and (identifier? x) (free-identifier=? x v))) (syntax->list exp))) -;; if a variable is only used in complex arithmetic operations, it's safe -;; to unbox it +;; if a variable is used at least once in complex arithmetic operations, +;; it's worth unboxing (define (could-be-unboxed-in? v exp) ;; if v is a direct child of exp, that means it's used in a boxed ;; fashion, and is not safe to unboxed ;; if not, recur on the subforms (define (look-at exp) - (and (not (direct-child-of? v exp)) - (andmap rec (syntax->list exp)))) + (ormap rec (syntax->list exp))) (define (rec exp) (syntax-parse exp @@ -126,7 +125,8 @@ ;; can be used in a complex arithmetic expr, can be a direct child [exp:inexact-complex-arith-opt-expr - (andmap rec (syntax->list #'exp))] + (or (direct-child-of? v #'exp) + (ormap rec (syntax->list #'exp)))] ;; recur down [((~and op (~or (~literal #%plain-lambda) (~literal define-values)))