102 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Scheme
		
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Scheme
		
	
	
	
; Copyright (c) 1994 by Richard Kelsey.  See file COPYING.
 | 
						|
 | 
						|
; Protocol specifications are lists of representations.
 | 
						|
 | 
						|
(set-compiler-parameter! 'lambda-node-type
 | 
						|
			 (lambda (node)
 | 
						|
			   (let ((vars (lambda-variables node)))
 | 
						|
			     (case (lambda-type node)
 | 
						|
			       ((cont jump)
 | 
						|
				(make-arrow-type (map variable-type vars)
 | 
						|
						 type/unknown)) ; what to do?
 | 
						|
			       ((proc known-proc)
 | 
						|
				(make-arrow-type (map variable-type (cdr vars))
 | 
						|
						 (variable-type (car vars))))
 | 
						|
			       (else
 | 
						|
				(error "unknown type of lambda node ~S" node))))))
 | 
						|
 | 
						|
(set-compiler-parameter! 'true-value #t)
 | 
						|
(set-compiler-parameter! 'false-value #f)
 | 
						|
 | 
						|
; Tail-calls with goto-protocols cause the lambda node to be annotated
 | 
						|
; as tail-called.
 | 
						|
; Calls with a tuple argument need their argument spread out into separate
 | 
						|
; variables.
 | 
						|
 | 
						|
(define (determine-lambda-protocol lambda-node call-refs)
 | 
						|
  (set-lambda-protocol! lambda-node #f)
 | 
						|
  (for-each (lambda (r)
 | 
						|
	      (let ((call (node-parent r)))
 | 
						|
		(cond ((goto-protocol? (literal-value (call-arg call 2)))
 | 
						|
		       (if (not (calls-this-primop? call 'unknown-tail-call))
 | 
						|
			   (bug "GOTO marker in non-tail-all ~S" call))
 | 
						|
		       (set-lambda-protocol! lambda-node 'tail-called)))
 | 
						|
		(unknown-call->known-call call)))
 | 
						|
	    call-refs)
 | 
						|
  (set-calls-known?! lambda-node))
 | 
						|
 | 
						|
(set-compiler-parameter! 'determine-lambda-protocol determine-lambda-protocol)
 | 
						|
 | 
						|
(define (unknown-call->known-call call)
 | 
						|
  (remove-call-arg call 2)  ; remove the protocol
 | 
						|
  (set-call-primop! call
 | 
						|
		    (case (primop-id (call-primop call))
 | 
						|
		      ((unknown-call)
 | 
						|
		       (get-primop (enum primop call)))
 | 
						|
		      ((unknown-tail-call)
 | 
						|
		       (get-primop (enum primop tail-call)))
 | 
						|
		      (else
 | 
						|
		       (bug "odd primop in call ~S" call)))))
 | 
						|
 | 
						|
; CONT is the continuation passed to PROCS.
 | 
						|
 | 
						|
(define (determine-continuation-protocol cont procs)
 | 
						|
  (for-each (lambda (proc)
 | 
						|
	      (let ((cont-var (car (lambda-variables proc))))
 | 
						|
		(walk-refs-safely
 | 
						|
		 (lambda (ref)
 | 
						|
		   (let ((call (node-parent ref)))
 | 
						|
		     (unknown-return->known-return call cont-var cont)))
 | 
						|
		 cont-var)))
 | 
						|
	    procs))
 | 
						|
 | 
						|
(set-compiler-parameter! 'determine-continuation-protocol
 | 
						|
			 determine-continuation-protocol)
 | 
						|
 | 
						|
; If the return is actually a tail-recursive call we change it to
 | 
						|
; a non-tail-recursive one (since we have identified the continuation)
 | 
						|
; and insert the appropriate continuation.
 | 
						|
 | 
						|
(define (unknown-return->known-return call cont-var cont)
 | 
						|
  (case (primop-id (call-primop call))
 | 
						|
    ((unknown-return)
 | 
						|
     (set-call-primop! call (get-primop (enum primop return))))
 | 
						|
    ((unknown-tail-call tail-call)
 | 
						|
     (let* ((vars (map copy-variable (lambda-variables cont)))
 | 
						|
	    (args (map make-reference-node vars)))
 | 
						|
       (let-nodes ((cont vars (return 0 (* cont-var) . args)))
 | 
						|
	 (replace (call-arg call 0) cont)
 | 
						|
	 (set-call-primop! call
 | 
						|
			   (if (calls-this-primop? call 'tail-call)
 | 
						|
			       (get-primop (enum primop call))
 | 
						|
			       (get-primop (enum primop unknown-call))))
 | 
						|
	 (set-call-exits! call 1)
 | 
						|
	 (if (and (calls-this-primop? call 'unknown-call)
 | 
						|
		  (goto-protocol? (literal-value (call-arg call 2))))
 | 
						|
	     (set-literal-value! (call-arg call 2) #f)))))
 | 
						|
    (else
 | 
						|
     (bug "odd return primop ~S" (call-primop call)))))
 | 
						|
 | 
						|
(define normal-protocol #f)
 | 
						|
(define goto-protocol 'goto)
 | 
						|
 | 
						|
(define (goto-protocol? x)
 | 
						|
  (eq? x goto-protocol))
 | 
						|
 | 
						|
(set-compiler-parameter! 'lookup-primop get-prescheme-primop)
 | 
						|
 | 
						|
(set-compiler-parameter! 'type/unknown type/unknown)
 | 
						|
 | 
						|
(set-compiler-parameter! 'type-eq? type-eq?)
 | 
						|
 |