0.6.12.11:
[sbcl.git] / src / compiler / codegen.lisp
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.
5
6 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; more information.
8 ;;;;
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.
14
15 (in-package "SB!C")
16 \f
17 ;;;; utilities used during code generation
18
19 (defun component-header-length (&optional
20                                 (component *component-being-compiled*))
21   #!+sb-doc
22   "Returns the number of bytes used by the code object header."
23   (let* ((2comp (component-info component))
24          (constants (ir2-component-constants 2comp))
25          (num-consts (length constants)))
26     (ash (logandc2 (1+ num-consts) 1) sb!vm:word-shift)))
27
28 (defun sb-allocated-size (name)
29   #!+sb-doc
30   "The size of the Name'd SB in the currently compiled component. Useful
31   mainly for finding the size for allocating stack frames."
32   (finite-sb-current-size (sb-or-lose name)))
33
34 (defun current-nfp-tn (vop)
35   #!+sb-doc
36   "Return the TN that is used to hold the number stack frame-pointer in VOP's
37   function. Returns NIL if no number stack frame was allocated."
38   (unless (zerop (sb-allocated-size 'non-descriptor-stack))
39     (let ((block (ir2-block-block (vop-block vop))))
40     (when (ir2-environment-number-stack-p
41            (environment-info
42             (block-environment block)))
43       (ir2-component-nfp (component-info (block-component block)))))))
44
45 (defun callee-nfp-tn (2env)
46   #!+sb-doc
47   "Return the TN that is used to hold the number stack frame-pointer in the
48   function designated by 2env. Returns NIL if no number stack frame was
49   allocated."
50   (unless (zerop (sb-allocated-size 'non-descriptor-stack))
51     (when (ir2-environment-number-stack-p 2env)
52       (ir2-component-nfp (component-info *component-being-compiled*)))))
53
54 (defun callee-return-pc-tn (2env)
55   #!+sb-doc
56   "Return the TN used for passing the return PC in a local call to the function
57   designated by 2env."
58   (ir2-environment-return-pc-pass 2env))
59 \f
60 ;;;; specials used during code generation
61
62 (defvar *trace-table-info*)
63 (defvar *code-segment* nil)
64 (defvar *elsewhere* nil)
65 (defvar *elsewhere-label* nil)
66 \f
67 ;;;; noise to emit an instruction trace
68
69 (defvar *prev-segment*)
70 (defvar *prev-vop*)
71
72 (defun trace-instruction (segment vop inst args)
73   (let ((*standard-output* *compiler-trace-output*))
74     (unless (eq *prev-segment* segment)
75       (format t "in the ~A segment:~%" (sb!assem:segment-name segment))
76       (setf *prev-segment* segment))
77     (unless (eq *prev-vop* vop)
78       (when vop
79         (format t "~%VOP ")
80         (if (vop-p vop)
81             (print-vop vop)
82             (format *compiler-trace-output* "~S~%" vop)))
83       (terpri)
84       (setf *prev-vop* vop))
85     (case inst
86       (:label
87        (format t "~A:~%" args))
88       (:align
89        (format t "~0,8T.align~0,8T~A~%" args))
90       (t
91        (format t "~0,8T~A~@[~0,8T~{~A~^, ~}~]~%" inst args))))
92   (values))
93 \f
94 ;;;; GENERATE-CODE and support routines
95
96 ;;; standard defaults for slots of SEGMENT objects
97 (defun default-segment-run-scheduler ()
98   (and *assembly-optimize*
99         (policy (lambda-bind
100                  (block-home-lambda
101                   (block-next (component-head *component-being-compiled*))))
102                 (or (> speed compilation-speed) (> space compilation-speed)))))
103 (defun default-segment-inst-hook ()
104   (and *compiler-trace-output*
105        #'trace-instruction))
106
107 (defun init-assembler ()
108   (setf *code-segment*
109         (sb!assem:make-segment :name "regular"
110                                :run-scheduler (default-segment-run-scheduler)
111                                :inst-hook (default-segment-inst-hook)))
112   #!+sb-dyncount
113   (setf (sb!assem:segment-collect-dynamic-statistics *code-segment*)
114         *collect-dynamic-statistics*)
115   (setf *elsewhere*
116         (sb!assem:make-segment :name "elsewhere"
117                                :run-scheduler (default-segment-run-scheduler)
118                                :inst-hook (default-segment-inst-hook)))
119   (values))
120
121 (defun generate-code (component)
122   (when *compiler-trace-output*
123     (format *compiler-trace-output*
124             "~|~%assembly code for ~S~2%"
125             component))
126   (let ((prev-env nil)
127         (*trace-table-info* nil)
128         (*prev-segment* nil)
129         (*prev-vop* nil)
130         (*fixups* nil))
131     (let ((label (sb!assem:gen-label)))
132       (setf *elsewhere-label* label)
133       (sb!assem:assemble (*elsewhere*)
134         (sb!assem:emit-label label)))
135     (do-ir2-blocks (block component)
136       (let ((1block (ir2-block-block block)))
137         (when (and (eq (block-info 1block) block)
138                    (block-start 1block))
139           (sb!assem:assemble (*code-segment*)
140             (sb!assem:emit-label (block-label 1block)))
141           (let ((env (block-environment 1block)))
142             (unless (eq env prev-env)
143               (let ((lab (gen-label)))
144                 (setf (ir2-environment-elsewhere-start (environment-info env))
145                       lab)
146                 (emit-label-elsewhere lab))
147               (setq prev-env env)))))
148       (do ((vop (ir2-block-start-vop block) (vop-next vop)))
149           ((null vop))
150         (let ((gen (vop-info-generator-function (vop-info vop))))
151           (if gen
152             (funcall gen vop)
153             (format t
154                     "missing generator for ~S~%"
155                     (template-name (vop-info vop)))))))
156     (sb!assem:append-segment *code-segment* *elsewhere*)
157     (setf *elsewhere* nil)
158     (values (sb!assem:finalize-segment *code-segment*)
159             (nreverse *trace-table-info*)
160             *fixups*)))
161
162 (defun emit-label-elsewhere (label)
163   (sb!assem:assemble (*elsewhere*)
164     (sb!assem:emit-label label)))
165
166 (defun label-elsewhere-p (label-or-posn)
167   (<= (label-position *elsewhere-label*)
168       (etypecase label-or-posn
169         (label
170          (label-position label-or-posn))
171         (index
172          label-or-posn))))