let.scm 6.0 KB

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