; Copyright (c) 1993-1999 by Richard Kelsey. See file COPYING. ; (cps-call ) -> ; + + ; ; (cps-sequence ) -> + + ; ; ( ) -> + + (define (cps-call primop exits first-arg-index args cps) (let ((call (make-call-node primop (+ (length args) first-arg-index) exits)) (arguments (make-arg-nodes args first-arg-index cps))) (let loop ((args arguments) (first #f) (last #f)) (if (null? args) (values call first last) (let ((arg (car args))) (attach call (arg-index arg) (arg-value arg)) (if (and last (arg-first arg)) (attach-body last (arg-first arg))) (loop (cdr args) (or first (arg-first arg)) (or (arg-last arg) last))))))) ; Record to hold information about arguments to calls. (define-record-type arg :arg (make-arg index rank value first last) arg? (index arg-index) ; The index of this argument in the call. (rank arg-rank) ; The estimated cost of executing this node at run time. (value arg-value) ; What CPS returned for this argument. (first arg-first) (last arg-last)) ; Convert the elements of EXP into nodes (if they aren't already) and put ; them into an ARG record. Returns the list of ARG records sorted ; by ARG-RANK. (define (make-arg-nodes exp start cps) (do ((index start (+ index 1)) (args exp (cdr args)) (vals '() (cons (receive (value first last) (cps (car args)) (make-arg index (node-rank first) value first last)) vals))) ((null? args) (sort-list vals (lambda (v1 v2) (> (arg-rank v1) (arg-rank v2))))))) ; Complexity analysis used to order argument evaluation. More complex ; arguments are to be evaluated first. This just counts reference nodes. ; It is almost certainly a waste of time. (define (node-rank first) (if (not first) 0 (complexity-analyze-vector (call-args first)))) (define (complexity-analyze node) (cond ((empty? node) 0) ((reference-node? node) 1) ((lambda-node? node) (if (not (empty? (lambda-body node))) (complexity-analyze-vector (call-args (lambda-body node))) 0)) ((call-node? node) (complexity-analyze-vector (call-args node))) (else 0))) (define (complexity-analyze-vector vec) (do ((i 0 (+ i 1)) (q 0 (+ q (complexity-analyze (vector-ref vec i))))) ((>= i (vector-length vec)) q))) ;---------------------------------------------------------------- ; (cps-sequence ) -> ; + + ; is the same as the used above, except that it returns ; a list of value nodes instead of exactly one. (define (cps-sequence nodes values-cps) (if (null? nodes) (bug "CPS: empty sequence")) (let loop ((nodes nodes) (first #f) (last #f)) (if (null? (cdr nodes)) (values (car nodes) first last) (receive (exp-first exp-last) (cps-sequent (car nodes) values-cps) (if (and last exp-first) (attach-body last exp-first)) (loop (cdr nodes) (or first exp-first) (or exp-last last)))))) (define (cps-sequent node values-cps) (receive (vals exp-first exp-last) (values-cps node) (receive (calls other) (partition-list call-node? vals) (map erase other) (if (null? calls) (values exp-first exp-last) (insert-let calls exp-first exp-last))))) (define (insert-let calls exp-first exp-last) (let* ((vars (map (lambda (call) (make-variable 'v (trivial-call-return-type call))) calls)) (cont (make-lambda-node 'c 'cont vars)) (call (make-call-node (get-primop (enum primop let)) (+ 1 (length calls)) 1))) (attach-call-args call (cons cont calls)) (cond (exp-first (attach-body exp-last call) (values exp-first cont)) (else (values call cont)))))