c-decl.scm 11 KB

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