717265ca03a9e65b303433fe7800a57834ee4690
[sbcl.git] / src / compiler / x86-64 / simd-pack.lisp
1 ;;;; SSE intrinsics support for x86-64
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 (defun ea-for-sse-stack (tn &optional (base rbp-tn))
15   (make-ea :qword :base base
16            :disp (frame-byte-offset (1+ (tn-offset tn)))))
17
18 (defun float-sse-p (tn)
19   (sc-is tn single-sse-reg single-sse-stack single-sse-immediate
20             double-sse-reg double-sse-stack double-sse-immediate))
21 (defun int-sse-p (tn)
22   (sc-is tn int-sse-reg int-sse-stack int-sse-immediate))
23 \f
24 (define-move-fun (load-int-sse-immediate 1) (vop x y)
25   ((int-sse-immediate) (int-sse-reg))
26   (let* ((x  (tn-value x))
27          (lo (%simd-pack-low x))
28          (hi (%simd-pack-high x)))
29     (cond ((= lo hi 0)
30            (inst pxor y y))
31           ((= lo hi (ldb (byte 64 0) -1))
32            ;; don't think this is recognized as dependency breaking...
33            (inst pcmpeqd y y))
34           (t
35            (inst movdqa y (register-inline-constant x))))))
36
37 (define-move-fun (load-float-sse-immediate 1) (vop x y)
38   ((single-sse-immediate double-sse-immediate)
39    (single-sse-reg double-sse-reg))
40   (let* ((x  (tn-value x))
41          (lo (%simd-pack-low x))
42          (hi (%simd-pack-high x)))
43     (cond ((= lo hi 0)
44            (inst xorps y y))
45           ((= lo hi (ldb (byte 64 0) -1))
46            (inst pcmpeqd y y))
47           (t
48            (inst movaps y (register-inline-constant x))))))
49
50 (define-move-fun (load-int-sse 2) (vop x y)
51   ((int-sse-stack) (int-sse-reg))
52   (inst movdqu y (ea-for-sse-stack x)))
53
54 (define-move-fun (load-float-sse 2) (vop x y)
55   ((single-sse-stack double-sse-stack) (single-sse-reg double-sse-reg))
56   (inst movups y (ea-for-sse-stack x)))
57
58 (define-move-fun (store-int-sse 2) (vop x y)
59   ((int-sse-reg) (int-sse-stack))
60   (inst movdqu (ea-for-sse-stack y) x))
61
62 (define-move-fun (store-float-sse 2) (vop x y)
63   ((double-sse-reg single-sse-reg) (double-sse-stack single-sse-stack))
64   (inst movups (ea-for-sse-stack y) x))
65
66 (define-vop (sse-move)
67   (:args (x :scs (single-sse-reg double-sse-reg int-sse-reg)
68             :target y
69             :load-if (not (location= x y))))
70   (:results (y :scs (single-sse-reg double-sse-reg int-sse-reg)
71                :load-if (not (location= x y))))
72   (:note "SSE move")
73   (:generator 0
74      (move y x)))
75 (define-move-vop sse-move :move
76   (int-sse-reg single-sse-reg double-sse-reg)
77   (int-sse-reg single-sse-reg double-sse-reg))
78
79 (define-vop (move-from-sse)
80   (:args (x :scs (single-sse-reg double-sse-reg int-sse-reg)))
81   (:results (y :scs (descriptor-reg)))
82   (:node-var node)
83   (:note "SSE to pointer coercion")
84   (:generator 13
85      (with-fixed-allocation (y
86                              simd-pack-widetag
87                              simd-pack-size
88                              node)
89        ;; see *simd-pack-element-types*
90        (storew (fixnumize
91                 (sc-case x
92                   (single-sse-reg 1)
93                   (double-sse-reg 2)
94                   (int-sse-reg 0)
95                   (t 0)))
96            y simd-pack-tag-slot other-pointer-lowtag)
97        (let ((ea (make-ea-for-object-slot
98                   y simd-pack-lo-value-slot other-pointer-lowtag)))
99          (if (float-sse-p x)
100              (inst movaps ea x)
101              (inst movdqa ea x))))))
102 (define-move-vop move-from-sse :move
103   (int-sse-reg single-sse-reg double-sse-reg) (descriptor-reg))
104
105 (define-vop (move-to-sse)
106   (:args (x :scs (descriptor-reg)))
107   (:results (y :scs (int-sse-reg double-sse-reg single-sse-reg)))
108   (:note "pointer to SSE coercion")
109   (:generator 2
110     (let ((ea (make-ea-for-object-slot
111                x simd-pack-lo-value-slot other-pointer-lowtag)))
112       (if (float-sse-p y)
113           (inst movaps y ea)
114           (inst movdqa y ea)))))
115 (define-move-vop move-to-sse :move
116   (descriptor-reg)
117   (int-sse-reg double-sse-reg single-sse-reg))
118
119 (define-vop (move-sse-arg)
120   (:args (x :scs (int-sse-reg double-sse-reg single-sse-reg) :target y)
121          (fp :scs (any-reg)
122              :load-if (not (sc-is y int-sse-reg double-sse-reg single-sse-reg))))
123   (:results (y))
124   (:note "SSE argument move")
125   (:generator 4
126      (sc-case y
127        ((int-sse-reg double-sse-reg single-sse-reg)
128         (unless (location= x y)
129           (if (or (float-sse-p x)
130                   (float-sse-p y))
131               (inst movaps y x)
132               (inst movdqa y x))))
133        ((int-sse-stack double-sse-stack single-sse-stack)
134         (if (float-sse-p x)
135             (inst movups (ea-for-sse-stack y fp) x)
136             (inst movdqu (ea-for-sse-stack y fp) x))))))
137 (define-move-vop move-sse-arg :move-arg
138   (int-sse-reg double-sse-reg single-sse-reg descriptor-reg)
139   (int-sse-reg double-sse-reg single-sse-reg))
140
141 (define-move-vop move-arg :move-arg
142   (int-sse-reg double-sse-reg single-sse-reg)
143   (descriptor-reg))
144
145 \f
146 (define-vop (%simd-pack-low)
147   (:translate %simd-pack-low)
148   (:args (x :scs (int-sse-reg double-sse-reg single-sse-reg)))
149   (:arg-types simd-pack)
150   (:results (dst :scs (unsigned-reg)))
151   (:result-types unsigned-num)
152   (:policy :fast-safe)
153   (:generator 3
154     (inst movd dst x)))
155
156 (defun %simd-pack-low (x)
157   (declare (type simd-pack x))
158   (%simd-pack-low x))
159
160 (define-vop (%simd-pack-high)
161   (:translate %simd-pack-high)
162   (:args (x :scs (int-sse-reg double-sse-reg single-sse-reg)))
163   (:arg-types simd-pack)
164   (:temporary (:sc sse-reg) tmp)
165   (:results (dst :scs (unsigned-reg)))
166   (:result-types unsigned-num)
167   (:policy :fast-safe)
168   (:generator 3
169     (inst movdqa tmp x)
170     (inst psrldq tmp 8)
171     (inst movd dst tmp)))
172
173 (defun %simd-pack-high (x)
174   (declare (type simd-pack x))
175   (%simd-pack-high x))
176
177 (define-vop (%make-simd-pack)
178   (:translate %make-simd-pack)
179   (:policy :fast-safe)
180   (:args (tag :scs (any-reg))
181          (lo :scs (unsigned-reg))
182          (hi :scs (unsigned-reg)))
183   (:arg-types tagged-num unsigned-num unsigned-num)
184   (:results (dst :scs (descriptor-reg) :from :load))
185   (:result-types t)
186   (:node-var node)
187   (:generator 13
188     (with-fixed-allocation (dst
189                             simd-pack-widetag
190                             simd-pack-size
191                             node)
192       ;; see *simd-pack-element-types*
193       (storew tag
194           dst simd-pack-tag-slot other-pointer-lowtag)
195       (storew lo
196           dst simd-pack-lo-value-slot other-pointer-lowtag)
197       (storew hi
198           dst simd-pack-hi-value-slot other-pointer-lowtag))))
199
200 (defun %make-simd-pack (tag low high)
201   (declare (type fixnum tag)
202            (type (unsigned-byte 64) low high))
203   (%make-simd-pack tag low high))
204
205 (define-vop (%make-simd-pack-ub64)
206   (:translate %make-simd-pack-ub64)
207   (:policy :fast-safe)
208   (:args (lo :scs (unsigned-reg))
209          (hi :scs (unsigned-reg)))
210   (:arg-types unsigned-num unsigned-num)
211   (:temporary (:sc sse-reg) tmp)
212   (:results (dst :scs (int-sse-reg)))
213   (:result-types simd-pack-int)
214   (:generator 5
215     (inst movd dst lo)
216     (inst movd tmp hi)
217     (inst punpcklqdq dst tmp)))
218
219 (defun %make-simd-pack-ub64 (low high)
220   (declare (type (unsigned-byte 64) low high))
221   (%make-simd-pack-ub64 low high))
222
223 #-sb-xc-host
224 (declaim (inline %make-simd-pack-ub64))
225 #-sb-xc-host
226 (defun %make-simd-pack-ub32 (w x y z)
227   (declare (type (unsigned-byte 32) w x y z))
228   (%make-simd-pack-ub64 (logior w (ash x 32))
229                         (logior y (ash z 32))))
230
231 #-sb-xc-host
232 (progn
233   (declaim (inline %simd-pack-ub32s %simd-pack-ub64s))
234   (defun %simd-pack-ub32s (pack)
235     (declare (type simd-pack pack))
236     (let ((lo (%simd-pack-low pack))
237           (hi (%simd-pack-high pack)))
238       (values (ldb (byte 32 0) lo)
239               (ash lo -32)
240               (ldb (byte 32 0) hi)
241               (ash hi -32))))
242
243   (defun %simd-pack-ub64s (pack)
244     (declare (type simd-pack pack))
245     (values (%simd-pack-low pack)
246             (%simd-pack-high pack))))
247
248
249 (define-vop (%make-simd-pack-double)
250   (:translate %make-simd-pack-double)
251   (:policy :fast-safe)
252   (:args (lo :scs (double-reg))
253          (hi :scs (double-reg)))
254   (:arg-types double-float double-float)
255   (:temporary (:sc double-sse-reg) tmp)
256   (:results (dst :scs (double-sse-reg)))
257   (:result-types simd-pack-double)
258   (:generator 5
259     (move dst lo)
260     (move tmp hi)
261     (inst unpcklpd dst tmp)))
262
263 (defun %make-simd-pack-double (low high)
264   (declare (type double-float low high))
265   (%make-simd-pack-double low high))
266
267 (define-vop (%make-simd-pack-single)
268   (:translate %make-simd-pack-single)
269   (:policy :fast-safe)
270   (:args (x :scs (single-reg))
271          (y :scs (single-reg))
272          (z :scs (single-reg))
273          (w :scs (single-reg)))
274   (:arg-types single-float single-float single-float single-float)
275   (:temporary (:sc sse-reg) tmp)
276   (:results (dst :scs (single-sse-reg)))
277   (:result-types simd-pack-single)
278   (:generator 5
279     (move dst x)
280     (inst unpcklps dst z)
281     (move tmp y)
282     (inst unpcklps tmp w)
283     (inst unpcklps dst tmp)))
284
285 (defun %make-simd-pack-single (x y z w)
286   (declare (type single-float x y z w))
287   (%make-simd-pack-single x y z w))
288
289 (defun %simd-pack-tag (pack)
290   (%simd-pack-tag pack))
291
292 (define-vop (%simd-pack-single-item)
293   (:args (x :scs (int-sse-reg double-sse-reg single-sse-reg)))
294   (:arg-types simd-pack)
295   (:info index)
296   (:results (dst :scs (single-reg)))
297   (:result-types single-float)
298   (:temporary (:sc sse-reg) tmp)
299   (:policy :fast-safe)
300   (:generator 3
301     (inst movdqa tmp x)
302     (inst psrldq tmp (* 4 index))
303     (inst xorps dst dst)
304     (inst movss dst tmp)))
305
306 #-sb-xc-host
307 (declaim (inline %simd-pack-singles))
308 #-sb-xc-host
309 (defun %simd-pack-singles (pack)
310   (declare (type simd-pack pack))
311   (values (%primitive %simd-pack-single-item pack 0)
312           (%primitive %simd-pack-single-item pack 1)
313           (%primitive %simd-pack-single-item pack 2)
314           (%primitive %simd-pack-single-item pack 3)))
315
316 (define-vop (%simd-pack-double-item)
317   (:args (x :scs (int-sse-reg double-sse-reg single-sse-reg)))
318   (:info index)
319   (:arg-types simd-pack)
320   (:results (dst :scs (double-reg)))
321   (:result-types double-float)
322   (:temporary (:sc sse-reg) tmp)
323   (:policy :fast-safe)
324   (:generator 3
325     (inst movdqa tmp x)
326     (inst psrldq tmp (* 8 index))
327     (inst xorpd dst dst)
328     (inst movsd dst tmp)))
329
330 #-sb-xc-host
331 (declaim (inline %simd-pack-doubles))
332 #-sb-xc-host
333 (defun %simd-pack-doubles (pack)
334   (declare (type simd-pack pack))
335   (values (%primitive %simd-pack-double-item pack 0)
336           (%primitive %simd-pack-double-item pack 1)))