let.scm 5.1 KB

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