let.scm 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
  2. ;;;
  3. ;;; Port Author: Andrew Whatson
  4. ;;;
  5. ;;; Original Authors: Richard Kelsey
  6. ;;;
  7. ;;; scheme48-1.9.2/ps-compiler/simp/let.scm
  8. (define-module (ps-compiler simp let)
  9. #:use-module (prescheme scheme48)
  10. #:use-module (ps-compiler node arch)
  11. #:use-module (ps-compiler node node)
  12. #:use-module (ps-compiler node node-util)
  13. #:use-module (ps-compiler node primop)
  14. #:use-module (ps-compiler node variable)
  15. #:use-module (ps-compiler param)
  16. #:use-module (ps-compiler simp join)
  17. #:use-module (ps-compiler simp simplify)
  18. #:use-module (ps-compiler util util)
  19. #:export (simplify-let))
  20. ;;; Simplifying LET nodes, i.e. calls to the LET primop.
  21. ;;;
  22. ;;; 1. Change the procedure to a JUMP procedure if necessary.
  23. ;;; 2. Check that the right number of arguments are present.
  24. ;;; 3. Substitute any values that can be substituted without reference to
  25. ;;; how they are used in the body; then remove the call if it is no
  26. ;;; longer necessary.
  27. ;;; 4. Try harder.
  28. (define (simplify-let call)
  29. (let ((proc (call-arg call 0)))
  30. (if (eq? (lambda-type proc) 'jump)
  31. (change-lambda-type proc 'cont))
  32. (cond ((n= (length (lambda-variables proc))
  33. (- (call-arg-count call) 1))
  34. (bug "wrong number of arguments in ~S" call))
  35. ((or (null? (lambda-variables proc))
  36. (substitute-let-arguments proc call quick-substitute))
  37. (remove-body call))
  38. (else
  39. (really-simplify-let proc call)))))
  40. ;; A value can be quickly substituted if it is a leaf node or if it has no
  41. ;; side-effects and is used only once.
  42. (define (quick-substitute var val)
  43. (or (literal-node? val)
  44. (reference-node? val)
  45. (and (not (side-effects? val))
  46. (null? (cdr (variable-refs var))))))
  47. ;; Simplify the arguments and then repeatedly simplify the body of PROC
  48. ;; and try substituting the arguments.
  49. ;; If all the arguments can be substituted the call node is removed.
  50. ;;
  51. ;; SUBSTITUTE-JOIN-ARGUMENTS copies arguments in an attempt to remove
  52. ;; conditionals via constant folding.
  53. (define (really-simplify-let proc call)
  54. (simplify-args call 1)
  55. (let loop ()
  56. (set-node-simplified?! proc #t)
  57. (simplify-lambda-body proc)
  58. (cond ((substitute-let-arguments proc call slow-substitute)
  59. (remove-body call))
  60. ((substitute-join-arguments proc call)
  61. (loop))
  62. ((not (node-simplified? proc))
  63. (loop)))))
  64. (define *duplicate-lambda-size* '-1) ;; don't duplicate anything
  65. (define *duplicate-jump-lambda-size* 1) ;; duplicate one call
  66. (define (slow-substitute var val)
  67. (cond ((or (literal-node? val) (reference-node? val))
  68. #t)
  69. ((call-node? val)
  70. (let ((refs (variable-refs var)))
  71. (and (not (null? refs))
  72. (null? (cdr refs))
  73. (or (not (side-effects? val 'allocate))
  74. (and (not (side-effects? val 'allocate 'read))
  75. (not-used-between? val (car refs)))))))
  76. ((every? called-node? (variable-refs var))
  77. (simplify-known-cont-calls (variable-refs var) val)
  78. (or (null? (cdr (variable-refs var)))
  79. (case (lambda-type val)
  80. ((proc known-proc)
  81. (small-node? val *duplicate-lambda-size*))
  82. ((jump)
  83. (small-node? val *duplicate-jump-lambda-size*))
  84. (else
  85. #f))))
  86. (else #f)))
  87. ;; This only detects the following situation:
  88. ;; (let (lambda (... var ...) (primop ... var ...))
  89. ;; ... value ...)
  90. ;; where the reference to VAR is contained within nested, non-writing calls
  91. ;; This depends on there being no simple calls with WRITE side-effects
  92. (define (not-used-between? call ref)
  93. (let ((top (lambda-body (call-arg (node-parent call) 0))))
  94. (let loop ((call (node-parent ref)))
  95. (cond ((eq? call top) #t)
  96. ((or (not (call-node? call))
  97. (eq? 'write (primop-side-effects (call-primop call))))
  98. #f)
  99. (else (loop (node-parent call)))))))
  100. (define (simplify-known-cont-calls refs l-node)
  101. (case (lambda-type l-node)
  102. ((proc)
  103. (determine-lambda-protocol l-node refs))
  104. ((cont)
  105. (bug "CONT lambda bound by LET ~S" l-node)))
  106. (if (calls-known? l-node)
  107. (simplify-known-lambda l-node)))
  108. ;; ($some-RETURN <proc> . <args>)
  109. ;; =>
  110. ;; ($JUMP <proc> . <args>)
  111. ;; could check argument reps as well
  112. (define (add-return-mark call l-node arg-count)
  113. (if (not (= (call-arg-count call) (+ arg-count 1)))
  114. (bug '"call ~S to join ~S has the wrong number of arguments"
  115. call l-node))
  116. (set-call-primop! call (get-primop (enum primop-enum jump))))
  117. ;; Removed arguments to a lambda-node in call position.
  118. ;; If any arguments are actually removed
  119. ;; REMOVE-NULL-ARGUMENTS shortens the argument vector.
  120. (define (substitute-let-arguments node call gone-proc)
  121. (let* ((vec (call-args call))
  122. (c (do ((vars (lambda-variables node) (cdr vars))
  123. (i 1 (+ i 1))
  124. (c 0 (if (keep-var-val (car vars) (vector-ref vec i) gone-proc)
  125. c
  126. (+ 1 c))))
  127. ((null? vars) c))))
  128. (cond ((= (+ c 1) (call-arg-count call)) #t)
  129. ((= c 0) #f)
  130. (else
  131. (remove-unused-variables node)
  132. (remove-null-arguments call (- (call-arg-count call) c))
  133. #f))))
  134. (define (keep-var-val var val gone-proc)
  135. (cond ((and (unused? var)
  136. (or (not (call-node? val))
  137. (not (side-effects? val 'allocate 'read))))
  138. (erase (detach val))
  139. #f)
  140. ((gone-proc var val)
  141. (substitute var val #t)
  142. #f)
  143. (else '#t)))
  144. ;; VAL is simple enough to be substituted in more than one location if
  145. ;; its body is a call with all leaf nodes.
  146. ;; -- no longer used --
  147. ;;(define (simple-lambda? val)
  148. ;; (vector-every? (lambda (n)
  149. ;; (and (not (lambda-node? n))
  150. ;; (call-args (lambda-body val))))
  151. (define (called-anywhere? var)
  152. (any? called-node? (variable-refs var)))