1 ;;;; the implementation-independent parts of the code generator. We use
2 ;;;; functions and information provided by the VM definition to convert
3 ;;;; IR2 into assembly code. After emitting code, we finish the
4 ;;;; assembly and then do the post-assembly phase.
6 ;;;; This software is part of the SBCL system. See the README file for
9 ;;;; This software is derived from the CMU CL system, which was
10 ;;;; written at Carnegie Mellon University and released into the
11 ;;;; public domain. The software is in the public domain and is
12 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
13 ;;;; files for more information.
17 ;;;; utilities used during code generation
19 ;;; the number of bytes used by the code object header
20 (defun component-header-length (&optional
21 (component *component-being-compiled
*))
22 (let* ((2comp (component-info component
))
23 (constants (ir2-component-constants 2comp
))
24 (num-consts (length constants
)))
25 (ash (logandc2 (1+ num-consts
) 1) sb
!vm
:word-shift
)))
27 ;;; the size of the NAME'd SB in the currently compiled component.
28 ;;; This is useful mainly for finding the size for allocating stack
30 (defun sb-allocated-size (name)
31 (finite-sb-current-size (sb-or-lose name
)))
33 ;;; the TN that is used to hold the number stack frame-pointer in
34 ;;; VOP's function, or NIL if no number stack frame was allocated
35 (defun current-nfp-tn (vop)
36 (unless (zerop (sb-allocated-size 'non-descriptor-stack
))
37 (let ((block (ir2-block-block (vop-block vop
))))
38 (when (ir2-physenv-number-stack-p
40 (block-physenv block
)))
41 (ir2-component-nfp (component-info (block-component block
)))))))
43 ;;; the TN that is used to hold the number stack frame-pointer in the
44 ;;; function designated by 2ENV, or NIL if no number stack frame was
46 (defun callee-nfp-tn (2env)
47 (unless (zerop (sb-allocated-size 'non-descriptor-stack
))
48 (when (ir2-physenv-number-stack-p 2env
)
49 (ir2-component-nfp (component-info *component-being-compiled
*)))))
51 ;;; the TN used for passing the return PC in a local call to the function
52 ;;; designated by 2ENV
53 (defun callee-return-pc-tn (2env)
54 (ir2-physenv-return-pc-pass 2env
))
56 ;;;; specials used during code generation
58 (defvar *trace-table-info
*)
59 (defvar *code-segment
* nil
)
60 (defvar *elsewhere
* nil
)
61 (defvar *elsewhere-label
* nil
)
64 (defvar *constant-segment
* nil
)
65 (defvar *constant-table
* nil
)
66 (defvar *constant-vector
* nil
))
69 ;;;; noise to emit an instruction trace
71 (defvar *prev-segment
*)
74 (defun trace-instruction (segment vop inst args
)
75 (let ((*standard-output
* *compiler-trace-output
*))
76 (unless (eq *prev-segment
* segment
)
77 (format t
"in the ~A segment:~%" (sb!assem
:segment-type segment
))
78 (setf *prev-segment
* segment
))
79 (unless (eq *prev-vop
* vop
)
84 (format *compiler-trace-output
* "~S~%" vop
)))
86 (setf *prev-vop
* vop
))
89 (format t
"~A:~%" args
))
91 (format t
"~0,8T.align~0,8T~A~%" args
))
93 (format t
"~0,8T~A~@[~0,8T~{~A~^, ~}~]~%" inst args
))))
96 ;;;; GENERATE-CODE and support routines
98 ;;; standard defaults for slots of SEGMENT objects
99 (defun default-segment-run-scheduler ()
100 (and *assembly-optimize
*
103 (block-next (component-head *component-being-compiled
*))))
104 (or (> speed compilation-speed
) (> space compilation-speed
)))))
105 (defun default-segment-inst-hook ()
106 (and *compiler-trace-output
*
107 #'trace-instruction
))
109 (defun init-assembler ()
111 (sb!assem
:make-segment
:type
:regular
112 :run-scheduler
(default-segment-run-scheduler)
113 :inst-hook
(default-segment-inst-hook)))
115 (setf (sb!assem
:segment-collect-dynamic-statistics
*code-segment
*)
116 *collect-dynamic-statistics
*)
118 (sb!assem
:make-segment
:type
:elsewhere
119 :run-scheduler
(default-segment-run-scheduler)
120 :inst-hook
(default-segment-inst-hook)
123 (setf *constant-segment
*
124 (sb!assem
:make-segment
:type
:elsewhere
126 :inst-hook
(default-segment-inst-hook)
128 *constant-table
* (make-hash-table :test
#'equal
)
129 *constant-vector
* (make-array 16 :adjustable t
:fill-pointer
0))
132 (defun generate-code (component)
133 (when *compiler-trace-output
*
134 (format *compiler-trace-output
*
135 "~|~%assembly code for ~S~2%"
138 (*trace-table-info
* nil
)
142 (let ((label (sb!assem
:gen-label
)))
143 (setf *elsewhere-label
* label
)
144 (sb!assem
:assemble
(*elsewhere
*)
145 (sb!assem
:emit-label label
)))
146 (do-ir2-blocks (block component
)
147 (let ((1block (ir2-block-block block
)))
148 (when (and (eq (block-info 1block
) block
)
149 (block-start 1block
))
150 (sb!assem
:assemble
(*code-segment
*)
151 ;; Align first emitted block of each loop: x86 and x86-64 both
152 ;; like 16 byte alignment, however, since x86 aligns code objects
153 ;; on 8 byte boundaries we cannot guarantee proper loop alignment
156 (let ((cloop (sb!c
::block-loop
1block
)))
158 (sb!c
::loop-tail cloop
)
159 (not (sb!c
::loop-info cloop
)))
160 (sb!assem
:emit-alignment sb
!vm
:n-lowtag-bits
#x90
)
161 ;; Mark the loop as aligned by saving the IR1 block aligned.
162 (setf (sb!c
::loop-info cloop
) 1block
)))
163 (sb!assem
:emit-label
(block-label 1block
)))
164 (let ((env (block-physenv 1block
)))
165 (unless (eq env prev-env
)
166 (let ((lab (gen-label)))
167 (setf (ir2-physenv-elsewhere-start (physenv-info env
))
169 (emit-label-elsewhere lab
))
170 (setq prev-env env
)))))
171 (do ((vop (ir2-block-start-vop block
) (vop-next vop
)))
173 (let ((gen (vop-info-generator-function (vop-info vop
))))
177 "missing generator for ~S~%"
178 (template-name (vop-info vop
)))))))
179 (sb!assem
:append-segment
*code-segment
* *elsewhere
*)
180 (setf *elsewhere
* nil
)
183 (unless (zerop (length *constant-vector
*))
184 (let ((constants (sb!vm
:sort-inline-constants
*constant-vector
*)))
185 (assemble (*constant-segment
*)
186 (sb!vm
:emit-constant-segment-header
188 (do-ir2-blocks (2block component nil
)
189 (when (policy (block-last (ir2-block-block 2block
))
192 (map nil
(lambda (constant)
193 (sb!vm
:emit-inline-constant
(car constant
) (cdr constant
)))
195 (sb!assem
:append-segment
*code-segment
* *constant-segment
*))
196 (setf *constant-segment
* nil
197 *constant-vector
* nil
198 *constant-table
* nil
))
199 (values (sb!assem
:finalize-segment
*code-segment
*)
200 (nreverse *trace-table-info
*)
203 (defun emit-label-elsewhere (label)
204 (sb!assem
:assemble
(*elsewhere
*)
205 (sb!assem
:emit-label label
)))
207 (defun label-elsewhere-p (label-or-posn)
208 (<= (label-position *elsewhere-label
*)
209 (etypecase label-or-posn
211 (label-position label-or-posn
))
216 (defun register-inline-constant (&rest constant-descriptor
)
217 (declare (dynamic-extent constant-descriptor
))
218 (let ((constant (sb!vm
:canonicalize-inline-constant constant-descriptor
)))
219 (or (gethash constant
*constant-table
*)
220 (multiple-value-bind (label value
) (sb!vm
:inline-constant-value constant
)
221 (vector-push-extend (cons constant label
) *constant-vector
*)
222 (setf (gethash constant
*constant-table
*) value
)))))