1.0.23.16: more generic assembly op optimizations on x86 and x86-64
[sbcl/tcr.git] / src / assembly / x86-64 / arith.lisp
blob3e839923758f57cf06d3ecd50ecacaf2b52a0c64
1 ;;;; simple cases for generic arithmetic
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!VM")
14 ;;;; addition, subtraction, and multiplication
16 (macrolet ((define-generic-arith-routine ((fun cost) &body body)
17 `(define-assembly-routine (,(symbolicate "GENERIC-" fun)
18 (:cost ,cost)
19 (:return-style :full-call)
20 (:translate ,fun)
21 (:policy :safe)
22 (:save-p t))
23 ((:arg x (descriptor-reg any-reg) rdx-offset)
24 (:arg y (descriptor-reg any-reg)
25 ;; this seems wrong esi-offset -- FIXME: What's it mean?
26 rdi-offset)
28 (:res res (descriptor-reg any-reg) rdx-offset)
30 (:temp rax unsigned-reg rax-offset)
31 (:temp rcx unsigned-reg rcx-offset))
33 (inst mov rcx x)
34 (inst or rcx y)
35 (inst test rcx fixnum-tag-mask) ; both fixnums?
36 (inst jmp :nz DO-STATIC-FUN) ; no - do generic
38 ,@body
39 (inst clc)
40 (inst ret)
42 DO-STATIC-FUN
43 (inst pop rax)
44 (inst push rbp-tn)
45 (inst lea
46 rbp-tn
47 (make-ea :qword :base rsp-tn :disp n-word-bytes))
48 (inst sub rsp-tn (fixnumize 2))
49 (inst push rax) ; callers return addr
50 (inst mov rcx (fixnumize 2)) ; arg count
51 (inst jmp
52 (make-ea :qword
53 :disp (+ nil-value
54 (static-fun-offset
55 ',(symbolicate "TWO-ARG-" fun))))))))
57 (define-generic-arith-routine (+ 10)
58 (move res x)
59 (inst add res y)
60 (inst jmp :no OKAY)
61 (inst rcr res 1) ; carry has correct sign
62 (inst sar res 2) ; remove type bits
64 (move rcx res)
66 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
67 (storew rcx res bignum-digits-offset other-pointer-lowtag))
69 OKAY)
71 (define-generic-arith-routine (- 10)
72 (move res x)
73 (inst sub res y)
74 (inst jmp :no OKAY)
75 (inst cmc) ; carry has correct sign now
76 (inst rcr res 1)
77 (inst sar res 2) ; remove type bits
79 (move rcx res)
81 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
82 (storew rcx res bignum-digits-offset other-pointer-lowtag))
83 OKAY)
85 (define-generic-arith-routine (* 30)
86 (move rax x) ; must use eax for 64-bit result
87 (inst sar rax n-fixnum-tag-bits) ; remove *8 fixnum bias
88 (inst imul y) ; result in edx:eax
89 (inst jmp :no OKAY) ; still fixnum
91 (inst shrd rax x n-fixnum-tag-bits) ; high bits from edx
92 (inst sar x n-fixnum-tag-bits) ; now shift edx too
94 (move rcx x) ; save high bits from cqo
95 (inst cqo) ; edx:eax <- sign-extend of eax
96 (inst cmp x rcx)
97 (inst jmp :e SINGLE-WORD-BIGNUM)
99 (with-fixed-allocation (res bignum-widetag (+ bignum-digits-offset 2))
100 (storew rax res bignum-digits-offset other-pointer-lowtag)
101 (storew rcx res (1+ bignum-digits-offset) other-pointer-lowtag))
102 (inst jmp DONE)
104 SINGLE-WORD-BIGNUM
106 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
107 (storew rax res bignum-digits-offset other-pointer-lowtag))
108 (inst jmp DONE)
110 OKAY
111 (move res rax)
112 DONE))
114 ;;;; negation
116 (define-assembly-routine (generic-negate
117 (:cost 10)
118 (:return-style :full-call)
119 (:policy :safe)
120 (:translate %negate)
121 (:save-p t))
122 ((:arg x (descriptor-reg any-reg) rdx-offset)
123 (:res res (descriptor-reg any-reg) rdx-offset)
125 (:temp rax unsigned-reg rax-offset)
126 (:temp rcx unsigned-reg rcx-offset))
127 (inst test x fixnum-tag-mask)
128 (inst jmp :z FIXNUM)
130 (inst pop rax)
131 (inst push rbp-tn)
132 (inst lea rbp-tn (make-ea :qword :base rsp-tn :disp n-word-bytes))
133 (inst sub rsp-tn (fixnumize 2))
134 (inst push rax)
135 (inst mov rcx (fixnumize 1)) ; arg count
136 (inst jmp (make-ea :qword
137 :disp (+ nil-value (static-fun-offset '%negate))))
139 FIXNUM
140 (move res x)
141 (inst neg res) ; (- most-negative-fixnum) is BIGNUM
142 (inst jmp :no OKAY)
143 (inst shr res n-fixnum-tag-bits) ; sign bit is data - remove type bits
144 (move rcx res)
146 (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
147 (storew rcx res bignum-digits-offset other-pointer-lowtag))
149 OKAY)
151 ;;;; comparison
153 (macrolet ((define-cond-assem-rtn (name translate static-fn test)
154 `(define-assembly-routine (,name
155 (:cost 10)
156 (:return-style :full-call)
157 (:policy :safe)
158 (:translate ,translate)
159 (:save-p t))
160 ((:arg x (descriptor-reg any-reg) rdx-offset)
161 (:arg y (descriptor-reg any-reg) rdi-offset)
163 (:res res descriptor-reg rdx-offset)
165 (:temp eax unsigned-reg rax-offset)
166 (:temp ecx unsigned-reg rcx-offset))
168 (inst mov ecx x)
169 (inst or ecx y)
170 (inst test ecx fixnum-tag-mask)
171 (inst jmp :nz DO-STATIC-FUN)
173 (inst cmp x y)
174 (load-symbol res t)
175 (inst mov eax nil-value)
176 (inst cmov ,test res eax)
177 (inst clc) ; single-value return
178 (inst ret)
180 DO-STATIC-FUN
181 (inst pop eax)
182 (inst push rbp-tn)
183 (inst lea rbp-tn (make-ea :qword
184 :base rsp-tn
185 :disp n-word-bytes))
186 (inst sub rsp-tn (fixnumize 2)) ; FIXME: Push 2 words on stack,
187 ; weirdly?
188 (inst push eax)
189 (inst mov ecx (fixnumize 2)) ; FIXME: FIXNUMIZE and
190 ; SINGLE-FLOAT-BITS are parallel,
191 ; should be named parallelly.
192 (inst jmp (make-ea :qword
193 :disp (+ nil-value
194 (static-fun-offset ',static-fn)))))))
196 (define-cond-assem-rtn generic-< < two-arg-< :ge)
197 (define-cond-assem-rtn generic-> > two-arg-> :le))
199 (define-assembly-routine (generic-eql
200 (:cost 10)
201 (:return-style :full-call)
202 (:policy :safe)
203 (:translate eql)
204 (:save-p t))
205 ((:arg x (descriptor-reg any-reg) rdx-offset)
206 (:arg y (descriptor-reg any-reg) rdi-offset)
208 (:res res descriptor-reg rdx-offset)
210 (:temp rax unsigned-reg rax-offset)
211 (:temp rcx unsigned-reg rcx-offset))
212 (inst mov rcx x)
213 (inst and rcx y)
214 (inst test rcx fixnum-tag-mask)
215 (inst jmp :nz DO-STATIC-FUN)
217 ;; At least one fixnum
218 (inst cmp x y)
219 (load-symbol res t)
220 (inst mov rax nil-value)
221 (inst cmov :ne res rax)
222 (inst clc)
223 (inst ret)
225 DO-STATIC-FUN
226 (inst pop rax)
227 (inst push rbp-tn)
228 (inst lea rbp-tn (make-ea :qword :base rsp-tn :disp n-word-bytes))
229 (inst sub rsp-tn (fixnumize 2))
230 (inst push rax)
231 (inst mov rcx (fixnumize 2))
232 (inst jmp (make-ea :qword
233 :disp (+ nil-value (static-fun-offset 'eql)))))
235 (define-assembly-routine (generic-=
236 (:cost 10)
237 (:return-style :full-call)
238 (:policy :safe)
239 (:translate =)
240 (:save-p t))
241 ((:arg x (descriptor-reg any-reg) rdx-offset)
242 (:arg y (descriptor-reg any-reg) rdi-offset)
244 (:res res descriptor-reg rdx-offset)
246 (:temp rax unsigned-reg rax-offset)
247 (:temp rcx unsigned-reg rcx-offset))
248 (inst mov rcx x)
249 (inst or rcx y)
250 (inst test rcx fixnum-tag-mask)
251 (inst jmp :nz DO-STATIC-FUN)
253 ;; Both fixnums
254 (inst cmp x y)
255 (load-symbol res t)
256 (inst mov rax nil-value)
257 (inst cmov :ne res rax)
258 (inst clc)
259 (inst ret)
261 DO-STATIC-FUN
262 (inst pop rax)
263 (inst push rbp-tn)
264 (inst lea rbp-tn (make-ea :qword :base rsp-tn :disp n-word-bytes))
265 (inst sub rsp-tn (fixnumize 2))
266 (inst push rax)
267 (inst mov rcx (fixnumize 2))
268 (inst jmp (make-ea :qword
269 :disp (+ nil-value (static-fun-offset 'two-arg-=)))))