c.scm 15 KB

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