c-decl.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. ; Copyright (c) 1993-2008 by Richard Kelsey. See file COPYING.
  2. ; C variable declarations.
  3. ;
  4. ; (write-function-prototypes forms port)
  5. ;
  6. ; (write-variable-declarations vars port indent)
  7. ; Writing declarations.
  8. (define (write-function-prototypes forms port)
  9. (for-each (lambda (f)
  10. (if (eq? (form-type f) 'lambda)
  11. (if (form-tail-called? f)
  12. (write-function-tail-prototype (form-c-name f)
  13. (form-exported? f)
  14. port)
  15. (write-function-prototype (form-var f)
  16. (form-c-name f)
  17. (form-exported? f)
  18. port))))
  19. forms))
  20. (define (write-function-tail-prototype name exported? port)
  21. (if (not exported?)
  22. (display "static " port))
  23. (display "long T" port)
  24. (display name port)
  25. (display "(void);" port)
  26. (newline port))
  27. (define (write-function-prototype var name exported? port)
  28. (if (not exported?)
  29. (display "static " port))
  30. (receive (result args)
  31. (parse-arrow-type (final-variable-type var))
  32. (display-c-type result
  33. (lambda (port)
  34. (display name port))
  35. port)
  36. (write-char #\( port)
  37. (if (null? args)
  38. (display "void" port)
  39. (begin
  40. (display-c-type (car args) #f port)
  41. (let loop ((args (cdr args)))
  42. (if (not (null? args))
  43. (begin
  44. (display ", " port)
  45. (display-c-type (car args) #f port)
  46. (loop (cdr args)))))))
  47. (display ");" port)
  48. (newline port)))
  49. ; Write declarations for global variables.
  50. (define (write-global-variable-declarations forms port)
  51. (for-each (lambda (form)
  52. (if (memq (form-type form)
  53. '(stob initialize alias))
  54. (let* ((var (form-var form))
  55. (type (final-variable-type var)))
  56. (if (not (or (eq? type type/unit)
  57. (eq? type type/null)))
  58. (really-write-variable-declaration
  59. var type (form-exported? form) port 0)))))
  60. forms))
  61. ; Write general variable declarations.
  62. (define (write-variable-declarations vars port indent)
  63. (for-each (lambda (var)
  64. (let ((type (final-variable-type var)))
  65. (if (not (or (eq? type type/unit)
  66. (eq? type type/null)))
  67. (really-write-variable-declaration var type #t port indent))))
  68. vars))
  69. (define (really-write-variable-declaration var type exported? port indent)
  70. (indent-to port indent)
  71. (if (not exported?)
  72. (display "static " port))
  73. (display-c-type type
  74. (lambda (port)
  75. (c-variable-no-shadowing var port))
  76. port)
  77. (writec port #\;))
  78. ;----------------------------------------------------------------
  79. ; Writing C types
  80. (define (display-c-type type name port)
  81. (display-c-base-type (type->c-base-type type) port)
  82. (if name (display " " port))
  83. (display-c-type-modifiers type name port))
  84. (define (write-c-coercion type out)
  85. (write-char #\( out)
  86. (display-c-type type #f out)
  87. (write-char #\) out))
  88. ; Searches through the type modifiers until the base type is found.
  89. ; Unspecified result types are assumed to be `void'.
  90. (define (type->c-base-type type)
  91. (let ((type (maybe-follow-uvar type)))
  92. (cond ((or (base-type? type)
  93. (record-type? type))
  94. type)
  95. ((pointer-type? type)
  96. (type->c-base-type (pointer-type-to type)))
  97. ((arrow-type? type)
  98. (let ((res (arrow-type-result type)))
  99. (cond ((and (uvar? res)
  100. (not (uvar-binding res)))
  101. type/unit)
  102. ((not (tuple-type? res))
  103. (type->c-base-type res))
  104. ((null? (tuple-type-types res))
  105. type/unit)
  106. (else
  107. (type->c-base-type (car (tuple-type-types res)))))))
  108. (else
  109. (bug "don't know how to write ~S as a C type" type)))))
  110. ; Table of C names for base types.
  111. (define c-decl-table (make-integer-table))
  112. (define (add-c-type-declaration! type decl)
  113. (table-set! c-decl-table (base-type-uid type) decl))
  114. (for-each (lambda (p)
  115. (let ((type (lookup-type (car p))))
  116. (add-c-type-declaration! type (cadr p))))
  117. '((boolean "char")
  118. (char "char")
  119. (integer "long")
  120. (unsigned-integer "unsigned long")
  121. (float "double")
  122. (address "char *")
  123. (input-port "FILE *")
  124. (output-port "FILE *")
  125. (unit "void")
  126. (null "void")))
  127. (define (display-c-base-type type port)
  128. (cond ((record-type? type)
  129. (display "struct " port)
  130. (write-c-identifier (record-type-name type) port))
  131. (else
  132. (display (or (table-ref c-decl-table (base-type-uid type))
  133. (bug "no C declaration for ~S" type))
  134. port))))
  135. ; Writes out the modifiers of TYPE with NAME used when the base type is reached.
  136. (define (display-c-type-modifiers type name port)
  137. (let label ((type type) (name name))
  138. (let ((type (maybe-follow-uvar type)))
  139. (cond ((or (base-type? type)
  140. (record-type? type))
  141. (if name (name port)))
  142. ((pointer-type? type)
  143. (label (pointer-type-to type)
  144. (lambda (port)
  145. (format port "*")
  146. (if name (name port)))))
  147. ((arrow-type? type)
  148. (receive (return-type args)
  149. (parse-arrow-type type)
  150. (display-c-type-modifiers return-type #f port)
  151. (format port "(*")
  152. (if name (name port))
  153. (format port ")(")
  154. (cond ((null? args)
  155. (display "void" port))
  156. (else
  157. (display-c-type (car args) #f port)
  158. (do ((args (cdr args) (cdr args)))
  159. ((null? args))
  160. (display ", " port)
  161. (display-c-type (car args) #f port))))
  162. (format port ")")))
  163. (else
  164. (bug "don't know how to write ~S as a C type" type))))))
  165. (define (parse-arrow-type type)
  166. (receive (first rest)
  167. (parse-return-type (arrow-type-result type))
  168. (values first
  169. (append (arrow-type-args type)
  170. (map make-pointer-type rest)))))
  171. (define (parse-return-type type)
  172. (cond ((not (tuple-type? type))
  173. (values (if (and (uvar? type)
  174. (not (uvar-binding type)))
  175. type/unit
  176. type)
  177. '()))
  178. ((null? (tuple-type-types type))
  179. (values type/unit '()))
  180. (else
  181. (values (car (tuple-type-types type))
  182. (cdr (tuple-type-types type))))))
  183. ;------------------------------------------------------------
  184. ; Collecting local variables. Each is added to this list when it is first
  185. ; used.
  186. (define *local-vars* '())
  187. (define (declare-local-variables port)
  188. (write-variable-declarations *local-vars* port 2))
  189. ; Some primops must be given continuations so that calls to them will
  190. ; be translated into separate C statements and so expand into arbitrarily
  191. ; complex chunks of C if necessary.
  192. (define (fixup-nasty-c-primops! call)
  193. (let ((top call))
  194. (let label ((call call))
  195. (cond ((call-node? call)
  196. (if (and (= 0 (call-exits call))
  197. (nasty-c-primop-call? call))
  198. (set! top (expand-nasty-c-primop! call top)))
  199. (walk-vector label (call-args call)))))
  200. (do ((i 0 (+ i 1)))
  201. ((= i (call-arg-count top)))
  202. (let ((arg (call-arg top i)))
  203. (if (lambda-node? arg)
  204. (fixup-nasty-c-primops! (lambda-body arg)))))))
  205. (define (nasty-c-primop-call? call)
  206. (case (primop-id (call-primop call))
  207. ((lshl ashl ashr) ; C does poorly when shifting by large amounts
  208. (not (literal-node? (call-arg call 1))))
  209. (else #f)))
  210. ; Give CALL a continuation and move it above TOP, replacing CALL
  211. ; with the continuation's variable.
  212. ;
  213. ; top = (p1 ... (p2 a1 ...) ...)
  214. ; =>
  215. ; (p2 (lambda (v) (p1 ... v ...)) a1 ...)
  216. (define (expand-nasty-c-primop! call top)
  217. (let* ((var (make-variable 'x (node-type call)))
  218. (cont (make-lambda-node 'c 'cont (list var))))
  219. (move call
  220. (lambda (call)
  221. (make-reference-node var)))
  222. (insert-body call
  223. cont
  224. (node-parent top))
  225. (set-call-exits! call 1)
  226. (insert-call-arg call 0 cont)
  227. call))
  228. ;------------------------------------------------------------
  229. ; Declare the variables used to pass arguments to procedures.
  230. ; This is done in each procedure so that the C compiler doesn't have to contend
  231. ; with the possibility of globally visible side-effects.
  232. (define (write-arg-variable-declarations lambdas merged port)
  233. (let ((lambdas (filter (lambda (l)
  234. (eq? 'jump (lambda-type l)))
  235. lambdas))
  236. (merged (map form-value merged)))
  237. (really-write-arg-variable-declarations lambdas "arg" port 2)
  238. (really-write-arg-variable-declarations merged "merged_arg" port 2)))
  239. (define (write-global-arg-variable-declarations forms port)
  240. (let ((lambdas (filter-map (lambda (f)
  241. (if (and (form-var f)
  242. (memq? 'tail-called
  243. (variable-flags (form-var f))))
  244. (form-value f)
  245. #f))
  246. forms)))
  247. (really-write-arg-variable-declarations lambdas "goto_arg" port 0)))
  248. (define (really-write-arg-variable-declarations lambdas name port indent)
  249. (for-each (lambda (data)
  250. (destructure (((uid type . indicies) data))
  251. (if (not (eq? type type/unit))
  252. (for-each (lambda (i)
  253. (indent-to port indent)
  254. (declare-arg-variable type uid i name port))
  255. indicies))))
  256. (get-variable-decl-data lambdas)))
  257. (define (get-variable-decl-data lambdas)
  258. (let ((data '()))
  259. (for-each (lambda (l)
  260. (do ((vars (if (eq? 'jump (lambda-type l))
  261. (lambda-variables l)
  262. (cdr (lambda-variables l)))
  263. (cdr vars))
  264. (i 0 (+ i 1)))
  265. ((null? vars))
  266. (let* ((type (final-variable-type (car vars)))
  267. (uid (type->uid type))
  268. (datum (assq uid data)))
  269. (cond ((not datum)
  270. (set! data (cons (list uid type i) data)))
  271. ((not (memq i (cddr datum)))
  272. (set-cdr! (cdr datum) (cons i (cddr datum))))))))
  273. lambdas)
  274. data))
  275. (define (declare-arg-variable type uid i name port)
  276. (display-c-type type
  277. (lambda (port)
  278. (format port "~A~DK~D" name uid i))
  279. port)
  280. (format port ";~%"))
  281. ;------------------------------------------------------------
  282. (define (write-argument-initializers arg-vars port indent)
  283. (really-write-argument-initializers arg-vars "arg" #f port indent))
  284. (define (write-merged-argument-initializers arg-vars port indent)
  285. (really-write-argument-initializers arg-vars "merged_arg" #f port indent))
  286. (define (write-global-argument-initializers arg-vars port indent)
  287. (really-write-argument-initializers arg-vars "goto_arg" #t port indent))
  288. (define (really-write-argument-initializers arg-vars name type? port indent)
  289. (do ((i 0 (+ i 1))
  290. (vars arg-vars (cdr vars)))
  291. ((null? vars) (values))
  292. (if (used? (car vars))
  293. (let* ((var (car vars))
  294. (type (final-variable-type var)))
  295. (cond ((not (eq? type/unit type))
  296. (indent-to port indent)
  297. (if type?
  298. (display-c-type type
  299. (lambda (port) (c-variable var port))
  300. port)
  301. (c-variable var port))
  302. (display " = " port)
  303. (display (c-argument-var name type i port) port)
  304. (write-char '#\; port)))))))
  305. (define (c-argument-var name type i port)
  306. (format #f "~A~DK~D" name (type->uid type) i))
  307. (define *type-uids* '())
  308. (define *next-type-uid* 0)
  309. (define (type->uid type)
  310. (cond ((any (lambda (p)
  311. (type-eq? type (car p)))
  312. *type-uids*)
  313. => cdr)
  314. (else
  315. (let ((id *next-type-uid*))
  316. (set! *next-type-uid* (+ id 1))
  317. (set! *type-uids* (cons (cons type id) *type-uids*))
  318. id))))
  319. ;----------------------------------------------------------------
  320. ; Random utility here for historical reasons.
  321. (define (goto-call? call)
  322. (and (calls-this-primop? call 'unknown-tail-call)
  323. (goto-protocol? (literal-value (call-arg call 2)))))
  324. ;----------------------------------------------------------------
  325. ; random type stuff
  326. (define (reference-type node)
  327. (finalize-variable-type (reference-variable node)))
  328. (define (finalize-variable-type var)
  329. (let* ((type (finalize-type (variable-type var)))
  330. (type (if (uvar? type)
  331. type/null
  332. type)))
  333. (set-variable-type! var type)
  334. type))
  335. (define final-variable-type finalize-variable-type)