top.scm 14 KB

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