diff options
Diffstat (limited to 'module/language/cps/cse.scm')
-rw-r--r-- | module/language/cps/cse.scm | 545 |
1 files changed, 0 insertions, 545 deletions
diff --git a/module/language/cps/cse.scm b/module/language/cps/cse.scm deleted file mode 100644 index c8a57ca0b..000000000 --- a/module/language/cps/cse.scm +++ /dev/null @@ -1,545 +0,0 @@ -;;; Continuation-passing style (CPS) intermediate language (IL) - -;; Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc. - -;;;; This library is free software; you can redistribute it and/or -;;;; modify it under the terms of the GNU Lesser General Public -;;;; License as published by the Free Software Foundation; either -;;;; version 3 of the License, or (at your option) any later version. -;;;; -;;;; This library is distributed in the hope that it will be useful, -;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;;; Lesser General Public License for more details. -;;;; -;;;; You should have received a copy of the GNU Lesser General Public -;;;; License along with this library; if not, write to the Free Software -;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -;;; Commentary: -;;; -;;; Common subexpression elimination for CPS. -;;; -;;; Code: - -(define-module (language cps cse) - #:use-module (ice-9 match) - #:use-module (srfi srfi-1) - #:use-module (language cps) - #:use-module (language cps dfg) - #:use-module (language cps effects-analysis) - #:use-module (language cps renumber) - #:use-module (language cps intset) - #:use-module (rnrs bytevectors) - #:export (eliminate-common-subexpressions)) - -(define (cont-successors cont) - (match cont - (($ $kargs names syms body) - (let lp ((body body)) - (match body - (($ $letk conts body) (lp body)) - (($ $continue k src exp) - (match exp - (($ $prompt escape? tag handler) (list k handler)) - (($ $branch kt) (list k kt)) - (_ (list k))))))) - - (($ $kreceive arity k) (list k)) - - (($ $kclause arity ($ $cont kbody)) (list kbody)) - - (($ $kfun src meta self tail clause) - (let lp ((clause clause)) - (match clause - (($ $cont kclause ($ $kclause _ _ alt)) - (cons kclause (lp alt))) - (#f '())))) - - (($ $kfun src meta self tail #f) '()) - - (($ $ktail) '()))) - -(define (compute-available-expressions dfg min-label label-count idoms) - "Compute and return the continuations that may be reached if flow -reaches a continuation N. Returns a vector of intsets, whose first -index corresponds to MIN-LABEL, and so on." - (let* ((effects (compute-effects dfg min-label label-count)) - ;; Vector of intsets, indicating that at a continuation N, the - ;; values from continuations M... are available. - (avail (make-vector label-count #f)) - (revisit-label #f)) - - (define (label->idx label) (- label min-label)) - (define (idx->label idx) (+ idx min-label)) - (define (get-effects label) (vector-ref effects (label->idx label))) - - (define (propagate! pred succ out) - (let* ((succ-idx (label->idx succ)) - (in (match (lookup-predecessors succ dfg) - ;; Fast path: normal control flow. - ((_) out) - ;; Slow path: control-flow join. - (_ (cond - ((vector-ref avail succ-idx) - => (lambda (in) - (intset-intersect in out))) - (else out)))))) - (when (and (<= succ pred) - (or (not revisit-label) (< succ revisit-label)) - (not (eq? in (vector-ref avail succ-idx)))) - ;; Arrange to revisit if this is not a forward edge and the - ;; available set changed. - (set! revisit-label succ)) - (vector-set! avail succ-idx in))) - - (define (clobber label in) - (let ((fx (get-effects label))) - (cond - ((not (causes-effect? fx &write)) - ;; Fast-path if this expression clobbers nothing. - in) - (else - ;; Kill clobbered expressions. There is no need to check on - ;; any label before than the last dominating label that - ;; clobbered everything. - (let ((first (let lp ((dom label)) - (let* ((dom (vector-ref idoms (label->idx dom)))) - (and (< min-label dom) - (let ((fx (vector-ref effects (label->idx dom)))) - (if (causes-all-effects? fx) - dom - (lp dom)))))))) - (let lp ((i first) (in in)) - (cond - ((intset-next in i) - => (lambda (i) - (if (effect-clobbers? fx (vector-ref effects (label->idx i))) - (lp (1+ i) (intset-remove in i)) - (lp (1+ i) in)))) - (else in)))))))) - - (synthesize-definition-effects! effects dfg min-label label-count) - - (vector-set! avail 0 empty-intset) - - (let lp ((n 0)) - (cond - ((< n label-count) - (let* ((label (idx->label n)) - ;; It's possible for "in" to be #f if it has no - ;; predecessors, as is the case for the ktail of a - ;; function with an iloop. - (in (or (vector-ref avail n) empty-intset)) - (out (intset-add (clobber label in) label))) - (lookup-predecessors label dfg) - (let visit-succs ((succs (cont-successors (lookup-cont label dfg)))) - (match succs - (() (lp (1+ n))) - ((succ . succs) - (propagate! label succ out) - (visit-succs succs)))))) - (revisit-label - (let ((n (label->idx revisit-label))) - (set! revisit-label #f) - (lp n))) - (else - (values avail effects)))))) - -(define (compute-truthy-expressions dfg min-label label-count) - "Compute a \"truth map\", indicating which expressions can be shown to -be true and/or false at each of LABEL-COUNT expressions in DFG, starting -from MIN-LABEL. Returns a vector of intsets, each intset twice as long -as LABEL-COUNT. The even elements of the intset indicate labels that -may be true, and the odd ones indicate those that may be false. It -could be that both true and false proofs are available." - (let ((boolv (make-vector label-count #f)) - (revisit-label #f)) - (define (label->idx label) (- label min-label)) - (define (idx->label idx) (+ idx min-label)) - (define (true-idx idx) (ash idx 1)) - (define (false-idx idx) (1+ (ash idx 1))) - - (define (propagate! pred succ out) - (let* ((succ-idx (label->idx succ)) - (in (match (lookup-predecessors succ dfg) - ;; Fast path: normal control flow. - ((_) out) - ;; Slow path: control-flow join. - (_ (cond - ((vector-ref boolv succ-idx) - => (lambda (in) - (intset-intersect in out))) - (else out)))))) - (when (and (<= succ pred) - (or (not revisit-label) (< succ revisit-label)) - (not (eq? in (vector-ref boolv succ-idx)))) - (set! revisit-label succ)) - (vector-set! boolv succ-idx in))) - - (vector-set! boolv 0 empty-intset) - - (let lp ((n 0)) - (cond - ((< n label-count) - (let* ((label (idx->label n)) - ;; It's possible for "in" to be #f if it has no - ;; predecessors, as is the case for the ktail of a - ;; function with an iloop. - (in (or (vector-ref boolv n) empty-intset))) - (define (default-propagate) - (let visit-succs ((succs (cont-successors (lookup-cont label dfg)))) - (match succs - (() (lp (1+ n))) - ((succ . succs) - (propagate! label succ in) - (visit-succs succs))))) - (match (lookup-cont label dfg) - (($ $kargs names syms body) - (match (find-call body) - (($ $continue k src ($ $branch kt)) - (propagate! label k (intset-add in (false-idx n))) - (propagate! label kt (intset-add in (true-idx n))) - (lp (1+ n))) - (_ (default-propagate)))) - (_ (default-propagate))))) - (revisit-label - (let ((n (label->idx revisit-label))) - (set! revisit-label #f) - (lp n))) - (else boolv))))) - -;; Returns a map of label-idx -> (var-idx ...) indicating the variables -;; defined by a given labelled expression. -(define (compute-defs dfg min-label label-count) - (define (cont-defs k) - (match (lookup-cont k dfg) - (($ $kargs names vars) vars) - (_ '()))) - (define (idx->label idx) (+ idx min-label)) - (let ((defs (make-vector label-count '()))) - (let lp ((n 0)) - (when (< n label-count) - (vector-set! - defs - n - (match (lookup-cont (idx->label n) dfg) - (($ $kargs _ _ body) - (match (find-call body) - (($ $continue k) (cont-defs k)))) - (($ $kreceive arity kargs) - (cont-defs kargs)) - (($ $kclause arity ($ $cont kargs ($ $kargs names syms))) - syms) - (($ $kfun src meta self) (list self)) - (($ $ktail) '()))) - (lp (1+ n)))) - defs)) - -(define (compute-label-and-var-ranges fun) - (match fun - (($ $cont kfun ($ $kfun src meta self)) - ((make-local-cont-folder min-label label-count min-var var-count) - (lambda (k cont min-label label-count min-var var-count) - (let ((min-label (min k min-label)) - (label-count (1+ label-count))) - (match cont - (($ $kargs names vars body) - (values min-label label-count - (fold min min-var vars) (+ var-count (length vars)))) - (($ $kfun src meta self) - (values min-label label-count (min self min-var) (1+ var-count))) - (_ - (values min-label label-count min-var var-count))))) - fun kfun 0 self 0)))) - -;; Compute a vector containing, for each node, a list of the nodes that -;; it immediately dominates. These are the "D" edges in the DJ tree. - -(define (compute-equivalent-subexpressions fun dfg) - (define (compute min-label label-count min-var var-count idoms avail effects) - (let ((defs (compute-defs dfg min-label label-count)) - (var-substs (make-vector var-count #f)) - (equiv-labels (make-vector label-count #f)) - (equiv-set (make-hash-table))) - (define (idx->label idx) (+ idx min-label)) - (define (label->idx label) (- label min-label)) - (define (idx->var idx) (+ idx min-var)) - (define (var->idx var) (- var min-var)) - - (define (for-each/2 f l1 l2) - (unless (= (length l1) (length l2)) - (error "bad lengths" l1 l2)) - (let lp ((l1 l1) (l2 l2)) - (when (pair? l1) - (f (car l1) (car l2)) - (lp (cdr l1) (cdr l2))))) - - (define (subst-var var) - ;; It could be that the var is free in this function; if so, its - ;; name will be less than min-var. - (let ((idx (var->idx var))) - (if (<= 0 idx) - (vector-ref var-substs idx) - var))) - - (define (compute-exp-key exp) - (match exp - (($ $const val) (cons 'const val)) - (($ $prim name) (cons 'prim name)) - (($ $fun body) #f) - (($ $rec names syms funs) #f) - (($ $call proc args) #f) - (($ $callk k proc args) #f) - (($ $primcall name args) - (cons* 'primcall name (map subst-var args))) - (($ $branch _ ($ $primcall name args)) - (cons* 'primcall name (map subst-var args))) - (($ $branch) #f) - (($ $values args) #f) - (($ $prompt escape? tag handler) #f))) - - (define (add-auxiliary-definitions! label exp-key) - (let ((defs (vector-ref defs (label->idx label)))) - (define (add-def! aux-key var) - (let ((equiv (hash-ref equiv-set aux-key '()))) - (hash-set! equiv-set aux-key - (acons label (list var) equiv)))) - (match exp-key - (('primcall 'box val) - (match defs - ((box) - (add-def! `(primcall box-ref ,(subst-var box)) val)))) - (('primcall 'box-set! box val) - (add-def! `(primcall box-ref ,box) val)) - (('primcall 'cons car cdr) - (match defs - ((pair) - (add-def! `(primcall car ,(subst-var pair)) car) - (add-def! `(primcall cdr ,(subst-var pair)) cdr)))) - (('primcall 'set-car! pair car) - (add-def! `(primcall car ,pair) car)) - (('primcall 'set-cdr! pair cdr) - (add-def! `(primcall cdr ,pair) cdr)) - (('primcall (or 'make-vector 'make-vector/immediate) len fill) - (match defs - ((vec) - (add-def! `(primcall vector-length ,(subst-var vec)) len)))) - (('primcall 'vector-set! vec idx val) - (add-def! `(primcall vector-ref ,vec ,idx) val)) - (('primcall 'vector-set!/immediate vec idx val) - (add-def! `(primcall vector-ref/immediate ,vec ,idx) val)) - (('primcall (or 'allocate-struct 'allocate-struct/immediate) - vtable size) - (match defs - (() #f) ;; allocate-struct in tail or kreceive position. - ((struct) - (add-def! `(primcall struct-vtable ,(subst-var struct)) - vtable)))) - (('primcall 'struct-set! struct n val) - (add-def! `(primcall struct-ref ,struct ,n) val)) - (('primcall 'struct-set!/immediate struct n val) - (add-def! `(primcall struct-ref/immediate ,struct ,n) val)) - (_ #t)))) - - ;; The initial substs vector is the identity map. - (let lp ((var min-var)) - (when (< (var->idx var) var-count) - (vector-set! var-substs (var->idx var) var) - (lp (1+ var)))) - - ;; Traverse the labels in fun in forward order, which will visit - ;; dominators first. - (let lp ((label min-label)) - (when (< (label->idx label) label-count) - (match (lookup-cont label dfg) - (($ $kargs names vars body) - (match (find-call body) - (($ $continue k src exp) - (let* ((exp-key (compute-exp-key exp)) - (equiv (hash-ref equiv-set exp-key '())) - (lidx (label->idx label)) - (fx (vector-ref effects lidx)) - (avail (vector-ref avail lidx))) - (let lp ((candidates equiv)) - (match candidates - (() - ;; No matching expressions. Add our expression - ;; to the equivalence set, if appropriate. Note - ;; that expressions that allocate a fresh object - ;; or change the current fluid environment can't - ;; be eliminated by CSE (though DCE might do it - ;; if the value proves to be unused, in the - ;; allocation case). - (when (and exp-key - (not (causes-effect? fx &allocation)) - (not (effect-clobbers? - fx - (&read-object &fluid)))) - (hash-set! equiv-set exp-key - (acons label (vector-ref defs lidx) - equiv)))) - (((and head (candidate . vars)) . candidates) - (cond - ((not (intset-ref avail candidate)) - ;; This expression isn't available here; try - ;; the next one. - (lp candidates)) - (else - ;; Yay, a match. Mark expression as equivalent. - (vector-set! equiv-labels lidx head) - ;; If we dominate the successor, mark vars - ;; for substitution. - (when (= label (vector-ref idoms (label->idx k))) - (for-each/2 - (lambda (var subst-var) - (vector-set! var-substs (var->idx var) subst-var)) - (vector-ref defs lidx) - vars))))))) - ;; If this expression defines auxiliary definitions, - ;; as `cons' does for the results of `car' and `cdr', - ;; define those. Do so after finding equivalent - ;; expressions, so that we can take advantage of - ;; subst'd output vars. - (add-auxiliary-definitions! label exp-key))))) - (_ #f)) - (lp (1+ label)))) - (values (compute-dom-edges idoms min-label) - equiv-labels min-label var-substs min-var))) - - (call-with-values (lambda () (compute-label-and-var-ranges fun)) - (lambda (min-label label-count min-var var-count) - (let ((idoms (compute-idoms dfg min-label label-count))) - (call-with-values - (lambda () - (compute-available-expressions dfg min-label label-count idoms)) - (lambda (avail effects) - (compute min-label label-count min-var var-count - idoms avail effects))))))) - -(define (apply-cse fun dfg - doms equiv-labels min-label var-substs min-var boolv) - (define (idx->label idx) (+ idx min-label)) - (define (label->idx label) (- label min-label)) - (define (idx->var idx) (+ idx min-var)) - (define (var->idx var) (- var min-var)) - (define (true-idx idx) (ash idx 1)) - (define (false-idx idx) (1+ (ash idx 1))) - - (define (subst-var var) - ;; It could be that the var is free in this function; if so, - ;; its name will be less than min-var. - (let ((idx (var->idx var))) - (if (<= 0 idx) - (vector-ref var-substs idx) - var))) - - (define (visit-fun-cont cont) - (rewrite-cps-cont cont - (($ $cont label ($ $kfun src meta self tail clause)) - (label ($kfun src meta self ,tail - ,(and clause (visit-fun-cont clause))))) - (($ $cont label ($ $kclause arity ($ $cont kbody body) alternate)) - (label ($kclause ,arity ,(visit-cont kbody body) - ,(and alternate (visit-fun-cont alternate))))))) - - (define (visit-cont label cont) - (rewrite-cps-cont cont - (($ $kargs names vars body) - (label ($kargs names vars ,(visit-term body label)))) - (_ (label ,cont)))) - - (define (visit-term term label) - (define (visit-exp exp) - ;; We shouldn't see $fun here. - (rewrite-cps-exp exp - ((or ($ $const) ($ $prim)) ,exp) - (($ $call proc args) - ($call (subst-var proc) ,(map subst-var args))) - (($ $callk k proc args) - ($callk k (subst-var proc) ,(map subst-var args))) - (($ $primcall name args) - ($primcall name ,(map subst-var args))) - (($ $branch k exp) - ($branch k ,(visit-exp exp))) - (($ $values args) - ($values ,(map subst-var args))) - (($ $prompt escape? tag handler) - ($prompt escape? (subst-var tag) handler)))) - - (define (visit-fun fun) - (rewrite-cps-exp fun - (($ $fun body) - ($fun ,(cse body dfg))))) - - (define (visit-exp* k src exp) - (match exp - (($ $fun) - (build-cps-term - ($continue k src ,(visit-fun exp)))) - (($ $rec names syms funs) - (build-cps-term - ($continue k src ($rec names syms (map visit-fun funs))))) - (_ - (cond - ((vector-ref equiv-labels (label->idx label)) - => (match-lambda - ((equiv . vars) - (let* ((eidx (label->idx equiv))) - (match exp - (($ $branch kt exp) - (let* ((bool (vector-ref boolv (label->idx label))) - (t (intset-ref bool (true-idx eidx))) - (f (intset-ref bool (false-idx eidx)))) - (if (eqv? t f) - (build-cps-term - ($continue k src - ($branch kt ,(visit-exp exp)))) - (build-cps-term - ($continue (if t kt k) src ($values ())))))) - (_ - ;; FIXME: can we always continue with $values? why - ;; or why not? - (rewrite-cps-term (lookup-cont k dfg) - (($ $kargs) - ($continue k src ($values vars))) - (_ - ($continue k src ,(visit-exp exp)))))))))) - (else - (build-cps-term - ($continue k src ,(visit-exp exp)))))))) - - (define (visit-dom-conts label) - (let ((cont (lookup-cont label dfg))) - (match cont - (($ $ktail) '()) - (($ $kargs) (list (visit-cont label cont))) - (else - (cons (visit-cont label cont) - (append-map visit-dom-conts - (vector-ref doms (label->idx label)))))))) - - (rewrite-cps-term term - (($ $letk conts body) - ,(visit-term body label)) - (($ $continue k src exp) - ,(let ((conts (append-map visit-dom-conts - (vector-ref doms (label->idx label))))) - (if (null? conts) - (visit-exp* k src exp) - (build-cps-term - ($letk ,conts ,(visit-exp* k src exp)))))))) - - (visit-fun-cont fun)) - -(define (cse fun dfg) - (call-with-values (lambda () (compute-equivalent-subexpressions fun dfg)) - (lambda (doms equiv-labels min-label var-substs min-var) - (apply-cse fun dfg doms equiv-labels min-label var-substs min-var - (compute-truthy-expressions dfg - min-label (vector-length doms)))))) - -(define (eliminate-common-subexpressions fun) - (call-with-values (lambda () (renumber fun)) - (lambda (fun nlabels nvars) - (cse fun (compute-dfg fun))))) |