;;; -*- Mode:LISP; Package:(NC LISP); Base:10; Readtable:CL -*- ;;; Copyright (c) 1985 Yale University ;;; Authors: N Adams, R Kelsey, D Kranz, J Philbin, J Rees. ;;; This material was developed by the T Project at the Yale University Computer ;;; Science Department. Permission to copy this software, to redistribute it, ;;; and to use it for any purpose is granted, subject to the following restric- ;;; tions and understandings. ;;; 1. Any copy made of this software must include this copyright notice in full. ;;; 2. Users of this software agree to make their best efforts (a) to return ;;; to the T Project at Yale any improvements or extensions that they make, ;;; so that these may be included in future releases; and (b) to inform ;;; the T Project of noteworthy uses of this software. ;;; 3. All materials developed as a consequence of the use of this software ;;; shall duly acknowledge such use, in accordance with the usual standards ;;; of acknowledging credit in academic research. ;;; 4. Yale has made no warrantee or representation that the operation of ;;; this software will be error-free, and Yale is under no obligation to ;;; provide any services, by way of maintenance, update, or otherwise. ;;; 5. In conjunction with products arising from the use of this material, ;;; there shall be no use of the name of the Yale University nor of any ;;; adaptation thereof in any advertising, promotional, or sales literature ;;; without prior written consent from Yale in each case. ;;; ;;; Copyright (c) 1985 David Kranz (defun addressable? (val) (or (eq val t) (eq val nil) (eq (zl:data-type val) 'zl:dtp-fix) (eq (zl:data-type val) 'zl:dtp-character))) (zl:defsubst reg-offset (x y) (cons x y)) (zl:defsubst machine-num (x) ($ x)) (defun lit (x) (list 'quote x)) (zl:defsubst register? (x) (and (integerp x) (>= x 0) (< x *real-registers*))) ;;; Registers and temps are represented in the same structure (zl:defsubst reg-node (reg) (svref *registers* reg)) (zl:defsubst temp-node (reg) (reg-node reg)) (defun reg-type (reg) (if (or (< reg *scratch-registers*) (>= reg (+ *real-registers* *pointer-temps*))) 'scratch 'pointer)) (defvar *lock-mark* 'lock) ;(object nil ((identification self) 'lock))) (zl:defsubst lock (reg) (if (< reg *no-of-registers*) (push *lock-mark* (reg-node reg)))) (zl:defsubst unlock (reg) (if (< reg *no-of-registers*) (pop (reg-node reg)))) (zl:defsubst locked? (reg) (let ((n (reg-node reg))) (and (consp n) (eq (car n) *lock-mark*)))) ;;; Locations ;;;========================================================================== ;;; Keeps track of where values are. ;;; A table of a-lists of form (( . )...) indexed by ;;; leaf values, i.e. variables, primops, or literals. (defvar *locations* (make-table 'locations)) (zl:defsubst leaf-locations (value) (table-entry *locations* value)) (zl:defsubst get-location (value type) (cdr (assoc type (leaf-locations value) :test #'eq))) (defun set-location (value type number) (if (null value) (zl:eh)) (let* ((locs (leaf-locations value)) (pair (assoc type locs :test #'eq))) (if pair (setf (cdr pair) number)) (setf (table-entry *locations* value) (cons (cons type number) locs)))) (defun clear-location (value type) (setf (leaf-locations value) (delete type (leaf-locations value) :test #'eq :key #'car)) nil) (zl:defsubst register-loc (value) (get-location value 'reg)) (zl:defsubst set-register-loc (value register) (if (null register) (clear-location value 'reg) (set-location value 'reg register))) (defsetf register-loc set-register-loc) ; ((identification self) 'register-loc) (zl:defsubst temp-loc (value) (get-location value 'temp)) (zl:defsubst set-temp-loc (value temp) (if (null temp) (clear-location value 'temp) (set-location value 'temp temp))) (defsetf temp-loc set-temp-loc) ; ((identification self) 'temp-loc) ;;; ->REGISTER Move the value of leaf-node REF into a register of type TYPE ;;; which can be either '* or a specific register. Force an existing value out ;;; if necessary, (defun ->register (type node var where) (let ((accessor (access-value node var))) (cond ((and (register? accessor) (or (and (eq (reg-type accessor) type) (eq where '*)) (eq accessor where))) accessor) (t (cond ((register? accessor) (setf (register-loc var) nil) (cond ((locked? accessor) (setf (cdr (reg-node accessor)) nil)) (t (setf (reg-node accessor) nil))))) (into-register type node var accessor where))))) (defun in-register? (type value where) (let ((reg (register-loc value))) (and reg (eq (reg-type reg) type) (or (eq where '*) (eq where reg))))) (defun get-target-register (node t-spec) (cond ((register? t-spec) (cond ((or (not (reg-node t-spec)) (and (not (locked? t-spec)) (dying? (reg-node t-spec) node))) t-spec) (t (get-register (reg-type t-spec) node '*)))) (t (get-register t-spec node '*)))) (defun get-register (type node where) (cond ((not (eq where '*)) (free-register node where) where) ((not (eq type 'scratch)) (really-get-register 'pointer node *scratch-registers* *real-registers* t)) (t (really-get-register 'scratch node 0 *scratch-registers* t)))) (defun get-reg-if-free (spec node) (cond ((register? spec) (if (reg-node spec) nil spec)) ((eq spec 'pointer) (really-get-register spec node *scratch-registers* *real-registers* nil)) ((eq spec 'scratch) (really-get-register spec node 0 *scratch-registers* nil)) ((eq spec '*) (really-get-register spec node 0 *real-registers* nil)) (t (bug "bad spec: ~s" spec)))) (defun really-get-register (type node start stop kick?) (do ((i start (1+ i))) ((>= i stop) (if kick? (select-and-kick-register node type) nil)) (if (not (reg-node i)) (return i)))) (defun into-register (type node value access where) (cond ((in-register? type value where) (register-loc value)) (t (let ((reg (get-register type node where))) (generate-move access reg) (let ((reg (register-loc value))) (if reg (setf (reg-node reg) nil))) (mark value reg) reg)))) ;;; SELECT-AND-KICK-REGISTER The first register which is not locked or used soo ;;; is selected. If none satisfy then the first register is selected. (defun select-and-kick-register (node type) (cond ((eq type 'pointer) (do ((i (1+ *scratch-registers*) (1+ i)) (default P)) ;kick P? ((>= i *real-registers*) (kick-register node default) default) (cond ((and (not (locked? i)) (not (used-soon? node (reg-node i)))) (kick-register node i) (return i)) (t (setq default i))))) (t (do ((i 0 (1+ i)) (default nil)) ((>= i *scratch-registers*) (free-register node default) default) (cond ((and (not (locked? i)) (not (used-soon? node (reg-node i)))) (free-register node i) (return i)) (t (setq default i))))))) ;;; USED-SOON? Is this variable used at this node or at one of its ;;; continuations? (defun used-soon? (node value) (flet ((var-used? (arg) (and (leaf-node? arg) (eq (leaf-value arg) value)))) (or (some #'var-used? (call-args node)) (some #'(lambda (cont) (some #'var-used? (call-args (lambda-body cont)))) (continuations node))))) (zl:defsubst free-register (node reg) (cond ((reg-node reg) ;=> (lambda (value) ; (let ((new (where-used value))) ; (cond (nil ;(and (register? new) (get-reg-if-free new node)) ; => (lambda (new) ; (mark value new) ; (set (reg-node reg) nil) ; (generate-move reg new))) ; (else (kick-register node reg)))) (defun kick-register (node reg) (let ((value (reg-node reg))) (cond ((locked? reg) (error "attempt to kick out of locked register")) ((or (temp-loc value) (not (variable-p value))) ; (and (not (eq value (lambda-self-var *lambda*))) ; (= (variable-number value) 0))) (setf (register-loc value) nil) (setf (reg-node reg) nil)) (t (let ((temp (get-temp value (reg-type reg) node))) (setf (register-loc value) nil) (setf (temp-loc value) temp) (setf (reg-node reg) nil) (generate-move reg temp)))))) ;;; ??? we don't have any temps... (defun really-get-temp (type node) (cond ((eq type 'scratch) (really-get-register 'scratch node (+ *real-registers* *pointer-temps*) *no-of-registers* nil)) (t (really-get-register 'pointer node A0 ;*real-registers* AN-1 ;(+ *real-registers* *pointer-temps*) nil)))) (defun get-temp (value type node) (let ((temp (really-get-temp type node))) (cond (temp (if (> temp *max-temp*) (setq *max-temp* temp)) (setf (temp-node temp) value) temp) (t (bug "all temps used"))))) (zl:defsubst cont (node) (car (call-args node))) (defun continuations (node) (do ((i (call-exits node) (1- i)) (args '())) ((zerop i) args) (let ((arg (call-arg-n i node))) (setq args (cond ((lambda-node? arg) (cons arg args)) (t (let ((label (variable-known (leaf-value arg)))) (cond (label (cons label args)) (t args))))))))) (zl:defsubst then-cont (node) (car (call-args node))) (zl:defsubst else-cont (node) (cadr (call-args node))) (defun live? (value node) (let ((value (cond ((and (consp value) (variable-p (cdr value))) (cdr value)) ((variable-p value) value) (t nil)))) (cond ((not value) nil) (t (some #'(lambda (cont) (member value (lambda-live cont) :test #'eq)) (continuations node)))))) (zl:defsubst dying? (value node) (not (live? value node))) (defun dead? (value node) (let ((parent (node-parent node))) (not (and (variable-p value) (or (member value (lambda-variables parent) :test #'eq) (member value (lambda-live parent) :test #'eq)))))) (zl:defsubst kill-if-dying (var node) (if (dying? var node) (kill var))) (defun kill-if-dead (node where) (if (and (leaf-node? node) (or (not (variable-p (leaf-value node))) (not (member (leaf-value node) (lambda-live where) :test #'eq)))) (kill (leaf-value node)))) (defun kill (value) (let ((reg (register-loc value))) (cond (reg (cond ((locked? reg) (unless (eq (cdr (reg-node reg)) value) (bug "horrible inconsistancy reg ~S value ~S" reg value)) (setf (cdr (reg-node reg)) nil)) (t (unless (eq (reg-node reg) value) (bug "horrible inconsistancy reg ~S value ~S" reg value)) (setf (reg-node reg) nil))) (setf (register-loc value) nil)))) (let ((reg (temp-loc value))) (cond (reg (cond ((locked? reg) (unless (eq (cdr (temp-node reg)) value) (bug "horrible inconsistancy reg ~S value ~S" reg value)) (setf (cdr (temp-node reg)) nil)) (t (unless (eq (temp-node reg) value) (bug "horrible inconsistancy reg ~S value ~S" reg value)) (setf (temp-node reg) nil))) (setf (temp-loc value) nil))))) ;;; pools for vector of registers (see ALLOCATE-CONDITIONAL-PRIMOP in reg.t) ;(define register-vector-pool ; (make-pool 'reg-vec-pool (lambda () (make-vector *no-of-registers*)))) (defun copy-registers () (copy-seq *registers*)) (zl:defsubst return-registers ()) ;(define-integrable (return-registers) ; (return-to-pool register-vector-pool *registers*)) (defun restore-slots () (restore-registers) (restore-temps)) (defun restore-registers () (dotimes (i *real-registers*) (cond ((reg-node i) (setf (register-loc (reg-node i)) i))))) (defun restore-temps () (dotimes (i *real-registers*) (cond ((temp-node i) (setf (temp-loc (temp-node i)) i))))) (defvar *pushed-o-regs* '()) (defun push-o-regs () (do ((o O0 (1+ o)) (frame ())) ((>= o ON) (push frame *pushed-o-regs*)) (let ((value (reg-node o))) (when value (push (cons o value) frame) (kill value))))) (defun pop-o-regs () (clear-o-regs) (dolist (reg-val (pop *pushed-o-regs*)) (mark (cdr reg-val) (car reg-val)))) ;;; say that the o regs are bashed ;;; called when about to do a call -efh (defun clear-o-regs () (do ((o O0 (1+ o))) ((>= o ON)) (unlock o) ;locked by parallel-assign (kill (reg-node o)))) (defun clear-slots () (dotimes (i (array-dimension *registers* 0)) (setf (svref *registers* i) nil)) ; (recycle *locations*) (setq *locations* (make-table 'locations))) (defun protect-access (access) (cond ((integerp access) (cond ((>= access 0) (lock access)))) ; ((fg? access)) ((register? (car access)) (if (/= (car access) SP) (lock (car access)))) ((consp (car access)) (lock (caar access)) (lock (cdar access))))) (defun release-access (access) (cond ((integerp access) (cond ((>= access 0) (unlock access)))) ; ((fg? access)) ((register? (car access)) (if (/= (car access) SP) (unlock (car access)))) ((consp (car access)) (unlock (caar access)) (unlock (cdar access))))) (defun mark (value reg) (setf (reg-node reg) value) (if (register? reg) (setf (register-loc value) reg) (setf (temp-loc value) reg))) (defun mark-temp (value reg) (setf (temp-node reg) value) (setf (temp-loc value) reg))