(module (debug-scc optimize-letrec current-letrec-pass) (define (unique-prelex x) (let ([x (make-prelex (prelex-name x) (prelex-operand x))]) (set-prelex-source-referenced?! x #t) x)) (define (build-assign* lhs* rhs* body) (define (mark-assigned! lhs) ;;; FIXME: this is very fragile (unless (prelex-source-assigned? lhs) (set-prelex-source-assigned?! lhs (or (prelex-global-location lhs) #t)))) (for-each mark-assigned! lhs*) (let f ([lhs* lhs*] [rhs* rhs*]) (cond [(null? lhs*) body] [else (make-seq (make-assign (car lhs*) (car rhs*)) (f (cdr lhs*) (cdr rhs*)))]))) (define (optimize-letrec/basic x) (define who 'optimize-letrec/basic) (define (do-rec*bind lhs* rhs* body) (make-bind lhs* (map (lambda (x) (make-constant #f)) lhs*) (build-assign* lhs* rhs* body))) (define (do-recbind lhs* rhs* body) (let ([t* (map unique-prelex lhs*)]) (make-bind lhs* (map (lambda (x) (make-constant #f)) lhs*) (make-bind t* rhs* (build-assign* lhs* t* body))))) (define (L x) (struct-case x [(clambda g cls* cp free name) (make-clambda g (map (lambda (x) (struct-case x [(clambda-case info body) (make-clambda-case info (E body))])) cls*) cp free name)])) (define (E x) (struct-case x [(constant) x] [(prelex) (assert (prelex-source-referenced? x)) x] [(assign lhs rhs) (assert (prelex-source-assigned? lhs)) (make-assign lhs (E rhs))] [(primref) x] [(bind lhs* rhs* body) (if (null? lhs*) (E body) (make-bind lhs* (map E rhs*) (E body)))] [(recbind lhs* rhs* body) (if (null? lhs*) (E body) (do-recbind lhs* (map E rhs*) (E body)))] [(rec*bind lhs* rhs* body) (if (null? lhs*) (E body) (do-rec*bind lhs* (map E rhs*) (E body)))] [(conditional e0 e1 e2) (make-conditional (E e0) (E e1) (E e2))] [(seq e0 e1) (make-seq (E e0) (E e1))] [(clambda g cls* cp free name) (L x)] [(funcall rator rand*) (make-funcall (E rator) (map E rand*))] [(mvcall p c) (make-mvcall (E p) (E c))] [(forcall rator rand*) (make-forcall rator (map E rand*))] [else (error who "invalid expression" (unparse x))])) (E x)) (define (optimize-letrec/waddell x) (define simple-primitives '()) (define who 'optimize-letrec/waddell) (define (extend-hash lhs* h ref) (for-each (lambda (lhs) (hashtable-set! h lhs #t)) lhs*) (lambda (x) (unless (hashtable-ref h x #f) (hashtable-set! h x #t) (ref x)))) (define (E* x* ref comp) (cond [(null? x*) '()] [else (cons (E (car x*) ref comp) (E* (cdr x*) ref comp))])) (define (do-rhs* i lhs* rhs* ref comp vref vcomp) (cond [(null? rhs*) '()] [else (let ([h (make-eq-hashtable)] [rest (do-rhs* (fxadd1 i) lhs* (cdr rhs*) ref comp vref vcomp)]) (let ([ref (lambda (x) (unless (hashtable-ref h x #f) (hashtable-set! h x #t) (ref x) (when (memq x lhs*) (vector-set! vref i #t))))] [comp (lambda () (vector-set! vcomp i #t) (comp))]) (cons (E (car rhs*) ref comp) rest)))])) (define (partition-rhs* i lhs* rhs* vref vcomp) (cond [(null? lhs*) (values '() '() '() '() '() '())] [else (let-values ([(slhs* srhs* llhs* lrhs* clhs* crhs*) (partition-rhs* (fxadd1 i) (cdr lhs*) (cdr rhs*) vref vcomp)] [(lhs rhs) (values (car lhs*) (car rhs*))]) (cond [(prelex-source-assigned? lhs) (values slhs* srhs* llhs* lrhs* (cons lhs clhs*) (cons rhs crhs*))] [(clambda? rhs) (values slhs* srhs* (cons lhs llhs*) (cons rhs lrhs*) clhs* crhs*)] [(or (vector-ref vref i) (vector-ref vcomp i)) (values slhs* srhs* llhs* lrhs* (cons lhs clhs*) (cons rhs crhs*))] [else (values (cons lhs slhs*) (cons rhs srhs*) llhs* lrhs* clhs* crhs*)] ))])) (define (do-recbind lhs* rhs* body ref comp letrec?) (let ([h (make-eq-hashtable)] [vref (make-vector (length lhs*) #f)] [vcomp (make-vector (length lhs*) #f)]) (let* ([ref (extend-hash lhs* h ref)] [body (E body ref comp)]) (let ([rhs* (do-rhs* 0 lhs* rhs* ref comp vref vcomp)]) (let-values ([(slhs* srhs* llhs* lrhs* clhs* crhs*) (partition-rhs* 0 lhs* rhs* vref vcomp)]) ;;; (let ([made-complex ;;; (filter (lambda (x) (not (var-assigned x))) ;;; clhs*)]) ;;; (unless (null? made-complex) ;;; (set! complex-count ;;; (+ complex-count (length made-complex))) ;;; (printf "COMPLEX (~s) = ~s\n" ;;; complex-count ;;; (map unparse made-complex)))) (let ([void* (map (lambda (x) (make-constant (void))) clhs*)]) (make-bind slhs* srhs* (make-bind clhs* void* (make-fix llhs* lrhs* (if letrec? (let ([t* (map unique-prelex clhs*)]) (make-bind t* crhs* (build-assign* clhs* t* body))) (build-assign* clhs* crhs* body))))))))))) (define (E x ref comp) (struct-case x [(constant) x] [(prelex) (ref x) x] [(assign lhs rhs) (ref lhs) (comp) (make-assign lhs (E rhs ref comp))] [(primref) x] [(bind lhs* rhs* body) (let ([rhs* (E* rhs* ref comp)]) (let ([h (make-eq-hashtable)]) (let ([body (E body (extend-hash lhs* h ref) comp)]) (make-bind lhs* rhs* body))))] [(recbind lhs* rhs* body) (if (null? lhs*) (E body ref comp) (do-recbind lhs* rhs* body ref comp #t))] [(rec*bind lhs* rhs* body) (if (null? lhs*) (E body ref comp) (do-recbind lhs* rhs* body ref comp #f))] [(conditional e0 e1 e2) (make-conditional (E e0 ref comp) (E e1 ref comp) (E e2 ref comp))] [(seq e0 e1) (make-seq (E e0 ref comp) (E e1 ref comp))] [(clambda g cls* cp free name) (make-clambda g (map (lambda (x) (struct-case x [(clambda-case info body) (let ([h (make-eq-hashtable)]) (let ([body (E body (extend-hash (case-info-args info) h ref) void)]) (make-clambda-case info body)))])) cls*) cp free name)] [(funcall rator rand*) (let ([rator (E rator ref comp)] [rand* (E* rand* ref comp)]) (struct-case rator [(primref op) (unless (memq op simple-primitives) (comp))] [else (comp)]) (make-funcall rator rand*))] [(mvcall p c) (let ([p (E p ref comp)] [c (E c ref comp)]) (comp) (make-mvcall p c))] [(forcall rator rand*) (make-forcall rator (E* rand* ref comp))] [else (error who "invalid expression" (unparse x))])) (E x (lambda (x) (error who "free var found" x)) void)) (define (optimize-letrec/scc x) (define who 'optimize-letrec/scc) (module (get-sccs-in-order) (define-struct node (data link* lowlink root done collection)) (define (create-graph v* e** data*) (define h (make-eq-hashtable)) (let ([v* (let f ([v* v*] [data* data*]) (cond [(null? v*) '()] [else (let ([node (make-node (car data*) '() #f #f #f #f)]) (hashtable-set! h (car v*) node) (cons node (f (cdr v*) (cdr data*))))]))]) (for-each (lambda (v e*) (set-node-link*! v (map (lambda (f) (or (hashtable-ref h f #f) (error who "invalid node" f))) e*))) v* e**) v*)) (define (compute-sccs v*) ; Tarjan's algorithm (define scc* '()) (define (compute-sccs v) (define index 0) (define stack '()) (define (tarjan v) (let ([v-index index]) (set-node-root! v v-index) (set! stack (cons v stack)) (set! index (fx+ index 1)) (for-each (lambda (v^) (unless (node-done v^) (unless (node-root v^) (tarjan v^)) (set-node-root! v (fxmin (node-root v) (node-root v^))))) (node-link* v)) (when (fx= (node-root v) v-index) (set! scc* (cons (let f ([ls stack]) (let ([v^ (car ls)]) (set-node-done! v^ #t) (cons v^ (if (eq? v^ v) (begin (set! stack (cdr ls)) '()) (f (cdr ls)))))) scc*))))) (tarjan v)) (for-each (lambda (v) (unless (node-done v) (compute-sccs v))) v*) (reverse scc*)) (define (get-sccs-in-order n* e** data*) (let ([G (create-graph n* e** data*)]) (let ([sccs (compute-sccs G)]) (map (lambda (scc) (map node-data scc)) sccs))))) (define (gen-letrecs scc* ordered? body) (define (mkfix b* body) (if (null? b*) body (make-fix (map binding-lhs b*) (map binding-rhs b*) body))) (define (gen-letrec scc fix* body) (define (mklet lhs* rhs* body) (if (null? lhs*) body (make-bind lhs* rhs* body))) (define (lambda-binding? x) (and (not (prelex-source-assigned? (binding-lhs x))) (clambda? (binding-rhs x)))) (define (mkset!s b* body) (cond [(null? b*) body] [else (let* ([b (car b*)] [lhs (binding-lhs b)]) (unless (prelex-source-assigned? lhs) (when (debug-scc) (printf "MADE COMPLEX ~s\n" (unparse lhs))) (set-prelex-source-assigned?! lhs (or (prelex-global-location lhs) #t))) (make-seq (make-assign lhs (binding-rhs b)) (mkset!s (cdr b*) body)))])) (cond [(null? (cdr scc)) (let ([b (car scc)]) (cond [(lambda-binding? b) (values (cons b fix*) body)] [(not (memq b (binding-free* b))) (values '() (mklet (list (binding-lhs b)) (list (binding-rhs b)) (mkfix fix* body)))] [else (values '() (mklet (list (binding-lhs b)) (list (make-funcall (make-primref 'void) '())) (mkset!s scc (mkfix fix* body))))]))] [else (let-values ([(lambda* complex*) (partition lambda-binding? scc)]) (cond [(null? complex*) (values (append lambda* fix*) body)] [else (let ([complex* (if ordered? (sort-bindings complex*) complex*)]) (values '() (mklet (map binding-lhs complex*) (map (lambda (x) (make-funcall (make-primref 'void) '())) complex*) (mkfix (append lambda* fix*) (mkset!s complex* body)))))]))])) (let-values ([(fix* body) (let f ([scc* scc*]) (cond [(null? scc*) (values '() body)] [else (let-values ([(fix* body) (f (cdr scc*))]) (gen-letrec (car scc*) fix* body))]))]) (mkfix fix* body))) (define (do-recbind lhs* rhs* body bc ordered?) (define (make-bindings lhs* rhs* bc i) (cond [(null? lhs*) '()] [else (let ([b (make-binding i (car lhs*) (car rhs*) #f bc '())]) (set-prelex-operand! (car lhs*) b) (cons b (make-bindings (cdr lhs*) (cdr rhs*) bc (+ i 1))))])) (define (complex? x) (or (binding-complex x) (prelex-source-assigned? (binding-lhs x)))) (define (insert-order-edges b*) (define (mark pb b*) (unless (null? b*) (let ([b (car b*)]) (if (complex? b) (let ([free* (binding-free* b)]) (unless (memq pb free*) (set-binding-free*! b (cons pb free*))) (mark b (cdr b*))) (mark pb (cdr b*)))))) (unless (null? b*) (let ([b (car b*)]) (if (complex? b) (mark b (cdr b*)) (insert-order-edges (cdr b*)))))) (let ([b* (make-bindings lhs* rhs* bc 0)]) (for-each (lambda (b) (set-binding-rhs! b (E (binding-rhs b) b))) b*) (for-each (lambda (x) (set-prelex-operand! x #f)) lhs*) (let ([body (E body bc)]) (when ordered? (insert-order-edges b*)) (let ([scc* (get-sccs-in-order b* (map binding-free* b*) b*)]) (when (debug-scc) (printf "SCCS:\n") (for-each (lambda (scc) (printf " ~s\n" (map unparse (map binding-lhs scc)))) scc*)) (gen-letrecs scc* ordered? body))))) (define (sort-bindings ls) (list-sort (lambda (x y) (< (binding-serial x) (binding-serial y))) ls)) (define-struct binding (serial lhs rhs complex prev free*)) (define (mark-complex bc) (unless (binding-complex bc) (set-binding-complex! bc #t) (mark-complex (binding-prev bc)))) (define (mark-free var bc) (let ([rb (prelex-operand var)]) (when rb (let ([lb (let ([pr (binding-prev rb)]) (let f ([bc bc]) (let ([bcp (binding-prev bc)]) (cond [(eq? bcp pr) bc] [else (f bcp)]))))]) (let ([free* (binding-free* lb)]) (unless (memq rb free*) ;(printf "MARK FREE ~s in ~s\n" ; (unparse (binding-lhs rb)) ; (unparse (binding-lhs lb))) (set-binding-free*! lb (cons rb free*)))))))) (define (E* x* bc) (map (lambda (x) (E x bc)) x*)) (define (L x bc) (struct-case x [(clambda g cls* cp free name) (let ([bc (make-binding #f #f #f #t bc '())]) (make-clambda g (map (lambda (x) (struct-case x [(clambda-case info body) (make-clambda-case info (E body bc))])) cls*) cp free name))])) (define (E x bc) (struct-case x [(constant) x] [(prelex) (assert (prelex-source-referenced? x)) (mark-free x bc) (when (prelex-source-assigned? x) (mark-complex bc)) x] [(assign lhs rhs) (assert (prelex-source-assigned? lhs)) ;(set-prelex-source-assigned?! lhs #t) (mark-free lhs bc) (mark-complex bc) (make-assign lhs (E rhs bc))] [(primref) x] [(bind lhs* rhs* body) (if (null? lhs*) (E body bc) (make-bind lhs* (E* rhs* bc) (E body bc)))] [(recbind lhs* rhs* body) (if (null? lhs*) (E body bc) (do-recbind lhs* rhs* body bc #f))] [(rec*bind lhs* rhs* body) (if (null? lhs*) (E body bc) (do-recbind lhs* rhs* body bc #t))] [(conditional e0 e1 e2) (make-conditional (E e0 bc) (E e1 bc) (E e2 bc))] [(seq e0 e1) (make-seq (E e0 bc) (E e1 bc))] [(clambda g cls* cp free name) (L x bc)] [(funcall rator rand*) (mark-complex bc) (make-funcall (E rator bc) (E* rand* bc))] [(mvcall p c) (mark-complex bc) (make-mvcall (E p bc) (E c bc))] [(forcall rator rand*) (mark-complex bc) (make-forcall rator (E* rand* bc))] [else (error who "invalid expression" (unparse x))])) ;(printf "===========================================\n") (let ([x (E x (make-binding #f #f #f #t #t '()))]) ;(pretty-print (unparse x)) x)) (define debug-scc (make-parameter #f)) (define current-letrec-pass (make-parameter 'scc (lambda (x) (if (memq x '(scc waddell basic)) x (die 'current-letrec-pass "invalid" x))))) (define (optimize-letrec x) (case (current-letrec-pass) [(scc) (optimize-letrec/scc x)] [(waddell) (optimize-letrec/waddell x)] [(basic) (optimize-letrec/basic x)] [else (die 'optimize-letrec "invalid" (current-letrec-pass))])) )