diff --git a/module/language/tree-il/optimize.scm b/module/language/tree-il/optimize.scm index 5f053c17c..43cea5e76 100644 --- a/module/language/tree-il/optimize.scm +++ b/module/language/tree-il/optimize.scm @@ -192,6 +192,74 @@ it does not handle and , it should be called before (lambda _ (values #f '())))) + (define (inline-values exp src names gensyms body) + (let loop ((exp exp)) + (match exp + ;; Some expression types are always singly-valued. + ((or ($ ) + ($ ) + ($ ) + ($ ) + ($ ) + ($ ) + ($ ) + ($ ) + ($ ) ; FIXME: these set! expressions + ($ ) ; could return zero values in + ($ )) ; the future + (and (= (length names) 1) + (make-let src names gensyms (list exp) body))) + (($ src + ($ _ (? singly-valued-primitive? name))) + (and (= (length names) 1) + (make-let src names gensyms (list exp) body))) + + ;; Statically-known number of values. + (($ src ($ _ 'values) vals) + (and (= (length names) (length vals)) + (make-let src names gensyms vals body))) + + ;; Not going to copy code into both branches. + (($ ) #f) + + ;; Bail on other applications. + (($ ) #f) + + ;; Propagate to tail positions. + (($ src names gensyms vals body) + (let ((body (loop body))) + (and body + (make-let src names gensyms vals body)))) + (($ src in-order? names gensyms vals body) + (let ((body (loop body))) + (and body + (make-letrec src in-order? names gensyms vals body)))) + (($ src names gensyms vals body) + (let ((body (loop body))) + (and body + (make-fix src names gensyms vals body)))) + (($ src exp + ($ src2 req opt rest kw inits gensyms body #f)) + (let ((body (loop body))) + (and body + (make-let-values src exp + (make-lambda-case src2 req opt rest kw + inits gensyms body #f))))) + (($ src winder body unwinder) + (let ((body (loop body))) + (and body + (make-dynwind src winder body unwinder)))) + (($ src fluids vals body) + (let ((body (loop body))) + (and body + (make-dynlet src fluids vals body)))) + (($ src exps) + (match exps + ((head ... tail) + (let ((tail (loop tail))) + (and tail + (make-sequence src (append head (list tail))))))))))) + (define (make-values src values) (match values ((single) single) ; 1 value @@ -358,6 +426,21 @@ it does not handle and , it should be called before (if (const? body*) body (make-fix src names gensyms vals body)))) + (($ src producer + ($ src2 req #f #f #f () gensyms body #f)) + ;; Peval both producer and consumer, then try to inline. If + ;; that succeeds, peval again. + (let* ((producer (maybe-unconst producer (loop producer env calls))) + (body (maybe-unconst body (loop body env calls)))) + (cond + ((inline-values producer src2 req gensyms body) + => (lambda (exp) (loop exp env calls))) + (else + (make-let-values + src producer + (make-lambda-case src2 req #f #f #f '() gensyms body #f)))))) + (($ ) + exp) (($ src winder body unwinder) (make-dynwind src (loop winder env calls) (loop body env calls) @@ -401,6 +484,18 @@ it does not handle and , it should be called before (make-conditional src condition (loop subsequent env calls) (loop alternate env calls))))) + (($ src + ($ _ '@call-with-values) + (producer + ($ _ _ + (and consumer + ;; No optional or kwargs. + ($ + _ req #f rest #f () gensyms body #f))))) + (loop (make-let-values src (make-application src producer '()) + consumer) + env calls)) + (($ src orig-proc orig-args) ;; todo: augment the global env with specialized functions (let* ((proc (loop orig-proc env calls))