c-decl.scm 15 KB

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