(include-if (null (get 'chead 'version)) "../chead.l")
(Liszt-file vector
   "$Header:vector.l 12.0$")
   "$ACIS:vector.l 12.0$")

;;; ----	v e c t o r			vector referencing
;;;
;;;				-[Thu Aug 11 18:29:32 1983 by layer]-


(defun cc-vset ()
   ;;  Set a vector created via 'vector'.
   (d-vset 'lisp))

(defun cc-vref ()
   ;;  Reference a vector created via 'vector'.
   (d-vref 'lisp))

(defun cc-vseti-byte ()
   ;;  Set a vector created via 'vectori-byte'.
   (d-vset 'byte))

(defun cc-vrefi-byte ()
   ;;  Reference a vector created via 'vectori-byte'.
   (d-vref 'byte))

(defun cc-vseti-word ()
   ;;  Set a vector created via 'vectori-word'.
   (d-vset 'word))

(defun cc-vrefi-word ()
   ;;  Reference a vector created via 'vectori-word'.
   (d-vref 'word))

(defun cc-vseti-long ()
   ;;  Set a vector created via 'vectori-long'.
   (d-vset 'long))

(defun cc-vrefi-long ()
   ;;  Reference a vector created via 'vectori-long'.
   (d-vref 'long))

;--- d-vset :: handle all types of vset's
(defun d-vset (type)
   ;;  Generic vector store.  Type is either 'lisp', 'byte', 'word',
   ;; or 'long'.
   (let ((vect (cadr v-form))
	 (index (caddr v-form))
	 (val (cadddr v-form))
	 (vect-addr) (index-addr)
	 (vect-val) (fetchval)
	 (temp) (size)
	 (vec-reg #+for-vax 'r0 #+for-68k 'a0)
	 (val-reg #+for-vax 'r1 #+for-68k 'd1)
	 (index-reg '#.fixnum-reg)
	 (temp-reg #+for-vax 'r4 #+for-68k 'd0)
	 (temp-areg #+for-vax 'bogus! #+for-68k 'a1)
	 (oklab (d-genlab))
	 (needlowcheck t))		; t if must check lower index bounds

       #+for-68k (d-regused '#.fixnum-reg)
       (makecomment `(doing vec set type ,type))
       (if (fixp index)
	   then (if (<& index 0)
		    then (comp-err "vector index less than 0 " v-form))
		(setq needlowcheck nil))

       ; Compute the value to be stored...
       ;
       ; If we are doing an immediate vector, then get the value
       ; instead of the boxed fixnum (in the case of byte), or
       ; word/long.
       (if (null (eq 'lisp type)) then (setq val `(cdr ,val)))

       (if (null (setq vect-val (d-simple val)))
	   then (let ((g-loc val-reg) g-cc g-ret)
		    (d-exp val))
		(setq vect-val val-reg)
	   else (setq vect-val (e-cvt vect-val)))

       ; make sure that we are not going to clobber val-reg...
       (if (not (and (d-simple vect) (d-simple index)))
	   then ; val-reg could be clobbered when we do the
		; fetching of the vector or index values
		(setq fetchval t)
		(e-move vect-val (e-cvt 'stack)))

       ; Compute the index...
       ;
       (if (setq index-addr (d-simple index))
	   then (let ((g-loc vec-reg) g-cc g-ret)
		    (d-exp vect))
		(setq vect-addr vec-reg)	; the vector op is in vec-reg
		; we really want the cdr of index (the actual number).
		; if we can do that simply, great.  otherwise we
		; bring the index into index-reg and then do the cdr ourselves
		(if (setq temp (d-simple `(cdr ,index)))
		    then (d-move temp index-reg)
		    else (d-move index-addr index-reg)
			 #+for-vax
			 (e-move `(0 ,index-reg) index-reg)
			 #+for-68k
			 (progn
			     (e-move index-reg 'a5)
			     (e-move '(0 a5) index-reg)))
		(setq index-addr index-reg)
	   else ; the index isn't computable simply, so we must
		; stack the vector location to keep it safe
		(let ((g-loc 'stack) g-cc g-ret)
		    (d-exp vect))
		(push nil g-locs)
		(incr g-loccnt)
		; compute index's value into index-reg
		(d-fixnumexp index)
		; now put vector address into vec-reg
		(d-move 'unstack vec-reg)
		(decr g-loccnt)
		(pop g-locs)
		(setq vect-addr vec-reg
		      index-addr index-reg)
		; must be sure that the cc's reflect the value of index-reg
		(e-tst index-reg))

       ;   At this point, vect-addr (always vec-reg) contains the location of
       ; the start of the vector,  index-addr (always index-reg) contains
       ; the index value.
       ;   The condition codes reflect the value of the index.
       ; First we insure that the index is non negative
       ; test must use a jmp in case the object file is large
       ;
       (if needlowcheck
	   then (e-write2 #+for-vax 'jgeq #+for-68k 'jpl oklab)
		(e-write2 'jmp 'vecindexerr)
		(e-label oklab)
		(setq oklab (d-genlab)))
       ;; now, we compare against the size of the vector
       ;; the size of the vector is in bytes, we may want to shift this
       ;; to reflect the size in words or longwords, depending on the
       ;; type of reference
       (if (eq type 'byte)
	   then ; can compare right away
		(e-cmp index-addr `(-8 ,vect-addr))
	   else ; shift size into temp-reg
		(setq size (if (eq type 'word) then 1 else 2))
		#+for-vax
		    (e-write4 'ashl (concat '$- size)
			      `(-8 ,vect-addr) temp-reg)
		#+for-68k
		(progn
		    (e-move `(-8 ,vect-addr) temp-reg)
		    (e-write3 'asrl `($ ,size) temp-reg))
		(e-cmp index-addr temp-reg)
		(d-clearreg temp-reg))
       ;; size is the number of objects, the index is 0 based so
       ;; it must be less than the vector size
       (e-write2 #+for-vax 'jlss #+for-68k 'jmi oklab)
       (e-write2 'jmp 'vecindexerr)
       (e-label oklab)

       (if fetchval
	   then ; unstack the value to store...
		(e-move (e-cvt 'unstack) val-reg)
		(setq vect-val val-reg))

       ;; if we get here then the access is in bounds
       (if (eq type 'lisp)
	   then #+for-vax
		(e-move vect-val `(0 ,vect-addr ,index-addr))
		#+for-68k
		(progn
		    (e-move index-addr temp-reg)
		    (e-write3 'asll '($ 2) temp-reg)
		    (e-add vect-addr temp-reg)
		    (e-move temp-reg temp-areg)
		    (e-move vect-val `(0 ,temp-areg)))
		(if g-loc (e-move vect-val (e-cvt g-loc)))
		(if g-cc then (d-handlecc))
	   else (setq temp (cadr (assq type '((byte movb)
					      (word movw)
					      (long movl)))))
		#+for-vax
		(e-write3 temp vect-val `(0 ,vect-addr ,index-addr))
		#+for-68k
		(progn
		    (e-move index-addr temp-reg)
		    (caseq type
			(word (e-write3 'asll '($ 1) temp-reg))
			(long (e-write3 'asll '($ 2) temp-reg)))
		    (e-write3 'lea `(% 0 ,vec-reg ,temp-reg) temp-areg)
		    (if (eq type 'long)
			then (e-write3 temp vect-val `(0 ,temp-areg))
			else (e-move vect-val 'd1)
			     (e-write3 temp 'd1 `(0 ,temp-areg))))
		(if g-loc
		    then (if (eq type 'byte)
			     then ; all bytes values are within the fixnum
				  ; range, we convert them to immediate
				  ; fixum with ease.
				  #+for-vax
				  (progn
				      (e-write4 'ashl '($ 2)
						index-reg index-reg)
				      (e-write3 'movab
						`(5120 ,index-reg)
						(e-cvt g-loc)))
				  #+for-68k
				  (progn
				      (e-move index-reg temp-reg)
				      (e-write3 'asll '($ 2) temp-reg)
				      (e-move temp-reg temp-areg)
				      (e-move
						(e-cvt '(fixnum 0))
						temp-reg)
				      (e-write3 'lea
						`(% 0 ,temp-areg ,temp-reg)
						temp-areg)
				      (e-move
						temp-areg
						(e-cvt g-loc)))
			     else ; must convert the hard way
				  (e-call-qnewint)
				  (d-clearreg)
				  (if (not (eq g-loc 'reg))
				      then (d-move 'reg g-loc)))
			 ; result is always non nil
			 (if (car g-cc) then (e-goto (car g-cc)))
		 elseif (car g-cc) then (e-goto (car g-cc))))
       (d-vectorindexcode)))

;--- d-vref :: handle all types of vref's
(defun d-vref (type)
   ;;  Generic vector reference.  Type is either 'lisp', 'byte', 'word',
   ;; or 'long'.
   (let ((vect (cadr v-form))
	 (index (caddr v-form))
	 (vect-addr) (index-addr) (temp) (size)
	 (vec-reg #+for-vax 'r0 #+for-68k 'a0)
	 (index-reg '#.fixnum-reg)
	 (temp-reg #+for-vax 'r4 #+for-68k 'd0)
	 (temp-areg #+for-vax 'rX #+for-68k 'a1)
	 (oklab (d-genlab))
	 (needlowcheck t))  ; t if must check lower index bounds

       #+for-68k (d-regused '#.fixnum-reg)
       (makecomment `(doing vec ref type ,type))
       (if (fixp index)
	   then (if (<& index 0)
		    then (comp-err "vector index less than 0 " v-form))
		(setq needlowcheck nil))

       (if (setq index-addr (d-simple index))
	   then (let ((g-loc vec-reg) g-cc g-ret)
		    (d-exp vect))
		(setq vect-addr vec-reg)	; the vector op is in vec-reg
		; we really want the cdr of index (the actual number).
		; if we can do that simply, great.  otherwise we
		; bring the index into index-reg and then do the cdr ourselves
		(if (setq temp (d-simple `(cdr ,index)))
		    then (d-move temp index-reg)
		    else (d-move index-addr index-reg)
			 #+for-vax
			 (e-move `(0 ,index-reg) index-reg)
			 #+for-68k
			 (progn
			     (e-move index-reg 'a5)
			     (e-move '(0 a5) index-reg)))
		(setq index-addr index-reg)
	   else ; the index isn't computable simply, so we must
		; stack the vector location to keep it safe
		(let ((g-loc 'stack) g-cc g-ret)
		    (d-exp vect))
		(push nil g-locs)
		(incr g-loccnt)
		; compute index's value into index-reg
		(d-fixnumexp index)
		; now put vector address into vec-reg
		(d-move 'unstack vec-reg)
		(decr g-loccnt)
		(pop g-locs)
		(setq vect-addr vec-reg
		      index-addr index-reg)
		; must be sure that the cc's reflect the value of index-reg
		(e-tst index-reg))
       
       ; at this point, vect-addr (always vec-reg) contains the location of
       ; the start of the vector,  index-addr (always index-reg) contains
       ; the index value.  the condition codes reflect the value of
       ; the index
       ; First we insure that the index is non negative
       ; test must use a jmp in case the object file is large
       (if needlowcheck
	   then (e-write2 #+for-vax 'jgeq #+for-68k 'jpl oklab)
		(e-write2 'jmp 'vecindexerr)
		(e-label oklab)
		(setq oklab (d-genlab)))

       ; now, we compare against the size of the vector
       ; the size of the vector is in bytes, we may want to shift this
       ; to reflect the size in words or longwords, depending on the
       ; type of reference
       (if (eq type 'byte)
	   then ; can compare right away
		(e-cmp index-addr `(-8 ,vect-addr))
	   else ; shift size into temp-reg
		(setq size (if (eq type 'word) then 1 else 2))
		#+for-vax
		(e-write4 'ashl (concat '$- size) `(-8 ,vect-addr) temp-reg)
		#+for-68k
		(progn
		    (e-move `(-8 ,vect-addr) temp-reg)
		    (e-write3 'asrl `($ ,size) temp-reg))
		(e-cmp index-addr temp-reg)
		(d-clearreg temp-reg))
       ; size is the number of objects, the index is 0 based so
       ; it must be less than the vector size
       (e-write2 #+for-vax 'jlss #+for-68k 'jmi oklab)
       (e-write2 'jmp 'vecindexerr)
       (e-label oklab)

       ;; if we get here then the access is in bounds
       (if g-loc
	   then ; we care about the value.
		; if the value is one of the fixnum types, then we
		; move the value to index-reg so it can be fixnum converted
		(if (eq type 'lisp)
		    then #+for-vax
			 (e-move `(0 ,vect-addr ,index-addr)
				   (e-cvt g-loc))
			 #+for-68k
			 (progn
			     (e-move index-addr temp-reg)
			     (e-write3 'asll '($ 2) temp-reg)
			     (e-add vect-addr temp-reg)
			     (e-move temp-reg temp-areg)
			     (e-move `(0 ,temp-areg) (e-cvt g-loc)))
			 (if g-cc then (d-handlecc))
		    else #+for-vax
			 (progn
			     (setq temp (cadr (assq type '((byte cvtbl)
							   (word cvtwl)
							   (long movl)))))
			     (e-write3 temp
				       `(0 ,vect-addr ,index-addr)
				       index-reg))
			 #+for-68k
			 (progn
			     (setq temp
				   (cadr (assq type '((byte movb)
						      (word movw)
						      (long movl)))))
			     (caseq type
				    (word (e-write3 'asll '($ 1) index-reg))
				    (long (e-write3 'asll '($ 2) index-reg)))
			     (e-write3 'lea `(% 0 ,vec-reg ,index-reg)
				       temp-areg)
			     (if (memq type '(byte word))
				 then (e-write2 'clrl index-reg))
			     (e-write3 temp `(0 ,temp-areg) index-reg))
			 (if (eq type 'byte)
			     then ; all bytes values are within the fixnum
				  ; range, we convert them to immediate
				  ; fixum with ease.
				  #+for-vax
				  (progn
				      (e-write4 'ashl '($ 2)
						index-reg index-reg)
				      (e-write3 'movab
						`(5120 ,index-reg)
						(e-cvt g-loc)))
				  #+for-68k
				  (progn
				      (e-write3 'asll '($ 2) index-reg)
				      (e-move index-reg temp-areg)
				      (e-move
						'($ _nilatom+0x1400)
						temp-reg)
				      (e-write3 'lea
						`(% 0 ,temp-areg ,temp-reg)
						temp-areg)
				      (e-move
						temp-areg
						(e-cvt g-loc)))
			     else ; must convert the hard way
				  (e-call-qnewint)
				  (d-clearreg)
				  (if (not (eq g-loc 'reg))
				      then (d-move 'reg g-loc)))
			 ; result is always non nil
			 (if (car g-cc) then (e-goto (car g-cc))))
	elseif g-cc
	     ; we dont care about the value, just whether it nil
	   then (if (eq type 'lisp)
		    then #+for-vax
			 (e-tst `(0 ,vect-addr ,index-addr))
			 #+for-68k
			 (progn
			     (e-move index-addr temp-reg)
			     (e-write3 'asll '($ 2) temp-reg)
			     (e-add vect-addr temp-reg)
			     (e-move temp-reg temp-areg)
			     (e-tst `(0 ,temp-areg)))
			 (d-handlecc)
		    else ; if fixnum, then it is always true
			 (if (car g-cc) then (e-goto (car g-cc)))))
       (d-vectorindexcode)))

;--- d-vectorindexcode :: put out code to call the vector range error.
; At this point the vector is in r0, the index an immediate fixnum in r5
; we call the function int:vector-range-error with two arguments, the
; vector and the index.
;
(defun d-vectorindexcode ()
   (if (null g-didvectorcode)
      then (let ((afterlab (d-genlab)))
	      (e-goto afterlab)
	      (e-label 'vecindexerr)
	      (d-move #+for-vax 'r0 #+for-68k 'a0 'stack)
	      (e-call-qnewint)
	      (d-move 'reg 'stack)
	      (d-calltran 'int:vector-range-error 2)
	      ; never returns
	      (e-label afterlab))
	   (setq g-didvectorcode t)))


;------------------------ vector access functions

;--- cc-vectorp :: check for vectorness
;
(defun cc-vectorp nil
  (d-typesimp (cadr v-form) #.(immed-const 18)))

;--- cc-vectorip :: check for vectoriness
;
(defun cc-vectorip nil
  (d-typesimp (cadr v-form) #.(immed-const 19)))

;--- c-vsize :: extract vsize
;
(defun c-vsize nil
   (d-vectorsize (cadr v-form) '2))

(defun c-vsize-byte nil
   (d-vectorsize (cadr v-form) '0))

(defun c-vsize-word nil
   (d-vectorsize (cadr v-form) '1))

(defun d-vectorsize (form shift)
   (let ((g-loc 'reg)
	 g-cc
	 g-ret)
       (d-exp form))
   ; get size into `fixnum-reg' for fixnum boxing
   (if (zerop shift)
       then (e-move '(-8 #+for-vax r0 #+for-68k a0) '#.fixnum-reg)
       else #+for-vax
	    (e-write4 'ashl (concat '$- shift) '(-8 r0) '#.fixnum-reg)
	    #+for-68k
	    (progn
		(e-move '(-8 a0) '#.fixnum-reg)
		(e-write3 'asrl `($ ,shift) '#.fixnum-reg)))
   (e-call-qnewint))
