+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file func
+ "$Header: func.l,v 1.14 87/12/15 17:02:38 sklower Exp $")
+
+;;; ---- f u n c function compilation
+;;;
+;;; -[Wed Aug 24 10:51:11 1983 by layer]-
+
+; cm-ncons :: macro out an ncons expression
+;
+(defun cm-ncons nil
+ `(cons ,(cadr v-form) nil))
+
+; cc-not :: compile a "not" or "null" expression
+;
+(defun cc-not nil
+ (makecomment '(beginning not))
+ (if (null g-loc)
+ then (let ((g-cc (cons (cdr g-cc) (car g-cc)))
+ (g-ret nil))
+ (d-exp (cadr v-form)))
+ else (let ((finlab (d-genlab))
+ (finlab2 (d-genlab))
+ (g-ret nil))
+ ; eval arg and jump to finlab if nil
+ (let ((g-cc (cons finlab nil))
+ g-loc)
+ (d-exp (cadr v-form)))
+ ; didn't jump, answer must be t
+ (d-move 'T g-loc)
+ (if (car g-cc)
+ then (e-goto (car g-cc))
+ else (e-goto finlab2))
+ (e-label finlab)
+ ; answer is nil
+ (d-move 'Nil g-loc)
+ (if (cdr g-cc) then (e-goto (cdr g-cc)))
+ (e-label finlab2))))
+
+;--- cc-numberp :: check for numberness
+;
+(defun cc-numberp nil
+ (d-typecmplx (cadr v-form)
+ '#.(immed-const (plus 1_2 1_4 1_9))))
+
+;--- cc-or :: compile an "or" expression
+;
+(defun cc-or nil
+ (let ((finlab (d-genlab))
+ (finlab2)
+ (exps (if (cdr v-form) thenret else '(nil)))) ; (or) => nil
+ (if (null (car g-cc))
+ then (d-exp (do ((g-cc (cons finlab nil))
+ (g-loc (if g-loc then 'reg))
+ (g-ret nil)
+ (ll exps (cdr ll)))
+ ((null (cdr ll)) (car ll))
+ (d-exp (car ll))))
+ (if g-loc
+ then (setq finlab2 (d-genlab))
+ (e-goto finlab2)
+ (e-label finlab)
+ (d-move 'reg g-loc)
+ (e-label finlab2)
+ else (e-label finlab))
+ else (if (null g-loc) then (setq finlab (car g-cc)))
+ (d-exp (do ((g-cc (cons finlab nil))
+ (g-loc (if g-loc then 'reg))
+ (g-ret nil)
+ (ll exps (cdr ll)))
+ ((null (cdr ll)) (car ll))
+ (d-exp (car ll))))
+ (if g-loc
+ then (setq finlab2 (d-genlab))
+ (e-goto finlab2)
+ (e-label finlab)
+ (d-move 'reg g-loc)
+ (e-goto (car g-cc)) ; result is t
+ (e-label finlab2)))
+ (d-clearreg))) ;we are not sure of the state due to possible branches.
+
+;--- c-prog :: compile a "prog" expression
+;
+; for interlisp compatibility, we allow the formal variable list to
+; contain objects of this form (vrbl init) which gives the initial value
+; for that variable (instead of nil)
+;
+(defun c-prog nil
+ (let ((g-decls g-decls))
+ (let (g-loc g-cc seeninit initf
+ (p-rettrue g-ret) (g-ret nil)
+ ((spcs locs initsv . initsn) (d-classify (cadr v-form))))
+
+ (e-pushnil (length locs)) ; locals initially nil
+ (d-bindprg spcs locs) ; bind locs and specs
+
+ (cond (initsv (d-pushargs initsv)
+ (mapc '(lambda (x)
+ (d-move 'unstack (d-loc x))
+ (decr g-loccnt)
+ (unpush g-locs))
+ (nreverse initsn))))
+
+ ; determine all possible labels
+ (do ((ll (cddr v-form) (cdr ll))
+ (labs nil))
+ ((null ll) (setq g-labs `((,(d-genlab) ,@labs)
+ ,@g-labs)))
+ (if (and (car ll) (symbolp (car ll)))
+ then (if (assq (car ll) labs)
+ then (comp-err "label is mulitiply defined " (car ll))
+ else (setq labs (cons (cons (car ll) (d-genlab))
+ labs)))))
+
+ ; compile each form which is not a label
+ (d-clearreg) ; unknown state after binding
+ (do ((ll (cddr v-form) (cdr ll)))
+ ((null ll))
+ (if (or (null (car ll)) (not (symbolp (car ll))))
+ then (d-exp (car ll))
+ else (e-label (cdr (assq (car ll) (cdar g-labs))))
+ (d-clearreg)))) ; dont know state after label
+
+ ; result is nil if fall out and care about value
+ (if (or g-cc g-loc) then (d-move 'Nil 'reg))
+
+ (e-label (caar g-labs)) ; return to label
+ (setq g-labs (cdr g-labs))
+ (d-unbind))) ; unbind our frame
+
+;--- d-bindprg :: do binding for a prog expression
+; - spcs : list of special variables
+; - locs : list of local variables
+; - specinit : init values for specs (or nil if all are nil)
+;
+(defun d-bindprg (spcs locs)
+ ; place the local vrbls and prog frame entry on the stack
+ (setq g-loccnt (+ g-loccnt (length locs))
+ g-locs (nconc locs `((prog . ,(length spcs)) ,@g-locs)))
+
+ ; now bind the specials, if any, to nil
+ (if spcs then (e-setupbind)
+ (mapc '(lambda (vrb)
+ (e-shallowbind vrb 'Nil))
+ spcs)
+ (e-unsetupbind)))
+
+;--- d-unbind :: remove one frame from g-locs
+;
+(defun d-unbind nil
+ (do ((count 0 (1+ count)))
+ ((dtpr (car g-locs))
+ (if (not (zerop (cdar g-locs)))
+ then (e-unshallowbind (cdar g-locs)))
+ (cond ((not (zerop count))
+ (e-dropnp count)
+
+ (setq g-loccnt (- g-loccnt count))))
+ (setq g-locs (cdr g-locs)))
+ (setq g-locs (cdr g-locs))))
+
+;--- d-classify :: seperate variable list into special and non-special
+; - lst : list of variables
+; returns ( xxx yyy zzz . aaa)
+; where xxx is the list of special variables and
+; yyy is the list of local variables
+; zzz are the non nil initial values for prog variables
+; aaa are the names corresponding to the values in zzz
+;
+(defun d-classify (lst)
+ (do ((ll lst (cdr ll))
+ (locs) (spcs) (init) (initsv) (initsn)
+ (name))
+ ((null ll) (cons spcs (cons locs (cons initsv initsn))))
+ (if (atom (car ll))
+ then (setq name (car ll))
+ else (setq name (caar ll))
+ (push name initsn)
+ (push (cadar ll) initsv))
+ (if (d-specialp name)
+ then (push name spcs)
+ else (push name locs))))
+
+; cm-progn :: compile a "progn" expression
+;
+(defun cm-progn nil
+ `((lambda nil ,@(cdr v-form))))
+
+; cm-prog1 :: compile a "prog1" expression
+;
+(defun cm-prog1 nil
+ (let ((gl (d-genlab)))
+ `((lambda (,gl)
+ ,@(cddr v-form)
+ ,gl)
+ ,(cadr v-form))))
+
+; cm-prog2 :: compile a "prog2" expression
+;
+(defun cm-prog2 nil
+ (let ((gl (d-genlab)))
+ `((lambda (,gl)
+ ,(cadr v-form)
+ (setq ,gl ,(caddr v-form))
+ ,@(cdddr v-form)
+ ,gl)
+ nil)))
+
+;--- cm-progv :: compile a progv form
+; a progv form looks like (progv 'l-vars 'l-inits 'g-exp1 ... 'g-expn)
+; l-vars should be a list of variables, l-inits a list of initial forms
+; We cannot permit returns and go-s through this form.
+;
+; we stack a (progv . 0) form on g-locs so that return and go will know
+; not to try to go through this form.
+;
+(defun c-progv nil
+ (let ((gl (d-genlab))
+ (g-labs (cons nil g-labs))
+ (g-locs (cons '(progv . 0) g-locs)))
+ (d-exp `((lambda (,gl)
+ (prog1 (progn ,@(cdddr v-form))
+ (internal-unbind-vars ,gl)))
+ (internal-bind-vars ,(cadr v-form) ,(caddr v-form))))))
+
+(defun c-internal-bind-vars nil
+ (let ((g-locs g-locs)
+ (g-loccnt g-loccnt))
+ (d-pushargs (cdr v-form))
+ (d-calldirect '_Ibindvars (length (cdr v-form)))))
+
+(defun c-internal-unbind-vars nil
+ (let ((g-locs g-locs)
+ (g-loccnt g-loccnt))
+ (d-pushargs (cdr v-form))
+ (d-calldirect '_Iunbindvars (length (cdr v-form)))))
+
+;--- cc-quote : compile a "quote" expression
+;
+; if we are just looking to set the ; cc, we just make sure
+; we set the cc depending on whether the expression quoted is
+; nil or not.
+(defun cc-quote nil
+ (let ((arg (cadr v-form))
+ argloc)
+ (if (null g-loc)
+ then (if (and (null arg) (cdr g-cc))
+ then (e-goto (cdr g-cc))
+ elseif (and arg (car g-cc))
+ then (e-goto (car g-cc))
+ elseif (null g-cc)
+ then (comp-warn "losing the value of this expression "
+ (or v-form)))
+ else (d-move (d-loclit arg nil) g-loc)
+ (d-handlecc))))
+
+;--- c-setarg :: set a lexpr's arg
+; form is (setarg index value)
+;
+(defun c-setarg nil
+ (if (not (eq 'lexpr g-ftype))
+ then (comp-err "setarg only allowed in lexprs"))
+ (if (and fl-inter (eq (length (cdr v-form)) 3)) ; interlisp setarg
+ then (if (not (eq (cadr v-form) (car g-args)))
+ then (comp-err "setarg: can only compile local setargs "
+ v-form)
+ else (setq v-form (cdr v-form))))
+ ; compile index into fixnum-reg, was (d-pushargs (list (cadr v-form)))
+ (let ((g-cc) (g-ret)
+ (g-loc '#.fixnum-reg))
+ (d-exp (cadr v-form)))
+ (let ((g-loc 'reg)
+ (g-cc nil)
+ (g-ret nil))
+ (d-exp (caddr v-form)))
+ #+(or for-vax for-tahoe)
+ (progn
+ (e-sub3 `(* -4 #.olbot-reg) '(0 #.fixnum-reg) '#.fixnum-reg)
+ (e-move 'r0 '(-8 #.olbot-reg #.fixnum-reg)))
+ #+for-68k
+ (progn
+ (e-sub `(-4 #.olbot-reg) '#.fixnum-reg)
+ (e-write3 'lea '(% -8 #.olbot-reg #.fixnum-reg) 'a5)
+ (e-move 'd0 '(0 a5))))
+
+;--- cc-stringp :: check for string ness
+;
+(defun cc-stringp nil
+ (d-typesimp (cadr v-form) #.(immed-const 0)))
+
+;--- cc-symbolp :: check for symbolness
+;
+(defun cc-symbolp nil
+ (d-typesimp (cadr v-form) #.(immed-const 1)))
+
+;--- c-return :: compile a "return" statement
+;
+(defun c-return nil
+ ; value is always put in reg
+ (let ((g-loc 'reg)
+ g-cc
+ g-ret)
+ (d-exp (cadr v-form)))
+
+ ; if we are doing a non local return, compute number of specials to unbind
+ ; and locals to pop
+ (if (car g-labs)
+ then (e-goto (caar g-labs))
+ else (do ((loccnt 0) ;; locals
+ (speccnt 0) ;; special
+ (catcherrset 0) ;; catch/errset frames
+ (ll g-labs (cdr ll))
+ (locs g-locs))
+ ((null ll) (comp-err "return used not within a prog or do"))
+ (if (car ll)
+ then (comp-note g-fname ": non local return used ")
+ ; unbind down to but not including
+ ; this frame.
+ (if (greaterp loccnt 0)
+ then (e-pop loccnt))
+ (if (greaterp speccnt 0)
+ then (e-unshallowbind speccnt))
+ (if (greaterp catcherrset 0)
+ then (comp-note
+ g-fname
+ ": return through a catch or errset"
+ v-form)
+ (do ((i 0 (1+ i)))
+ ((=& catcherrset i))
+ (d-popframe)))
+ (e-goto (caar ll))
+ (return)
+ else ; determine number of locals and special on
+ ; stack for this frame, add to running
+ ; totals
+ (do ()
+ ((dtpr (car locs))
+ (if (eq 'catcherrset (caar locs)) ; catchframe
+ then (incr catcherrset)
+ elseif (eq 'progv (caar locs))
+ then (comp-err "Attempt to 'return' through a progv"))
+ (setq speccnt (+ speccnt (cdar locs))
+ locs (cdr locs)))
+ (incr loccnt)
+ (setq locs (cdr locs)))))))
+
+; c-rplaca :: compile a "rplaca" expression
+;
+#+(or for-vax for-tahoe)
+(defun c-rplaca nil
+ (let ((ssimp (d-simple (caddr v-form)))
+ (g-ret nil))
+ (let ((g-loc (if ssimp then 'reg else 'stack))
+ (g-cc nil))
+ (d-exp (cadr v-form)))
+ (if (null ssimp)
+ then (push nil g-locs)
+ (incr g-loccnt)
+ (let ((g-loc 'r1)
+ (g-cc nil))
+ (d-exp (caddr v-form)))
+ (d-move 'unstack 'reg)
+ (unpush g-locs)
+ (decr g-loccnt)
+ (e-move 'r1 '(4 r0))
+ else (e-move (e-cvt ssimp) '(4 r0)))
+ (d-clearreg))) ; cant tell what we are clobbering
+
+#+for-68k
+(defun c-rplaca nil
+ (let ((ssimp (d-simple (caddr v-form)))
+ (g-ret nil))
+ (makecomment `(c-rplaca starting :: v-form = ,v-form))
+ (let ((g-loc (if ssimp then 'areg else 'stack))
+ (g-cc nil))
+ (d-exp (cadr v-form)))
+ (if (null ssimp)
+ then (push nil g-locs)
+ (incr g-loccnt)
+ (let ((g-loc 'd1)
+ (g-cc nil))
+ (d-exp (caddr v-form)))
+ (d-move 'unstack 'areg)
+ (unpush g-locs)
+ (decr g-loccnt)
+ (e-move 'd1 '(4 a0))
+ else (e-move (e-cvt ssimp) '(4 a0)))
+ (e-move 'a0 'd0)
+ (d-clearreg)
+ (makecomment `(c-rplaca done))))
+
+; c-rplacd :: compile a "rplacd" expression
+;
+#+(or for-vax for-tahoe)
+(defun c-rplacd nil
+ (let ((ssimp (d-simple (caddr v-form)))
+ (g-ret nil))
+ (let ((g-loc (if ssimp then 'reg else 'stack))
+ (g-cc nil))
+ (d-exp (cadr v-form)))
+ (if (null ssimp)
+ then (push nil g-locs)
+ (incr g-loccnt)
+ (let ((g-loc 'r1)
+ (g-cc nil))
+ (d-exp (caddr v-form)))
+ (d-move 'unstack 'reg)
+ (unpush g-locs)
+ (decr g-loccnt)
+ (e-move 'r1 '(0 r0))
+ else (e-move (e-cvt ssimp) '(0 r0)))
+ (d-clearreg)))
+
+#+for-68k
+(defun c-rplacd nil
+ (let ((ssimp (d-simple (caddr v-form)))
+ (g-ret nil))
+ (makecomment `(c-rplacd starting :: v-form = ,v-form))
+ (let ((g-loc (if ssimp then 'areg else 'stack))
+ (g-cc nil))
+ (d-exp (cadr v-form)))
+ (if (null ssimp)
+ then (push nil g-locs)
+ (incr g-loccnt)
+ (let ((g-loc 'd1)
+ (g-cc nil))
+ (d-exp (caddr v-form)))
+ (d-move 'unstack 'areg)
+ (unpush g-locs)
+ (decr g-loccnt)
+ (e-move 'd1 '(0 a0))
+ else (e-move (e-cvt ssimp) '(0 a0)))
+ (e-move 'a0 'd0)
+ (d-clearreg)
+ (makecomment `(d-rplacd done))))
+
+;--- cc-setq :: compile a "setq" expression
+;
+(defun cc-setq nil
+ (prog nil
+ (let (tmp tmp2)
+ (if (null (cdr v-form))
+ then (d-exp nil) ; (setq)
+ (return)
+ elseif (oddp (length (cdr v-form)))
+ then (comp-err "wrong number of args to setq "
+ (or v-form))
+ elseif (cdddr v-form) ; if multiple setq's
+ then (do ((ll (cdr v-form) (cddr ll))
+ (g-loc)
+ (g-cc nil))
+ ((null (cddr ll)) (setq tmp ll))
+ (setq g-loc (d-locv (car ll)))
+ (d-exp (cadr ll))
+ (d-clearuse (car ll)))
+ else (setq tmp (cdr v-form)))
+
+ ; do final setq
+ (let ((g-loc (d-locv (car tmp)))
+ (g-cc (if g-loc then nil else g-cc))
+ (g-ret nil))
+ (d-exp (cadr tmp))
+ (d-clearuse (car tmp)))
+ (if g-loc
+ then (d-move (setq tmp2 (d-locv (car tmp))) g-loc)
+ (if g-cc
+ then #+for-68k (d-cmpnil tmp2)
+ (d-handlecc))))))
+
+; cc-typep :: compile a "typep" expression
+;
+; this returns the type of the expression, it is always non nil
+;
+#+(or for-vax for-tahoe)
+(defun cc-typep nil
+ (let ((argloc (d-simple (cadr v-form)))
+ (g-ret))
+ (if (null argloc)
+ then (let ((g-loc 'reg) g-cc)
+ (d-exp (cadr v-form)))
+ (setq argloc 'reg))
+ (if g-loc
+ then #+for-vax (e-write4 'ashl '($ -9) (e-cvt argloc) 'r0)
+ #+for-tahoe (e-write4 'shar '($ 9) (e-cvt argloc) 'r0)
+ (e-write3 'cvtbl "_typetable+1[r0]" 'r0)
+ (e-move "_tynames+4[r0]" 'r0)
+ (e-move '(0 r0) (e-cvt g-loc)))
+ (if (car g-cc) then (e-goto (car g-cc)))))
+
+#+for-68k
+(defun cc-typep nil
+ (let ((argloc (d-simple (cadr v-form)))
+ (g-ret))
+ (if (null argloc)
+ then (let ((g-loc 'reg) g-cc)
+ (d-exp (cadr v-form)))
+ (setq argloc 'reg))
+ (if g-loc
+ then (e-move (e-cvt argloc) 'd0)
+ (e-sub '#.nil-reg 'd0)
+ (e-write3 'moveq '($ 9) 'd1)
+ (e-write3 'asrl 'd1 'd0)
+ (e-write3 'lea '"_typetable+1" 'a5)
+ (e-add 'd0 'a5)
+ (e-write3 'movb '(0 a5) 'd0)
+ (e-write2 'extw 'd0)
+ (e-write2 'extl 'd0)
+ (e-write3 'asll '($ 2) 'd0)
+ (e-write3 'lea "_tynames+4" 'a5)
+ (e-add 'd0 'a5)
+ (e-move '(0 a5) 'a5)
+ (e-move '(0 a5) (e-cvt g-loc)))
+ (if (car g-cc) then (e-goto (car g-cc)))))
+
+; cm-symeval :: compile a symeval expression.
+; the symbol cell in franz lisp is just the cdr.
+;
+(defun cm-symeval nil
+ `(cdr ,(cadr v-form)))
+
+; c-*throw :: compile a "*throw" expression
+;
+; the form of *throw is (*throw 'tag 'val) .
+; we calculate and stack the value of tag, then calculate val
+; we call Idothrow to do the actual work, and only return if the
+; throw failed.
+;
+(defun c-*throw nil
+ (let ((arg2loc (d-simple (caddr v-form)))
+ g-cc
+ g-ret
+ arg1loc)
+ ; put on the C runtime stack value to throw, and
+ ; tag to throw to.
+ (if arg2loc
+ then (if (setq arg1loc (d-simple (cadr v-form)))
+ then (C-push (e-cvt arg2loc))
+ (C-push (e-cvt arg1loc))
+ else (let ((g-loc 'reg))
+ (d-exp (cadr v-form)) ; calc tag
+ (C-push (e-cvt arg2loc))
+ (C-push (e-cvt 'reg))))
+ else (let ((g-loc 'stack))
+ (d-exp (cadr v-form)) ; calc tag to stack
+ (push nil g-locs)
+ (incr g-loccnt)
+ (setq g-loc 'reg)
+ (d-exp (caddr v-form)) ; calc value into reg
+ (C-push (e-cvt 'reg))
+ (C-push (e-cvt 'unstack))
+ (unpush g-locs)
+ (decr g-loccnt)))
+ ; now push the type of non local go we are doing, in this case
+ ; it is a C_THROW
+ (C-push '($ #.C_THROW))
+ #+for-vax
+ (e-write3 'calls '$3 '_Inonlocalgo)
+ #+for-tahoe
+ (e-write3 'callf '$16 '_Inonlocalgo)
+ #+for-68k
+ (e-quick-call '_Inonlocalgo)))
+
+;--- cm-zerop :: convert zerop to a quick test
+; zerop is only allowed on fixnum and flonum arguments. In both cases,
+; if the value of the first 32 bits is zero, then we have a zero.
+; thus we can define it as a macro:
+#+(or for-vax for-tahoe)
+(defun cm-zerop nil
+ (cond ((atom (cadr v-form))
+ `(and (null (cdr ,(cadr v-form))) (not (bigp ,(cadr v-form)))))
+ (t (let ((gnsy (gensym)))
+ `((lambda (,gnsy)
+ (and (null (cdr ,gnsy))
+ (not (bigp ,gnsy))))
+ ,(cadr v-form))))))
+
+#+for-68k
+(defun cm-zerop nil
+ (cond ((atom (cadr v-form))
+ `(and (=& 0 ,(cadr v-form)) ;was (cdr ,(cadr v-form))
+ (not (bigp ,(cadr v-form)))))
+ (t (let ((gnsy (gensym)))
+ `((lambda (,gnsy)
+ (and (=& 0 ,gnsy) ;was (cdr ,gnsy)
+ (not (bigp ,gnsy))))
+ ,(cadr v-form))))))