call.scm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. ; Copyright (c) 1993-2008 by Richard Kelsey. See file COPYING.
  2. (define (simplify-jump call)
  3. (cond ((lambda-node? (call-arg call 0))
  4. (set-call-primop! call (get-primop (enum primop let)))
  5. (set-call-exits! call 1)
  6. (set-node-simplified?! call #f))
  7. (else
  8. (default-simplifier call))))
  9. (define simplify-return simplify-jump)
  10. ; If the procedure is a lambda-node:
  11. ; 1. note that we know where the continuation lambda is used (and turn any
  12. ; tail-calls using it into regular calls)
  13. ; 2. change the primop to LET
  14. ; 3. the procedure is now the continuation
  15. ; 4. the continuation is now a jump lambda
  16. ; 5. change the primop used to call the continuation to jump
  17. ; 6. swap the cont and proc.
  18. ; (CALL <cont> (LAMBDA (c . vars) ...) . args))
  19. ; =>
  20. ; (LET (LAMBDA (c . vars) ...) <cont> . args)
  21. ; If the continuation just returns somewhere else, replace UNKNOWN-CALL
  22. ; with UNKNOWN-TAIL-CALL.
  23. (define (simplify-known-call call)
  24. (let ((proc (call-arg call 1))
  25. (cont (call-arg call 0)))
  26. (cond ((lambda-node? proc)
  27. (determine-continuation-protocol cont (list proc))
  28. (set-call-primop! call (get-primop (enum primop let)))
  29. (change-lambda-type proc 'cont)
  30. (change-lambda-type cont 'jump)
  31. (for-each (lambda (ref)
  32. (set-call-primop! (node-parent ref)
  33. (get-primop (enum primop jump))))
  34. (variable-refs (car (lambda-variables proc))))
  35. (move cont
  36. (lambda (cont)
  37. (detach proc)
  38. (attach call 1 cont)
  39. proc)))
  40. ((trivial-continuation? cont)
  41. (replace cont (detach (call-arg (lambda-body cont) 0)))
  42. (set-call-primop! call (get-primop (enum primop tail-call)))
  43. (set-call-exits! call 0))
  44. (else
  45. (default-simplifier call)))))
  46. ; (CALL (CONT (v1 ... vN) (RETURN c v1 ... vN)) ...args...)
  47. (define (trivial-continuation? cont)
  48. (let ((body (lambda-body cont)))
  49. (and (calls-this-primop? body 'return)
  50. (= (length (lambda-variables cont))
  51. (- (call-arg-count body ) 1))
  52. (let loop ((vars (lambda-variables cont)) (i 1))
  53. (cond ((null? vars)
  54. #t)
  55. ((and (reference-node? (call-arg body i))
  56. (eq? (car vars)
  57. (reference-variable (call-arg body i))))
  58. (loop (cdr vars) (+ i 1)))
  59. (else #f))))))
  60. ; The same as the above, except that the continuation is a reference node
  61. ; and not a lambda, so we substitute it for the proc's continuation variable.
  62. (define (simplify-known-tail-call call)
  63. (let ((proc (call-arg call 1))
  64. (cont (call-arg call 0)))
  65. (cond ((lambda-node? proc)
  66. (set-call-primop! call (get-primop (enum primop let)))
  67. (change-lambda-type proc 'cont)
  68. (substitute (car (lambda-variables proc)) cont #t)
  69. (set-lambda-variables! proc (cdr (lambda-variables proc)))
  70. (remove-call-arg call 0)
  71. (set-call-exits! call 1) ; must be after REMOVE-CALL-ARG
  72. (mark-changed proc))
  73. (else
  74. (default-simplifier call)))))
  75. (define (simplify-test call)
  76. (simplify-arg call 2)
  77. (let ((value (call-arg call 2)))
  78. (cond ((literal-node? value)
  79. (fold-conditional call (if (eq? false-value (literal-value value))
  80. 1
  81. 0)))
  82. ((reference-node? value)
  83. (simplify-variable-test call (reference-variable value)))
  84. ((collapse-multiple-zero-bit-tests call)
  85. )
  86. (else
  87. (default-simplifier call)))))
  88. (define (simplify-variable-test call var)
  89. (cond ((flag-assq 'test (variable-flags var))
  90. => (lambda (pair)
  91. (fold-conditional call (cdr pair))))
  92. (else
  93. (let ((pair (cons 'test 0))
  94. (flags (variable-flags var)))
  95. (set-variable-flags! var (cons pair flags))
  96. (simplify-arg call 0)
  97. (set-cdr! pair 1)
  98. (simplify-arg call 1)
  99. (set-variable-flags! var flags)))))
  100. (define (fold-conditional call index)
  101. (replace-body call (detach-body (lambda-body (call-arg call index)))))
  102. ; (if (and (= 0 (bitwise-and 'j x))
  103. ; (= 0 (bitwise-and 'j y)))
  104. ; ...)
  105. ; =>
  106. ; (if (= 0 (bitwise-and (bitwise-or x y) 'j))
  107. ; ...)
  108. ; This comes up in the Scheme48 VM.
  109. (define (collapse-multiple-zero-bit-tests test)
  110. (receive (mask first-arg)
  111. (zero-bit-test (call-arg test 2))
  112. (if mask
  113. (let ((false-exit (call-arg test 1))
  114. (true-exit (call-arg test 0)))
  115. (simplify-lambda-body true-exit)
  116. (simplify-lambda-body false-exit)
  117. (let ((call (lambda-body true-exit)))
  118. (if (and (eq? 'test (primop-id (call-primop call)))
  119. (node-equal? false-exit (call-arg call 1)))
  120. (receive (new-mask second-arg)
  121. (zero-bit-test (call-arg call 2))
  122. (if (and new-mask (= mask new-mask))
  123. (fold-zero-bit-tests test first-arg second-arg
  124. (call-arg call 0))
  125. #f))
  126. #f)))
  127. #f)))
  128. ; = and bitwise-and always have any literal node as arg1
  129. ;
  130. ; 1. call to =
  131. ; 2. first arg is literal 0
  132. ; 3. second arg is call to and
  133. ; 4. first arg of and-call is numeric literal
  134. ; 5. second arg of and-call has no side-effects (reads are okay)
  135. ; Returns #f or the two arguments to bitwise-and.
  136. (define (zero-bit-test call)
  137. (if (eq? '= (primop-id (call-primop call)))
  138. (let ((literal-0 (call-arg call 0))
  139. (bitwise-and-call (call-arg call 1)))
  140. (if (and (literal-node? literal-0)
  141. (number? (literal-value literal-0))
  142. (= 0 (literal-value literal-0))
  143. (call-node? bitwise-and-call)
  144. (eq? 'bitwise-and (primop-id (call-primop bitwise-and-call)))
  145. (literal-node? (call-arg bitwise-and-call 0))
  146. (number? (literal-value (call-arg bitwise-and-call 0)))
  147. (not (side-effects? (call-arg bitwise-and-call 1) 'read)))
  148. (values (literal-value (call-arg bitwise-and-call 0))
  149. (call-arg bitwise-and-call 1))
  150. (values #f #f)))
  151. (values #f #f)))
  152. (define (fold-zero-bit-tests test first-arg second-arg true-cont)
  153. (detach second-arg)
  154. (replace (call-arg test 0) (detach true-cont))
  155. (move first-arg
  156. (lambda (first-arg)
  157. (let-nodes ((call (bitwise-ior 0 first-arg second-arg)))
  158. call))))
  159. (define (expand-test call)
  160. (bug "Trying to expand a call to TEST (~D) ~S"
  161. (node-hash (node-parent (nontrivial-ancestor call)))
  162. call))
  163. ; TEST can be simplified using any literal value.
  164. ; The check for reference nodes is a heuristic. It will only help if the
  165. ; two tests end up being sequential.
  166. (define (simplify-test? call index value)
  167. (cond ((literal-node? value)
  168. #t)
  169. ((reference-node? value)
  170. (any? (lambda (r)
  171. (eq? 'test (primop-id (call-primop (node-parent r)))))
  172. (variable-refs (reference-variable value))))
  173. (else
  174. #f)))
  175. (define (simplify-unknown-call call)
  176. (simplify-args call 0)
  177. (let ((proc (call-arg call 1)))
  178. (cond ((lambda-node? proc)
  179. (determine-lambda-protocol proc (list proc))
  180. (mark-changed proc))
  181. ((and (reference-node? proc)
  182. (variable-simplifier (reference-variable proc)))
  183. => (lambda (proc)
  184. (proc call))))))
  185. ; Simplify a cell. A set-once cell is one that is set only once and does
  186. ; not escape. If such a cell is set to a value that can be hoisted (without
  187. ; moving variables out of scope) to the point the cell is created the cell
  188. ; is replace with the value.
  189. ; This should make use of the type of the cell.
  190. (define (simplify-allocation call)
  191. (set-node-simplified?! call #t)
  192. (simplify-args call 0) ; simplify all arguments, including continuation
  193. (let ((var (car (lambda-variables (call-arg call 0)))))
  194. (if (every? cell-use? (variable-refs var))
  195. (receive (uses sets)
  196. (partition-list (lambda (n)
  197. (eq? 'contents
  198. (primop-id (call-primop (node-parent n)))))
  199. (variable-refs var))
  200. (simplify-cell-part call uses sets)))))
  201. (define (cell-use? ref)
  202. (let ((call (node-parent ref)))
  203. (case (primop-id (call-primop call))
  204. ((contents)
  205. #t)
  206. ((set-contents)
  207. (= (node-index ref) set/owner))
  208. (else
  209. #f))))
  210. (define (simplify-cell-part call my-uses my-sets)
  211. (cond ((null? my-uses)
  212. (for-each (lambda (n) (remove-body (node-parent n)))
  213. my-sets))
  214. ((null? my-sets)
  215. (for-each (lambda (n)
  216. (replace-call-with-value
  217. (node-parent n)
  218. (make-undefined-literal)))
  219. my-uses))
  220. ; ((null? (cdr my-sets))
  221. ; (set-literal-value! (call-arg call 1) 'single-set)
  222. ; (really-simplify-single-set call (car my-sets) my-uses))
  223. (else
  224. (if (neq? 'small (literal-value (call-arg call 1)))
  225. (set-literal-value! (call-arg call 1) 'small)))))