home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / misc / setf / letopt.el < prev    next >
Encoding:
Text File  |  1992-04-22  |  16.8 KB  |  458 lines

  1. ;;; $Header: /home/user3/miles/src/elisp/RCS/letopt.el,v 1.5 1992/04/21 17:28:40 miles Exp $
  2. ;;; ----------------------------------------------------------------
  3. ;;; letopt.el -- Let optimization
  4. ;;; Copyright (C) April 1992, Miles Bader <miles@cogsci.ed.ac.uk>
  5. ;;; ----------------------------------------------------------------
  6. ;;; This program is free software; you can redistribute it and/or modify
  7. ;;; it under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 2 of the License, or
  9. ;;; (at your option) any later version.
  10. ;;;
  11. ;;; This program is distributed in the hope that it will be useful,
  12. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;;; GNU General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with this program; if not, write to the Free Software
  18. ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. ;;; ----------------------------------------------------------------
  20. ;;;
  21. ;;; This file contains functions that remove unecessary bindings from a let.
  22. ;;; A binding is considered unecessary if all uses can (hopefully without loss
  23. ;;; of efficiency) be replaced with their definition, without any change in
  24. ;;; the result.  Bindings here are assumed to be only used within the lexical
  25. ;;; scope of the let, so these routines should only be called if you know
  26. ;;; this to be the case (e.g., by the macro which produces the let).
  27. ;;;
  28. ;;; The main entry point is LETOPT-MAYBE-OPTIMIZE-LET.  LETOPT-MAYBE-PROGN
  29. ;;; shouldn't really be here, but it is.
  30. ;;;
  31. ;;; The only special forms recognized are: QUOTE, FUNCTION, SETQ, LET and LET*,
  32. ;;; (COND is converted to IF), PROGN,
  33. ;;;
  34. ;;; Any unknown functions will be considered to have side effects unless the
  35. ;;; name of the function has a non-NIL 'SIDE-EFFECT-FREE property.  Jamie
  36. ;;; Zawinski's byte compiler asserts this property for many common functions.
  37. ;;;
  38. ;;; [Much of this stuff probably ought to be part of the compiler, but it
  39. ;;; isn't.  Oh well.]
  40. ;;;
  41.  
  42. (provide 'letopt)
  43.  
  44. ;;; The proper environment to use while compiling.  It's nil otherwise,
  45. ;;; and so doesn't cause any problems.
  46. (defvar byte-compile-macro-environment)
  47.  
  48. ;;; ----------------------------------------------------------------
  49.  
  50. (defmacro maybe-let (bindings &rest body)
  51.   "(maybe-let VARLIST BODY...) is like let, but doesn't guarantee that the
  52. variables will be bound, just that the result will be as if they were
  53. *either* lexically or dynamically bound to the given values.  So you can't
  54. depend on them being visible by (non-lexically enclosed) functions called by
  55. this function (although you can't depend on them NOT being visible either)."
  56.   (%letopt-optimize bindings body 'let))
  57.  
  58. (defmacro maybe-let* (bindings &rest body)
  59.   "(maybe-let* VARLIST BODY...) is like let*, but doesn't guarantee that the
  60. variables will be bound, just that the result will be as if they were
  61. *either* lexically or dynamically bound to the given values.  So you can't
  62. depend on them being visible by (non-lexically enclosed) functions called by
  63. this function (although you can't depend on them NOT being visible either)."
  64.   (%letopt-optimize bindings body 'let*))
  65.  
  66. (defun function-side-effect-free-p (function)
  67.   (and (symbolp function)
  68.        (get function 'side-effect-free)))
  69.  
  70. (defun letopt-maybe-progn (forms)
  71.   "Return FORMS with a "
  72.   (cond ((null forms) nil)
  73.     ((null (cdr forms)) (car forms))
  74.     (t (cons 'progn forms))))
  75.  
  76. (defun letopt-maybe-optimize-form (form)
  77.   "If FORM is a let or let*, return it with unecessary bindings removed.
  78. A binding is considered unecessary if all uses can (hopefully without loss
  79. of efficiency) be replaced with their definition, without any change in
  80. the result.  Bindings here are assumed to be only used within the lexical
  81. scope of the let, so these routines should only be called if you know
  82. this to be the case (e.g., by the macro which produces the let)."
  83.   (let ((form (macroexpand form byte-compile-macro-environment)))
  84.     (if (or (atom form) (not (memq (car form) '(let let*))))
  85.     form
  86.     (%letopt-optimize (nth 1 form) (nth 2 form) (car form)))))
  87.  
  88. ;;; ----------------------------------------------------------------
  89.                   
  90. (defun %letopt-eq-adjoin (thing list)
  91.   (if (memq thing list)
  92.       list
  93.       (cons thing list)))
  94.  
  95. (defun %letopt-eq-delete-one (thing list)
  96.   (cond ((null list) nil)
  97.     ((eq (car list) thing) (cdr list))
  98.     (t
  99.      (let ((prev list) (tail (cdr list)))
  100.        (while tail
  101.          (cond ((eq (car tail) thing)
  102.             (setcdr prev (cdr tail))
  103.             (setq tail nil))
  104.            (t
  105.             (setq prev tail tail (cdr tail))))))
  106.      list)))
  107.  
  108. ;;; ----------------------------------------------------------------
  109. ;;; Stuff to expand all macros in a form
  110.  
  111. ;;; Returns FORM with all macros expanded
  112. (defun %letopt-expand-macros (form)
  113.   (cond ((atom form) form)
  114.     ((eq (car form) 'cond)
  115.      (if (null (cdr form))
  116.          nil
  117.          (` (if (, (%letopt-expand-macros
  118.             (car (car (cdr form)))))
  119.             (, (%letopt-expand-macros
  120.             (letopt-maybe-progn (cdr (car (cdr form))))))
  121.             (, (%letopt-expand-macros
  122.             (` (cond (,@ (cdr (cdr form)))))))))))
  123.     ((and (eq (car form) 'setq) (nthcdr 3 form))
  124.      ;; we split up multiple setqs to make things easier below
  125.      (` (progn (setq (, (nth 1 form))
  126.              (, (%letopt-expand-macros (nth 2 form))))
  127.            (, (%letopt-expand-macros
  128.                (` (setq (,@ (nthcdr 3 form)))))))))
  129.     ((memq (car form) '(quote function))
  130.      (list (car form)
  131.            (%letopt-maybe-expand-macros-in-lambda (nth 1 form))))
  132.     ((memq (car form) '(let let*))
  133.      (nconc (list (car form)
  134.               (%letopt-expand-macros-in-bindings (nth 1 form)))
  135.         (mapcar (function %letopt-expand-macros)
  136.             (nthcdr 2 form))))
  137.     (t
  138.      (let ((expanded
  139.         (macroexpand form byte-compile-macro-environment)))
  140.        (cond ((eq expanded form)
  141.           (cons (%letopt-maybe-expand-macros-in-lambda (car form))
  142.             (mapcar (function %letopt-expand-macros)
  143.                 (cdr form))))
  144.          (t
  145.           (%letopt-expand-macros expanded)))))))
  146.  
  147. (defun %letopt-expand-macros-in-bindings (bindings)
  148.   (mapcar (function
  149.        (lambda (binding)
  150.         (list (car binding)
  151.           (%letopt-expand-macros (nth 1 binding)))))
  152.       bindings))
  153.  
  154. (defun %letopt-maybe-expand-macros-in-lambda (form)
  155.   (if (or (atom form)
  156.       (not (eq (car form) 'lambda)))
  157.       form
  158.       (cons 'lambda
  159.         (cons (nth 1 form)
  160.           (mapcar (function %letopt-expand-macros)
  161.               (nthcdr 2 form))))))
  162.  
  163. ;;; ----------------------------------------------------------------
  164.  
  165. ;; This expects macros to be already expanded, and only expects to
  166. ;; find the special forms QUOTE, FUNCTION, SETQ, LET and LET*.  [most other
  167. ;; special forms can be treated as if they were arguments for this purpose]
  168. (defun %letopt-find-free-variables (form &optional bound free)
  169.   (cond ((symbolp form)
  170.      (if (memq form bound)
  171.          free
  172.          (%letopt-eq-adjoin form free)))
  173.     ((atom form)
  174.      free)
  175.     ;; note: we just look at setq like a normal function
  176.     ((memq (car form) '(quote function))
  177.      free)
  178.     ((memq (car form) '(let let*))
  179.      (let ((bindings (car (cdr form)))
  180.            (new-bound bound))
  181.        (while bindings
  182.          (setq free
  183.            (%letopt-find-free-variables (car (cdr (car bindings)))
  184.                         (if (eq (car form) 'let*)
  185.                             new-bound
  186.                             bound)
  187.                         free))
  188.          (setq new-bound (cons (car (car bindings)) new-bound))
  189.          (setq bindings (cdr bindings)))
  190.        (%letopt-find-free-variables-in-forms (cdr (cdr form))
  191.                          new-bound
  192.                          free)))
  193.     (t
  194.      (%letopt-find-free-variables-in-forms (cdr form) bound free))))
  195.  
  196. (defun %letopt-find-free-variables-in-forms (forms &optional bound free)
  197.   (while forms
  198.     (setq free (%letopt-find-free-variables (car forms) bound free))
  199.     (setq forms (cdr forms)))
  200.   free)
  201.  
  202. ;;; ----------------------------------------------------------------
  203. ;;; Stuff to destructivel replace all occurances of one form in another
  204.  
  205. ;; This expects macros to be already expanded, and only expects to
  206. ;; find the special forms QUOTE, FUNCTION, SETQ, LET and LET*
  207. ;;
  208. ;; Destructive.
  209. (defun %letopt-replace-in-form (from to form)
  210.   (cond ((equal form from) to)
  211.     ((atom form) form)
  212.     ((memq (car form) '(quote function))
  213.      (%letopt-maybe-replace-in-lambda from to (nth 1 form))
  214.      form)
  215.     ((memq (car form) '(let let*))
  216.      (%letopt-replace-in-let from to (nth 1 form) (nthcdr 2 form)
  217.                  (eq (car form) 'let*))
  218.      form)
  219.     (t
  220.      (%letopt-maybe-replace-in-lambda from to (car form))
  221.      (%letopt-replace-in-forms from to (cdr form))
  222.      form)))
  223.  
  224. (defun %letopt-maybe-replace-in-lambda (from to form)
  225.   (if (and (listp form) (eq (car form) 'lambda))
  226.       (%letopt-replace-in-forms from to (nthcdr 2 form)))
  227.   form)
  228.  
  229. (defun %letopt-replace-in-let (from to bindings forms let*p)
  230.   (let ((boundp nil))
  231.     (while (and bindings (or (not boundp) (not let*p)))
  232.       (setcar (cdr (car bindings))
  233.           (%letopt-replace-in-form from to (nth 1 (car bindings))))
  234.       (if (equal (car (car bindings)) from)
  235.       (setq boundp t))
  236.       (setq bindings (cdr bindings)))
  237.     (if (not boundp)
  238.     (%letopt-replace-in-forms from to forms)))
  239.   forms)
  240.  
  241. (defun %letopt-replace-in-forms (from to forms)
  242.   (let ((tail forms))
  243.     (while tail
  244.       (setcar tail (%letopt-replace-in-form from to (car tail)))
  245.       (setq tail (cdr tail))))
  246.   forms)
  247.  
  248. ;;; ----------------------------------------------------------------
  249.  
  250. ;;; Find out how many times VAR is used in FORM, and any damaging side
  251. ;;; effects.
  252. ;;;
  253. ;;; Params:
  254. ;;;   VAR -- the variable
  255. ;;;   FORM -- the form we're looking at right now
  256. ;;;   DEPS -- either a list of the variables VAR depends on, or
  257. ;;;    a symbol that VAR is a direct copy of.
  258. ;;;   Uses -- A list of (#USES . CHANGED-DEPENDENCIES) sofar (see below for
  259. ;;;       the meaning of this).
  260. ;;;
  261. ;;; Returns one of:
  262. ;;;   NIL -- The variable is rebound somewhere in form, or used in a context
  263. ;;;    where some of its dependencies aren't valid.
  264. ;;;   A list of (#USES . CHANGED-DEPENDENCIES) --
  265. ;;;       #USES is the # of times VAR is used
  266. ;;;    CHANGED-DEPENDENCIES is the subset of DEPS which may have a different
  267. ;;;     meaning than at the time when VAR was bound (any use of VAR when
  268. ;;;     CHANGED-DEPENDENCIES is non-NIL means that we have to keep VAR).
  269. ;;;
  270. ;;; This expects macros to be already expanded, and only expects to
  271. ;;; find the special forms QUOTE, FUNCTION, SETQ, LET and LET*
  272. ;;;
  273. (defun %letopt-var-uses (var form deps uses)
  274.   ;;(princ (format "\nVar: %s, Uses: %s, Form: %s" var uses form))
  275.   (cond ((eq var form)
  276.      (cond ((cdr uses) nil)
  277.            (t
  278.         (setcar uses (1+ (car uses)))
  279.         uses)))
  280.     ((atom form) uses)
  281.     ((memq (car form) '(function quote))
  282.      ;; Handle lambda expressions used as a value.  The lambda is
  283.      ;; probably called outside of this function, but we could still
  284.      ;; replace occurances of VAR, since nothing we can replace it with
  285.      ;; would be any _less_ dynamic.
  286.      ;; However, since it may be evaluated at any time after this
  287.      ;; occurance, we can't trust that there isn't some destructive
  288.      ;; function lurking after we analyze the lambda that would trash
  289.      ;; something before we can use it.  _SO_ we treat any occurance of
  290.      ;; VAR inside the lambda as forcing it to be bound.
  291.      (let ((uniq-tag (list 'force-binding)))
  292.        (%letopt-remove-changed-dep uniq-tag
  293.         (%letopt-var-uses-in-maybe-lambda var (nth 1 form) deps
  294.          (%letopt-add-changed-dep uniq-tag uses)))))
  295.     ((eq (car form) 'setq)
  296.      (setq uses (%letopt-var-uses var (nth 2 form) deps uses))
  297.      (let ((sets (nth 1 form)))
  298.        (cond ((null uses))
  299.          ((eq sets var)
  300.           (setq uses nil))
  301.          ((if (atom deps)
  302.               (eq sets deps)
  303.               (memq sets deps))
  304.           (%letopt-add-changed-dep sets uses)))) 
  305.      uses)
  306.     ((memq (car form) '(let let*))
  307.      (%letopt-var-uses-in-let var (nth 1 form) (nthcdr 2 form)
  308.                   deps uses (eq (car form) 'let*)))
  309.     ((memq (car form) '(setcar setcdr rplaca rplacd aset fset set put))
  310.      ;; things that we know trash only their first arg
  311.      (%letopt-handle-function-side-effects
  312.       nil (list (nth 1 form)) deps
  313.       (%letopt-var-uses-in-forms var (cdr form) deps uses)))
  314.     ((memq (car form) '(progn save-excursion if))
  315.      ;; special forms that we know don't have any side effects
  316.      (%letopt-var-uses-in-forms var (cdr form) deps uses))
  317.     (t
  318.      ;; a normal function call
  319.      (%letopt-var-uses-in-maybe-lambda var (car form) deps
  320.       (%letopt-handle-function-side-effects
  321.        (function-side-effect-free-p (car form))
  322.        (cdr form)
  323.        deps
  324.        (%letopt-var-uses-in-forms var (cdr form) deps uses))))))
  325.  
  326. (defun %letopt-handle-function-side-effects (se-free-p args deps uses)
  327.   (cond ((or se-free-p (null uses) (atom deps))
  328.      uses)
  329.     (t
  330.      ;; We can't use this becuase it assumes too much (different
  331.      ;; variables can point too the same thing...):
  332.      ;;(while args
  333.      ;;  (let ((arg (car args)))
  334.      ;;    (if (and (symbolp arg) (memq arg deps))
  335.      ;;        (%letopt-add-changed-dep arg uses)))
  336.      ;;  (setq args (cdr args)))
  337.      ;; Instead, trash everything:
  338.      ;;(princ (format "\nTRASH: %s => EVERYTHING" args))
  339.      (%letopt-add-changed-dep '(EVERYTHING) uses)
  340.      uses)))
  341.  
  342. ;;; Add DEP to the set of changed dependencies in USES.  DEP should either be
  343. ;;; a variable that is in the set of current dependencies, or some non-atom
  344. ;;; tag that indicates a condition (that would invalidate the calculation of
  345. ;;; the variable we're trying to replace).
  346. (defun %letopt-add-changed-dep (dep uses)
  347.   (setcdr uses (cons dep (cdr uses)))
  348.   uses)
  349. (defun %letopt-remove-changed-dep (dep uses)
  350.   (if uses
  351.       (setcdr uses (%letopt-eq-delete-one dep (cdr uses))))
  352.   uses)
  353.  
  354. ;;; If VAR is a dependency, add it to the set of changed dependencies in USES
  355. (defun %letopt-maybe-bind-in-uses (var deps uses)
  356.   (if (and (listp deps) (memq var deps))
  357.       (%letopt-add-changed-dep var uses)
  358.       nil))
  359.  
  360. (defun %letopt-unbind-in-uses (bindings uses)
  361.   (and uses
  362.        (while bindings
  363.      (%letopt-remove-changed-dep (car bindings) uses)
  364.      (setq bindings (cdr bindings))))
  365.   uses)
  366.  
  367. (defun %letopt-var-uses-in-maybe-lambda (var form deps uses)
  368.   (if (or (atom form) (not (eq (car form) 'lambda)))
  369.       uses
  370.       (let ((deps-bound nil)
  371.         (params (nth 1 form)))
  372.     (while params
  373.       (if (%letopt-maybe-bind-in-uses (car params) deps uses)
  374.           (setq deps-bound (cons (car params) deps-bound)))
  375.       (setq params (cdr params)))
  376.     (%letopt-unbind-in-uses deps-bound
  377.      (%letopt-var-uses-in-forms var (nthcdr 2 form) deps uses)))))
  378.  
  379. (defun %letopt-var-uses-in-let (var bindings forms deps uses let*p)
  380.   (let ((boundp nil)
  381.     (deps-bound nil))
  382.     (while (and bindings uses (or (not boundp) (not let*p)))
  383.       (let ((binding (car bindings)))
  384.     (setq uses (%letopt-var-uses var (nth 1 binding) deps uses))
  385.     (cond ((null uses))
  386.           ((eq (car binding) var)
  387.            ;; the variable we're looking at is shadowed, nothing can happen
  388.            (setq boundp t))
  389.           ((%letopt-maybe-bind-in-uses (car binding) deps uses)
  390.            ;; we bind one of the things it depends on
  391.            (setq deps-bound (cons (car binding) deps-bound)))))
  392.       (setq bindings (cdr bindings)))
  393.     (%letopt-unbind-in-uses deps-bound
  394.      (if (and uses (not boundp))
  395.      ;; undo any dependencies we bound
  396.      (%letopt-var-uses-in-forms var forms deps uses)
  397.      uses))))
  398.  
  399. (defun %letopt-var-uses-in-forms (var forms deps uses)
  400.   (while (and forms uses)
  401.     (setq uses (%letopt-var-uses var (car forms) deps uses))
  402.     (setq forms (cdr forms)))
  403.   uses)
  404.  
  405. ;;; ----------------------------------------------------------------
  406.  
  407. ;;; Return T if FORM is something we can reasonably have multiple copies of
  408. ;;; without worrying about side-effects, efficiency or correctness.
  409. (defun %letopt-can-duplicate-p (form)
  410.   (or ;; variable
  411.       (atom form)
  412.       ;; quoted atom (we don't duplicate quoted lists, because then they
  413.       ;; wouldn't be eq)
  414.       (and (memq (car form) '(quote function))
  415.        (atom (nth 1 form)))))
  416.  
  417. (defun %letopt-optimize-let-bindings (bindings forms let*p)
  418.   (and bindings
  419.        (let* ((other-bindings
  420.            (%letopt-optimize-let-bindings (cdr bindings) forms let*p))
  421.           (binding (car bindings))
  422.           (var (nth 0 binding))
  423.           (val-form (%letopt-expand-macros (nth 1 binding)))
  424.           (deps
  425.            (if (symbolp val-form)
  426.            val-form
  427.            (%letopt-find-free-variables val-form)))
  428.           (var-uses
  429.            (%letopt-var-uses-in-let
  430.         var other-bindings forms deps (list 0) t)))
  431.      ;;(princ (format "\nOLB: (%s <= %s <%s>) => %s" var val-form deps var-uses))
  432.      (cond ((or (null var-uses)
  433.             (and (> (car var-uses) 1)
  434.              (not (%letopt-can-duplicate-p val-form))))
  435.         ;; can't optimize it away
  436.         (cons binding other-bindings))
  437.            (let*p
  438.         (%letopt-replace-in-let var val-form other-bindings forms t)
  439.         other-bindings)
  440.            (t
  441.         (%letopt-replace-in-forms var val-form forms)
  442.         other-bindings)))))
  443.  
  444. (defun %letopt-optimize (bindings forms let-fun)
  445.   (let* ((new-forms
  446.       (mapcar (function %letopt-expand-macros) forms))
  447.      (new-bindings
  448.       (%letopt-optimize-let-bindings
  449.        (%letopt-expand-macros-in-bindings bindings)
  450.        new-forms
  451.        (eq let-fun 'let*))))
  452.     (cond ((null new-bindings)
  453.        (letopt-maybe-progn new-forms))
  454.       (t
  455.        (cons let-fun (cons new-bindings new-forms))))))
  456.  
  457. ;;; ----------------------------------------------------------------
  458.