top.scm 11 KB

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