home *** CD-ROM | disk | FTP | other *** search
- (include-if (null (get 'chead 'version)) "../chead.l")
- (Liszt-file fixnum
- "$Header: /usr/src/local/franz/liszt/RCS/fixnum.l,v 1.16 88/04/26 11:50:18 sklower Exp $")
-
- ;;; ---- f i x n u m fixnum compilation
- ;;;
- ;;; -[Fri Aug 26 14:07:53 1983 by layer]-
-
- ; There are a few functions in lisp which are only permitted to take
- ; fixnum operands and produce fixnum results. The compiler recognizes
- ; these functions and open codes them.
- ;
-
- ;--- d-fixnumexp :: compute a fixnum from an expression
- ; x - a lisp expression which must return a fixnum
- ;
- ; This is an almost equivalent to d-exp, except that
- ; 1] it will do clever things if the expression can be open coded in a
- ; fixnum way.
- ; 2] the result must be a fixnum, and is left in r5 unboxed.
- ;
- (defun d-fixnumexp (x)
- (d-fixnumcode (d-fixexpand x)))
-
-
- ;--- c-fixnumop :: compute a fixnum result
- ; This is the extry point into this code from d-exp. The form to evaluate
- ; is in v-form. The only way we could get here is if the car of v-form
- ; is a function which we've stated is a fixnum returning function.
- ;
- (defun c-fixnumop nil
- (d-fixnumexp v-form)
- (d-fixnumbox))
-
- ;--- d-fixnumbox :: rebox a fixnum in r5
- ;
- #+(or for-vax for-tahoe)
- (defun d-fixnumbox ()
- (let (x)
- (e-write3 'moval (concat "*$5120[" '#.fixnum-reg "]") 'r0)
- (e-sub3 '($ 1024) '#.fixnum-reg 'r1)
- (e-write2 'blssu (setq x (d-genlab)))
- (e-call-qnewint)
- (e-writel x)
- (d-clearreg)))
-
- #+for-68k
- (defun d-fixnumbox ()
- (let (x)
- (d-regused '#.fixnum-reg)
- (e-move '#.fixnum-reg 'd0)
- (e-write3 'asll '($ 2) 'd0)
- ; add onto the base of the fixnums
- (e-add (e-cvt '(fixnum 0)) 'd0)
- (e-move '#.fixnum-reg 'd1)
- (e-sub '($ 1024) 'd1)
- (e-write2 'jcs (setq x (d-genlab))) ;branch carry set
- (e-call-qnewint)
- (e-writel x)
- (d-clearreg)))
-
- ;--- d-fixexpand :: pass over a fixnum expression doing local optimizations
- ;
- ; This code gets the first look at the operands of a fixnum expression.
- ; It handles the strange cases, like (+) or (/ 3), and it also insures
- ; that constants are folded (or collapsed as we call it here).
- ;
- ; things to watch out for:
- ; (+ x y z) we can fold x,y,z , likewise in the case of *
- ; (- x y z) we can only fold y and z since they are negated but x is not,
- ; likewise for /
- (defun d-fixexpand (x)
- (prog nil
- (setq x (d-macroexpand x))
- loop
- (if (and (dtpr x) (symbolp (car x)) (get (car x) 'fixop))
- then (if (memq (car x) '(+ *))
- then (setq x (cons (car x)
- (d-collapse (cdr x) (car x))))
- else (setq x
- (cons (car x)
- (cons (cadr x)
- (d-collapse (cddr x) (car x))))))
- (if (null (cdr x))
- then ; (- or +) => 0 (* or /) => 1
- (setq x
- (cdr (assq (car x)
- '((+ . 0) (- . 0)
- (* . 1) (/ . 1)))))
- (go loop)
- elseif (null (cddr x)) then
- ; (+ n) => n, (- n) => (- 0 n), (* n) => n,
- ; (/ n) => (/ 1 n)
- (setq x
- (if (memq (car x) '(* +))
- then (cadr x)
- elseif (eq (car x) '-)
- then `(- 0 ,(cadr x))
- elseif (eq (car x) '/)
- then `(/ 1 ,(cadr x))
- else (comp-err
- "Internal fixexpand error ")))
- (go loop)))
- (return x)))
-
- ;--- d-toplevmacroexpand :: expand top level form if macro
- ; a singe level of macro expansion is done. this is a nice general
- ; routine and should be used by d-exp.
- ;**** out of date **** will be removed soon
- (defun d-toplevmacroexpand (x)
- (let ((fnbnd (and (dtpr x) (symbolp (car x)) (getd (car x)))))
- (if (and fnbnd (or (and (bcdp fnbnd) (eq (getdisc fnbnd) 'macro))
- (and (dtpr fnbnd) (eq (car fnbnd) 'macro))))
- then (d-toplevmacroexpand (apply fnbnd x))
- else x)))
-
-
- ;--- d-collapse :: collapse (fold) constants
- ;
- ; this is used to reduce the number of operations. since we know that
- ; fixnum operations are commutative.
- ;
- (defun d-collapse (form op)
- (let (const res conlist)
- ; generate list of constants (conlist) and non constants (res)
- (do ((xx form (cdr xx)))
- ((null xx))
- (if (numberp (car xx))
- then (if (fixp (car xx))
- then (setq conlist (cons (car xx) conlist))
- else (comp-err "Illegal operand in fixnum op "
- (car xx)))
- else (setq res (cons (car xx) res))))
-
- ; if no constants found thats ok, but if we found some,
- ; then collapse and return the form with the collapsed constant
- ; at the end.
-
- (if (null conlist)
- then form ; no change
- else (setq res (nreverse
- (cons (apply (cond ((or (eq op '/) (eq op '*)) 'times)
- (t 'plus))
- (cons (cond ((or (eq op '/) (eq op '*)) 1)
- (t 0))
- conlist))
- res))))))
-
-
- ;---- d-fixnumcode :: emit code for prescanned fixnum expression
- ; expr - a expression which should return an unboxed fixnum value
- ; in r5.
- ; This function checks if the expression is indeed a guaranteed fixnum
- ; arithmetic expression, and if so , generates code for the operation.
- ; If the expression is not a fixnum operation, then a normal evaluation
- ; of the cdr of the expression is done, which will grab the fixnum value
- ; and put it in r5.
- ;
- #+(or for-vax for-tahoe)
- (defun d-fixnumcode (expr)
- (let ((operator (and (dtpr expr)
- (symbolp (car expr))
- (get (car expr) 'fixop)))
- (g-ret nil)
- tmp)
- ; the existance of a fixop property on a function says that it is a
- ; special fixnum only operation.
- (if (null operator)
- then (let ((g-loc '#.fixnum-reg) g-cc) ; non fixnum op, do normal
- (d-exp `(cdr ,expr))) ; eval to get unboxed number
- else (do ((xx (cdr expr) (cdr xx)) ; fixnum op, scan all args
- (lop) (rop) (res) (opnd))
- ((null xx))
- (setq opnd (car xx))
- (if (fixp opnd)
- then (setq rop `(immed ,opnd))
- elseif (and (symbolp opnd)
- (setq rop (d-simple `(cdr ,opnd))))
- thenret
- else (if (and lop (not (eq lop '#.unCstack)))
- then (C-push (e-cvt lop))
- (setq lop '#.unCstack))
- (d-fixnumcode (d-fixexpand opnd))
- (setq rop 'r5))
- (if (null lop)
- then (if (cdr xx)
- then (setq lop rop)
- else (e-move (e-cvt rop) 'r5))
- else (if (cdr xx)
- then (setq res '#.Cstack)
- else (setq res 'r5))
- (if (setq tmp (d-shiftcheck operator rop))
- then (e-write4 #+for-vax 'ashl
- #+for-tahoe 'shal
- (e-cvt (list 'immed tmp))
- (e-cvt lop)
- (e-cvt res))
- else (e-write4 operator (e-cvt rop)
- (e-cvt lop)
- (e-cvt res)))
- (if (cdr xx)
- then (setq lop '#.unCstack)
- else (setq lop "r5")))))))
-
- #+for-68k
- (defun d-fixnumcode (expr)
- (let ((operator (and (dtpr expr)
- (symbolp (car expr))
- (get (car expr) 'fixop)))
- (g-ret nil)
- tmp)
- ; the existance of a fixop property on a function says that it is a
- ; special fixnum only operation.
- (makecomment `(d-fixnumcode ,expr))
- (if (null operator)
- then (let ((g-loc '#.fixnum-reg) g-cc) ; non fixnum op, do normal
- (d-exp `(cdr ,expr))) ; eval to get unboxed number
- (d-regused '#.fixnum-reg)
- else (do ((xx (cdr expr) (cdr xx)) ; fixnum op, scan all args
- (lop) (rop) (res) (opnd))
- ((null xx))
- (setq opnd (car xx))
- (if (fixp opnd)
- then (setq rop `(immed ,opnd))
- elseif (and (symbolp opnd)
- (setq rop (d-simple `(cdr ,opnd))))
- thenret
- else (if (and lop (not (eq lop '#.unCstack)))
- then (C-push (e-cvt lop))
- (setq lop '#.unCstack))
- (d-fixnumcode (d-fixexpand opnd))
- (setq rop '#.fixnum-reg))
- (if (null lop)
- then (if (cdr xx)
- then (setq lop rop)
- else (e-move
- (e-cvt rop)
- '#.fixnum-reg))
- else (if (cdr xx)
- then (setq res '#.Cstack)
- else (setq res '#.fixnum-reg))
- (if (setq tmp (d-shiftcheck operator rop))
- then (d-asll tmp (e-cvt lop) (e-cvt res))
- else (e-move (e-cvt lop) 'd0)
- (e-write3 operator (e-cvt rop) 'd0)
- (e-move 'd0 (e-cvt res)))
- (if (cdr xx)
- then (setq lop '#.unCstack)
- else (setq lop '#.fixnum-reg)))))
- (makecomment '(d-fixnumcode done))))
-
- ;--- d-shiftcheck :: check if we can shift instead of multiply
- ; return t if the operator is a multiply and the operand is an
- ; immediate whose value is a power of two.
- (defun d-shiftcheck (operator operand)
- (and (eq operator #+(or for-vax for-tahoe) 'lmul
- #+for-68k 'mull3)
- (dtpr operand)
- (eq (car operand) 'immed)
- (cdr (assoc (cadr operand) arithequiv))))
-
- ; this table is incomplete
- ;
- (setq arithequiv '((1 . 0) (2 . 1) (4 . 2) (8 . 3) (16 . 4) (32 . 5)
- (64 . 6) (128 . 7) (256 . 8) (512 . 9) (1024 . 10)
- (2048 . 11) (4096 . 12) (8192 . 13) (16384 . 14)
- (32768 . 15) (65536 . 16) (131072 . 17)))
-
-
- ;--- cc-oneplus :: compile 1+ form = cc-oneplus =
- ; 1+ increments a fixnum only. We generate code to check if the number
- ; to be incremented is a small fixnum less than or equal to 1022. This
- ; check is done by checking the address of the fixnum's box. If the
- ; number is in that range, we just increment the box pointer by 4.
- ; otherwise we call we call _qoneplus which does the add and calls
- ; _qnewint
- ;
- #+(or for-vax for-tahoe)
- (defun cc-oneplus nil
- (if (null g-loc)
- then (if (car g-cc) then (e-goto (car g-cc)))
- else (let ((argloc (d-simple (cadr v-form)))
- (lab1 (d-genlab))
- (lab2 (d-genlab)))
- (if (null argloc)
- then (let ((g-loc 'r0) g-cc g-ret)
- (d-exp (cadr v-form)))
- (setq argloc 'reg))
- (e-cmp (e-cvt argloc) '($ #.(+ 5120 (* 4 1022))))
- (e-write2 'jleq lab1)
- (if (not (eq argloc 'r0)) then (d-move argloc 'reg))
- (e-quick-call '_qoneplus)
- (if (and g-loc (not (eq g-loc 'reg)))
- then (d-move 'reg g-loc))
- (if (car g-cc)
- then (e-goto (car g-cc))
- else (e-goto lab2))
- (e-label lab1)
- (e-add3 '($ 4) (e-cvt argloc) (e-cvt g-loc))
- (if (car g-cc) then (e-goto (car g-cc)))
- (e-label lab2))))
-
- #+for-68k
- (defun cc-oneplus nil
- (if (null g-loc)
- then (if (car g-cc) then (e-goto (car g-cc)))
- else (let ((argloc (d-simple (cadr v-form)))
- (lab1 (d-genlab))
- (lab2 (d-genlab)))
- (if (null argloc)
- then (let ((g-loc 'areg) g-cc g-ret)
- (d-exp (cadr v-form)))
- (setq argloc 'areg))
- ; ($ (+ Fixzero (* 4 1022))
- (d-cmp argloc '(fixnum 1022))
- (e-write2 'jle lab1)
- (if (not (eq argloc 'areg)) then (d-move argloc 'areg))
- (e-quick-call '_qoneplus)
- (if (and g-loc (not (eq g-loc 'reg)))
- then (d-move 'reg g-loc))
- (if (car g-cc)
- then (e-goto (car g-cc))
- else (e-goto lab2))
- (e-label lab1)
- (if (not (eq argloc 'reg))
- then (d-move argloc 'reg))
- (e-write3 'addql "#4" 'd0)
- (if (and g-loc (not (eq g-loc 'reg)))
- then (d-move 'reg g-loc))
- (if (car g-cc) then (e-goto (car g-cc)))
- (e-label lab2))))
-
-
-
- ;--- cc-oneminus :: compile the 1- form
- ; just like 1+ we check to see if we are decrementing an small fixnum.
- ; and if we are we just decrement the pointer to the fixnum and save
- ; a call to qinewint. The valid range of fixnums we can decrement are
- ; 1023 to -1023. This requires two range checks (as opposed to one for 1+).
- ;
- #+(or for-vax for-tahoe)
- (defun cc-oneminus nil
- (if (null g-loc)
- then (if (car g-cc) then (e-goto (car g-cc)))
- else (let ((argloc (d-simple (cadr v-form)))
- (lab1 (d-genlab))
- (lab2 (d-genlab))
- (lab3 (d-genlab)))
- (if (null argloc)
- then (let ((g-loc 'r0) g-cc)
- (d-exp (cadr v-form)))
- (setq argloc 'reg))
- (e-cmp (e-cvt argloc) '($ #.(- 5120 (* 4 1024))))
- (e-write2 'jleq lab1) ; not within range
- (e-cmp (e-cvt argloc) '($ #.(+ 5120 (* 4 1023))))
- (e-write2 'jleq lab2) ; within range
- ; not within range, must do it the hard way.
- (e-label lab1)
- (if (not (eq argloc 'r0)) then (d-move argloc 'reg))
- (e-quick-call '_qoneminus)
- (if (and g-loc (not (eq g-loc 'reg)))
- then (d-move 'reg g-loc))
- (if (car g-cc)
- then (e-goto (car g-cc))
- else (e-goto lab3))
- (e-label lab2)
- ; we are within range, just decrement the pointer by the
- ; size of a word (4 bytes).
- (e-sub3 '($ 4) (e-cvt argloc) (e-cvt g-loc))
- (if (car g-cc) then (e-goto (car g-cc)))
- (e-label lab3))))
-
- #+for-68k
- (defun cc-oneminus nil
- (if (null g-loc)
- then (if (car g-cc) then (e-goto (car g-cc)))
- else (let ((argloc (d-simple (cadr v-form)))
- (lab1 (d-genlab))
- (lab2 (d-genlab))
- (lab3 (d-genlab)))
- (if (null argloc)
- then (let ((g-loc 'areg) g-cc)
- (d-exp (cadr v-form)))
- (setq argloc 'areg))
- ; ($ (- Fixzero (* 4 1024)))
- (d-cmp argloc '(fixnum -1024))
- (e-write2 'jle lab1) ; not within range
- (d-cmp argloc '(fixnum 1023))
- (e-write2 'jle lab2) ; within range
- ; not within range, must do it the hard way.
- (e-label lab1)
- (if (not (eq argloc 'areg)) then (d-move argloc 'areg))
- (e-quick-call '_qoneminus)
- (if (and g-loc (not (eq g-loc 'reg)))
- then (d-move 'reg g-loc))
- (if (car g-cc)
- then (e-goto (car g-cc))
- else (e-goto lab3))
- (e-label lab2)
- ; we are within range, just decrement the pointer by the
- ; size of a word (4 bytes).
- (if (not (eq argloc 'reg))
- then (d-move argloc 'reg))
- (e-sub '($ 4) 'd0)
- (if (and g-loc (not (eq g-loc 'reg)))
- then (d-move 'reg g-loc))
- (if (car g-cc) then (e-goto (car g-cc)))
- (e-label lab3))))
-
- ;--- cm-< :: compile a < expression
- ;
- ; the operands to this form can either be fixnum or flonums but they
- ; must be of the same type.
- ;
- ; We can compile the form just like an eq form since all we want is
- ; a compare and a jump. The comparisons are inverted since that is
- ; the way eq expects it.
-
- (defun cm-< nil
- (if (not (= 2 (length (cdr v-form))))
- then (comp-err "incorrect number of arguments to < " v-form))
- ; only can do fixnum stuff if we know that one of the args is
- ; a fixnum.
- ;
- (if (or (fixp (cadr v-form)) (fixp (caddr v-form)))
- then `(<& ,(cadr v-form) ,(caddr v-form))
- else `(lessp ,(cadr v-form) ,(caddr v-form))))
-
- ;--- c-<& :: fixnum <
- ;
- ; We can compile the form just like an eq form since all we want is
- ; a compare and a jump. The comparisons are inverted since that is
- ; the way eq expects it.
-
- (defun cc-<& nil
- (let ((g-trueop #+(or for-vax for-tahoe) 'jgeq #+for-68k 'jpl)
- (g-falseop #+(or for-vax for-tahoe) 'jlss #+for-68k 'jmi)
- (v-form `(eq (cdr ,(cadr v-form)) (cdr ,(caddr v-form)))))
- (cc-eq)))
-
- ;--- cm-> :: compile a > expression
- ;
- ; the operands to this form can either be fixnum or flonums but they
- ; must be of the same type.
- ; We can compile the form just like an eq form since all we want is
- ; a compare and a jump. The comparisons are inverted since that is
- ; the way eq expects it.
- (defun cm-> nil
- (if (not (= 2 (length (cdr v-form))))
- then (comp-err "incorrect number of arguments to > " v-form))
- ; only can do fixnum stuff if we know that one of the args is
- ; a fixnum.
- ;
- (if (or (fixp (cadr v-form)) (fixp (caddr v-form)))
- then `(>& ,(cadr v-form) ,(caddr v-form))
- else `(greaterp ,(cadr v-form) ,(caddr v-form))))
-
- ;--- cc->& :: compile a fixnum > function
- ;
- ; We can compile the form just like an eq form since all we want is
- ; a compare and a jump. The comparisons are inverted since that is
- ; the way eq expects it.
- (defun cc->& nil
- (let ((g-trueop #+(or for-vax for-tahoe) 'jleq #+for-68k 'jle)
- (g-falseop #+(or for-vax for-tahoe) 'jgtr #+for-68k 'jgt)
- (v-form `(eq (cdr ,(cadr v-form)) (cdr ,(caddr v-form)))))
- (cc-eq)))
-
- ;--- cm-= : compile an = expression
- ; The = function is a strange one. It can compare two fixnums or two
- ; flonums which is fine on a pdp-10 where they are the same size, but
- ; is a real pain on a vax where they are different sizes.
- ; We thus can see if one of the arguments is a fixnum and assume that
- ; the other one is and then call =&, the fixnum equal code.
- ;
- (defun cm-= nil
- (if (not (= 2 (length (cdr v-form))))
- then (comp-err "incorrect number of arguments to = : " v-form))
- (if (or (fixp (cadr v-form)) (fixp (caddr v-form)))
- then `(=& ,(cadr v-form) ,(caddr v-form))
- else `(equal ,(cadr v-form) ,(caddr v-form))))
-
- ;--- cm-=&
- ;
- ; if the number is within the small fixnum range, we can just
- ; do pointer comparisons.
- ;
- (defun cm-=& nil
- (if (or (and (fixp (cadr v-form))
- (< (cadr v-form) 1024)
- (> (cadr v-form) -1025))
- (and (fixp (caddr v-form))
- (< (caddr v-form) 1024)
- (> (caddr v-form) -1025)))
- then `(eq ,(cadr v-form) ,(caddr v-form))
- else `(eq (cdr ,(cadr v-form)) (cdr ,(caddr v-form)))))
-
- ; this should be converted
- #+(or for-vax for-tahoe)
- (defun c-\\ nil
- (d-fixop 'ediv 'remainder))
-
- #+(or for-vax for-tahoe)
- (defun d-fixop (opcode lispopcode)
- (prog (op1 op2 rop1 rop2 simpleop1)
- (if (not (eq 3 (length v-form))) ; only handle two ops for now
- then (d-callbig lispopcode (cdr v-form) nil)
- else (setq op1 (cadr v-form)
- op2 (caddr v-form))
- (if (fixp op1)
- then (setq rop1 `($ ,op1) ; simple int
- simpleop1 t)
- else (if (setq rop1 (d-simple `(cdr ,op1)))
- then (setq rop1 (e-cvt rop1))
- else (let ((g-loc 'reg) g-cc g-ret)
- (d-exp op1))
- (setq rop1 '(0 r0))))
- (if (fixp op2)
- then (setq rop2 `($ ,op2))
- else (if (setq rop2 (d-simple `(cdr ,op2)))
- then (setq rop2 (e-cvt rop2))
- else (C-push rop1)
- (setq rop1 '#.unCstack)
- (let ((g-loc 'reg)
- g-cc g-ret)
- (d-exp op2))
- (setq rop2 '(0 r0))))
- (if (eq opcode 'ediv)
- then (if (not simpleop1)
- then #+for-vax (progn (e-move rop1 'r2) ;need quad
- (e-write4 'ashq '$-32 'r1 'r1))
- #+for-tahoe (let ((x (d-genlab)))
- (e-write2 'clrl 'r2)
- (e-move rop1 'r3)
- (e-write2 'jgeq x)
- (e-write3 'mnegl '($ 1) 'r2)
- (e-writel x))
- (setq rop1 #+for-vax 'r1 #+for-tahoe 'r2))
- ; word div.
- (e-write5 'ediv rop2 rop1 'r0 'r5)
- else (e-write4 opcode rop2 rop1 'r5))
- (d-fixnumbox)
- (d-clearreg))))
-