;;;; Cyclone Scheme ;;;; https://github.com/justinethier/cyclone ;;;; ;;;; Copyright (c) 2014-2018, Justin Ethier ;;;; All rights reserved. ;;;; ;;;; This file is part of the cps-optimizations module. ;;;; (cond-expand (program (import (scheme base) (scheme write) (scheme cyclone ast) (scheme cyclone primitives) (scheme cyclone util) (scheme cyclone pretty-print)))) ;; Local variable reduction: ;; Reduce given sexp by replacing certain lambda calls with a let containing ;; local variables. Based on the way cyclone transforms code, this will ;; typically be limited to if expressions embedded in other expressions. (define (opt:local-var-reduction sexp) (define (scan exp) ;(write `(DEBUG scan ,exp)) (newline) (cond ((ast:lambda? exp) (ast:%make-lambda (ast:lambda-id exp) (ast:lambda-args exp) (map scan (ast:lambda-body exp)) (ast:lambda-has-cont exp))) ((quote? exp) exp) ((const? exp) exp) ((ref? exp) exp) ((define? exp) `(define ,(define->var exp) ,@(map scan (define->exp exp)))) ((set!? exp) `(set! ,(scan (set!->var exp)) ,(scan (set!->exp exp)))) ((if? exp) `(if ,(scan (if->condition exp)) ,(scan (if->then exp)) ,(scan (if->else exp)))) ((app? exp) (cond ((and (list? exp) (ast:lambda? (car exp)) (equal? (length exp) 2) (ast:lambda? (cadr exp)) (list? (ast:lambda-args (cadr exp))) (equal? 1 (length (ast:lambda-args (cadr exp)))) (lvr:local-tail-call-only? (ast:lambda-body (car exp)) (car (ast:lambda-args (car exp)))) ;(tagged-list? 'Cyc-seq (car (ast:lambda-body (cadr exp)))) ;; TODO: DEBUG line, remove this once it works! ) ;;(write `(tail-call-only? passed for ,exp)) (newline) ;;(write `(replace with ,(lvr:tail-calls->values ;; (car (ast:lambda-body (car exp))) ;; (car (ast:lambda-args (car exp)))))) ;;(newline) ;TODO: need to revisit this, may need to replace values with assignments to the "let" variable. ;would need to be able to carry that through to cgen and assign properly over there... (let* ((value (lvr:tail-calls->values (car (ast:lambda-body (car exp))) (car (ast:lambda-args (car exp))) (car (ast:lambda-args (cadr exp))) )) (var (car (ast:lambda-args (cadr exp)))) (body (ast:lambda-body (cadr exp))) (av (cond-expand (program #f) (else (adb:get/default var #f)))) (ref-count (if av (cond-expand (program #f) (else (adbv:ref-count av))) 1)) ;; Dummy value ) (if (and (> ref-count 0) ;; 0 ==> local var is never used value) `(let ((,var ,value)) ,@body) (map scan exp)) ;; failsafe )) (else (map scan exp)))) (else (error "unknown expression type: " exp)) )) (scan sexp)) ;; Local variable reduction helper: ;; Scan sexp to determine if sym is only called in a tail-call position (define (lvr:local-tail-call-only? sexp sym) (call/cc (lambda (return) (define (scan exp fail?) ;;(write `(DEBUG lvr:local-tail-call-only? scan ,exp)) (newline) (cond ((ast:lambda? exp) (return #f)) ;; Could be OK if not ref'd... ((quote? exp) exp) ((const? exp) exp) ((ref? exp) (if (equal? exp sym) (return #f))) ;; Assume not a tail call ((define? exp) (return #f)) ;; Fail fast ((set!? exp) (return #f)) ;; Fail fast ((if? exp) (scan (if->condition exp) #t) ;; fail if found under here (scan (if->then exp) fail?) (scan (if->else exp) fail?)) ((app? exp) (cond ;;; TODO: may need to check for prim:cont? and abort accordingly ;; check out code generated for scheme/cyclone/util.sld WRT symbol->string ;; cannot proceed with this since by definition these functions require CPS ((and (prim? (car exp)) (prim:cont? (car exp))) (return #f)) ((and (equal? (car exp) sym) (not fail?)) (map (lambda (e) (scan e fail?)) (cdr exp))) ;; Sym is OK, skip (else (map (lambda (e) (scan e fail?)) exp)))) (else exp))) (scan sexp #f) (return #t)))) ;; Local variable reduction helper: ;; Transform all tail calls of sym in the sexp to just the value passed (define (lvr:tail-calls->values sexp sym assign-sym) (call/cc (lambda (return) (define (scan exp) ;;(write `(DEBUG scan ,exp)) (newline) (cond ((ast:lambda? exp) (return #f)) ;; Could be OK if not ref'd... ((quote? exp) exp) ((const? exp) exp) ((ref? exp) (if (equal? exp sym) (return #f))) ;; Assume not a tail call ((define? exp) (return #f)) ;; Fail fast ((set!? exp) (return #f)) ;; Fail fast ((if? exp) `(if ,(if->condition exp) ,(scan (if->then exp)) ,(scan (if->else exp)))) ((app? exp) (cond ((and (equal? (car exp) sym) (= (length exp) 2) ) `(Cyc-local-set! ,assign-sym ,(cadr exp))) (else ;; TODO: can we be smarter? Consider example from match.scm match-gen-or-step (return #f)))) (else exp))) (cond ;((or (quote? sexp) ; (const? sexp)) ; ;; Special case, set the value directly ; ;; TODO: this is a bit of a hack, may way to re-think how this ; ;; whole module works at some point, but for now this works. ; (return ; `(Cyc-local-set! ,assign-sym ,sexp))) (else (return (scan sexp))))))) (cond-expand (program (define sexp '( ;(define zunda ; ((lambda ; (k$1057 first-row-perm$61$668 mat$62$669) ; (first-row-perm$61$668 ; (lambda ; (first-row$65$670) ; ((lambda ; (number-of-cols$68$671) ; ((lambda ; (make-row->func$71$672) ; (first-row-perm$61$668 ; (lambda ; (r$1062) ; (make-row->func$71$672 ; (lambda ; (r$1063) ; (make-row->func$71$672 ; (lambda ; (r$1064) ; (zebra k$1057 ; r$1062 ; r$1063 ; r$1064 ; (cdr mat$62$669) ; number-of-cols$68$671)) ; -1 ; 1)) ; 1 ; -1)) ; 'child)) ; (lambda ; (k$1066 if-equal$76$674 if-different$77$675) ; (k$1066 ; (lambda ; (k$1067 row$78$676) ; ((lambda ; (vec$79$677) ; ((lambda ; (first$85$679 row$86$680) ; ((lambda ; (lp$80$87$681) ; ((lambda ; (lp$80$87$681) ; (Cyc-seq ; (set! ; lp$80$87$681 ; (lambda ; (k$1073 i$88$682 first$89$683 row$90$684) ; (if (Cyc-fast-eq ; i$88$682 ; number-of-cols$68$671) ; (k$1073 ; (Cyc-fast-eq ; i$88$682 ; number-of-cols$68$671)) ; ((lambda ; (k$1080) ; (if (Cyc-fast-eq ; (car first$89$683) ; (car row$90$684)) ; (k$1080 if-equal$76$674) ; (k$1080 if-different$77$675))) ; (lambda ; (r$1079) ; (Cyc-seq ; (vector-set! ; vec$79$677 ; i$88$682 ; r$1079) ; ((cell-get lp$80$87$681) ; k$1073 ; (Cyc-fast-plus i$88$682 1) ; (cdr first$89$683) ; (cdr row$90$684)))))))) ; ((cell-get lp$80$87$681) ; (lambda ; (r$1069) ; (k$1067 ; (lambda ; (k$1070 i$92$686) ; (k$1070 ; (vector-ref vec$79$677 i$92$686))))) ; 0 ; first$85$679 ; row$86$680))) ; (cell lp$80$87$681))) ; #f)) ; first-row$65$670 ; row$78$676)) ; (make-vector number-of-cols$68$671))))))) ; (length first-row$65$670))) ; 'now)))) ; (define *num-passed* 0) ;(define write-to-string ; (lambda ; (k$3086 x$892$1775) ; (call-with-output-string ; k$3086 ; (lambda ; (k$3088 out$893$1776) ; ((lambda ; (x$895$1777) ; ((lambda ; (wr$896$1778) ; (Cyc-seq ; (set! wr$896$1778 ; (lambda ; (k$3091 x$897$1779) ; (if (pair? x$897$1779) ; ((lambda ; (k$3112) ; (if (symbol? (car x$897$1779)) ; (if (pair? (cdr x$897$1779)) ; (if (null? (cddr x$897$1779)) ; (k$3112 ; (assq (car x$897$1779) ; '((quote . "'") ; (quasiquote . "`") ; (unquote . ",") ; (unquote-splicing . ",@")))) ; (k$3112 #f)) ; (k$3112 #f)) ; (k$3112 #f))) ; (lambda ; (tmp$900$902$1780) ; (if tmp$900$902$1780 ; ((lambda ; (s$903$1781) ; (display ; (lambda ; (r$3094) ; (wr$896$1778 k$3091 (cadr x$897$1779))) ; (cdr s$903$1781) ; out$893$1776)) ; tmp$900$902$1780) ; (display ; (lambda ; (r$3097) ; (wr$896$1778 ; (lambda ; (r$3098) ; ((lambda ; (lp$907$1783) ; (Cyc-seq ; (set! lp$907$1783 ; (lambda ; (k$3103 ls$908$1784) ; (if (pair? ls$908$1784) ; (display ; (lambda ; (r$3105) ; (wr$896$1778 ; (lambda ; (r$3106) ; (lp$907$1783 ; k$3103 ; (cdr ls$908$1784))) ; (car ls$908$1784))) ; " " ; out$893$1776) ; (if (null? ls$908$1784) ; (k$3103 #f) ; (display ; (lambda ; (r$3110) ; (write k$3103 ; ls$908$1784 ; out$893$1776)) ; " . " ; out$893$1776))))) ; (lp$907$1783 ; (lambda ; (r$3099) ; (display k$3091 ")" out$893$1776)) ; (cdr x$897$1779)))) ; #f)) ; (car x$897$1779))) ; "(" ; out$893$1776)))) ; (write k$3091 x$897$1779 out$893$1776)))) ; (wr$896$1778 k$3088 x$895$1777))) ; #f)) ; x$892$1775))))) ;(define match-gen-or-step ; (lambda ; (k$14021 ; expr$3499$3540$3621$9398 ; rename$3500$3541$3622$9399 ; compare$3501$3542$3623$9400) ; ((lambda ; (v.1$3507$3599$3659$9436) ; ((lambda ; (k$14141) ; (if (pair? v.1$3507$3599$3659$9436) ; (Cyc-seq ; (car v.1$3507$3599$3659$9436) ; (if (pair? (cdr v.1$3507$3599$3659$9436)) ; (if (null? (car (cdr v.1$3507$3599$3659$9436))) ; (if (pair? (cdr (cdr v.1$3507$3599$3659$9436))) ; (Cyc-seq ; (car (cdr (cdr v.1$3507$3599$3659$9436))) ; (if (pair? (cdr (cdr (cdr v.1$3507$3599$3659$9436)))) ; (Cyc-seq ; (car (cdr (cdr (cdr v.1$3507$3599$3659$9436)))) ; (if (pair? (cdr (cdr (cdr (cdr v.1$3507$3599$3659$9436))))) ; (Cyc-seq ; (cdr (cdr (cdr (cdr (cdr v.1$3507$3599$3659$9436))))) ; (k$14141 ; (cons (car (cdr (cdr (cdr (cdr v.1$3507$3599$3659$9436))))) ; #f))) ; (k$14141 #f))) ; (k$14141 #f))) ; (k$14141 #f)) ; (k$14141 #f)) ; (k$14141 #f))) ; (k$14141 #f))) ; (lambda ; (tmp$3544$3546$3624$9401) ; (list ; (lambda (r$14022) (k$14021 (car r$14022))))))) ; (cdr expr$3499$3540$3621$9398)))) (define slot-set! (lambda (k$7170 name$2424$3603 obj$2425$3604 idx$2426$3605 val$2427$3606) ((lambda (vec$2428$3607) ((lambda (r$7171) (k$7170 (vector-set! r$7171 idx$2426$3605 val$2427$3606))) (vector-ref vec$2428$3607 2))) obj$2425$3604))) ) ) ;(pretty-print ; (ast:ast->pp-sexp ; (ast:sexp->ast sexp))) (pretty-print (ast:ast->pp-sexp (opt:local-var-reduction (ast:sexp->ast sexp))) ) ))