123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
- ;;;
- ;;; Port Author: Andrew Whatson
- ;;;
- ;;; Original Authors: Richard Kelsey, Timo Harter
- ;;;
- ;;; scheme48-1.9.2/ps-compiler/prescheme/c-decl.scm
- ;;;
- ;;; C variable declarations.
- ;;;
- ;;; (write-function-prototypes forms port)
- ;;;
- ;;; (write-variable-declarations vars port indent)
- ;;;
- ;;; Writing declarations.
- (define-module (ps-compiler prescheme c-decl)
- #:use-module (ice-9 format)
- #:use-module (ice-9 match)
- #:use-module (prescheme scheme48)
- #:use-module (ps-compiler node node)
- #:use-module (ps-compiler node node-util)
- #:use-module (ps-compiler node primop)
- #:use-module (ps-compiler node variable)
- #:use-module (ps-compiler prescheme c-call)
- #:use-module (ps-compiler prescheme c-util)
- #:use-module (ps-compiler prescheme flatten)
- #:use-module (ps-compiler prescheme form)
- #:use-module (ps-compiler prescheme merge)
- #:use-module (ps-compiler prescheme type)
- #:use-module (ps-compiler prescheme type-var)
- #:use-module (ps-compiler util util)
- #:export (form-c-name
- c-argument-var
- write-c-coercion
- display-c-type
- add-c-type-declaration!
- write-argument-initializers
- declare-local-variables
- fixup-nasty-c-primops!
- *next-type-uid*
- parse-return-type
- *type-uids*
- write-arg-variable-declarations
- write-function-prototypes
- write-global-argument-initializers
- write-global-arg-variable-declarations
- write-global-variable-declarations
- write-merged-argument-initializers
- write-variable-declarations))
- (define (form-c-name form)
- (let* ((var (form-var form))
- (name (c-ify (variable-name var))))
- (if (generated-top-variable? var)
- (string-append "H" name (number->string (c-variable-id var)))
- name)))
- (define (write-function-prototypes forms port)
- (for-each (lambda (f)
- (if (eq? (form-type f) 'lambda)
- (if (form-tail-called? f)
- (write-function-tail-prototype (form-c-name f)
- (form-exported? f)
- port)
- (write-function-prototype (form-var f)
- (form-c-name f)
- (form-exported? f)
- port))))
- forms))
- (define (write-function-tail-prototype name exported? port)
- (if (not exported?)
- (display "static " port))
- (display "long T" port)
- (display name port)
- (display "(void);" port)
- (newline port))
- (define (write-function-prototype var name exported? port)
- (if (not exported?)
- (display "static " port))
- (receive (result args)
- (parse-arrow-type (final-variable-type var))
- (display-c-type result
- (lambda (port)
- (display name port))
- port)
- (write-char #\( port)
- (if (null? args)
- (display "void" port)
- (begin
- (display-c-type (car args) #f port)
- (let loop ((args (cdr args)))
- (if (not (null? args))
- (begin
- (display ", " port)
- (display-c-type (car args) #f port)
- (loop (cdr args)))))))
- (display ");" port)
- (newline port)))
- ;; Write declarations for global variables.
- (define (write-global-variable-declarations forms port)
- (for-each (lambda (form)
- (if (memq (form-type form)
- '(stob initialize alias))
- (let* ((var (form-var form))
- (type (final-variable-type var)))
- (if (not (or (eq? type type/unit)
- (eq? type type/null)))
- (really-write-variable-declaration
- var type (form-exported? form) port 0)))))
- forms))
- ;; Write general variable declarations.
- (define (write-variable-declarations vars port indent)
- (for-each (lambda (var)
- (let ((type (final-variable-type var)))
- (if (not (or (eq? type type/unit)
- (eq? type type/null)))
- (really-write-variable-declaration var type #t port indent))))
- vars))
- (define (really-write-variable-declaration var type exported? port indent)
- (indent-to port indent)
- (if (not exported?)
- (display "static " port))
- (display-c-type type
- (lambda (port)
- (c-variable-no-shadowing var port))
- port)
- (writec port #\;))
- ;;----------------------------------------------------------------
- ;; Writing C types
- (define (display-c-type type name port)
- (display-c-base-type (type->c-base-type type) port)
- (if name (display " " port))
- (display-c-type-modifiers type name port))
- (define (write-c-coercion type out)
- (write-char #\( out)
- (display-c-type type #f out)
- (write-char #\) out))
- ;; Searches through the type modifiers until the base type is found.
- ;; Unspecified result types are assumed to be `void'.
- (define (type->c-base-type type)
- (let ((type (maybe-follow-uvar type)))
- (cond ((or (base-type? type)
- (record-type? type))
- type)
- ((pointer-type? type)
- (type->c-base-type (pointer-type-to type)))
- ((arrow-type? type)
- (let ((res (arrow-type-result type)))
- (cond ((and (uvar? res)
- (not (uvar-binding res)))
- type/unit)
- ((not (tuple-type? res))
- (type->c-base-type res))
- ((null? (tuple-type-types res))
- type/unit)
- (else
- (type->c-base-type (car (tuple-type-types res)))))))
- (else
- (bug "don't know how to write ~S as a C type" type)))))
- ;; Table of C names for base types.
- (define c-decl-table (make-integer-table))
- (define (add-c-type-declaration! type decl)
- (table-set! c-decl-table (base-type-uid type) decl))
- (for-each (lambda (p)
- (let ((type (lookup-type (car p))))
- (add-c-type-declaration! type (cadr p))))
- '((boolean "char")
- (char "char")
- (integer "long")
- (unsigned-integer "unsigned long")
- (float "double")
- (address "char *")
- (input-port "FILE *")
- (output-port "FILE *")
- (unit "void")
- (null "void")))
- (define (display-c-base-type type port)
- (cond ((record-type? type)
- (display "struct " port)
- (write-c-identifier (record-type-name type) port))
- (else
- (display (or (table-ref c-decl-table (base-type-uid type))
- (bug "no C declaration for ~S" type))
- port))))
- ;; Writes out the modifiers of TYPE with NAME used when the base type is reached.
- (define (display-c-type-modifiers type name port)
- (let label ((type type) (name name))
- (let ((type (maybe-follow-uvar type)))
- (cond ((or (base-type? type)
- (record-type? type))
- (if name (name port)))
- ((pointer-type? type)
- (label (pointer-type-to type)
- (lambda (port)
- (format port "*")
- (if name (name port)))))
- ((arrow-type? type)
- (receive (return-type args)
- (parse-arrow-type type)
- (display-c-type-modifiers return-type #f port)
- (format port "(*")
- (if name (name port))
- (format port ")(")
- (cond ((null? args)
- (display "void" port))
- (else
- (display-c-type (car args) #f port)
- (do ((args (cdr args) (cdr args)))
- ((null? args))
- (display ", " port)
- (display-c-type (car args) #f port))))
- (format port ")")))
- (else
- (bug "don't know how to write ~S as a C type" type))))))
- (define (parse-arrow-type type)
- (receive (first rest)
- (parse-return-type (arrow-type-result type))
- (values first
- (append (arrow-type-args type)
- (map make-pointer-type rest)))))
- (define (parse-return-type type)
- (cond ((not (tuple-type? type))
- (values (if (and (uvar? type)
- (not (uvar-binding type)))
- type/unit
- type)
- '()))
- ((null? (tuple-type-types type))
- (values type/unit '()))
- (else
- (values (car (tuple-type-types type))
- (cdr (tuple-type-types type))))))
- ;;------------------------------------------------------------
- ;; Collecting local variables. Each is added to this list when it is first
- ;; used.
- (define (declare-local-variables port)
- (write-variable-declarations *local-vars* port 2))
- ;; Some primops must be given continuations so that calls to them will
- ;; be translated into separate C statements and so expand into arbitrarily
- ;; complex chunks of C if necessary.
- (define (fixup-nasty-c-primops! call)
- (let ((top call))
- (let label ((call call))
- (cond ((call-node? call)
- (if (and (= 0 (call-exits call))
- (nasty-c-primop-call? call))
- (set! top (expand-nasty-c-primop! call top)))
- (walk-vector label (call-args call)))))
- (do ((i 0 (+ i 1)))
- ((= i (call-arg-count top)))
- (let ((arg (call-arg top i)))
- (if (lambda-node? arg)
- (fixup-nasty-c-primops! (lambda-body arg)))))))
- (define (nasty-c-primop-call? call)
- (case (primop-id (call-primop call))
- ((lshl ashl ashr) ;; C does poorly when shifting by large amounts
- (not (literal-node? (call-arg call 1))))
- (else #f)))
- ;; Give CALL a continuation and move it above TOP, replacing CALL
- ;; with the continuation's variable.
- ;;
- ;; top = (p1 ... (p2 a1 ...) ...)
- ;; =>
- ;; (p2 (lambda (v) (p1 ... v ...)) a1 ...)
- (define (expand-nasty-c-primop! call top)
- (let* ((var (make-variable 'x (node-type call)))
- (cont (make-lambda-node 'c 'cont (list var))))
- (move call
- (lambda (call)
- (make-reference-node var)))
- (insert-body call
- cont
- (node-parent top))
- (set-call-exits! call 1)
- (insert-call-arg call 0 cont)
- call))
- ;;------------------------------------------------------------
- ;; Declare the variables used to pass arguments to procedures.
- ;; This is done in each procedure so that the C compiler doesn't have to contend
- ;; with the possibility of globally visible side-effects.
- (define (write-arg-variable-declarations lambdas merged port)
- (let ((lambdas (filter (lambda (l)
- (eq? 'jump (lambda-type l)))
- lambdas))
- (merged (map form-value merged)))
- (really-write-arg-variable-declarations lambdas "arg" port 2)
- (really-write-arg-variable-declarations merged "merged_arg" port 2)))
- (define (write-global-arg-variable-declarations forms port)
- (let ((lambdas (filter-map (lambda (f)
- (if (and (form-var f)
- (memq? 'tail-called
- (variable-flags (form-var f))))
- (form-value f)
- #f))
- forms)))
- (really-write-arg-variable-declarations lambdas "goto_arg" port 0)))
- (define (really-write-arg-variable-declarations lambdas name port indent)
- (for-each (lambda (data)
- (match data
- ((uid type . indicies)
- (if (not (eq? type type/unit))
- (for-each (lambda (i)
- (indent-to port indent)
- (declare-arg-variable type uid i name port))
- indicies)))))
- (get-variable-decl-data lambdas)))
- (define (get-variable-decl-data lambdas)
- (let ((data '()))
- (for-each (lambda (l)
- (do ((vars (if (eq? 'jump (lambda-type l))
- (lambda-variables l)
- (cdr (lambda-variables l)))
- (cdr vars))
- (i 0 (+ i 1)))
- ((null? vars))
- (let* ((type (final-variable-type (car vars)))
- (uid (type->uid type))
- (datum (assq uid data)))
- (cond ((not datum)
- (set! data (cons (list uid type i) data)))
- ((not (memq i (cddr datum)))
- (set-cdr! (cdr datum) (cons i (cddr datum))))))))
- lambdas)
- data))
- (define (declare-arg-variable type uid i name port)
- (display-c-type type
- (lambda (port)
- (format port "~A~DK~D" name uid i))
- port)
- (format port ";~%"))
- ;;------------------------------------------------------------
- (define (write-argument-initializers arg-vars port indent)
- (really-write-argument-initializers arg-vars "arg" #f port indent))
- (define (write-merged-argument-initializers arg-vars port indent)
- (really-write-argument-initializers arg-vars "merged_arg" #f port indent))
- (define (write-global-argument-initializers arg-vars port indent)
- (really-write-argument-initializers arg-vars "goto_arg" #t port indent))
- (define (really-write-argument-initializers arg-vars name type? port indent)
- (do ((i 0 (+ i 1))
- (vars arg-vars (cdr vars)))
- ((null? vars) (values))
- (if (used? (car vars))
- (let* ((var (car vars))
- (type (final-variable-type var)))
- (cond ((not (eq? type/unit type))
- (indent-to port indent)
- (if type?
- (display-c-type type
- (lambda (port) (c-variable var port))
- port)
- (c-variable var port))
- (display " = " port)
- (display (c-argument-var name type i port) port)
- (write-char '#\; port)))))))
- (define (c-argument-var name type i port)
- (format #f "~A~DK~D" name (type->uid type) i))
- (define *type-uids* '())
- (define *next-type-uid* 0)
- (define (type->uid type)
- (cond ((any (lambda (p)
- (type-eq? type (car p)))
- *type-uids*)
- => cdr)
- (else
- (let ((id *next-type-uid*))
- (set! *next-type-uid* (+ id 1))
- (set! *type-uids* (cons (cons type id) *type-uids*))
- id))))
|