1.0.23.55: three stale bugs
[sbcl.git] / src / assembly / x86-64 / arith.lisp
1 ;;;; simple cases for generic arithmetic
2
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.
11
12 (in-package "SB!VM")
13 \f
14 ;;;; addition, subtraction, and multiplication
15
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)
27
28                  (:res res (descriptor-reg any-reg) rdx-offset)
29
30                  (:temp rax unsigned-reg rax-offset)
31                  (:temp rcx unsigned-reg rcx-offset))
32
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
37
38                 ,@body
39                 (inst clc)
40                 (inst ret)
41
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))))))))
56
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
63
64     (move rcx res)
65
66     (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
67       (storew rcx res bignum-digits-offset other-pointer-lowtag))
68
69     OKAY)
70
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
78
79     (move rcx res)
80
81     (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
82       (storew rcx res bignum-digits-offset other-pointer-lowtag))
83     OKAY)
84
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
90
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
93
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)
98
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)
103
104     SINGLE-WORD-BIGNUM
105
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)
109
110     OKAY
111     (move res rax)
112     DONE))
113 \f
114 ;;;; negation
115
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)
124
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)
129
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))))
138
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)
145
146   (with-fixed-allocation (res bignum-widetag (1+ bignum-digits-offset))
147     (storew rcx res bignum-digits-offset other-pointer-lowtag))
148
149   OKAY)
150 \f
151 ;;;; comparison
152
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)
162
163                  (:res res descriptor-reg rdx-offset)
164
165                  (:temp eax unsigned-reg rax-offset)
166                  (:temp ecx unsigned-reg rcx-offset))
167
168                 (inst mov ecx x)
169                 (inst or ecx y)
170                 (inst test ecx fixnum-tag-mask)
171                 (inst jmp :nz DO-STATIC-FUN)
172
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)
179
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)))))))
195
196   (define-cond-assem-rtn generic-< < two-arg-< :ge)
197   (define-cond-assem-rtn generic-> > two-arg-> :le))
198
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)
207
208                           (:res res descriptor-reg rdx-offset)
209
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)
216
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)
224
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)))))
234
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)
243
244                           (:res res descriptor-reg rdx-offset)
245
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)
252
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)
260
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-=)))))
270
271