From 7853d333495376f065c63a19866ac2eba6f8926a Mon Sep 17 00:00:00 2001 From: Vincent St-Amour Date: Wed, 7 Jul 2010 18:41:25 -0400 Subject: [PATCH] Improved unboxed complex operations. Intermediate results are kept as unboxed floats as long as we stay within complex arithmetic code. --- .../generic/n-ary-inexact-complex.rkt | 2 +- .../generic/nested-inexact-complex.rkt | 3 + .../hand-optimized/inexact-complex-div.rkt | 57 +++++--- .../hand-optimized/inexact-complex-mult.rkt | 39 +++-- .../hand-optimized/inexact-complex.rkt | 43 +++--- .../hand-optimized/n-ary-inexact-complex.rkt | 34 +++-- .../hand-optimized/nested-inexact-complex.rkt | 16 +++ collects/typed-scheme/private/optimize.rkt | 135 +++++++++++++----- 8 files changed, 210 insertions(+), 119 deletions(-) create mode 100644 collects/tests/typed-scheme/optimizer/generic/nested-inexact-complex.rkt create mode 100644 collects/tests/typed-scheme/optimizer/hand-optimized/nested-inexact-complex.rkt diff --git a/collects/tests/typed-scheme/optimizer/generic/n-ary-inexact-complex.rkt b/collects/tests/typed-scheme/optimizer/generic/n-ary-inexact-complex.rkt index 77c5d033d5..1116e006c5 100644 --- a/collects/tests/typed-scheme/optimizer/generic/n-ary-inexact-complex.rkt +++ b/collects/tests/typed-scheme/optimizer/generic/n-ary-inexact-complex.rkt @@ -1,3 +1,3 @@ (module n-ary-inexact-complex typed/scheme #:optimize (require racket/unsafe/ops) - (+ 1.0+2.0i 2.0+4.0i 3.0+6.0i)) + (+ 1.0+2.0i 2.0+4.0i 3.0+6.0i 4.0+8.0i)) diff --git a/collects/tests/typed-scheme/optimizer/generic/nested-inexact-complex.rkt b/collects/tests/typed-scheme/optimizer/generic/nested-inexact-complex.rkt new file mode 100644 index 0000000000..710d09c07c --- /dev/null +++ b/collects/tests/typed-scheme/optimizer/generic/nested-inexact-complex.rkt @@ -0,0 +1,3 @@ +(module nested-inexact-complex typed/scheme #:optimize + (require racket/unsafe/ops) + (+ 1.0+2.0i (- 2.0+4.0i 3.0+6.0i))) diff --git a/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-div.rkt b/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-div.rkt index 3b2dc5a675..e982f7d7cf 100644 --- a/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-div.rkt +++ b/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-div.rkt @@ -1,25 +1,36 @@ (module inexact-complex-div typed/scheme #:optimize (require racket/unsafe/ops) - (let ((t1 (let ((t1 1.0+2.0i) - (t2 2.0+4.0i)) - (let ((a (unsafe-flreal-part t1)) - (b (unsafe-flimag-part t1)) - (c (unsafe-flreal-part t2)) - (d (unsafe-flimag-part t2))) - (let ((den (unsafe-fl+ (unsafe-fl* c c) (unsafe-fl* d d)))) - (unsafe-make-flrectangular - (unsafe-fl/ (unsafe-fl+ (unsafe-fl* a c) (unsafe-fl* b d)) - den) - (unsafe-fl/ (unsafe-fl- (unsafe-fl* b c) (unsafe-fl* a d)) - den)))))) - (t2 3.0+6.0i)) - (let ((a (unsafe-flreal-part t1)) - (b (unsafe-flimag-part t1)) - (c (unsafe-flreal-part t2)) - (d (unsafe-flimag-part t2))) - (let ((den (unsafe-fl+ (unsafe-fl* c c) (unsafe-fl* d d)))) - (unsafe-make-flrectangular - (unsafe-fl/ (unsafe-fl+ (unsafe-fl* a c) (unsafe-fl* b d)) - den) - (unsafe-fl/ (unsafe-fl- (unsafe-fl* b c) (unsafe-fl* a d)) - den)))))) + (let* ((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 3.0+6.0i) + (unboxed-gensym-8 (unsafe-flreal-part unboxed-gensym-7)) + (unboxed-gensym-9 (unsafe-flimag-part unboxed-gensym-7)) + (unboxed-gensym-12 (unsafe-fl+ (unsafe-fl* unboxed-gensym-5 unboxed-gensym-5) + (unsafe-fl* unboxed-gensym-6 unboxed-gensym-6))) + (unboxed-gensym-13 (unsafe-fl+ (unsafe-fl* unboxed-gensym-8 unboxed-gensym-8) + (unsafe-fl* unboxed-gensym-9 unboxed-gensym-9))) + (unboxed-gensym-14 (unsafe-fl/ (unsafe-fl+ (unsafe-fl* unboxed-gensym-2 + unboxed-gensym-5) + (unsafe-fl* unboxed-gensym-3 + unboxed-gensym-6)) + unboxed-gensym-12)) + (unboxed-gensym-15 (unsafe-fl/ (unsafe-fl- (unsafe-fl* unboxed-gensym-3 + unboxed-gensym-5) + (unsafe-fl* unboxed-gensym-2 + unboxed-gensym-6)) + unboxed-gensym-12)) + (unboxed-gensym-10 (unsafe-fl/ (unsafe-fl+ (unsafe-fl* unboxed-gensym-14 + unboxed-gensym-8) + (unsafe-fl* unboxed-gensym-15 + unboxed-gensym-9)) + unboxed-gensym-13)) + (unboxed-gensym-11 (unsafe-fl/ (unsafe-fl- (unsafe-fl* unboxed-gensym-15 + unboxed-gensym-8) + (unsafe-fl* unboxed-gensym-14 + unboxed-gensym-9)) + unboxed-gensym-13))) + (unsafe-make-flrectangular unboxed-gensym-10 unboxed-gensym-11))) diff --git a/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-mult.rkt b/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-mult.rkt index 70726ba8f1..594cad0589 100644 --- a/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-mult.rkt +++ b/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex-mult.rkt @@ -1,23 +1,20 @@ (module inexact-complex-mult typed/scheme #:optimize (require racket/unsafe/ops) - (let ((t1 (let ((t1 1.0+2.0i) - (t2 2.0+4.0i)) - (let ((a (unsafe-flreal-part t1)) - (b (unsafe-flimag-part t1)) - (c (unsafe-flreal-part t2)) - (d (unsafe-flimag-part t2))) - (unsafe-make-flrectangular - (unsafe-fl- (unsafe-fl* a c) - (unsafe-fl* b d)) - (unsafe-fl+ (unsafe-fl* b c) - (unsafe-fl* a d)))))) - (t2 3.0+6.0i)) - (let ((a (unsafe-flreal-part t1)) - (b (unsafe-flimag-part t1)) - (c (unsafe-flreal-part t2)) - (d (unsafe-flimag-part t2))) - (unsafe-make-flrectangular - (unsafe-fl- (unsafe-fl* a c) - (unsafe-fl* b d)) - (unsafe-fl+ (unsafe-fl* b c) - (unsafe-fl* a d)))))) + (let* ((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 3.0+6.0i) + (unboxed-gensym-8 (unsafe-flreal-part unboxed-gensym-7)) + (unboxed-gensym-9 (unsafe-flimag-part unboxed-gensym-7)) + (unboxed-gensym-12 (unsafe-fl- (unsafe-fl* unboxed-gensym-2 unboxed-gensym-5) + (unsafe-fl* unboxed-gensym-3 unboxed-gensym-6))) + (unboxed-gensym-13 (unsafe-fl+ (unsafe-fl* unboxed-gensym-3 unboxed-gensym-5) + (unsafe-fl* unboxed-gensym-2 unboxed-gensym-6))) + (unboxed-gensym-10 (unsafe-fl- (unsafe-fl* unboxed-gensym-12 unboxed-gensym-8) + (unsafe-fl* unboxed-gensym-13 unboxed-gensym-9))) + (unboxed-gensym-11 (unsafe-fl+ (unsafe-fl* unboxed-gensym-13 unboxed-gensym-8) + (unsafe-fl* unboxed-gensym-12 unboxed-gensym-9)))) + (unsafe-make-flrectangular unboxed-gensym-10 unboxed-gensym-11))) diff --git a/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex.rkt b/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex.rkt index 72a694b95e..80b60091e4 100644 --- a/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex.rkt +++ b/collects/tests/typed-scheme/optimizer/hand-optimized/inexact-complex.rkt @@ -1,27 +1,20 @@ (module inexact-complex typed/scheme #:optimize (require racket/unsafe/ops) - (let-values (((real imag) - (let-values (((t1-real t1-imag) - (let ((t 1.0+2.0i)) - (values (unsafe-flreal-part t) - (unsafe-flimag-part t)))) - ((t2-real t2-imag) - (let ((t 2.0+4.0i)) - (values (unsafe-flreal-part t) - (unsafe-flimag-part t))))) - (values - (unsafe-fl+ t1-real t2-real) - (unsafe-fl+ t1-imag t2-imag))))) - (unsafe-make-flrectangular real imag)) - (let-values (((real imag) - (let-values (((t1-real t1-imag) - (let ((t 1.0+2.0i)) - (values (unsafe-flreal-part t) - (unsafe-flimag-part t)))) - ((t2-real t2-imag) - (let ((t 2.0+4.0i)) - (values (unsafe-flreal-part t) - (unsafe-flimag-part t))))) - (values (unsafe-fl- t1-real t2-real) - (unsafe-fl- t1-imag t2-imag))))) - (unsafe-make-flrectangular real imag))) + (let* ((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))) + (unsafe-make-flrectangular unboxed-gensym-7 unboxed-gensym-8)) + (let* ((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))) + (unsafe-make-flrectangular unboxed-gensym-7 unboxed-gensym-8))) diff --git a/collects/tests/typed-scheme/optimizer/hand-optimized/n-ary-inexact-complex.rkt b/collects/tests/typed-scheme/optimizer/hand-optimized/n-ary-inexact-complex.rkt index 536cdac454..52df33259b 100644 --- a/collects/tests/typed-scheme/optimizer/hand-optimized/n-ary-inexact-complex.rkt +++ b/collects/tests/typed-scheme/optimizer/hand-optimized/n-ary-inexact-complex.rkt @@ -1,15 +1,23 @@ (module n-ary-inexact-complex typed/scheme #:optimize (require racket/unsafe/ops) - (let ((t1 (let ((t1 1.0+2.0i) - (t2 2.0+4.0i)) - (unsafe-make-flrectangular - (unsafe-fl+ (unsafe-flreal-part t1) - (unsafe-flreal-part t2)) - (unsafe-fl+ (unsafe-flimag-part t1) - (unsafe-flimag-part t2))))) - (t2 3.0+6.0i)) - (unsafe-make-flrectangular - (unsafe-fl+ (unsafe-flreal-part t1) - (unsafe-flreal-part t2)) - (unsafe-fl+ (unsafe-flimag-part t1) - (unsafe-flimag-part t2))))) + (let* ((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 3.0+6.0i) + (unboxed-gensym-8 (unsafe-flreal-part unboxed-gensym-7)) + (unboxed-gensym-9 (unsafe-flimag-part unboxed-gensym-7)) + (unboxed-gensym-10 4.0+8.0i) + (unboxed-gensym-11 (unsafe-flreal-part unboxed-gensym-10)) + (unboxed-gensym-12 (unsafe-flimag-part unboxed-gensym-10)) + (unboxed-gensym-13 (unsafe-fl+ (unsafe-fl+ (unsafe-fl+ unboxed-gensym-2 + unboxed-gensym-5) + unboxed-gensym-8) + unboxed-gensym-11)) + (unboxed-gensym-14 (unsafe-fl+ (unsafe-fl+ (unsafe-fl+ unboxed-gensym-3 + unboxed-gensym-6) + unboxed-gensym-9) + unboxed-gensym-12))) + (unsafe-make-flrectangular unboxed-gensym-13 unboxed-gensym-14))) diff --git a/collects/tests/typed-scheme/optimizer/hand-optimized/nested-inexact-complex.rkt b/collects/tests/typed-scheme/optimizer/hand-optimized/nested-inexact-complex.rkt new file mode 100644 index 0000000000..7a62e33f60 --- /dev/null +++ b/collects/tests/typed-scheme/optimizer/hand-optimized/nested-inexact-complex.rkt @@ -0,0 +1,16 @@ +(module nested-inexact-complex typed/scheme #:optimize + (require racket/unsafe/ops) + (let* ((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 3.0+6.0i) + (unboxed-gensym-8 (unsafe-flreal-part unboxed-gensym-7)) + (unboxed-gensym-9 (unsafe-flimag-part unboxed-gensym-7)) + (unboxed-gensym-10 (unsafe-fl- unboxed-gensym-5 unboxed-gensym-8)) + (unboxed-gensym-11 (unsafe-fl- unboxed-gensym-6 unboxed-gensym-9)) + (unboxed-gensym-12 (unsafe-fl+ unboxed-gensym-2 unboxed-gensym-10)) + (unboxed-gensym-13 (unsafe-fl+ unboxed-gensym-3 unboxed-gensym-11))) + (unsafe-make-flrectangular unboxed-gensym-12 unboxed-gensym-13))) diff --git a/collects/typed-scheme/private/optimize.rkt b/collects/typed-scheme/private/optimize.rkt index 8dc2fed09a..a58227ca3a 100644 --- a/collects/typed-scheme/private/optimize.rkt +++ b/collects/typed-scheme/private/optimize.rkt @@ -1,7 +1,7 @@ #lang scheme/base (require syntax/parse (for-template scheme/base scheme/flonum scheme/fixnum scheme/unsafe/ops racket/private/for) - "../utils/utils.rkt" "../utils/tc-utils.rkt" unstable/match scheme/match unstable/syntax + "../utils/utils.rkt" "../utils/tc-utils.rkt" unstable/match scheme/match unstable/syntax unstable/values (rep type-rep) syntax/id-table racket/dict (types abbrev type-table utils subtype)) (provide optimize) @@ -60,10 +60,21 @@ #:when (dict-ref tbl #'i #f) #:with unsafe (dict-ref tbl #'i))) +;; to generate temporary symbols in a predictable manner +;; these identifiers are unique within a sequence of unboxed operations +;; necessary to have predictable symbols to add in the hand-optimized versions +;; of the optimizer tests (which check for equality of expanded code) +(define *unboxed-gensym-counter* 0) +(define (unboxed-gensym) + (set! *unboxed-gensym-counter* (add1 *unboxed-gensym-counter*)) + (format-unique-id #'here "unboxed-gensym-~a" *unboxed-gensym-counter*)) + (define-syntax-class inexact-complex-opt-expr (pattern e:unboxed-inexact-complex-opt-expr - #:with opt #'(let-values (((real imag) e.opt)) - (unsafe-make-flrectangular real imag)))) + #:with opt + (begin (set! *unboxed-gensym-counter* 0) + #'(let* (e.bindings ...) + (unsafe-make-flrectangular e.real-part e.imag-part))))) ;; it's faster to take apart a complex number and use unsafe operations on ;; its parts than it is to use generic operations ;; we keep the real and imaginary parts unboxed as long as we stay within @@ -73,52 +84,104 @@ c1:unboxed-inexact-complex-opt-expr c2:unboxed-inexact-complex-opt-expr cs:unboxed-inexact-complex-opt-expr ...) - #:with opt - (begin (log-optimization "binary inexact complex" #'op) - (for/fold ([o #'c1.opt]) - ([e (syntax->list #'(c2.opt cs.opt ...))]) - #`(let-values (((t1-real t1-imag) #,o) - ((t2-real t2-imag) #,e)) - (values - (op.unsafe t1-real t2-real) - (op.unsafe t1-imag t2-imag)))))) + #:with real-part (unboxed-gensym) + #:with imag-part (unboxed-gensym) + #:with (bindings ...) + (begin (log-optimization "unboxed binary inexact complex" #'op) + #`(#,@(append (syntax->list #'(c1.bindings ... c2.bindings ... cs.bindings ... ...)) + (list #`(real-part #,(for/fold ((o #'c1.real-part)) + ((e (syntax->list #'(c2.real-part cs.real-part ...)))) + #`(op.unsafe #,o #,e))) + #`(imag-part #,(for/fold ((o #'c1.imag-part)) + ((e (syntax->list #'(c2.imag-part cs.imag-part ...)))) + #`(op.unsafe #,o #,e)))))))) (pattern (#%plain-app (~and op (~literal *)) c1:unboxed-inexact-complex-opt-expr c2:unboxed-inexact-complex-opt-expr cs:unboxed-inexact-complex-opt-expr ...) - #:with opt - (begin (log-optimization "binary inexact complex" #'op) - (for/fold ([o #'c1.opt]) - ([e (syntax->list #'(c2.opt cs.opt ...))]) - #`(let-values (((a b) #,o) - ((c d) #,e)) - (values - (unsafe-fl- (unsafe-fl* a c) (unsafe-fl* b d)) - (unsafe-fl+ (unsafe-fl* b c) (unsafe-fl* a d))))))) + #:with real-part (unboxed-gensym) + #:with imag-part (unboxed-gensym) + #:with (bindings ...) + (begin (log-optimization "unboxed binary inexact complex" #'op) + #`(c1.bindings ... c2.bindings ... cs.bindings ... ... + ;; we want to bind the intermediate results to reuse them + ;; the final results are bound to real-part and imag-part + #,@(let loop ([o1 #'c1.real-part] + [o2 #'c1.imag-part] + [e1 (syntax->list #'(c2.real-part cs.real-part ...))] + [e2 (syntax->list #'(c2.imag-part cs.imag-part ...))] + [rs (append (map (lambda (x) (unboxed-gensym)) + (syntax->list #'(cs.real-part ...))) + (list #'real-part))] + [is (append (map (lambda (x) (unboxed-gensym)) + (syntax->list #'(cs.imag-part ...))) + (list #'imag-part))] + [res '()]) + (if (null? e1) + (reverse res) + (loop (car rs) (car is) (cdr e1) (cdr e2) (cdr rs) (cdr is) + ;; complex multiplication, imag part, then real part (reverse) + (list* #`(#,(car is) + (unsafe-fl+ (unsafe-fl* #,o2 #,(car e1)) + (unsafe-fl* #,o1 #,(car e2)))) + #`(#,(car rs) + (unsafe-fl- (unsafe-fl* #,o1 #,(car e1)) + (unsafe-fl* #,o2 #,(car e2)))) + res))))))) (pattern (#%plain-app (~and op (~literal /)) c1:unboxed-inexact-complex-opt-expr c2:unboxed-inexact-complex-opt-expr cs:unboxed-inexact-complex-opt-expr ...) - #:with opt - (begin (log-optimization "binary inexact complex" #'op) - (for/fold ([o #'c1.opt]) - ([e (syntax->list #'(c2.opt cs.opt ...))]) - #`(let-values (((a b) #,o) - ((c d) #,e)) - (let ((den (unsafe-fl+ (unsafe-fl* c c) (unsafe-fl* d d)))) - (values - (unsafe-fl/ (unsafe-fl+ (unsafe-fl* a c) (unsafe-fl* b d)) - den) - (unsafe-fl/ (unsafe-fl- (unsafe-fl* b c) (unsafe-fl* a d)) - den))))))) + #:with real-part (unboxed-gensym) + #:with imag-part (unboxed-gensym) + #:with (denominators ...) + (for/list + ([e1 (syntax->list #'(c2.real-part cs.real-part ...))] + [e2 (syntax->list #'(c2.imag-part cs.imag-part ...))]) + #`(#,(unboxed-gensym) (unsafe-fl+ (unsafe-fl* #,e1 #,e1) (unsafe-fl* #,e2 #,e2)))) + #:with (bindings ...) + (begin (log-optimization "unboxed binary inexact complex" #'op) + #`(c1.bindings ... c2.bindings ... cs.bindings ... ... denominators ... + ;; we want to bind the intermediate results to reuse them + ;; the final results are bound to real-part and imag-part + #,@(let loop ([o1 #'c1.real-part] + [o2 #'c1.imag-part] + [e1 (syntax->list #'(c2.real-part cs.real-part ...))] + [e2 (syntax->list #'(c2.imag-part cs.imag-part ...))] + [d (map (lambda (x) (car (syntax-e x))) + (syntax->list #'(denominators ...)))] + [rs (append (map (lambda (x) (unboxed-gensym)) + (syntax->list #'(cs.real-part ...))) + (list #'real-part))] + [is (append (map (lambda (x) (unboxed-gensym)) + (syntax->list #'(cs.imag-part ...))) + (list #'imag-part))] + [res '()]) + (if (null? e1) + (reverse res) + (loop (car rs) (car is) (cdr e1) (cdr e2) (cdr d) (cdr rs) (cdr is) + ;; complex division, imag part, then real part (reverse) + (list* #`(#,(car is) + (unsafe-fl/ (unsafe-fl- (unsafe-fl* #,o2 #,(car e1)) + (unsafe-fl* #,o1 #,(car e2))) + #,(car d))) + #`(#,(car rs) + (unsafe-fl/ (unsafe-fl+ (unsafe-fl* #,o1 #,(car e1)) + (unsafe-fl* #,o2 #,(car e2))) + #,(car d))) + res))))))) (pattern e:opt-expr ;; can't work on inexact reals, which are a subtype of inexact ;; complexes, so this has to be equality #:when (match (type-of #'e) [(tc-result1: (== -InexactComplex type-equal?)) #t] [_ #f]) - #:with opt #'(let ((t e.opt)) - (values (unsafe-flreal-part t) - (unsafe-flimag-part t))))) + #:with e* (unboxed-gensym) + #:with real-part (unboxed-gensym) + #:with imag-part (unboxed-gensym) + #:with (bindings ...) + #'((e* e.opt) + (real-part (unsafe-flreal-part e*)) + (imag-part (unsafe-flimag-part e*))))) (define-syntax-class inexact-complex-unary-op (pattern (~or (~literal real-part) (~literal flreal-part)) #:with unsafe #'unsafe-flreal-part)