pcs/newpcs/pca.s

271 lines
7.9 KiB
Common Lisp
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; -*- Mode: Lisp -*- Filename: pca.s
; Last Revision: 1-Oct-85 1700ct
;--------------------------------------------------------------------------;
; ;
; TI SCHEME -- PCS Compiler ;
; Copyright 1985 (c) Texas Instruments ;
; ;
; David Bartley ;
; ;
; Closure Analysis and Heap Allocation ;
; ;
;--------------------------------------------------------------------------;
;
; Pass 1
;
; Mark lambda expressions to be closed (LAMBDA-CLOSED?=T) at the point
; of definition whenever any of the following occur:
;
; -- the identifier bound to the lambda expression is used as a
; funarg [p1-id]
;
; -- the lambda expression is itself used as a funarg
; [p1-lambda]
;
; -- the identifier bound to the lambda expression is modified
; by SET! [p1-set!]
;
; -- the expression is a MULAMBDA [p1-lambda]
;
; Mark all identifiers which are bound to closures by LETREC:
;
; -- ID-INIT: the lambda expression the ID was bound to
; (else it is NIL) [p1-lambda]
;
; Pass 2
;
; Determine which variables must be heap-allocated by gathering the
; following facts used later:
;
; -- ID-SET!?: it is modified by a SET! [p2-set!]
;
; -- ID-FREEREF?: it is freely referenced by some function
;
; -- ID-FUNARGSEES?: it is "visible" to a closed function
;
; We do not compute the transitive closure of functions reachable from
; closed functions. Instead, we consider an ID to be funargref'd if
; (1) ID is freely referenced from SOME function AND (2) ID is visible,
; though not necessarily referenced, from a closed function.
;
; An ID will be heap-allocated if it is potentially referenced from a
; funarg (both ID-FREEREF? and ID-FUNARGSEES? set non-nil) and must
; exist at runtime. It exists at runtime if it is modified (ID-SET!?),
; or is initialized to some value other than a lambda expression
; (ID-INIT=NIL), or the lambda expression it is bound to is closed.
;
;--------------------------------------------------------------------------;
(define pcs-closure-analysis
(lambda (exp)
(letrec
;----!
(
(p1-exp
(lambda (x)
(case (car x)
(quote '())
(T (p1-id x))
(lambda (p1-lambda x))
(set! (p1-set! x))
;; (if (p1-args (cdr x))) treat as a primop
;; (begin (p1-args (cdr x))) treat as a primop
(letrec (p1-letrec x))
(else (p1-application x))
)))
(p1-id
(lambda (id)
(close-funarg (id-init id))))
(p1-set!
(lambda (x)
(p1-id (set!-id x))
(p1-exp (set!-exp x))))
(p1-lambda
(lambda (x)
(create-lambda-label x '())
(close-funarg x)
(p1-exp (lambda-body x))))
(p1-letrec
(lambda (x)
(let ((pairs (letrec-pairs x)))
(p1-pairs-1 pairs) ; link up lambda's and id's
(p1-pairs-2 pairs) ; find funargref's to id's
(p1-exp (letrec-body x)))))
(p1-pairs-1
(lambda (pairs)
(when pairs
(let* ((pr (car pairs))
(id (car pr))
(exp (cadr pr)))
(when (eq? (car exp) 'lambda)
(create-lambda-label exp id)
(set-id-init id exp)
(when (negative? (lambda-nargs exp))
(close-funarg exp)))
(p1-pairs-1 (cdr pairs))))))
(p1-pairs-2
(lambda (pairs)
(when pairs
(let* ((pr (car pairs))
(id (car pr))
(exp (cadr pr)))
(if (eq? (car exp) 'lambda)
(p1-exp (lambda-body exp))
(p1-exp exp))
(p1-pairs-2 (cdr pairs))))))
(p1-application
(lambda (x)
(let ((fn (car x))
(args (cdr x)))
(p1-args args)
(cond ((or (atom? fn)
(eq? (car fn) 'T))
'())
((eq? (car fn) 'LAMBDA)
(p1-exp (lambda-body fn)))
(else
(p1-exp fn))))))
(p1-args
(lambda (args)
(when args
(p1-exp (car args))
(p1-args (cdr args)))))
(close-funarg
(lambda (fn)
(when fn
(set-lambda-closed? fn #!true))))
(create-lambda-label
(lambda (fn id)
(set-lambda-label fn
(if (null? id)
(pcs-make-label 'lambda)
(cons (id-number id)(id-name id))))))
;; ------ pass 2 -------
(p2-exp
(lambda (x env locals)
(case (car x)
(quote '())
(T (p2-id x env locals))
(lambda (p2-lambda x env locals))
(set! (p2-set! x env locals))
;; (if (p2-args (cdr x) env locals)) treat as a primop
;; (begin (p2-args (cdr x) env locals)) treat as a primop
(letrec (p2-letrec x env locals))
(else (p2-application x env locals))
)))
(p2-id
(lambda (id env locals)
(when (not (memq id locals))
(set-id-freeref? id #!true))))
(p2-set!
(lambda (x env locals)
(let ((id (set!-id x))
(val (set!-exp x)))
(set-id-set!? id #!true)
(p2-id id env locals)
(p2-exp val env locals))))
(p2-lambda
(lambda (x env locals)
(let ((bvl (lambda-bvl x)))
(when (lambda-closed? x)
(do ((env env (cdr env)))
((null? env))
(do ((rib (car env)(cdr rib)))
((null? rib))
(set-id-funargsees? (car rib) #!true))))
(p2-exp (lambda-body x)
(cons bvl env)
bvl))))
(p2-letrec
(lambda (x env locals)
(let* ((pairs (letrec-pairs x))
(bvl (mapcar car pairs))
(body (letrec-body x))
(env (cons bvl env))
(locals (append bvl locals)))
(p2-pairs pairs env locals)
(p2-exp body env locals))))
(p2-pairs
(lambda (pairs env locals)
(when pairs
(p2-exp (cadr (car pairs)) env locals)
(p2-pairs (cdr pairs) env locals))))
;; p2-application must process IDs in function position
;; because they may need to be heap allocated; e.g:
;; (lambda (f)
;; (lambda (x) ; 'f' must be heap allocated
;; (f x))) ; 'f' appears only in function position
(p2-application
(lambda (x env locals)
(let ((fn (car x)))
(if (or (eq? fn 'THE-ENVIRONMENT)
(eq? fn '%MAKE-HASHED-ENVIRONMENT))
(smash-the-environment #!true env)
(let ((args (cdr x)))
(when (eq? fn '%CALL/CC)
(smash-the-environment #!false env))
(p2-args args env locals)
(when (pair? fn)
(if (eq? (car fn) 'LAMBDA)
(p2-exp (lambda-body fn)
(cons (lambda-bvl fn) env)
(lambda-bvl fn))
(p2-exp fn env locals))))))))
;; (THE-ENVIRONMENT) requires all visible lexical variables
;; to be heap-allocated
(smash-the-environment
(lambda (smash-all? env)
(when env
(do ((rib (car env) ; CDR down this rib
(cdr rib)))
((null? rib))
(let ((id (car rib))
(yes #!true))
(set-id-funargsees? id yes)
(set-id-freeref? id yes)
(when smash-all?
(set-id-set!? id yes)
(close-funarg (id-init id)))))
(smash-the-environment smash-all? (cdr env))))) ; get the next rib
(p2-args
(lambda (args env locals)
(when args
(p2-exp (car args) env locals)
(p2-args (cdr args) env locals))))
;----!
)
(begin
(p1-exp exp)
(p2-exp exp '() '())
'())))) ; executed for effect only
;==================================================================