Cleanup float complex optimizations.

This changes might have bad changes, we should take a closer look at the
diffs.
This commit is contained in:
Eric Dobson 2013-09-04 23:13:54 -07:00
parent 2ea55efeec
commit a1759de5b6
4 changed files with 343 additions and 518 deletions

View File

@ -1,7 +1,7 @@
#lang racket/base
(require syntax/parse syntax/stx syntax/id-table racket/dict
racket/match racket/syntax
racket/syntax racket/match syntax/parse/experimental/specialize
"../utils/utils.rkt" racket/unsafe/ops unstable/sequence
(for-template racket/base racket/math racket/flonum racket/unsafe/ops)
(utils tc-utils)
@ -14,6 +14,26 @@
float-complex-call-site-opt-expr arity-raising-opt-msg
unboxed-vars-table unboxed-funs-table)
(define-literal-syntax-class +)
(define-literal-syntax-class -)
(define-literal-syntax-class *)
(define-literal-syntax-class /)
(define-literal-syntax-class conjugate)
(define-literal-syntax-class magnitude)
(define-literal-syntax-class make-polar)
(define-literal-syntax-class exp)
(define-literal-syntax-class make-rectangular^ (make-rectangular unsafe-make-flrectangular))
(define-literal-syntax-class real-part^ (real-part flreal-part unsafe-flreal-part))
(define-literal-syntax-class imag-part^ (imag-part flimag-part unsafe-flimag-part))
(define-merged-syntax-class projection^ (real-part^ imag-part^))
(define-merged-syntax-class float-complex-op (+^ -^ *^ conjugate^ exp^))
(define-merged-syntax-class float-complex->float-op (magnitude^ projection^))
(define-syntax-class/specialize float-expr (subtyped-expr -Flonum))
(define-syntax-class/specialize float-complex-expr (subtyped-expr -FloatComplex))
;; contains the bindings which actually exist as separate bindings for each component
;; associates identifiers to lists (real-binding imag-binding orig-binding-occurrence)
@ -28,18 +48,23 @@
;; params first, then all imaginary parts, then all boxed arguments
(define unboxed-funs-table (make-free-id-table))
(define complex-unboxing-opt-msg "Complex number unboxing.")
(define arity-raising-opt-msg "Complex number arity raising.")
(define (binding-names)
(generate-temporaries (list "unboxed-real-" "unboxed-imag-")))
(define arity-raising-opt-msg "Complex number arity raising.")
(define-syntax-rule (log-unboxing-opt opt-label)
(log-opt opt-label "Complex number unboxing."))
(define-syntax-rule (log-arity-raising-opt opt-label)
(log-opt opt-label arity-raising-opt-msg))
;; If a part is 0.0?
(define (0.0? stx)
(equal? (syntax->datum stx) 0.0))
(define (get-part-or-0.0 stx) ; if a component is unavailable, pretend it's 0.0
(if (syntax->datum stx)
stx
#'0.0))
;; a+bi / c+di, names for real and imag parts of result -> one let-values binding clause
(define (unbox-one-complex-/ a b c d res-real res-imag)
(define both-real? (and (equal? (syntax->datum b) 0.0)
(equal? (syntax->datum d) 0.0)))
(define both-real? (and (0.0? b) (0.0? d)))
;; we have the same cases as the Racket `/' primitive (except for the non-float ones)
(define d=0-case
#`(values (unsafe-fl+ (unsafe-fl/ #,a #,c)
@ -83,401 +108,252 @@
;; complex operations
(define-syntax-class unboxed-float-complex-opt-expr
#:commit
#:attributes (real-binding imag-binding (bindings 1))
(pattern (#%plain-app (~and op (~literal +))
;; We let racket's optimizer handle optimization of 0.0s
(pattern (#%plain-app op:+^ (~between cs:unboxed-float-complex-opt-expr 2 +inf.0) ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unboxed binary float complex")]
#:with (bindings ...)
#`(cs.bindings ... ...
#,@(let ()
(define (fl-sum cs) (n-ary->binary #'unsafe-fl+ cs))
(list
#`((real-binding) #,(fl-sum #'(cs.real-binding ...)))
#`((imag-binding) #,(fl-sum #'(cs.imag-binding ...)))))))
(pattern (#%plain-app op:-^ (~between cs:unboxed-float-complex-opt-expr 2 +inf.0) ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unboxed binary float complex")]
#:with (bindings ...)
#`(cs.bindings ... ...
#,@(let ()
(define (fl-subtract cs) (n-ary->binary #'unsafe-fl- cs))
(list
#`((real-binding) #,(fl-subtract #'(cs.real-binding ...)))
#`((imag-binding) #,(fl-subtract #'(cs.imag-binding ...)))))))
(pattern (#%plain-app op:-^ c1:unboxed-float-complex-opt-expr) ; unary -
#:when (subtypeof? this-syntax -FloatComplex)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...)
#`(c1.bindings ...
[(real-binding) (unsafe-fl- 0.0 c1.real-binding)]
[(imag-binding) (unsafe-fl- 0.0 c1.imag-binding)]))
(pattern (#%plain-app op:*^
c1:unboxed-float-complex-opt-expr
c2:unboxed-float-complex-opt-expr
cs:unboxed-float-complex-opt-expr ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed binary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(#,@(append (syntax->list #'(c1.bindings ... c2.bindings ... cs.bindings ... ...))
(let ()
;; we can skip the real parts of imaginaries (#f) and vice versa
(define (skip-0s l)
(let ((l (filter syntax->datum (syntax->list l))))
(case (length l)
((0) #'0.0)
((1) (car l))
(else
(for/fold ((o (car l)))
((e (cdr l)))
#`(unsafe-fl+ #,o #,e))))))
(list
#`((real-binding) #,(skip-0s #'(c1.real-binding c2.real-binding cs.real-binding ...)))
#`((imag-binding) #,(skip-0s #'(c1.imag-binding c2.imag-binding cs.imag-binding ...)))))))))
#:when (or (subtypeof? this-syntax -FloatComplex) (subtypeof? this-syntax -Number))
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unboxed binary float complex")]
#:with (bindings ...)
#`(c1.bindings ... c2.bindings ... cs.bindings ... ...
;; we want to bind the intermediate results to reuse them
;; the final results are bound to real-binding and imag-binding
#,@(let ((lr (syntax->list #'(c1.real-binding c2.real-binding cs.real-binding ...)))
(li (syntax->list #'(c1.imag-binding c2.imag-binding cs.imag-binding ...))))
(let loop ([o1 (car lr)]
[o2 (car li)]
[e1 (cdr lr)]
[e2 (cdr li)]
[rs (append (stx-map (lambda (x) (generate-temporary "unboxed-real-"))
#'(cs.real-binding ...))
(list #'real-binding))]
[is (append (stx-map (lambda (x) (generate-temporary "unboxed-imag-"))
#'(cs.imag-binding ...))
(list #'imag-binding))]
[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)
;; we eliminate operations on the imaginary parts of reals
(let ((o-real? (0.0? o2))
(e-real? (0.0? (car e2))))
(list* #`((#,(car is))
#,(cond ((and o-real? e-real?) #'0.0)
(o-real? #`(unsafe-fl* #,o1 #,(car e2)))
(e-real? #`(unsafe-fl* #,o2 #,(car e1)))
(else
#`(unsafe-fl+ (unsafe-fl* #,o2 #,(car e1))
(unsafe-fl* #,o1 #,(car e2))))))
#`((#,(car rs))
#,(cond ((or o-real? e-real?)
#`(unsafe-fl* #,o1 #,(car e1)))
(else
#`(unsafe-fl- (unsafe-fl* #,o1 #,(car e1))
(unsafe-fl* #,o2 #,(car e2))))))
res))))))))
(pattern (#%plain-app (~and op (~literal -))
(pattern (#%plain-app op:/^
c1:unboxed-float-complex-opt-expr
c2:unboxed-float-complex-opt-expr
cs:unboxed-float-complex-opt-expr ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed binary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(#,@(append (syntax->list #'(c1.bindings ... c2.bindings ... cs.bindings ... ...))
(let ()
;; unlike addition, we simply can't skip real parts of imaginaries
(define (skip-0s l)
(let* ((l1 (stx-map get-part-or-0.0 l))
;; but we can skip all but the first 0
(l2 (filter (lambda (x) (not (equal? (syntax->datum x) 0.0)))
(cdr l1))))
(case (length l2)
((0) (car l1))
(else
(for/fold ((o (car l1)))
((e l2))
#`(unsafe-fl- #,o #,e))))))
(list
#`((real-binding) #,(skip-0s #'(c1.real-binding c2.real-binding cs.real-binding ...)))
#`((imag-binding) #,(skip-0s #'(c1.imag-binding c2.imag-binding cs.imag-binding ...)))))))))
(pattern (#%plain-app (~and op (~literal -)) c1:unboxed-float-complex-opt-expr) ; unary -
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(c1.bindings ...
[(real-binding) (unsafe-fl- 0.0 #,(get-part-or-0.0 #'c1.real-binding))]
[(imag-binding) (unsafe-fl- 0.0 #,(get-part-or-0.0 #'c1.imag-binding))])))
#:when (subtypeof? this-syntax -FloatComplex)
#:with (real-binding imag-binding) (binding-names)
#:with reals #'(c1.real-binding c2.real-binding cs.real-binding ...)
#:with imags #'(c1.imag-binding c2.imag-binding cs.imag-binding ...)
#:do [(log-unboxing-opt "unboxed binary float complex")]
#:with (bindings ...)
#`(c1.bindings ... c2.bindings ... cs.bindings ... ...
;; we want to bind the intermediate results to reuse them
;; the final results are bound to real-binding and imag-binding
#,@(let loop ([a (stx-car #'reals)]
[b (stx-car #'imags)]
[e1 (cdr (syntax->list #'reals))]
[e2 (cdr (syntax->list #'imags))]
[rs (append (stx-map (lambda (x) (generate-temporary "unboxed-real-"))
#'(cs.real-binding ...))
(list #'real-binding))]
[is (append (stx-map (lambda (x) (generate-temporary "unboxed-imag-"))
#'(cs.imag-binding ...))
(list #'imag-binding))]
[res '()])
(if (null? e1)
(reverse res)
(loop (car rs) (car is) (cdr e1) (cdr e2) (cdr rs) (cdr is)
(cons (unbox-one-complex-/ a b (car e1) (car e2) (car rs) (car is))
res))))))
(pattern (#%plain-app op:/^ c1:unboxed-float-complex-opt-expr) ; unary /
#:when (subtypeof? this-syntax -FloatComplex)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...)
#`(c1.bindings ...
#,(unbox-one-complex-/ #'1.0 #'0.0 #'c1.real-binding #'c1.imag-binding
#'real-binding #'imag-binding)))
(pattern (#%plain-app (~and op (~literal *))
c1:unboxed-float-complex-opt-expr
c2:unboxed-float-complex-opt-expr
cs:unboxed-float-complex-opt-expr ...)
#:when (or (subtypeof? this-syntax -FloatComplex) (subtypeof? this-syntax -Number))
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed binary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(c1.bindings ... c2.bindings ... cs.bindings ... ...
;; we want to bind the intermediate results to reuse them
;; the final results are bound to real-binding and imag-binding
#,@(let ((lr (stx-map get-part-or-0.0
#'(c1.real-binding c2.real-binding cs.real-binding ...)))
(li (stx-map get-part-or-0.0
#'(c1.imag-binding c2.imag-binding cs.imag-binding ...))))
(let loop ([o1 (car lr)]
[o2 (car li)]
[e1 (cdr lr)]
[e2 (cdr li)]
[rs (append (stx-map (lambda (x) (generate-temporary "unboxed-real-"))
#'(cs.real-binding ...))
(list #'real-binding))]
[is (append (stx-map (lambda (x) (generate-temporary "unboxed-imag-"))
#'(cs.imag-binding ...))
(list #'imag-binding))]
[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)
;; we eliminate operations on the imaginary parts of reals
(let ((o-real? (equal? (syntax->datum o2) 0.0))
(e-real? (equal? (syntax->datum (car e2)) 0.0)))
(list* #`((#,(car is))
#,(cond ((and o-real? e-real?) #'0.0)
(o-real? #`(unsafe-fl* #,o1 #,(car e2)))
(e-real? #`(unsafe-fl* #,o2 #,(car e1)))
(else
#`(unsafe-fl+ (unsafe-fl* #,o2 #,(car e1))
(unsafe-fl* #,o1 #,(car e2))))))
#`((#,(car rs))
#,(cond ((or o-real? e-real?)
#`(unsafe-fl* #,o1 #,(car e1)))
(else
#`(unsafe-fl- (unsafe-fl* #,o1 #,(car e1))
(unsafe-fl* #,o2 #,(car e2))))))
res)))))))))
(pattern (#%plain-app op:conjugate^ c:unboxed-float-complex-opt-expr)
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding #'c.real-binding
#:with imag-binding (generate-temporary "unboxed-imag-")
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...)
#`(c.bindings ...
((imag-binding) (unsafe-fl- 0.0 c.imag-binding))))
(pattern (#%plain-app (~and op (~literal /))
c1:unboxed-float-complex-opt-expr
c2:unboxed-float-complex-opt-expr
cs:unboxed-float-complex-opt-expr ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with reals (stx-map get-part-or-0.0
#'(c1.real-binding c2.real-binding cs.real-binding ...))
#:with imags (stx-map get-part-or-0.0
#'(c1.imag-binding c2.imag-binding cs.imag-binding ...))
#:with (bindings ...)
(begin (log-optimization "unboxed binary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(c1.bindings ... c2.bindings ... cs.bindings ... ...
;; we want to bind the intermediate results to reuse them
;; the final results are bound to real-binding and imag-binding
#,@(let loop ([a (stx-car #'reals)]
[b (stx-car #'imags)]
[e1 (cdr (syntax->list #'reals))]
[e2 (cdr (syntax->list #'imags))]
[rs (append (stx-map (lambda (x) (generate-temporary "unboxed-real-"))
#'(cs.real-binding ...))
(list #'real-binding))]
[is (append (stx-map (lambda (x) (generate-temporary "unboxed-imag-"))
#'(cs.imag-binding ...))
(list #'imag-binding))]
[res '()])
(if (null? e1)
(reverse res)
(loop (car rs) (car is) (cdr e1) (cdr e2) (cdr rs) (cdr is)
(cons (unbox-one-complex-/ a b (car e1) (car e2) (car rs) (car is))
res)))))))
(pattern (#%plain-app (~and op (~literal /)) c1:unboxed-float-complex-opt-expr) ; unary /
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(c1.bindings ...
#,(unbox-one-complex-/ #'1.0 #'0.0 #'c1.real-binding #'c1.imag-binding
#'real-binding #'imag-binding))))
(pattern (#%plain-app op:magnitude^ c:unboxed-float-complex-opt-expr)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding #'0.0
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...)
#`(c.bindings ...
((real-binding)
(unsafe-flsqrt
(unsafe-fl+ (unsafe-fl* c.real-binding c.real-binding)
(unsafe-fl* c.imag-binding c.imag-binding))))))
(pattern (#%plain-app (~and op (~literal conjugate)) c:unboxed-float-complex-opt-expr)
#:when (subtypeof? this-syntax -FloatComplex)
#:with real-binding #'c.real-binding
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(#,@(append (syntax->list #'(c.bindings ...))
(list #`((imag-binding) #,(if (syntax->datum #'c.imag-binding)
#'(unsafe-fl- 0.0 c.imag-binding)
;; our input has no imaginary part
#'0.0)))))))
(pattern (#%plain-app op:exp^ c:unboxed-float-complex-opt-expr)
#:with (real-binding imag-binding) (binding-names)
#:with scaling-factor (generate-temporary "unboxed-scaling-")
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...)
#`(c.bindings ...
((scaling-factor) (unsafe-flexp c.real-binding))
((real-binding) (unsafe-fl* (unsafe-flcos c.imag-binding) scaling-factor))
((imag-binding) (unsafe-fl* (unsafe-flsin c.imag-binding) scaling-factor))))
(pattern (#%plain-app (~and op (~literal magnitude)) c:unboxed-float-complex-opt-expr)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding #'#f
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(c.bindings ...
((real-binding) (unsafe-flsqrt
#,(cond [(not (syntax->datum #'c.imag-binding))
;; just the real part (has to have at least 1 part)
#'(unsafe-fl* c.real-binding c.real-binding)]
[(not (syntax->datum #'c.real-binding))
;; just the imaginary part
#'(unsafe-fl* c.imag-binding c.imag-binding)]
[else
;; both parts
#'(unsafe-fl+ (unsafe-fl* c.real-binding c.real-binding)
(unsafe-fl* c.imag-binding c.imag-binding))]))))))
(pattern (#%plain-app (~and op (~literal exp)) c:unboxed-float-complex-opt-expr)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with scaling-factor (generate-temporary "unboxed-scaling-")
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(c.bindings ...
((scaling-factor) #,(if (syntax->datum #'c.real-binding)
#'(unsafe-flexp c.real-binding)
;; our input has no real part, pretend it's 0.0
#'1.0))
((real-binding) #,(if (syntax->datum #'c.imag-binding)
#'(unsafe-fl* (unsafe-flcos c.imag-binding) scaling-factor)
#'1.0))
((imag-binding) #,(if (syntax->datum #'c.imag-binding)
#'(unsafe-fl* (unsafe-flsin c.imag-binding) scaling-factor)
#'0.0)))))
(pattern (#%plain-app (~and op (~or (~literal real-part) (~literal unsafe-flreal-part)))
c:unboxed-float-complex-opt-expr)
#:with real-binding #'c.real-binding
#:with imag-binding #'#f
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#'(c.bindings ...)))
(pattern (#%plain-app (~and op (~or (~literal imag-part) (~literal unsafe-flimag-part)))
c:unboxed-float-complex-opt-expr)
#:with real-binding #'c.imag-binding
#:with imag-binding #'#f
#:with (bindings ...)
(begin (log-optimization "unboxed unary float complex"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#'(c.bindings ...)))
(pattern (#%plain-app op:real-part^ c:unboxed-float-complex-opt-expr)
#:with real-binding #'c.real-binding
#:with imag-binding #'0.0
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...) #'(c.bindings ...))
(pattern (#%plain-app op:imag-part^ c:unboxed-float-complex-opt-expr)
#:with real-binding #'c.imag-binding
#:with imag-binding #'0.0
#:do [(log-unboxing-opt "unboxed unary float complex")]
#:with (bindings ...) #'(c.bindings ...))
;; special handling of reals inside complex operations
;; must be after any cases that we are supposed to handle
(pattern e:float-arg-expr
#:with real-binding (generate-temporary 'unboxed-float-)
#:with imag-binding #'#f
#:with (bindings ...)
(begin (log-optimization "float-arg-expr in complex ops"
complex-unboxing-opt-msg
this-syntax)
#`(((real-binding) e.opt))))
#:with real-binding (generate-temporary 'unboxed-float-)
#:with imag-binding #'0.0
#:do [(log-unboxing-opt "float-arg-expr in complex ops")]
#:with (bindings ...) #`(((real-binding) e.opt)))
;; we can eliminate boxing that was introduced by the user
(pattern (#%plain-app (~and op (~or (~literal make-rectangular)
(~literal unsafe-make-flrectangular)))
real:float-arg-expr imag:float-arg-expr)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "make-rectangular elimination"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#'(((real-binding) real.opt)
((imag-binding) imag.opt))))
(pattern (#%plain-app (~and op (~literal make-polar))
r:float-arg-expr theta:float-arg-expr)
#:with magnitude (generate-temporary)
#:with angle (generate-temporary)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "make-rectangular elimination"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#'(((magnitude) r.opt)
((angle) theta.opt)
((real-binding) (unsafe-fl* magnitude (unsafe-flcos angle)))
((imag-binding) (unsafe-fl* magnitude (unsafe-flsin angle))))))
(pattern (#%plain-app op:make-rectangular^ real:float-arg-expr imag:float-arg-expr)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "make-rectangular elimination")]
#:with (bindings ...)
#'(((real-binding) real.opt)
((imag-binding) imag.opt)))
(pattern (#%plain-app op:make-polar^ r:float-arg-expr theta:float-arg-expr)
#:with radius (generate-temporary)
#:with angle (generate-temporary)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "make-rectangular elimination")]
#:with (bindings ...)
#'(((radius) r.opt)
((angle) theta.opt)
((real-binding) (unsafe-fl* radius (unsafe-flcos angle)))
((imag-binding) (unsafe-fl* radius (unsafe-flsin angle)))))
;; if we see a variable that's already unboxed, use the unboxed bindings
(pattern v:id
#:with unboxed-info (dict-ref unboxed-vars-table #'v #f)
#:when (syntax->datum #'unboxed-info)
#:with (real-binding imag-binding orig-binding) #'unboxed-info
#:with (bindings ...)
(begin (log-optimization "leave var unboxed"
complex-unboxing-opt-msg
this-syntax)
;; we need to introduce both the binding and the use at the
;; same time
(add-disappeared-use (syntax-local-introduce #'v))
(add-disappeared-binding (syntax-local-introduce #'orig-binding))
#'()))
#:with unboxed-info (dict-ref unboxed-vars-table #'v #f)
#:when (syntax->datum #'unboxed-info)
#:with (real-binding imag-binding orig-binding) #'unboxed-info
#:do [(log-unboxing-opt "leave var unboxed")
;; we need to introduce both the binding and the use at the
;; same time
(add-disappeared-use (syntax-local-introduce #'v))
(add-disappeared-binding (syntax-local-introduce #'orig-binding))]
#:with (bindings ...) #'())
;; else, do the unboxing here
;; we can unbox literals right away
(pattern (quote n)
#:when (let ((x (syntax->datum #'n)))
(and (number? x)
(not (eq? (imag-part x) 0))))
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unboxed literal"
complex-unboxing-opt-msg
this-syntax)
(let ((n (syntax->datum #'n)))
#`(((real-binding) #,(datum->syntax
#'here
(exact->inexact (real-part n))))
((imag-binding) #,(datum->syntax
#'here
(exact->inexact (imag-part n))))))))
(pattern (quote n)
#:when (real? (syntax->datum #'n))
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding #'#f
#:with (bindings ...)
(begin (log-optimization "unboxed literal"
complex-unboxing-opt-msg
this-syntax)
#`(((real-binding) #,(datum->syntax
#'here
(exact->inexact (syntax->datum #'n)))))))
(pattern (quote n*)
#:do [(define n (syntax->datum #'n*))]
#:when (and (number? n) (not (equal? (imag-part n) 0)))
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unboxed literal")]
#:with (bindings ...)
#`(((real-binding) '#,(exact->inexact (real-part n)))
((imag-binding) '#,(exact->inexact (imag-part n)))))
(pattern (quote n*)
#:do [(define n (syntax->datum #'n*))]
#:when (real? n)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding #'0.0
#:do [(log-unboxing-opt "unboxed literal")]
#:with (bindings ...)
#`(((real-binding) '#,(exact->inexact n))))
(pattern e:float-complex-expr
#:with e* (generate-temporary)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unbox float-complex")]
#:with (bindings ...)
#`(((e*) e.opt)
((real-binding) (unsafe-flreal-part e*))
((imag-binding) (unsafe-flimag-part e*))))
(pattern e:opt-expr
#:when (subtypeof? #'e -Number) ; complex, maybe exact, maybe not
#:with e* (generate-temporary)
#:with (real-binding imag-binding) (binding-names)
#:do [(log-unboxing-opt "unbox complex")]
#:with (bindings ...)
#'(((e*) e.opt)
((real-binding) (exact->inexact (real-part e*)))
((imag-binding) (exact->inexact (imag-part e*)))))
(pattern e:expr
#:when (subtypeof? #'e -FloatComplex)
#:with e* (generate-temporary)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unbox float-complex"
complex-unboxing-opt-msg
this-syntax)
#`(((e*) #,((optimize) #'e))
((real-binding) (unsafe-flreal-part e*))
((imag-binding) (unsafe-flimag-part e*)))))
(pattern e:expr
#:when (subtypeof? #'e -Number) ; complex, maybe exact, maybe not
#:with e* (generate-temporary)
#:with real-binding (generate-temporary "unboxed-real-")
#:with imag-binding (generate-temporary "unboxed-imag-")
#:with (bindings ...)
(begin (log-optimization "unbox complex"
complex-unboxing-opt-msg
this-syntax)
#`(((e*) #,((optimize) #'e))
((real-binding) (exact->inexact (real-part e*)))
((imag-binding) (exact->inexact (imag-part e*))))))
(pattern e:expr
#:with (bindings ...)
(error (format "non exhaustive pattern match" #'e))
#:with real-binding #'#f
#:with imag-binding #'#f))
#:do [(error (format "non exhaustive pattern match" #'e))]
#:with (bindings ...) (list)
#:with real-binding #f
#:with imag-binding #f))
(define-syntax-class float-complex-unary-op
#:commit
(pattern (~or (~literal real-part) (~literal flreal-part))
#:with unsafe (begin (add-disappeared-use this-syntax)
#'unsafe-flreal-part))
(pattern (~or (~literal imag-part) (~literal flimag-part))
#:with unsafe (begin (add-disappeared-use this-syntax)
#'unsafe-flimag-part)))
(define-syntax-class float-complex-op
#:commit
(pattern (~or (~literal +) (~literal -) (~literal *) (~literal conjugate) (~literal exp))))
(define-syntax-class float-complex->float-op
#:commit
(pattern (~or (~literal magnitude)
(~literal real-part) (~literal flreal-part) (~literal unsafe-flreal-part)
(~literal imag-part) (~literal flimag-part) (~literal unsafe-flimag-part))))
(define-syntax-class float-complex-expr
#:commit
(pattern e:expr
#:when (subtypeof? #'e -FloatComplex)
#:with opt ((optimize) #'e)))
(define-syntax-class float-complex-opt-expr
#:commit
#:attributes (opt)
;; Dummy pattern that can't actually match.
;; We just want to detect "unexpected" Complex _types_ that come up.
;; (not necessarily complex _values_, in fact, most of the time this
@ -508,139 +384,91 @@
this-syntax))
;; We don't actually want to match.
#:when #f
#:with real-binding #'#f ; required, otherwise syntax/parse is not happy
#:with imag-binding #'#f
#:with (bindings ...) #'()
;; required, otherwise syntax/parse is not happy
#:with opt #'#f)
;; we can optimize taking the real of imag part of an unboxed complex
;; hopefully, the compiler can eliminate unused bindings for the other part if it's not used
(pattern (#%plain-app (~and op (~or (~literal real-part) (~literal flreal-part) (~literal unsafe-flreal-part)
(~literal imag-part) (~literal flimag-part) (~literal unsafe-flimag-part)))
c:float-complex-expr)
#:with c*:unboxed-float-complex-opt-expr #'c
#:with opt
(begin (log-optimization "complex accessor elimination"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(let*-values (c*.bindings ...)
#,(if (or (free-identifier=? #'op #'real-part)
(free-identifier=? #'op #'flreal-part)
(free-identifier=? #'op #'unsafe-flreal-part))
(get-part-or-0.0 #'c*.real-binding)
(get-part-or-0.0 #'c*.imag-binding)))))
(pattern (#%plain-app op:projection^ c:float-complex-expr)
#:with c*:unboxed-float-complex-opt-expr #'c
#:do [(log-unboxing-opt "complex accessor elimination")]
#:with opt #`(let*-values (c*.bindings ...)
#,(if (or (free-identifier=? #'op #'real-part)
(free-identifier=? #'op #'flreal-part)
(free-identifier=? #'op #'unsafe-flreal-part))
#'c*.real-binding
#'c*.imag-binding)))
(pattern (#%plain-app op:float-complex-unary-op n:float-complex-expr)
#:with opt
(begin (log-optimization "unary float complex"
complex-unboxing-opt-msg
this-syntax)
#'(op.unsafe n.opt)))
(pattern (#%plain-app (~and op (~literal make-polar)) r theta)
#:when (subtypeof? this-syntax -FloatComplex)
#:with exp*:unboxed-float-complex-opt-expr this-syntax
#:with opt
(begin (log-optimization "make-polar"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(let*-values (exp*.bindings ...)
(unsafe-make-flrectangular #,(get-part-or-0.0 #'exp*.real-binding)
#,(get-part-or-0.0 #'exp*.imag-binding)))))
(pattern (#%plain-app op:make-polar^ r theta)
#:when (subtypeof? this-syntax -FloatComplex)
#:with exp:unboxed-float-complex-opt-expr this-syntax
#:do [(log-unboxing-opt "make-polar")]
#:with opt #`(let*-values (exp.bindings ...)
(unsafe-make-flrectangular exp.real-binding exp.imag-binding)))
(pattern (#%plain-app op:id args:expr ...)
#:with unboxed-info (dict-ref unboxed-funs-table #'op #f)
#:when (syntax->datum #'unboxed-info)
#:with (~var e* (float-complex-call-site-opt-expr
#'unboxed-info #'op)) ; no need to optimize op
this-syntax
#:with opt
(begin (log-optimization "call to fun with unboxed args"
arity-raising-opt-msg
this-syntax)
#'e*.opt))
#:do [(define unboxed-info (dict-ref unboxed-funs-table #'op #f))]
#:when unboxed-info
;no need to optimize op
#:with (~var || (float-complex-call-site-opt-expr unboxed-info #'op)) this-syntax
#:do [(log-arity-raising-opt "call to fun with unboxed args")])
(pattern e:float-complex-arith-opt-expr
#:with opt #'e.opt))
(pattern :float-complex-arith-opt-expr))
(define-syntax-class float-complex-arith-opt-expr
#:commit
#:attributes (opt)
(pattern (#%plain-app op:float-complex->float-op e:expr ...)
#:when (subtypeof? this-syntax -Flonum)
#:with exp*:unboxed-float-complex-opt-expr this-syntax
#:with real-binding #'exp*.real-binding
#:with imag-binding #'#f
#:with (bindings ...) #'(exp*.bindings ...)
#:with opt
(begin (add-disappeared-use #'op)
#`(let*-values (exp*.bindings ...)
#,(get-part-or-0.0 #'real-binding))))
#:when (subtypeof? this-syntax -Flonum)
#:with exp:unboxed-float-complex-opt-expr this-syntax
#:with opt #`(let*-values (exp.bindings ...) exp.real-binding))
(pattern (#%plain-app op:float-complex-op e:expr ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:with exp*:unboxed-float-complex-opt-expr this-syntax
#:with real-binding #'exp*.real-binding
#:with imag-binding #'exp*.imag-binding
#:with (bindings ...) #'(exp*.bindings ...)
#:with opt
(begin (add-disappeared-use #'op)
#`(let*-values (exp*.bindings ...)
(unsafe-make-flrectangular #,(get-part-or-0.0 #'exp*.real-binding)
#,(get-part-or-0.0 #'exp*.imag-binding)))))
#:when (subtypeof? this-syntax -FloatComplex)
#:with exp:unboxed-float-complex-opt-expr this-syntax
#:with opt #`(let*-values (exp.bindings ...)
(unsafe-make-flrectangular exp.real-binding exp.imag-binding)))
;; division is special. can only optimize if none of the arguments can be exact 0.
;; otherwise, optimization is unsound (we'd give a result where we're supposed to throw an error)
(pattern (#%plain-app (~literal /) e:expr ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:when (let ([irritants
(for/list ([c (in-syntax #'(e ...))]
#:when (match (type-of c)
[(tc-result1: t)
(subtype -Zero t)]
[_ #t]))
c)])
(define safe-to-opt? (null? irritants))
;; result is Float-Complex, but unsafe to optimize, missed optimization
(unless safe-to-opt?
(log-missed-optimization
"Float-Complex division, potential exact 0s on the rhss"
(string-append
"This expression has a Float-Complex type, but cannot be safely unboxed. "
"The second (and later) arguments could potentially be exact 0."
(if (null? irritants)
""
"\nTo fix, change the highlighted expression(s) to have Float (or Float-Complex) type(s)."))
this-syntax irritants))
safe-to-opt?)
#:with exp*:unboxed-float-complex-opt-expr this-syntax
#:with real-binding #'exp*.real-binding
#:with imag-binding #'exp*.imag-binding
#:with (bindings ...) #'(exp*.bindings ...)
#:with opt
(begin (add-disappeared-use #'op)
#`(let*-values (exp*.bindings ...)
(unsafe-make-flrectangular #,(get-part-or-0.0 #'exp*.real-binding)
#,(get-part-or-0.0 #'exp*.imag-binding)))))
(pattern (#%plain-app op:/^ e:expr ...)
#:when (subtypeof? this-syntax -FloatComplex)
#:when (let ([irritants
(for/list ([c (in-syntax #'(e ...))]
#:when (match (type-of c)
[(tc-result1: t)
(subtype -Zero t)]
[_ #t]))
c)])
(define safe-to-opt? (null? irritants))
;; result is Float-Complex, but unsafe to optimize, missed optimization
(unless safe-to-opt?
(log-missed-optimization
"Float-Complex division, potential exact 0s on the rhss"
(string-append
"This expression has a Float-Complex type, but cannot be safely unboxed. "
"The second (and later) arguments could potentially be exact 0."
(if (null? irritants)
""
"\nTo fix, change the highlighted expression(s) to have Float (or Float-Complex) type(s)."))
this-syntax irritants))
safe-to-opt?)
#:with exp:unboxed-float-complex-opt-expr this-syntax
#:with opt #`(let*-values (exp.bindings ...)
(unsafe-make-flrectangular exp.real-binding exp.imag-binding)))
(pattern v:id
#:with unboxed-info (dict-ref unboxed-vars-table #'v #f)
#:when (syntax->datum #'unboxed-info)
#:when (subtypeof? #'v -FloatComplex)
#:with (real-binding imag-binding orig-binding) #'unboxed-info
#:with (bindings ...) #'()
;; unboxed variable used in a boxed fashion, we have to box
#:with opt
(begin (log-optimization "unboxed complex variable"
complex-unboxing-opt-msg
this-syntax)
;; we need to introduce both the binding and the use at the
;; same time
(add-disappeared-use (syntax-local-introduce #'v))
(add-disappeared-binding (syntax-local-introduce #'orig-binding))
#'(unsafe-make-flrectangular real-binding imag-binding))))
#:do [(define unboxed-info (dict-ref unboxed-vars-table #'v #f))]
#:when unboxed-info
#:when (subtypeof? #'v -FloatComplex)
#:with (real-binding imag-binding orig-binding) unboxed-info
;; we need to introduce both the binding and the use at the same time
#:do [(log-unboxing-opt "unboxed complex variable")
(add-disappeared-use (syntax-local-introduce #'v))
(add-disappeared-binding (syntax-local-introduce #'orig-binding))]
;; unboxed variable used in a boxed fashion, we have to box
#:with opt #'(unsafe-make-flrectangular real-binding imag-binding)))
;; takes as argument a structure describing which arguments will be unboxed
;; and the optimized version of the operator. operators are optimized elsewhere
@ -651,21 +479,18 @@
;; call site of a function with unboxed parameters
;; the calling convention is: real parts of unboxed, imag parts, boxed
(pattern (#%plain-app op:expr args:expr ...)
#:with ((to-unbox ...) (boxed ...)) unboxed-info
#:with opt
(let ((args (syntax->list #'(args ...)))
(unboxed (syntax->datum #'(to-unbox ...)))
(boxed (syntax->datum #'(boxed ...))))
(define (get-arg i) (list-ref args i))
(syntax-parse (map get-arg unboxed)
[(e:unboxed-float-complex-opt-expr ...)
(log-optimization "unboxed call site"
complex-unboxing-opt-msg
this-syntax)
(add-disappeared-use #'op)
#`(let*-values (e.bindings ... ...)
(#%plain-app #,opt-operator
#,@(stx-map get-part-or-0.0 #'(e.real-binding ...))
#,@(stx-map get-part-or-0.0 #'(e.imag-binding ...))
#,@(map (lambda (i) ((optimize) (get-arg i)))
boxed)))])))) ; boxed params
#:with ((to-unbox ...) (boxed ...)) unboxed-info
#:with opt
(let ((args (syntax->list #'(args ...)))
(unboxed (syntax->datum #'(to-unbox ...)))
(boxed (syntax->datum #'(boxed ...))))
(define (get-arg i) (list-ref args i))
(syntax-parse (map get-arg unboxed)
[(e:unboxed-float-complex-opt-expr ...)
(log-unboxing-opt "unboxed call site")
#`(let*-values (e.bindings ... ...)
(#%plain-app #,opt-operator
e.real-binding ...
e.imag-binding ...
#,@(map (lambda (i) ((optimize) (get-arg i)))
boxed)))])))) ; boxed params

View File

@ -2,31 +2,19 @@
#<<END
TR opt: float-complex-parts2.rkt 45:0 (real-part (+ 1.0+2.0i 2.0+4.0i)) -- complex accessor elimination
TR opt: float-complex-parts2.rkt 45:11 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 45:11 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 45:14 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 45:14 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 45:23 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 45:23 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 46:0 (unsafe-flreal-part (+ 1.0+2.0i 2.0+4.0i)) -- complex accessor elimination
TR opt: float-complex-parts2.rkt 46:20 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 46:20 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 46:23 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 46:23 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 46:32 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 46:32 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 47:0 (imag-part (+ 1.0+2.0i 2.0+4.0i)) -- complex accessor elimination
TR opt: float-complex-parts2.rkt 47:11 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 47:11 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 47:14 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 47:14 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 47:23 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 47:23 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 48:0 (unsafe-flimag-part (+ 1.0+2.0i 2.0+4.0i)) -- complex accessor elimination
TR opt: float-complex-parts2.rkt 48:20 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 48:20 (+ 1.0+2.0i 2.0+4.0i) -- unboxed binary float complex
TR opt: float-complex-parts2.rkt 48:23 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 48:23 1.0+2.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 48:32 2.0+4.0i -- unboxed literal
TR opt: float-complex-parts2.rkt 48:32 2.0+4.0i -- unboxed literal
END
#<<END
@ -37,6 +25,18 @@ END
END
#lang typed/scheme
#:optimize

View File

@ -10,16 +10,16 @@ TR opt: make-polar.rkt 34:39 (real-part p) -- complex accessor elimination
TR opt: make-polar.rkt 34:39 (real-part p) -- unboxed unary float complex
TR opt: make-polar.rkt 34:50 p -- leave var unboxed
TR opt: make-polar.rkt 34:50 p -- unbox float-complex
TR opt: make-polar.rkt 34:50 p -- unboxed complex variable
TR opt: make-polar.rkt 35:39 (imag-part p) -- complex accessor elimination
TR opt: make-polar.rkt 35:50 p -- leave var unboxed
TR opt: make-polar.rkt 35:50 p -- unboxed complex variable
END
#<<END
"-0.3070.486"
END
#lang typed/scheme
#:optimize

View File

@ -7,7 +7,6 @@ TR opt: real-part-loop.rkt 31:6 loop -- fun -> unboxed fun
TR opt: real-part-loop.rkt 31:6 loop -- unboxed let loop
TR opt: real-part-loop.rkt 32:20 v -- leave var unboxed
TR opt: real-part-loop.rkt 32:20 v -- unbox float-complex
TR opt: real-part-loop.rkt 32:20 v -- unboxed complex variable
TR opt: real-part-loop.rkt 32:6 (> (real-part v) 70000.2) -- binary float comp
TR opt: real-part-loop.rkt 32:9 (real-part v) -- complex accessor elimination
TR opt: real-part-loop.rkt 32:9 (real-part v) -- unboxed unary float complex
@ -22,6 +21,7 @@ END
END
#lang typed/racket/base
#:optimize