c.scm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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, Timo Harter, Martin Gasbichler
  6. ;;;
  7. ;;; scheme48-1.9.2/ps-compiler/prescheme/c.scm
  8. ;;;
  9. ;;; Translating the node tree into C
  10. (define-module (ps-compiler prescheme c)
  11. #:use-module (ice-9 format)
  12. #:use-module (prescheme scheme48)
  13. #:use-module (ps-compiler node node)
  14. #:use-module (ps-compiler node node-util)
  15. #:use-module (ps-compiler node variable)
  16. #:use-module (ps-compiler prescheme c-call)
  17. #:use-module (ps-compiler prescheme c-decl)
  18. #:use-module (ps-compiler prescheme c-util)
  19. #:use-module (ps-compiler prescheme flatten)
  20. #:use-module (ps-compiler prescheme form)
  21. #:use-module (ps-compiler prescheme hoist)
  22. #:use-module ((ps-compiler prescheme infer-early) #:select (literal-value-type))
  23. #:use-module (ps-compiler prescheme merge)
  24. #:use-module (ps-compiler prescheme record)
  25. #:use-module (ps-compiler prescheme type)
  26. #:use-module (ps-compiler prescheme type-var)
  27. #:use-module (ps-compiler util util)
  28. #:export (write-c-file
  29. *doing-tail-called-procedure?*
  30. *current-merged-procedure*
  31. *extra-tail-call-args*
  32. write-c-block
  33. no-value-node?
  34. note-jump-generated!))
  35. (define (write-c-file init-name file header forms)
  36. (set! *c-variable-id* 0)
  37. (set! *type-uids* '())
  38. (set! *next-type-uid* 0)
  39. (let* ((real-out (open-output-file file))
  40. (out (make-tracking-output-port real-out)))
  41. (merge-forms forms)
  42. (check-hoisting forms)
  43. (format #t "Translating~%")
  44. (write-c-header header out)
  45. (write-function-prototypes forms out)
  46. (write-global-arg-variable-declarations forms out)
  47. (write-global-variable-declarations forms out)
  48. (newline out)
  49. (for-each (lambda (f)
  50. (case (form-type f)
  51. ((lambda)
  52. (compile-proc-to-c f out))
  53. ((alias constant integrate merged stob initialize unused)
  54. (values))
  55. (else
  56. (bug "unknown type of form ~S" f))))
  57. forms)
  58. (write-c-main init-name out forms)
  59. (newline out)
  60. (set! *type-uids* '())
  61. (close-output-port out)
  62. (close-output-port real-out)))
  63. (define (write-c-main init-name out forms)
  64. (set! *doing-tail-called-procedure?* #f)
  65. (set! *current-merged-procedure* #f)
  66. (cond ((any? (lambda (f)
  67. (or (eq? (form-type f) 'initialize)
  68. (eq? (form-type f) 'stob)
  69. (eq? (form-type f) 'alias)))
  70. forms)
  71. (write-c-main-header (if init-name init-name 'main) out)
  72. (for-each (lambda (f)
  73. (case (form-type f)
  74. ((initialize alias)
  75. (write-initialize (form-var f) (form-value f) out))
  76. ((stob)
  77. (write-stob (form-var f)
  78. (form-value-type f)
  79. (lambda-body (form-value f))
  80. out))))
  81. forms)
  82. (write-c-main-end out))))
  83. (define (write-c-header header out)
  84. (format out "#include <stdio.h>~%")
  85. (format out "#include <string.h>~%")
  86. (format out "#include <stdlib.h>~%")
  87. (format out "#include \"prescheme.h\"~%")
  88. (for-each (lambda (s)
  89. (display s out)
  90. (newline out))
  91. header)
  92. (for-each (lambda (rtype)
  93. (declare-record-type rtype out))
  94. (all-record-types))
  95. (newline out)
  96. (values))
  97. (define (declare-record-type rtype out)
  98. (format out "~%struct ")
  99. (write-c-identifier (record-type-name rtype) out)
  100. (format out " {~%")
  101. (for-each (lambda (field)
  102. (format out " ")
  103. (display-c-type (record-field-type field)
  104. (lambda (port)
  105. (write-c-identifier (record-field-name field)
  106. out))
  107. out)
  108. (format out ";~%"))
  109. (record-type-fields rtype))
  110. (format out "};"))
  111. ;; Even when finished we need to keep the lambda around for help with
  112. ;; calls to it.
  113. (define (compile-proc-to-c form out)
  114. (format #t " ~A~%" (form-c-name form))
  115. (let ((name (form-c-name form)))
  116. (proc->c name form (form-shadowed form) out #f)
  117. (for-each make-form-unused! (form-merged form))
  118. (erase (detach-body (lambda-body (form-value form))))
  119. (suspend-form-use! form)))
  120. (define (no-value-node? node)
  121. (or (undefined-value-node? node)
  122. (and (reference-node? node)
  123. (let ((type (final-variable-type (reference-variable node))))
  124. (or (eq? type type/unit)
  125. (eq? type type/null))))))
  126. ;;------------------------------------------------------------
  127. ;; Initialization procedure at the end of the file (often called `main').
  128. ;; Header for initialization code
  129. (define (write-c-main-header initname out)
  130. (format out "void~%")
  131. (write-c-identifier initname out)
  132. (format out "(void)~%{"))
  133. ;; Write the end of the initialization code
  134. (define (write-c-main-end out)
  135. (format out "~&}"))
  136. (define (write-initialize var value out)
  137. (let ((wants (maybe-follow-uvar (variable-type var))))
  138. (receive (value has)
  139. (cond ((variable? value)
  140. (values value (final-variable-type value)))
  141. ((literal-node? value)
  142. (values (literal-value value) (literal-type value)))
  143. ((reference-node? value)
  144. (let ((var (reference-variable value)))
  145. (values var (final-variable-type var))))
  146. (else
  147. (error "unknown kind of initial value ~S" value)))
  148. (cond ((not (unspecific? value))
  149. (c-assign-to-variable var out 0)
  150. (if (not (type-eq? wants has))
  151. (write-c-coercion wants out))
  152. (cond ((input-port? value)
  153. (display "0" out))
  154. ((output-port? value)
  155. (display "1" out))
  156. ((variable? value)
  157. (c-variable value out))
  158. (else
  159. (c-literal-value value has out)))
  160. (writec out '#\;))))))
  161. (define (write-stob var type call out)
  162. (let ((value (literal-value (call-arg call 0)))
  163. (wants (final-variable-type var)))
  164. (c-assign-to-variable var out 0)
  165. (cond ((vector? value)
  166. (if (not (type-eq? type wants))
  167. (write-c-coercion wants out))
  168. (format out "malloc(~D * sizeof(" (vector-length value))
  169. (display-c-type (pointer-type-to type) #f out)
  170. (format out "));")
  171. (do ((i 0 (+ i 1)))
  172. ((>= i (vector-length value)))
  173. (let* ((elt (call-arg call (+ i 1)))
  174. (has (finalize-type
  175. (if (reference-node? elt)
  176. (variable-type (reference-variable elt))
  177. (literal-value-type (literal-value elt))))))
  178. (newline out)
  179. (c-variable var out)
  180. (format out "[~D] = " i)
  181. (if (not (type-eq? (pointer-type-to type) has))
  182. (write-c-coercion (pointer-type-to type) out))
  183. (c-value elt out)
  184. (write-char #\; out))))
  185. (else
  186. (error "don't know how to generate stob value ~S" value)))))
  187. ;;------------------------------------------------------------
  188. ;; Writing out a procedure.
  189. (define (proc->c name form rename-vars port maybe-merged-count)
  190. (let ((top (form-value form))
  191. (merged (form-merged form))
  192. (tail? (form-tail-called? form))
  193. (exported? (form-exported? form))
  194. (lambda-kids lambda-block)) ;; filled in by the hoist code
  195. (let ((lambdas (filter (lambda (l)
  196. (not (proc-lambda? l)))
  197. (lambda-kids top))))
  198. (if maybe-merged-count
  199. (merged-proc->c name top lambdas merged maybe-merged-count port tail?)
  200. (real-proc->c name (form-var form) top lambdas
  201. merged rename-vars port tail? exported?))
  202. (values))))
  203. (define (write-merged-form form port)
  204. (format #t " ~A~%" (form-c-name form))
  205. ;; (breakpoint "write-merged-form ~S" form)
  206. (proc->c (form-c-name form)
  207. form
  208. '()
  209. port
  210. (length (variable-refs (form-var form)))))
  211. ;;------------------------------------------------------------
  212. ;; 1. write the header
  213. ;; 2. declare the local variables
  214. ;; 3. write out the body
  215. ;; 4. write out all of the label lambdas
  216. (define (real-proc->c id var top lambdas merged rename-vars port tail? exported?)
  217. (let ((vars (cdr (lambda-variables top)))
  218. (return-type (final-variable-type (car (lambda-variables top))))
  219. (all-lambdas (append lambdas (gather-merged-lambdas merged)))
  220. (merged-procs (gather-merged-procs merged)))
  221. (set! *doing-tail-called-procedure?* tail?)
  222. (set! *current-merged-procedure* #f)
  223. (receive (first rest)
  224. (parse-return-type return-type)
  225. (set! *extra-tail-call-args*
  226. (do ((i (length rest) (- i 1))
  227. (args '() (cons (format #f "TT~D" (- i 1)) args)))
  228. ((= i 0)
  229. args))))
  230. (set! *jumps-to-do* '())
  231. (write-procedure-header id return-type vars port tail? exported?)
  232. (write-char '#\{ port)
  233. (newline port)
  234. (for-each (lambda (v)
  235. (set-variable-flags! v (cons 'shadowed (variable-flags v))))
  236. rename-vars)
  237. (write-arg-variable-declarations all-lambdas merged port)
  238. (write-rename-variable-declarations rename-vars port)
  239. (write-merged-declarations merged port)
  240. (fixup-nasty-c-primops! (lambda-body top))
  241. (for-each (lambda (form)
  242. (write-merged-decls form port))
  243. merged)
  244. (clear-lambda-generated?-flags lambdas)
  245. (set! *local-vars* '())
  246. (let ((body (call-with-string-output-port
  247. (lambda (temp-port)
  248. (let ((temp-port (make-tracking-output-port temp-port)))
  249. (write-c-block (lambda-body top) temp-port 2)
  250. (write-jump-lambdas temp-port 0)
  251. (for-each (lambda (f)
  252. (write-merged-form f temp-port))
  253. (reverse merged)) ;; makes for more readable output
  254. (newline temp-port)
  255. (force-output temp-port))))))
  256. (declare-local-variables port)
  257. (if tail?
  258. (write-global-argument-initializers (cdr (lambda-variables top))
  259. port 2))
  260. (format port "~% {")
  261. (display body port)
  262. (write-char '#\} port))
  263. (for-each (lambda (v)
  264. (set-variable-flags! v (delq! 'shadowed (variable-flags v))))
  265. rename-vars)
  266. (values)))
  267. ;; These global variables should be replaced with fluids.
  268. (define *doing-tail-called-procedure?* #f)
  269. (define *current-merged-procedure* #f)
  270. (define *extra-tail-call-args* '())
  271. (define (gather-merged-lambdas merged)
  272. (let loop ((merged merged) (lambdas '()))
  273. (if (null? merged)
  274. lambdas
  275. (loop (append (form-merged (car merged)) (cdr merged))
  276. (append (form-lambdas (car merged)) lambdas)))))
  277. (define (gather-merged-procs merged)
  278. (let loop ((merged merged) (procs '()))
  279. (if (null? merged)
  280. procs
  281. (loop (append (form-merged (car merged)) (cdr merged))
  282. (cons (form-value (car merged)) procs)))))
  283. (define (write-merged-decls form port)
  284. (let ((top (form-value form))
  285. (merged (form-merged form)))
  286. (let ((vars (filter (lambda (var)
  287. (and (used? var)
  288. (not (eq? type/unit (final-variable-type var)))))
  289. (cdr (lambda-variables top)))))
  290. (write-variable-declarations vars port 2))
  291. (write-merged-declarations merged port)))
  292. (define (merged-proc->c name top lambdas merged return-count port tail?)
  293. (let ((vars (cdr (lambda-variables top)))
  294. (body (lambda-body top)))
  295. (set! *doing-tail-called-procedure?* tail?)
  296. (set! *current-merged-procedure* name)
  297. (write-merged-header name top port)
  298. (write-char '#\{ port)
  299. (clear-lambda-generated?-flags lambdas)
  300. (write-c-block body port 2)
  301. (write-jump-lambdas port 0)
  302. (if (not tail?)
  303. (write-merged-return name return-count port))
  304. (for-each (lambda (f)
  305. (write-merged-form f port))
  306. (reverse merged)) ;; makes for more readable output
  307. (write-char '#\} port)
  308. (newline port)
  309. (values)))
  310. (define (write-merged-header name top port)
  311. (format port "~% ~A: {~%" name)
  312. (if (not (null? (cdr (lambda-variables top))))
  313. (write-merged-argument-initializers (cdr (lambda-variables top)) port 2)))
  314. ;; We use `default:' for the last tag so that the C compiler will
  315. ;; know that the code following the switch is unreachable (to avoid
  316. ;; a spurious warning if this is the end of the procedure).
  317. (define (write-merged-return name return-count port)
  318. (format port "~%#ifndef USE_DIRECT_THREADING~% ~A_return:~% switch (~A_return_tag) {~%" name name)
  319. (do ((i 0 (+ i 1)))
  320. ((>= i (- return-count 1)))
  321. (format port " case ~S: goto ~A_return_~S;~%" i name i))
  322. (format port " default: goto ~A_return_~S;~%" name (- return-count 1))
  323. (format port " }~%#endif~%"))
  324. (define (write-merged-declarations forms port)
  325. (for-each (lambda (f)
  326. (if (not (form-tail-called? f))
  327. (write-merged-declaration f port)))
  328. forms))
  329. (define (write-merged-declaration form port)
  330. (let ((name (form-c-name form))
  331. (types (lambda-return-types (form-value form))))
  332. (format port "~%#ifdef USE_DIRECT_THREADING~% void *~A_return_address;~%#else~% int ~A_return_tag;~%#endif" name name)
  333. (do ((i 0 (+ i 1))
  334. (types types (cdr types)))
  335. ((null? types))
  336. (let ((type (car types)))
  337. (cond ((not (or (eq? type type/unit)
  338. (eq? type type/null)))
  339. (format port "~% ")
  340. (display-c-type type
  341. (lambda (port)
  342. (format port "~A~D_return_value" name i))
  343. port)
  344. (writec port #\;)))))))
  345. (define (lambda-return-types node)
  346. (let ((type (final-variable-type (car (lambda-variables node)))))
  347. (if (tuple-type? type)
  348. (tuple-type-types type)
  349. (list type))))
  350. (define (write-procedure-header id return-type vars port tail? exported?)
  351. (newline port)
  352. (if (not exported?)
  353. (display "static " port))
  354. (receive (first rest)
  355. (parse-return-type return-type)
  356. (display-c-type (if tail? type/integer first)
  357. (lambda (port)
  358. (if tail? (write-char #\T port))
  359. (display id port))
  360. port)
  361. (write-char '#\( port)
  362. (if (not tail?)
  363. (let ((args (append vars
  364. (do ((i 0 (+ i 1))
  365. (rest rest (cdr rest))
  366. (res '() (cons (cons i (car rest)) res)))
  367. ((null? rest)
  368. (reverse res))))))
  369. (if (null? args)
  370. (display "void" port)
  371. (write-variables args port))))
  372. (write-char '#\) port)
  373. (newline port)))
  374. ;; Write the names of VARS out to the port. VARS may contain pairs of the
  375. ;; form (<integer> . <type>) as well as variables.
  376. (define (write-variables vars port)
  377. (let ((do-one (lambda (var)
  378. (display-c-type (if (pair? var)
  379. (make-pointer-type (cdr var))
  380. (final-variable-type var))
  381. (lambda (port)
  382. (if (pair? var)
  383. (format port "TT~D" (car var))
  384. (c-variable var port)))
  385. port))))
  386. (cond ((null? vars)
  387. (values))
  388. ((null? (cdr vars))
  389. (do-one (car vars)))
  390. (else
  391. (do-one (car vars))
  392. (do ((vars (cdr vars) (cdr vars)))
  393. ((null? vars)
  394. (values))
  395. (write-char '#\, port)
  396. (write-char '#\space port)
  397. (do-one (car vars)))))))
  398. (define (write-rename-variable-declarations vars port)
  399. (for-each (lambda (var)
  400. (indent-to port 2)
  401. (display-c-type (final-variable-type var)
  402. (lambda (port)
  403. (writec port #\R)
  404. (write-c-identifier (variable-name var) port))
  405. port)
  406. (display " = " port)
  407. (write-c-identifier (variable-name var) port)
  408. (format port ";~%"))
  409. vars))
  410. (define (write-c-block body port indent)
  411. (write-c-block-with-args body '() port indent))
  412. (define (write-c-block-with-args body arg-vars port indent)
  413. (if (not (null? arg-vars))
  414. (write-argument-initializers arg-vars port indent))
  415. (call->c body port indent)
  416. (write-char '#\} port))
  417. ;; Jump lambdas. These are generated more-or-less in the order they are
  418. ;; referenced.
  419. (define (clear-lambda-generated?-flags lambdas)
  420. (for-each (lambda (l)
  421. (set-lambda-block! l #f))
  422. lambdas))
  423. (define *jumps-to-do* '())
  424. (define (note-jump-generated! proc)
  425. (if (not (lambda-block proc))
  426. (begin
  427. (set! *jumps-to-do* (cons proc *jumps-to-do*))
  428. (set-lambda-block! proc #t))))
  429. (define (write-jump-lambdas port indent)
  430. (let loop ()
  431. (let ((jumps (reverse *jumps-to-do*)))
  432. (set! *jumps-to-do* '())
  433. (for-each (lambda (jump)
  434. (jump-lambda->c jump port indent))
  435. jumps)
  436. (if (not (null? *jumps-to-do*))
  437. (loop)))))
  438. (define (jump-lambda->c node port indent)
  439. (newline port)
  440. (indent-to port indent)
  441. (display " L" port)
  442. (display (lambda-id node) port)
  443. (display ": {" port)
  444. (newline port)
  445. (write-c-block-with-args (lambda-body node)
  446. (lambda-variables node)
  447. port
  448. (+ '2 indent)))