source: branches/1.1/ccl/compiler/X86/x86-backend.lisp

Last change on this file was 6466, checked in by Gary Byers, 18 years ago

Allow label-valued temporaries, support :talign directive in vinsn templates.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.2 KB
Line 
1;;;-*- Mode: Lisp; Package: CCL -*-
2;;;
3;;; Copyright (C) 2005, Clozure Associates
4;;; This file is part of OpenMCL.
5;;;
6;;; OpenMCL is licensed under the terms of the Lisp Lesser GNU Public
7;;; License , known as the LLGPL and distributed with OpenMCL as the
8;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL,
9;;; which is distributed with OpenMCL as the file "LGPL". Where these
10;;; conflict, the preamble takes precedence.
11;;;
12;;; OpenMCL is referenced in the preamble as the "LIBRARY."
13;;;
14;;; The LLGPL is also available online at
15;;; http://opensource.franz.com/preamble.html
16
17(in-package "CCL")
18
19(next-nx-defops)
20(defvar *x862-specials* nil)
21(let* ((newsize (%i+ (next-nx-num-ops) 10))
22 (old *x862-specials*)
23 (oldsize (length old)))
24 (declare (fixnum newsize oldsize))
25 (unless (>= oldsize newsize)
26 (let* ((v (make-array newsize :initial-element nil)))
27 (dotimes (i oldsize (setq *x862-specials* v))
28 (setf (svref v i) (svref old i))))))
29
30(defun x86-encode-vinsn-operand-type (thing backend)
31 (when thing
32 (if (atom thing)
33 (x86::encode-operand-type :label)
34 (ecase (car thing)
35 (:% (ecase (arch::target-lisp-node-size (backend-target-arch backend))
36 (8 (x86::encode-operand-type :reg64))
37 (4 (x86::encode-operand-type :reg32))))
38 (:%q (x86::encode-operand-type :reg64))
39 (:%l (x86::encode-operand-type :reg32))
40 (:%w (x86::encode-operand-type :reg16))
41 (:%b (x86::encode-operand-type :reg8))
42 (:%xmm (x86::encode-operand-type :regxmm))
43 (:%mmx (x86::encode-operand-type :regmmx))
44 (:@ (x86::encode-operand-type :anymem))
45 (:$1 (x86::encode-operand-type :imm1) )
46 (:$b (x86::encode-operand-type :imm8s ))
47 (:$ub (x86::encode-operand-type :imm8))
48 (:$w (x86::encode-operand-type :imm16))
49 (:$l (x86::encode-operand-type :imm32s))
50 (:$ul (x86::encode-operand-type :imm32))
51 (:$q (x86::encode-operand-type :imm64))
52 (:%shift (x86::encode-operand-type :shiftcount :reg8))))))
53
54(defun lookup-x86-opcode (form backend)
55 (when (consp form)
56 (let* ((name (string (car form)))
57 (templates (gethash name x86::*x86-opcode-template-lists*)))
58 (declare (fixnum node-size))
59 (when templates
60 (flet ((optype (thing)
61 (x86-encode-vinsn-operand-type thing backend)))
62 (let* ((operands (cdr form))
63 (type0 (optype (pop operands)))
64 (type1 (optype (pop operands)))
65 (type2 (optype (car operands))))
66 (dolist (template templates)
67 (when (x86::match-template-types template type0 type1 type2)
68 (collect ((types))
69 (if type0 (types type0))
70 (if type1 (types type1))
71 (if type2 (types type2))
72 (return (values (x86::x86-opcode-template-ordinal template)
73 (types))))))))))))
74
75(defun fixup-opcode-ordinals (vinsn-template opcode-templates)
76 (let* ((changed ()))
77 (dolist (vinsn-opcode (vinsn-template-opcode-alist vinsn-template))
78 (destructuring-bind (old-ordinal name &optional type0 type1 type2) vinsn-opcode
79 (let* ((opcode-templates (gethash name opcode-templates)))
80 (unless opcode-templates
81 (error "Unknown X86 instruction - ~a. Odd, because it was once a known instruction." name))
82 (let* ((new-ordinal (dolist (template opcode-templates)
83 (when (x86::match-template-types template type0 type1 type2)
84 (return (x86::x86-opcode-template-ordinal template))))))
85 (unless new-ordinal
86 (error "No match for opcode ~s in ~s" vinsn-opcode vinsn-template))
87 (unless (eql old-ordinal new-ordinal)
88 (setf (car vinsn-opcode) new-ordinal)
89 (push (cons old-ordinal new-ordinal) changed))))))
90 (when changed
91 ;;(format t "~& opcode ordinals changed in ~s: ~s" vinsn-template changed)
92 (flet ((update-instruction (i)
93 (when (consp i)
94 (let* ((pair (assoc (car i) changed :test #'eq)))
95 (when pair
96 (setf (car i) (cdr pair)))))))
97 (labels ((fixup-form (form)
98 (unless (atom form)
99 (if (atom (car form))
100 (update-instruction form)
101 (dolist (f (cdr form))
102 (fixup-form f))))))
103 (dolist (form (vinsn-template-body vinsn-template))
104 (fixup-form form)))))))
105
106(defparameter *report-missing-vinsns* nil)
107
108(defun fixup-x86-vinsn-templates (template-hash opcode-templates)
109 (maphash #'(lambda (name vinsn-template)
110 (if (not (cdr vinsn-template))
111 (when *report-missing-vinsns*
112 (warn "Reference to undefined vinsn ~s" name))
113 (fixup-opcode-ordinals (cdr vinsn-template) opcode-templates)))
114 template-hash))
115
116
117
118;;; This defines a template. All expressions in the body must be
119;;; evaluable at macroexpansion time.
120(defun define-x86-vinsn (backend vinsn-name results args temps body)
121 (let* ((opcode-lookup (backend-lookup-opcode backend))
122 (backend-name (backend-name backend))
123 (arch-name (backend-target-arch-name backend))
124 (template-hash (backend-p2-template-hash-name backend))
125 (name-list ())
126 (attrs 0)
127 (nhybrids 0)
128 (local-labels ())
129 (referenced-labels ())
130 (source-indicator (form-symbol arch-name "-VINSN"))
131 (opcode-alist ()))
132 (flet ((valid-spec-name (x)
133 (or (and (consp x)
134 (consp (cdr x))
135 (null (cddr x))
136 (atom (car x))
137 (or (assoc (cadr x) *vreg-specifier-constant-constraints* :test #'eq)
138 (assoc (cadr x) *spec-class-storage-class-alist* :test #'eq)
139 (eq (cadr x) :label)
140 (and (consp (cadr x)) (eq (caadr x) :label) (consp (cdadr x)) (null (cddadr x)))
141 (and (consp (cadr x))
142 (or
143 (assoc (caadr x) *vreg-specifier-constant-constraints* :test #'eq)
144 (assoc (caadr x) *spec-class-storage-class-alist* :test #'eq))))
145 (car x))
146 (error "Invalid vreg spec: ~s" x)))
147 (add-spec-name (vname)
148 (if (member vname name-list :test #'eq)
149 (error "Duplicate name ~s in vinsn ~s" vname vinsn-name)
150 (push vname name-list))))
151 (declare (dynamic-extent valid-spec-name add-spec-name))
152 (when (consp vinsn-name)
153 (setq attrs (encode-vinsn-attributes (cdr vinsn-name))
154 vinsn-name (car vinsn-name)))
155 (unless (and (symbolp vinsn-name) (eq *CCL-PACKAGE* (symbol-package vinsn-name)))
156 (setq vinsn-name (intern (string vinsn-name) *CCL-PACKAGE*)))
157 (dolist (n (append args temps))
158 (add-spec-name (valid-spec-name n)))
159 (dolist (form body)
160 (if (atom form)
161 (add-spec-name form)))
162 (setq name-list (nreverse name-list))
163 ;; We now know that "args" is an alist; we don't know if
164 ;; "results" is. First, make sure that there are no duplicate
165 ;; result names (and validate "results".)
166 (do* ((res results tail)
167 (tail (cdr res) (cdr tail)))
168 ((null res))
169 (let* ((name (valid-spec-name (car res))))
170 (if (assoc name tail :test #'eq)
171 (error "Duplicate result name ~s in ~s." name results))))
172 (let* ((non-hybrid-results ())
173 (match-args args))
174 (dolist (res results)
175 (let* ((res-name (car res)))
176 (if (not (assoc res-name args :test #'eq))
177 (if (not (= nhybrids 0))
178 (error "result ~s should also name an argument. " res-name)
179 (push res-name non-hybrid-results))
180 (if (eq res-name (caar match-args))
181 (setf nhybrids (1+ nhybrids)
182 match-args (cdr match-args))
183 (error "~S - hybrid results should appear in same order as arguments." res-name)))))
184 (dolist (name non-hybrid-results)
185 (add-spec-name name)))
186 (let* ((k -1))
187 (declare (fixnum k))
188 (let* ((name-alist (mapcar #'(lambda (n) (cons n (list (incf k)))) name-list)))
189 (flet ((find-name (n)
190 (let* ((pair (assoc n name-alist :test #'eq)))
191 (declare (list pair))
192 (if pair
193 (cdr pair)
194 (or (subprim-name->offset n backend)
195 (error "Unknown name ~s" n))))))
196 (labels ((simplify-simple-operand (op)
197 (if (atom op)
198 (if (typep op 'fixnum)
199 op
200 (if (eq op :rcontext)
201 op
202 (if (constantp op)
203 (progn
204 (if (keywordp op)
205 (pushnew op referenced-labels))
206 (eval op))
207 (find-name op))))
208 (if (eq (car op) :^)
209 (list :^ (simplify-simple-operand (cadr op)))
210 (if (eq (car op) :apply)
211 `(,(cadr op) ,@(mapcar #'simplify-operand (cddr op)))
212 (if (member (car op)
213 '(:tra :align :byte :word :long :quad :talign))
214 `(,(car op) ,(simplify-operand (cadr op)))
215 (simplify-operand (eval op))))))) ; Handler-case this?
216 (simplify-memory-operand (op)
217 ;; This happens to be the only place that
218 ;; we allow segment registers.
219 (let* ((seg nil)
220 (disp nil)
221 (base nil)
222 (index nil)
223 (scale nil))
224 (do* ((form op (cdr form)))
225 ((null form) (list seg disp base index scale))
226 (let* ((head (car form)))
227 (if (consp head)
228 (case (car head)
229 (:%seg
230 (if (eq form op)
231 (setq seg (simplify-operand (cadr head)))
232 (error "Bad :%seg in ~s" op)))
233 ((:%q :% :%l)
234 (let* ((r (simplify-operand head)))
235 (if base
236 (if index
237 (error "Extra register ~s in ~s"
238 head op)
239 (setq index r))
240 (setq base r))))
241 (t
242 (if (and (null (cdr form))
243 (or disp base index))
244 (progn
245 (setq scale (simplify-simple-operand head))
246 (if (and base (not index))
247 (setq index base base nil)))
248 (if (not (or disp base index))
249 (setq disp (simplify-simple-operand head))
250 (error "~s not expected in ~s" op)))))
251 (if (and (null (cdr form))
252 (or disp base index))
253 (progn
254 (setq scale (simplify-simple-operand head))
255 (if (and base (not index))
256 (setq index base base nil)))
257 (if (not (or disp base index))
258 (setq disp (simplify-simple-operand head))
259 (error "~s not expected in ~s" op))))))))
260 (simplify-operand (op)
261 (cond ((atom op)
262 (simplify-simple-operand op))
263 ((eq (car op) :@)
264 (cons :@
265 (simplify-memory-operand (cdr op))))
266 ((member (car op)
267 '(:% :%q :%l :%w :%b :$ :$1 :$b :$ub :$w :$l
268 :$ul :$q :%mmx :%xmm :%shift))
269 (simplify-simple-operand (cadr op)))
270 (t
271 (simplify-simple-operand op)))))
272 (labels ((simplify-constraint (guard)
273 ;; A constraint is one of
274
275 ;; (:eq|:lt|:gt vreg-name constant) ; "value"
276 ;; of vreg relop constant
277
278 ;; (:pred <function-name> <operand>* ;
279 ;; <function-name> unquoted, each <operand>
280 ;; is a vreg-name or constant expression.
281
282 ;; (:type vreg-name typeval) ; vreg is of
283 ;; "type" typeval
284 ;;
285 ;;(:not <constraint>) ; constraint is false
286 ;; (:and <constraint> ...) ; conjuntion
287 ;; (:or <constraint> ...) ; disjunction
288 ;; There's no "else"; we'll see how ugly it
289 ;; is without one.
290 (destructuring-bind (guardname &rest others) guard
291 (ecase guardname
292 (:not
293 (destructuring-bind (negation) others
294 `(:not ,(simplify-constraint negation))))
295 (:pred
296 (destructuring-bind (predicate &rest operands) others
297 `(:pred ,predicate ,@(mapcar #'simplify-operand operands))))
298 ((:eq :lt :gt :type)
299 (destructuring-bind (vreg constant) others
300 (unless (constantp constant)
301 (error "~S : not constant in constraint ~s ." constant guard))
302 `(,guardname ,(find-name vreg) ,(eval constant))))
303 ((:or :and)
304 (unless others (error "Missing constraint list in ~s ." guard))
305 `(,guardname ,(mapcar #'simplify-constraint others))))))
306 (simplify-form (form)
307 (if (atom form)
308 (progn
309 (if (keywordp form) (push form local-labels) )
310 form)
311 (destructuring-bind (&whole w opname &rest opvals) form
312 (if (consp opname) ; A constraint, we presume ...
313 (cons (simplify-constraint opname)
314 (mapcar #'simplify-form opvals))
315 (if (keywordp opname)
316 (progn
317 (list opname
318 (simplify-operand (car opvals)))
319 )
320 (let* ((name (string opname)))
321 (multiple-value-bind (opnum types)
322 (funcall opcode-lookup form backend)
323 (if (not opnum)
324 (error "Unknown ~A instruction in ~s" backend-name form)
325 (let* ((opvals (mapcar #'simplify-operand opvals)))
326 (setf (assq opnum opcode-alist) (cons name types))
327 `(,opnum ,@opvals)))))))))))
328 (let* ((template (make-vinsn-template :name vinsn-name
329 :result-vreg-specs results
330 :argument-vreg-specs args
331 :temp-vreg-specs temps
332 :nhybrids nhybrids
333 :results&args (append results (nthcdr nhybrids args))
334 :nvp (- (+ (length results) (length args) (length temps))
335 nhybrids)
336 :body (prog1 (mapcar #'simplify-form body)
337 (dolist (ref referenced-labels)
338 (unless (memq ref local-labels)
339 (error
340 "local-label ~S was referenced but ~
341 never defined in VINSN-TEMPLATE definition for ~s"
342 ref vinsn-name))))
343 :local-labels local-labels
344 :attributes attrs
345 :opcode-alist opcode-alist)))
346
347 `(progn
348 (set-vinsn-template ',vinsn-name ,template ,template-hash)
349 (record-source-file ',vinsn-name ',source-indicator)
350 ',vinsn-name))))))))))
351
352
353
354#+x8632-target
355(require "X8632-BACKEND")
356#+x8664-target
357(require "X8664-BACKEND")
358
359(defparameter *x86-backend*
360 #+x8632-target *x8632-backend*
361 #+x8664-target *x8664-backend*
362 #-x86-target nil)
363
364
365(defun fixup-x86-backend (&rest args)
366 #+x8632-target (apply #'fixup-x8632-backend args)
367 #+x8664-target (apply #'fixup-x8664-backend args)
368 #-x86-target (declare (ignore args))
369 )
370
371(provide "X86-BACKEND")
Note: See TracBrowser for help on using the repository browser.