inline.scm 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. ;;; a simple inliner
  2. ;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. (define-module (language tree-il inline)
  17. #:use-module (system base pmatch)
  18. #:use-module (system base syntax)
  19. #:use-module (language tree-il)
  20. #:export (inline!))
  21. ;; Possible optimizations:
  22. ;; * constant folding, propagation
  23. ;; * procedure inlining
  24. ;; * always when single call site
  25. ;; * always for "trivial" procs
  26. ;; * otherwise who knows
  27. ;; * dead code elimination
  28. ;; * degenerate case optimizations
  29. ;; * "fixing letrec"
  30. (define (boolean-value x)
  31. (let ((src (tree-il-src x)))
  32. (record-case x
  33. ((<void>)
  34. (make-const src #t))
  35. ((<conditional> test consequent alternate)
  36. (record-case (boolean-value test)
  37. ((<const> exp)
  38. (case exp
  39. ((#t) (boolean-value consequent))
  40. ((#f) (boolean-value alternate))
  41. (else x)))
  42. (else x)))
  43. ((<lambda> meta body)
  44. (make-const src #t))
  45. ((<const> exp)
  46. (make-const src (not (not exp))))
  47. (else
  48. x))))
  49. ;; This is a completely brain-dead optimization pass whose sole claim to
  50. ;; fame is ((lambda () x)) => x.
  51. (define (inline! x)
  52. (define (inline1 x)
  53. (record-case x
  54. ((<application> src proc args)
  55. (record-case proc
  56. ;; ((lambda (y ...) x) z ...) => (let ((y z) ...) x)
  57. ((<lambda> body)
  58. (let lp ((lcase body))
  59. (and lcase
  60. (record-case lcase
  61. ((<lambda-case> req opt rest kw inits gensyms body alternate)
  62. (if (and (= (length gensyms) (length req) (length args)))
  63. (let ((x (make-let src req gensyms args body)))
  64. (or (inline1 x) x))
  65. (lp alternate)))))))
  66. ((<primitive-ref> name)
  67. (case name
  68. ((@call-with-values)
  69. (pmatch args
  70. ;; (call-with-values (lambda () foo) (lambda (a b . c) bar))
  71. ;; => (let-values (((a b . c) foo)) bar)
  72. ;;
  73. ;; Note that this is a singly-binding form of let-values.
  74. ;; Also note that Scheme's let-values expands into
  75. ;; call-with-values, then here we reduce it to tree-il's
  76. ;; let-values.
  77. ((,producer ,consumer)
  78. (guard (lambda? consumer)
  79. (lambda-case? (lambda-body consumer))
  80. (not (lambda-case-opt (lambda-body consumer)))
  81. (not (lambda-case-kw (lambda-body consumer)))
  82. (not (lambda-case-alternate (lambda-body consumer))))
  83. (make-let-values
  84. src
  85. (let ((x (make-application src producer '())))
  86. (or (inline1 x) x))
  87. (lambda-body consumer)))
  88. (else #f)))
  89. ((memq memv)
  90. (pmatch args
  91. ((,k ,l) (guard (const? l) (list? (const-exp l)))
  92. (if (null? (const-exp l))
  93. (make-const #f #f)
  94. (let lp ((elts (const-exp l)))
  95. (let ((test (make-application
  96. #f
  97. (make-primitive-ref #f (case name
  98. ((memq) 'eq?)
  99. ((memv) 'eqv?)
  100. (else (error "what"))))
  101. (list k (make-const #f (car elts))))))
  102. (if (null? (cdr elts))
  103. test
  104. (make-conditional
  105. src
  106. test
  107. (make-const #f #t)
  108. (lp (cdr elts))))))))
  109. (else #f)))
  110. (else #f)))
  111. (else #f)))
  112. ((<conditional> test consequent alternate)
  113. (let ((btest (boolean-value test)))
  114. (or (record-case btest
  115. ((<const> exp)
  116. (case exp
  117. ((#t) consequent)
  118. ((#f) alternate)
  119. (else #f)))
  120. (else #f))
  121. (if (eq? test btest)
  122. x
  123. (make-conditional (conditional-src x)
  124. btest consequent alternate)))))
  125. ((<let> gensyms body)
  126. (if (null? gensyms) body x))
  127. ((<letrec> gensyms body)
  128. (if (null? gensyms) body x))
  129. ((<fix> gensyms body)
  130. (if (null? gensyms) body x))
  131. ((<lambda-case> req opt rest kw gensyms body alternate)
  132. (define (args-compatible? args gensyms)
  133. (let lp ((args args) (gensyms gensyms))
  134. (cond
  135. ((null? args) (null? gensyms))
  136. ((null? gensyms) #f)
  137. ((and (lexical-ref? (car args))
  138. (eq? (lexical-ref-gensym (car args)) (car gensyms)))
  139. (lp (cdr args) (cdr gensyms)))
  140. (else #f))))
  141. (and (not opt) (not kw) rest (not alternate)
  142. (record-case body
  143. ((<application> proc args)
  144. ;; (lambda args (apply (lambda ...) args)) => (lambda ...)
  145. (and (primitive-ref? proc)
  146. (eq? (primitive-ref-name proc) '@apply)
  147. (pair? args)
  148. (lambda? (car args))
  149. (args-compatible? (cdr args) gensyms)
  150. (lambda-body (car args))))
  151. (else #f))))
  152. ;; Actually the opposite of inlining -- if the prompt cannot be proven to
  153. ;; be escape-only, ensure that its body is the application of a thunk.
  154. ((<prompt> src tag body handler)
  155. (define (escape-only? handler)
  156. (and (pair? (lambda-case-req handler))
  157. (let ((cont (car (lambda-case-gensyms handler))))
  158. (tree-il-fold (lambda (leaf escape-only?)
  159. (and escape-only?
  160. (not
  161. (and (lexical-ref? leaf)
  162. (eq? (lexical-ref-gensym leaf) cont)))))
  163. (lambda (down escape-only?) escape-only?)
  164. (lambda (up escape-only?) escape-only?)
  165. #t
  166. (lambda-case-body handler)))))
  167. (define (make-thunk body)
  168. (make-lambda #f '() (make-lambda-case #f '() #f #f #f '() '() body #f)))
  169. (if (or (and (application? body)
  170. (lambda? (application-proc body))
  171. (null? (application-args body)))
  172. (escape-only? handler))
  173. x
  174. (make-prompt src tag
  175. (make-application #f (make-thunk body) '())
  176. handler)))
  177. (else #f)))
  178. (post-order! inline1 x))