top.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. ; Copyright (c) 1993-2008 by Richard Kelsey. See file COPYING.
  2. ; Entry point
  3. (define (prescheme-compiler package-id spec-files init-name c-file . commands)
  4. (reset-node-id)
  5. (initialize-lambdas)
  6. (reset-record-data!)
  7. (reset-type-vars!)
  8. (receive (copy no-copy shadow integrate header)
  9. (parse-prescheme-commands commands)
  10. (let ((forms (prescheme-front-end (if (list? package-id)
  11. package-id
  12. (list package-id))
  13. spec-files copy no-copy shadow)))
  14. (for-each simplify-form forms)
  15. (let ((forms (remove-unreferenced-forms forms)))
  16. (for-each integrate-stob-form forms)
  17. ; prevent further automatic integration
  18. (for-each (lambda (form)
  19. (remove-variable-known-value! (form-var form)))
  20. forms)
  21. (integrate-by-command integrate forms)
  22. (for-each resimplify-form forms)
  23. (let* ((forms (remove-unreferenced-forms forms))
  24. (forms (integrate-single-uses forms))
  25. (forms (remove-unreferenced-forms forms)))
  26. (for-each resimplify-form forms)
  27. (for-each determine-form-protocol forms)
  28. (let ((forms (form-tail-calls->jumps forms)))
  29. (for-each maybe-add-self-label forms)
  30. (let ((forms (hoist-nested-procedures forms)))
  31. (for-each remove-polymorphism forms)
  32. ; (if cps-file (write-cps-file cps-file forms))
  33. (if c-file (write-c-file init-name c-file header forms)))))))))
  34. ;(define (expand-and-eval-program package-id spec-files output-file . commands)
  35. ; (reset-node-id)
  36. ; (reset-record-data!)
  37. ; (receive (copy no-copy shadow integrate header)
  38. ; (parse-prescheme-commands commands)
  39. ; (let ((forms (prescheme-front-end package-id spec-files copy no-copy shadow)))
  40. ; (call-with-output-file output-file
  41. ; (lambda (out)
  42. ; (display-forms-as-scheme forms out))))))
  43. ;(define (simplify-and-print-program package-id spec-files output-file c-file . commands)
  44. ; (reset-node-id)
  45. ; (reset-record-data!)
  46. ; (receive (copy no-copy shadow integrate header)
  47. ; (parse-prescheme-commands commands)
  48. ; (let ((forms (prescheme-front-end package-id spec-files copy no-copy shadow)))
  49. ; (for-each simplify-form forms)
  50. ; (let ((forms (remove-unreferenced-forms forms)))
  51. ; (call-with-output-file output-file
  52. ; (lambda (out)
  53. ; (display-cps-forms-as-scheme forms out)))))))
  54. (define command-names '(copy no-copy shadow integrate header))
  55. (define (parse-prescheme-commands commands)
  56. (let ((res (map list command-names)))
  57. (for-each (lambda (command)
  58. (cond ((assq (car command) res)
  59. => (lambda (l)
  60. (set-cdr! l (append (reverse (cdr command))
  61. (cdr l)))))
  62. (else
  63. (error "unknown directive ~S" command))))
  64. commands)
  65. (apply values (map (lambda (l) (reverse (cdr l))) res))))
  66. ;--------------------------------------------------
  67. (define (simplify-form form)
  68. (format #t " ~A " (form-name form))
  69. (let ((status (expand-and-simplify-form form)))
  70. (if status
  71. (format #t "(~A): " status)
  72. (format #t ": "))
  73. (display-type (variable-type (form-var form))
  74. (current-output-port))
  75. (newline (current-output-port))))
  76. ;--------------------------------------------------
  77. (define (integrate-single-uses forms)
  78. (format #t "In-lining single-use procedures~%")
  79. (let loop ((forms forms) (done '()) (hit? #f))
  80. (cond ((null? forms)
  81. (if hit?
  82. (loop (reverse done) '() #f)
  83. (reverse done)))
  84. ((single-called-use? (car forms))
  85. (let ((form (car forms)))
  86. ; (format #t " ~S~%" (variable-name (form-var form)))
  87. (integrate-single-use form
  88. (car (variable-refs (form-var form)))
  89. #f)
  90. (set-form-value! form #f)
  91. (make-form-unused! form)
  92. (loop (cdr forms) done #t)))
  93. (else
  94. (loop (cdr forms) (cons (car forms) done) hit?)))))
  95. (define (single-called-use? form)
  96. (let ((var (form-var form)))
  97. (and (not (form-exported? form))
  98. (eq? (form-type form) 'lambda)
  99. (not (null? (variable-refs var)))
  100. (null? (cdr (variable-refs var)))
  101. (called-node? (car (variable-refs var))))))
  102. (define (integrate-single-use form ref copy?)
  103. (let* ((in-node (node-base ref))
  104. (in-form (node-form in-node))
  105. (type (variable-type (form-var form))))
  106. (use-this-form! in-form)
  107. (let ((node (cond (copy?
  108. (copy-node-tree (form-node form)))
  109. (else
  110. (also-use-this-form! form)
  111. (form-node form)))))
  112. (if (type-scheme? type)
  113. (if (not (called-node? ref))
  114. (error "integrating polymorphic value into non-call position")
  115. (instantiate-type&value type node ref)))
  116. (determine-lambda-protocol node (list ref))
  117. (replace ref node)
  118. (simplify-all in-node (form-name form))
  119. (suspend-form-use! in-form))))
  120. ; Commands are (<proc> <caller>)
  121. (define (integrate-by-command commands forms)
  122. (for-each (lambda (command)
  123. (receive (proc refs)
  124. (process-integrate-command command forms)
  125. (if proc
  126. (for-each (lambda (r)
  127. (integrate-single-use proc r #t))
  128. refs))))
  129. commands))
  130. ; Horrendous error checking and notification.
  131. (define (process-integrate-command command forms)
  132. (let* ((proc (any (lambda (f)
  133. (eq? (form-name f) (car command)))
  134. forms))
  135. (var (if proc (form-var proc) #f))
  136. (node (if proc (form-value proc) #f))
  137. (caller (any (lambda (f)
  138. (eq? (form-name f) (cadr command)))
  139. forms))
  140. (refs (if (and var caller)
  141. (filter (lambda (ref)
  142. (eq? caller (node-form ref)))
  143. (variable-refs var))
  144. #f)))
  145. (cond ((or (not proc) (not var) (not caller))
  146. (cond ((or (not proc) (not var))
  147. (format #t "Bad command: no value for ~S~%"
  148. (car command)))
  149. ((or (not node)
  150. (not (lambda-node? node)))
  151. (format #t "Bad command: ~S is not a procedure~%"
  152. (car command))))
  153. (if (not caller)
  154. (format #t "Bad command: no definition for ~S~%"
  155. (cadr command)))
  156. (values #f #f))
  157. ((or (null? refs) (not node) (not (lambda-node? node)))
  158. (if (null? refs)
  159. (format #t "Bad command: ~S is not referenced by ~S~%"
  160. (car command) (cadr command)))
  161. (if (or (not node)
  162. (not (lambda-node? node)))
  163. (format #t "Bad command: ~S is not a procedure~%"
  164. (car command)))
  165. (values #f #f))
  166. (else
  167. (values proc refs)))))
  168. ;--------------------------------------------------
  169. (define (determine-form-protocol form)
  170. (let ((var (form-var form)))
  171. (cond ((and (not (form-exported? form))
  172. (eq? 'lambda (form-type form))
  173. (every? called-node? (variable-refs var)))
  174. (determine-lambda-protocol (form-node form) (variable-refs var))
  175. (note-known-global-lambda! var (form-node form))))))
  176. ;--------------------------------------------------
  177. (define (form-tail-calls->jumps forms)
  178. (receive (hits useless)
  179. (find-jump-procs (filter-map (lambda (form)
  180. (if (eq? 'lambda (form-type form))
  181. (form-node form)
  182. #f))
  183. forms)
  184. find-form-proc-calls)
  185. (for-each (lambda (p)
  186. (let* ((procs (cdr p))
  187. (proc-forms (map node-form procs))
  188. (owner (node-flag (node-base (car p))))
  189. (vars (map form-var proc-forms)))
  190. (use-this-form! owner)
  191. (for-each also-use-this-form! proc-forms)
  192. (procs->jumps (cdr p) vars (car p))
  193. (simplify-node (form-value owner)) ; worth it?
  194. (suspend-form-use! owner)
  195. (for-each (lambda (f)
  196. (set-form-value! f #f)
  197. (make-form-unused! f))
  198. proc-forms)))
  199. hits)
  200. (for-each (lambda (p)
  201. (make-form-unused! (node-form p)))
  202. useless)
  203. (filter (lambda (f)
  204. (not (eq? (form-type f) 'unused)))
  205. forms)))
  206. (define (find-form-proc-calls l)
  207. (let ((refs (variable-refs (form-var (node-form l)))))
  208. (cond ((and refs (every? called-node? refs))
  209. refs)
  210. ((calls-known? l)
  211. (bug "cannot find calls for known lambda ~S" l))
  212. (else #f))))
  213. ;--------------------------------------------------
  214. ; Determine an actual type for a polymorphic procedure.
  215. (define (remove-polymorphism form)
  216. (if (and (null? (variable-refs (form-var form)))
  217. (eq? 'lambda (form-type form)))
  218. (for-each (lambda (var)
  219. (if (and (null? (variable-refs var))
  220. (uvar? (maybe-follow-uvar (variable-type var))))
  221. (unused-variable-warning var form)))
  222. (cdr (lambda-variables (form-node form)))))
  223. (if (type-scheme? (variable-type (form-var form)))
  224. (make-monomorphic! (form-var form))))
  225. (define (unused-variable-warning var form)
  226. (format #t "Warning: argument `~S' of `~S' is not used, and `~S' is not called;~%"
  227. (variable-name var) (form-name form) (form-name form))
  228. (format #t " assuming the type of argument `~S' of procedure `~S' is `long'.~%"
  229. (variable-name var) (form-name form))
  230. (set-variable-type! var type/integer))
  231. ;--------------------------------------------------
  232. ; Various methods for getting values from thunks. These are no longer used
  233. ; here.
  234. (define (thunk-value thunk)
  235. (let ((refs (variable-refs (car (lambda-variables thunk)))))
  236. (if (= 1 (length refs))
  237. (call-arg (node-parent (car refs)) 2)
  238. #f)))
  239. (define (simple-thunk? thunk value)
  240. (eq? (node-parent (node-parent value)) thunk))
  241. ;----------------------------------------------------------------
  242. ; Turning internal tail-recursive calls to jumps.
  243. ; f = (proc (c . vars)
  244. ; ... ([unknown-]tail-call c f . args) ...)
  245. ; =>
  246. ; f = (proc (c . vars)
  247. ; (letrec ((f' (jump . vars) ... (jump f' . args) ...))
  248. ; (jump f' . vars)))
  249. (define (maybe-add-self-label form)
  250. (if (eq? 'lambda (form-type form))
  251. (let* ((node (form-node form))
  252. (self-calls (filter (lambda (ref)
  253. (and (eq? (node-index ref) 1)
  254. (calls-this-primop? (node-parent ref)
  255. (if (calls-known? node)
  256. 'tail-call
  257. 'unknown-tail-call))
  258. (eq? node (node-base ref))))
  259. (variable-refs (form-var form)))))
  260. (if (not (null? self-calls))
  261. (begin
  262. (use-this-form! form)
  263. (replace-self-calls-with-jumps node self-calls)
  264. (suspend-form-use! form))))))
  265. (define (replace-self-calls-with-jumps proc refs)
  266. (let* ((outside-var (reference-variable (car refs)))
  267. (var (make-variable (variable-name outside-var)
  268. (variable-type outside-var)))
  269. (old-vars (cdr (lambda-variables proc)))
  270. (new-vars (map copy-variable old-vars))
  271. (args (map make-reference-node new-vars))
  272. (body (lambda-body proc))
  273. (jump-proc (make-lambda-node (lambda-name proc) 'jump old-vars)))
  274. (for-each (lambda (var)
  275. (set-variable-binder! var proc))
  276. new-vars)
  277. (set-cdr! (lambda-variables proc) new-vars)
  278. (for-each (lambda (ref)
  279. (let ((call (node-parent ref)))
  280. (if (not (calls-known? proc))
  281. (remove-call-arg call 2)) ; remove TAIL? argument
  282. (remove-call-arg call 0) ; remove continuation argument
  283. (replace (call-arg call 0) (make-reference-node var))
  284. (set-call-primop! call (get-primop (enum primop jump)))))
  285. refs)
  286. (let-nodes ((call (jump 0 (* var) . args)))
  287. (move-body body (lambda (body)
  288. (attach-body jump-proc body)
  289. call))
  290. (put-in-letrec (list var) (list jump-proc) call))))