Simplify EMIT-GENERIC-VOP.
[sbcl.git] / src / compiler / vmdef.lisp
1 ;;;; implementation-independent facilities used for defining the
2 ;;;; compiler's interface to the VM in a given implementation
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
12
13 (in-package "SB!C")
14
15 ;;; Return the template having the specified name, or die trying.
16 (defun template-or-lose (x)
17   (the template
18        (or (gethash x *backend-template-names*)
19            (error "~S is not a defined template." x))))
20
21 ;;; Return the SC structure, SB structure or SC number corresponding
22 ;;; to a name, or die trying.
23 (defun sc-or-lose (x)
24   (the sc
25        (or (gethash x *backend-sc-names*)
26            (error "~S is not a defined storage class." x))))
27 (defun sb-or-lose (x)
28   (the sb
29        (or (gethash x *backend-sb-names*)
30            (error "~S is not a defined storage base." x))))
31 (defun sc-number-or-lose (x)
32   (the sc-number (sc-number (sc-or-lose x))))
33
34 ;;; This is like the non-meta versions, except we go for the
35 ;;; meta-compile-time info. These should not be used after load time,
36 ;;; since compiling the compiler changes the definitions.
37 (defun meta-sc-or-lose (x)
38   (the sc
39        (or (gethash x *backend-meta-sc-names*)
40            (error "~S is not a defined storage class." x))))
41 (defun meta-sb-or-lose (x)
42   (the sb
43        (or (gethash x *backend-meta-sb-names*)
44            (error "~S is not a defined storage base." x))))
45 (defun meta-sc-number-or-lose (x)
46   (the sc-number (sc-number (meta-sc-or-lose x))))
47 \f
48 ;;;; side effect classes
49
50 (!def-boolean-attribute vop
51   any)
52 \f
53 ;;;; move/coerce definition
54
55 ;;; Compute at compiler load time the costs for moving between all SCs that
56 ;;; can be loaded from FROM-SC and to TO-SC given a base move cost Cost.
57 (defun compute-move-costs (from-sc to-sc cost)
58   (declare (type sc from-sc to-sc) (type index cost))
59   (let ((to-scn (sc-number to-sc))
60         (from-costs (sc-load-costs from-sc)))
61     (dolist (dest-sc (cons to-sc (sc-alternate-scs to-sc)))
62       (let ((vec (sc-move-costs dest-sc))
63             (dest-costs (sc-load-costs dest-sc)))
64         (setf (svref vec (sc-number from-sc)) cost)
65         (dolist (sc (append (sc-alternate-scs from-sc)
66                             (sc-constant-scs from-sc)))
67           (let* ((scn (sc-number sc))
68                  (total (+ (svref from-costs scn)
69                            (svref dest-costs to-scn)
70                            cost))
71                  (old (svref vec scn)))
72             (unless (and old (< old total))
73               (setf (svref vec scn) total))))))))
74 \f
75 ;;;; primitive type definition
76
77 ;;; Return the primitive type corresponding to the specified name, or
78 ;;; die trying.
79 (defun primitive-type-or-lose (name)
80   (the primitive-type
81        (or (gethash name *backend-primitive-type-names*)
82            (error "~S is not a defined primitive type." name))))
83
84 ;;; Return true if SC is either one of PTYPE's SC's, or one of those
85 ;;; SC's alternate or constant SCs.
86 (defun sc-allowed-by-primitive-type (sc ptype)
87   (declare (type sc sc) (type primitive-type ptype))
88   (let ((scn (sc-number sc)))
89     (dolist (allowed (primitive-type-scs ptype) nil)
90       (when (eql allowed scn)
91         (return t))
92       (let ((allowed-sc (svref *backend-sc-numbers* allowed)))
93         (when (or (member sc (sc-alternate-scs allowed-sc))
94                   (member sc (sc-constant-scs allowed-sc)))
95           (return t))))))
96 \f
97 ;;;; generation of emit functions
98
99 (eval-when (:compile-toplevel :load-toplevel :execute)
100   ;; We need the EVAL-WHEN because EMIT-VOP (below)
101   ;; uses #.MAX-VOP-TN-REFS, not just MAX-VOP-TN-REFS.
102   ;; -- AL 20010218
103   ;;
104   ;; See also the description of VOP-INFO-TARGETS. -- APD, 2002-01-30
105   (def!constant max-vop-tn-refs 256))
106
107 ;;; FIXME: This is a remarkably eccentric way of implementing what
108 ;;; would appear to be by nature a closure.  A closure isn't any more
109 ;;; threadsafe than this special variable implementation, but at least
110 ;;; it's more idiomatic, and one could imagine closing over an
111 ;;; extensible pool to make a thread-safe implementation.
112 (declaim (type (simple-vector #.max-vop-tn-refs) *vop-tn-refs*))
113 (defvar *vop-tn-refs* (make-array max-vop-tn-refs :initial-element nil))
114
115 (def!constant sc-bits (integer-length (1- sc-number-limit)))
116
117 ;; a function that emits the VOPs for this template. Arguments:
118 ;;  1] Node for source context.
119 ;;  2] IR2-BLOCK that we place the VOP in.
120 ;;  3] This structure.
121 ;;  4] Head of argument TN-REF list.
122 ;;  5] Head of result TN-REF list.
123 ;;  6] If INFO-ARG-COUNT is non-zero, then a list of the magic
124 ;;     arguments.
125 ;;
126 ;; Two values are returned: the first and last VOP emitted. This vop
127 ;; sequence must be linked into the VOP Next/Prev chain for the
128 ;; block. At least one VOP is always emitted.
129 (defun emit-vop (node block template args results &optional info)
130   (let* ((vop (make-vop block node template args results))
131          (num-args (vop-info-num-args template))
132          (last-arg (1- num-args))
133          (num-results (vop-info-num-results template))
134          (num-operands (+ num-args num-results))
135          (last-result (1- num-operands))
136          (ref-ordering (vop-info-ref-ordering template)))
137     (declare (type vop vop)
138              (type (integer 0 #.max-vop-tn-refs)
139                    num-args num-results num-operands)
140              (type (integer -1 #.(1- max-vop-tn-refs)) last-arg last-result))
141     (setf (vop-codegen-info vop) info)
142     (unwind-protect
143          (let ((refs *vop-tn-refs*))
144            (declare (type (simple-vector #.max-vop-tn-refs) refs))
145            (do ((index 0 (1+ index))
146                 (ref args (and ref (tn-ref-across ref))))
147                ((= index num-args))
148              (setf (svref refs index) ref))
149            (do ((index num-args (1+ index))
150                 (ref results (and ref (tn-ref-across ref))))
151                ((= index num-operands))
152              (setf (svref refs index) ref))
153            (let ((temps (vop-info-temps template)))
154              (when temps
155                (let ((index num-operands)
156                      (prev nil))
157                  (dotimes (i (length temps))
158                    (let* ((temp (aref temps i))
159                           (tn (if (logbitp 0 temp)
160                                   (make-wired-tn nil
161                                                  (ldb (byte sc-bits 1) temp)
162                                                  (ash temp (- (1+ sc-bits))))
163                                   (make-restricted-tn nil (ash temp -1))))
164                           (write-ref (reference-tn tn t)))
165                      ;; KLUDGE: These formulas must be consistent with
166                      ;; those in COMPUTE-REF-ORDERING, and this is
167                      ;; currently maintained by hand. -- WHN
168                      ;; 2002-01-30, paraphrasing APD
169                      (setf (aref refs index) (reference-tn tn nil))
170                      (setf (aref refs (1+ index)) write-ref)
171                      (if prev
172                          (setf (tn-ref-across prev) write-ref)
173                          (setf (vop-temps vop) write-ref))
174                      (setf prev write-ref)
175                      (incf index 2))))))
176            (let ((prev nil))
177              (flet ((add-ref (ref)
178                       (setf (tn-ref-vop ref) vop)
179                       (setf (tn-ref-next-ref ref) prev)
180                       (setf prev ref)))
181                (declare (inline add-ref))
182                (dotimes (i (length ref-ordering))
183                  (let* ((index (aref ref-ordering i))
184                         (ref (aref refs index)))
185                    (if (or (= index last-arg) (= index last-result))
186                        (do ((ref ref (tn-ref-across ref)))
187                            ((null ref))
188                          (add-ref ref))
189                        (add-ref ref)))))
190              (setf (vop-refs vop) prev))
191            (let ((targets (vop-info-targets template)))
192              (when targets
193                (dotimes (i (length targets))
194                  (let ((target (aref targets i)))
195                    (target-if-desirable
196                     (aref refs (ldb (byte 8 8) target))
197                     (aref refs (ldb (byte 8 0) target)))))))
198            (values vop vop))
199       (fill *vop-tn-refs* nil))))
200 \f
201 ;;;; function translation stuff
202
203 ;;; Add Template into List, removing any old template with the same name.
204 ;;; We also maintain the increasing cost ordering.
205 (defun adjoin-template (template list)
206   (declare (type template template) (list list))
207   (sort (cons template
208               (remove (template-name template) list
209                       :key #'template-name))
210         #'<=
211         :key #'template-cost))
212 \f
213 ;;; Return a function type specifier describing TEMPLATE's type computed
214 ;;; from the operand type restrictions.
215 (defun template-type-specifier (template)
216   (declare (type template template))
217   (flet ((convert (types more-types)
218            (flet ((frob (x)
219                     (if (eq x '*)
220                         t
221                         (ecase (first x)
222                           (:or `(or ,@(mapcar #'primitive-type-specifier
223                                               (rest x))))
224                           (:constant `(constant-arg ,(third x)))))))
225              `(,@(mapcar #'frob types)
226                ,@(when more-types
227                    `(&rest ,(frob more-types)))))))
228     (let* ((args (convert (template-arg-types template)
229                           (template-more-args-type template)))
230            (result-restr (template-result-types template))
231            (results (if (template-conditional-p template)
232                         '(boolean)
233                         (convert result-restr
234                                  (cond ((template-more-results-type template))
235                                        ((/= (length result-restr) 1) '*)
236                                        (t nil))))))
237       `(function ,args
238                  ,(if (= (length results) 1)
239                       (first results)
240                       `(values ,@results))))))
241
242 #!-sb-fluid (declaim (inline template-conditional-p))
243 (defun template-conditional-p (template)
244   (declare (type template template))
245   (let ((rtypes (template-result-types template)))
246     (or (eq rtypes :conditional)
247         (eq (car rtypes) :conditional))))