123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
- ;;;
- ;;; Port Author: Andrew Whatson
- ;;;
- ;;; Original Authors: Richard Kelsey, Timo Harter, Mike Sperber
- ;;;
- ;;; scheme48-1.9.2/ps-compiler/prescheme/primop/c-base.scm
- (define-module (ps-compiler prescheme primop c-base)
- #: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 variable)
- #:use-module (ps-compiler prescheme c)
- #:use-module (ps-compiler prescheme c-call)
- #:use-module (ps-compiler prescheme c-decl)
- #:use-module (ps-compiler prescheme form)
- #:use-module ((ps-compiler prescheme infer-early) #:select (get-variable-type))
- #:use-module (ps-compiler prescheme primop c-primop)
- #:use-module (ps-compiler prescheme merge)
- #:use-module (ps-compiler prescheme spec)
- #:use-module (ps-compiler prescheme type)
- #:use-module (ps-compiler util util))
- (define-c-generator let #f
- (lambda (call port indent)
- (let ((args (call-args call))
- (vars (lambda-variables (call-arg call 0))))
- (do ((i 1 (+ i 1))
- (vars vars (cdr vars)))
- ((null? vars))
- (let ((val (vector-ref args i)))
- (if (not (lambda-node? val))
- (c-assignment (car vars) val port indent)))))))
- (define-c-generator letrec1 #f
- (lambda (call port indent)
- (values)))
- (define-c-generator letrec2 #f
- (lambda (call port indent)
- (values)))
- (define-c-generator jump #f
- (lambda (call port indent)
- (let ((proc (called-lambda call)))
- (assign-argument-vars (lambda-variables proc) call 1 port indent)
- (indent-to port indent)
- (display "goto " port)
- (writec port #\L)
- (display (lambda-id proc) port)
- (write-char #\; port)
- (note-jump-generated! proc)
- (values))))
- (define (assign-argument-vars vars call start port indent)
- (really-assign-argument-vars vars call start "arg" port indent))
- (define (assign-merged-argument-vars vars call start port indent)
- (really-assign-argument-vars vars call start "merged_arg" port indent))
- (define (assign-global-argument-vars vars call start port indent)
- (really-assign-argument-vars vars call start "goto_arg" port indent))
- (define (really-assign-argument-vars vars call start name port indent)
- (let ((args (call-args call)))
- (do ((i start (+ i 1))
- (vars vars (cdr vars)))
- ((>= i (vector-length args)))
- (if (not (or (undefined-value-node? (vector-ref args i))
- (eq? type/unit (get-variable-type (car vars)))))
- (c-assignment (c-argument-var name
- (get-variable-type (car vars))
- (- i start)
- port)
- (vector-ref args i)
- port indent)))))
- ;; Calls
- ;; Unknown calls have a first argument of 'goto if they are supposed to be
- ;; tail-recursive. For known calls the protocol field of the lambda node
- ;; is set to 'tail-called if any of the calls are supposed to be tail-recursive.
- ;;
- ;; Calls to non-tail-called procedures are just regular C calls. For tail-
- ;; called procedures there are two kinds of calls:
- ;; Tail-call from a tail-called procedure: proceed through the driver loop
- ;; All others: start a driver loop
- ;;
- ;; Known and unknown calls are handled identically, except that known calls
- ;; may be to merged procedures.
- ;;
- ;; Merged procedures with GOTO calls:
- ;; This works if we merge the return points as well. Possibly there should be
- ;; one return switch per C procedure. There do have to be separate return point
- ;; variables (and one global one for the switch).
- (define-c-generator call #f
- (lambda (call port indent)
- (cond ((merged-procedure-reference (call-arg call 1))
- => (lambda (form)
- (generate-merged-call call 2 form port indent)))
- (else
- (generate-c-call call 2 port indent)))))
- (define-c-generator tail-call #f
- (lambda (call port indent)
- (cond ((merged-procedure-reference (call-arg call 1))
- => (lambda (form)
- (generate-merged-goto-call call 2 form port indent)))
- (else
- (generate-c-tail-call call 2 port indent)))))
- (define-c-generator unknown-call #f
- (lambda (call port indent)
- (if (goto-protocol? (literal-value (call-arg call 2)))
- (user-warning "ignoring GOTO declaration for non-tail-recursive call to"
- (variable-name (reference-variable
- (call-arg call 1)))))
- (generate-c-call call 3 port indent)))
- (define-c-generator unknown-tail-call #f
- (lambda (call port indent)
- (generate-c-tail-call call 3 port indent)))
- (define (generate-merged-goto-call call start form port indent)
- (let ((proc (form-value form)))
- (assign-merged-argument-vars (cdr (lambda-variables proc))
- call start
- port indent)
- (indent-to port indent)
- (display "goto " port)
- (display (form-c-name form) port)
- (write-char #\; port)
- (values)))
- (define (generate-goto-call call start port indent)
- (let ((proc (call-arg call 1)))
- (if (not (global-reference? proc))
- (bug "incorrect procedure in goto call ~S" call))
- (assign-global-argument-vars (cdr (lambda-variables
- (global-lambda
- (reference-variable proc))))
- call start
- port indent)
- ;; T is the marker for the tail-call version of the procedure
- (indent-to port indent)
- (display "return((long)T" port)
- (c-value proc port)
- (display ");" port)))
- (define (global-lambda var)
- (let ((form (maybe-variable->form var)))
- (if (and form
- (or (eq? 'lambda (form-type form))
- (eq? 'merged (form-type form))))
- (form-value form)
- (bug "value of ~S, called using goto, is not a known procedure"
- var))))
- ;; C requires that we dereference all but calls to global functions.
- ;; Calls to literals are macros that must take care of themselves.
- (define (generate-c-call call start port indent)
- (let ((vars (lambda-variables (call-arg call 0)))
- (args (call-args call))
- (proc (call-arg call 1)))
- (if (and (global-reference? proc)
- (memq? 'tail-called (variable-flags (reference-variable proc))))
- (call-with-driver-loop call start port indent (car vars))
- (let ((deref? (or (and (reference-node? proc)
- (variable-binder (reference-variable proc)))
- (call-node? proc))))
- (if (used? (car vars))
- (c-assign-to-variable (car vars) port indent))
- (if deref?
- (display "(*" port))
- (c-value proc port)
- (if deref?
- (writec port #\)))
- (write-value+result-var-list args start (cdr vars) port)))
- (writec port #\;)
- (values)))
- (define (generate-c-tail-call call start port indent)
- (let ((proc (call-arg call 1))
- (args (call-args call))
- (cont (call-arg call 0)))
- (cond ((not (and (global-reference? proc)
- (memq? 'tail-called
- (variable-flags (reference-variable proc)))))
- (let* ((type (get-variable-type (reference-variable cont)))
- (void? (or (eq? type type/unit)
- (eq? type type/null))))
- (indent-to port indent)
- (if (not void?)
- (display "return " port))
- (c-value proc port)
- (write-value-list-with-extras args start *extra-tail-call-args* port)
- (if void?
- (begin
- (display ";" port)
- (indent-to port indent)
- (display "return" port)))))
- (*doing-tail-called-procedure?*
- (generate-goto-call call start port indent))
- (else
- (call-with-driver-loop call start port indent #f)))
- (writec port #\;)
- (values)))
- (define (global-reference? node)
- (and (reference-node? node)
- (global-variable? (reference-variable node))))
- (define (call-with-driver-loop call start port indent result-var)
- (let* ((proc-var (reference-variable (call-arg call 1)))
- (vars (lambda-variables (global-lambda proc-var))))
- (assign-global-argument-vars (cdr vars) call start port indent)
- (if result-var
- (c-assign-to-variable result-var port indent)
- (begin
- (indent-to port indent)
- (display "return " port)))
- (display "TTrun_machine((long)" port)
- (display "T" port)
- (write-c-identifier (variable-name proc-var) port)
- (display ")" port)))
- (define (generate-merged-call call start form port indent)
- (let ((return-index (form-return-count form))
- (name (form-c-name form))
- (res (lambda-variables (call-arg call 0))))
- (set-form-return-count! form (+ 1 return-index))
- (assign-merged-argument-vars (cdr (lambda-variables (form-value form)))
- call start port indent)
- (format port "~%#ifdef USE_DIRECT_THREADING~%")
- (indent-to port indent)
- (format port "~A_return_address = &&~A_return_~S;~%#else~%" name name return-index)
- (indent-to port indent)
- (format port "~A_return_tag = ~D;~%#endif~%" name return-index)
- (indent-to port indent)
- (format port "goto ~A;" name)
- (indent-to port (- indent 1))
- (format port "~A_return_~S:" name return-index)
- (do ((i 0 (+ i 1))
- (res res (cdr res)))
- ((null? res))
- (let ((var (car res)))
- (cond ((and (used? var)
- (let ((type (get-variable-type var)))
- (and (not (eq? type type/unit))
- (not (eq? type type/null)))))
- (c-assign-to-variable var port indent)
- (format port "~A~D_return_value;" name i)))))))
- ;; Returns
- (define-c-generator return #f
- (lambda (call port indent)
- (if *current-merged-procedure*
- (generate-return-from-merged-call call 1 port indent)
- (really-generate-c-return call 1 port indent))))
- (define-c-generator unknown-return #f
- (lambda (call port indent)
- (cond (*doing-tail-called-procedure?*
- (generate-return-from-tail-call call port indent))
- (*current-merged-procedure*
- (generate-return-from-merged-call call 1 port indent))
- (else
- (really-generate-c-return call 1 port indent)))))
- (define (generate-return-from-tail-call call port indent)
- (if (not (no-value-node? (call-arg call 1)))
- (c-assignment "TTreturn_value" (call-arg call 1) port indent))
- (indent-to port indent)
- (display "return(0L);" port))
- (define (generate-return-from-merged-call call start port indent)
- (let ((name *current-merged-procedure*))
- (do ((i start (+ i 1)))
- ((= i (call-arg-count call)))
- (let ((arg (call-arg call i)))
- (if (not (no-value-node? arg))
- (c-assignment (format #f "~A~D_return_value" name (- i start))
- arg port indent))))
- (format port "~%#ifdef USE_DIRECT_THREADING~%")
- (indent-to port indent)
- (format port "goto *~A_return_address;~%#else~%" name)
- (indent-to port indent)
- (format port "goto ~A_return;~%#endif~%" name)))
- (define (really-generate-c-return call start port indent)
- (do ((i (+ start 1) (+ i 1)))
- ((= i (call-arg-count call)))
- (let ((arg (call-arg call i)))
- (if (not (no-value-node? arg))
- (begin
- (indent-to port indent)
- (format port "*TT~D = " (- (- i start) 1))
- (c-value arg port)
- (write-char #\; port)))))
- (let ((result (call-arg call start)))
- (cond
- ((and (not (no-value-node? result))
- (let ((type (get-variable-type
- (reference-variable (call-arg call 0)))))
- (and (not (eq? type type/unit))
- (not (eq? type type/null)))))
- (indent-to port indent)
- (display "return" port)
- (write-char #\space port)
- (c-value result port)
- (display ";" port))
- (else
- (if (call-node? result)
- ;; emit for the side effects
- (begin
- (indent-to port indent)
- (primop-generate-c (call-primop result) result port 0)
- (display ";" port)
- (newline port)))
- (indent-to port indent)
- (display "return" port)
- (display ";" port))))
- (values))
- ;; Allocate
- ;;(define-c-generator allocate #f
- ;; (lambda (call port indent)
- ;; (let ((cont (call-arg call 0))
- ;; (size (call-arg call 1)))
- ;; (c-assign-to-variable (car (lambda-variables cont)) port indent)
- ;; (display "(long) malloc(" port)
- ;; (c-value size port)
- ;; (display "* sizeof(char));" port))))
- (define-c-generator global-ref #t
- (lambda (call port indent)
- (c-value (call-arg call 0) port)))
- (define-c-generator global-set! #f
- (lambda (call port indent)
- (let ((value (call-arg call 2)))
- (if (not (and (literal-node? value)
- (unspecific? (literal-value value))))
- (c-assignment (reference-variable (call-arg call 1))
- value
- port indent)))))
- ;; if (ARG1 OP ARG2) {
- ;; cont1 }
- ;; else {
- ;; cont2 }
- (define-c-generator test #f
- (lambda (call port indent)
- (match (call-args call)
- (#(cont1 cont2 value)
- (generate-c-conditional-prelude port indent)
- (c-value value port)
- (generate-c-conditional-jumps cont1 cont2 port indent)))))
- (define (generate-c-conditional-prelude port indent)
- (indent-to port indent)
- (display "if " port)
- (writec port #\())
- (define (generate-c-conditional-jumps cont1 cont2 port indent)
- (display ") {" port)
- (write-c-block (lambda-body cont1) port (+ indent 2))
- (newline port)
- (indent-to port indent)
- (display "else {" port)
- (write-c-block (lambda-body cont2) port (+ indent 2)))
- (define-c-generator unspecific #t
- (lambda (call port indent)
- (bug "generating code for undefined value ~S" call)))
- (define-c-generator uninitialized-value #t
- (lambda (call port indent)
- (bug "generating code for uninitialized value ~S" call)))
- (define-c-generator null-pointer? #t
- (lambda (call port indent)
- (display "NULL == " port)
- (c-value (call-arg call 0) port)))
- (define-c-generator null-pointer #t
- (lambda (call port indent)
- (display "NULL" port)))
- (define-c-generator eq? #t
- (lambda (call port indent)
- (simple-c-primop "==" call port)))
|