]> gitweb.factorcode.org Git - factor.git/blob - basis/math/vectors/simd/simd.factor
math.vectors.simd: vlshift, vrshift, hlshift and hrshift were being miscompiled if...
[factor.git] / basis / math / vectors / simd / simd.factor
1 USING: accessors alien arrays byte-arrays classes combinators
2 cpu.architecture effects fry functors generalizations generic
3 generic.parser kernel lexer literals locals macros math math.functions
4 math.vectors math.vectors.private math.vectors.simd.intrinsics
5 namespaces parser prettyprint.custom quotations sequences
6 sequences.generalizations sequences.private vocabs vocabs.loader
7 words ;
8 QUALIFIED-WITH: alien.c-types c
9 IN: math.vectors.simd
10
11 ERROR: bad-simd-length got expected ;
12
13 ERROR: bad-simd-vector obj ;
14
15 <<
16 <PRIVATE
17 ! Primitive SIMD constructors
18
19 GENERIC: new-underlying ( underlying seq -- seq' )
20
21 : make-underlying ( seq quot -- seq' )
22     dip new-underlying ; inline
23 : change-underlying ( seq quot -- seq' )
24     '[ underlying>> @ ] keep new-underlying ; inline
25 PRIVATE>
26 >>
27
28 <PRIVATE
29
30 ! Helper for boolean vector literals
31
32 : vector-true-value ( class -- value )
33     { c:float c:double } member? [ -1 bits>double ] [ -1 ] if ; foldable
34
35 : vector-false-value ( type -- value )
36     { c:float c:double } member? [ 0.0 ] [ 0 ] if ; foldable
37
38 : boolean>element ( bool/elt type -- elt )
39     swap {
40         { t [ vector-true-value  ] }
41         { f [ vector-false-value ] }
42         [ nip ]
43     } case ; inline
44
45 PRIVATE>
46
47 ! SIMD base type
48
49 TUPLE: simd-128
50     { underlying byte-array read-only initial: $[ 16 <byte-array> ] } ;
51
52 GENERIC: simd-element-type ( obj -- c-type )
53 GENERIC: simd-rep ( simd -- rep )
54 GENERIC: simd-with ( n exemplar -- v )
55
56 M: object simd-element-type drop f ;
57 M: object simd-rep drop f ;
58
59 <<
60 <PRIVATE
61
62 DEFER: simd-construct-op
63
64 ! Unboxers for SIMD operations
65 : if-both-vectors ( a b rep t f -- )
66     [ 2over [ simd-128? ] both? ] 2dip if ; inline
67
68 : if-both-vectors-match ( a b rep t f -- )
69     [ 3dup [ drop [ simd-128? ] both? ] [ '[ simd-rep _ eq? ] both? ] 3bi and ]
70     2dip if ; inline
71
72 : simd-unbox ( a -- a (a) )
73     [ ] [ underlying>> ] bi ; inline
74
75 : v->v-op ( a rep quot: ( (a) rep -- (c) ) fallback-quot -- c )
76     drop [ simd-unbox ] 2dip 2curry make-underlying ; inline
77
78 : vx->v-op ( a obj rep quot: ( (a) obj rep -- (c) ) fallback-quot -- c )
79     drop [ simd-unbox ] 3dip 3curry make-underlying ; inline
80
81 : vn->v-op ( a n rep quot: ( (a) n rep -- (c) ) fallback-quot -- c )
82     drop [ [ simd-unbox ] [ >fixnum ] bi* ] 2dip 3curry make-underlying ; inline
83
84 : vx->x-op ( a obj rep quot: ( (a) obj rep -- obj ) fallback-quot -- obj )
85     drop [ underlying>> ] 3dip call ; inline
86
87 : v->x-op ( a rep quot: ( (a) rep -- obj ) fallback-quot -- obj )
88     drop [ underlying>> ] 2dip call ; inline
89
90 : (vv->v-op) ( a b rep quot: ( (a) (b) rep -- (c) ) -- c )
91     [ [ simd-unbox ] [ underlying>> ] bi* ] 2dip 3curry make-underlying ; inline
92
93 : (vv->x-op) ( a b rep quot: ( (a) (b) rep -- n ) -- n )
94     [ [ underlying>> ] bi@ ] 2dip 3curry call ; inline
95
96 : (vvx->v-op) ( a b obj rep quot: ( (a) (b) obj rep -- (c) ) -- c )
97     [ [ simd-unbox ] [ underlying>> ] bi* ] 3dip 2curry 2curry make-underlying ; inline
98     
99 : vv->v-op ( a b rep quot: ( (a) (b) rep -- (c) ) fallback-quot -- c )
100     [ '[ _ (vv->v-op) ] ] [ '[ drop @ ] ] bi* if-both-vectors-match ; inline
101
102 :: vvx->v-op ( a b obj rep quot: ( (a) (b) obj rep -- (c) ) fallback-quot -- c )
103     a b rep
104     [ obj swap quot (vvx->v-op) ]
105     [ drop obj fallback-quot call ] if-both-vectors-match ; inline
106
107 : vv'->v-op ( a b rep quot: ( (a) (b) rep -- (c) ) fallback-quot -- c )
108     [ '[ _ (vv->v-op) ] ] [ '[ drop @ ] ] bi* if-both-vectors ; inline
109
110 : vv->x-op ( a b rep quot: ( (a) (b) rep -- obj ) fallback-quot -- obj )
111     [ '[ _ (vv->x-op) ] ] [ '[ drop @ ] ] bi* if-both-vectors-match ; inline
112
113 PRIVATE>
114 >>
115
116 <<
117
118 ! SIMD vectors as sequences
119
120 M: simd-128 hashcode* underlying>> hashcode* ; inline
121 M: simd-128 clone [ clone ] change-underlying ; inline
122 M: simd-128 byte-length drop 16 ; inline
123
124 M: simd-128 new-sequence
125     2dup length =
126     [ nip [ 16 (byte-array) ] make-underlying ]
127     [ length bad-simd-length ] if ; inline
128
129 M: simd-128 equal?
130     dup simd-rep [ drop v= vall? ] [ 3drop f ] if-both-vectors-match ; inline
131
132 ! SIMD primitive operations
133
134 M: simd-128 v+
135     dup simd-rep [ (simd-v+)                ] [ call-next-method ] vv->v-op ; inline
136 M: simd-128 v-
137     dup simd-rep [ (simd-v-)                ] [ call-next-method ] vv->v-op ; inline
138 M: simd-128 vneg
139     dup simd-rep [ (simd-vneg)              ] [ call-next-method ] v->v-op  ; inline
140 M: simd-128 v+-
141     dup simd-rep [ (simd-v+-)               ] [ call-next-method ] vv->v-op ; inline
142 M: simd-128 vs+
143     dup simd-rep [ (simd-vs+)               ] [ call-next-method ] vv->v-op ; inline
144 M: simd-128 vs-
145     dup simd-rep [ (simd-vs-)               ] [ call-next-method ] vv->v-op ; inline
146 M: simd-128 vs*
147     dup simd-rep [ (simd-vs*)               ] [ call-next-method ] vv->v-op ; inline
148 M: simd-128 v*
149     dup simd-rep [ (simd-v*)                ] [ call-next-method ] vv->v-op ; inline
150 M: simd-128 v*high
151     dup simd-rep [ (simd-v*high)            ] [ call-next-method ] vv->v-op ; inline
152 M: simd-128 v/
153     dup simd-rep [ (simd-v/)                ] [ call-next-method ] vv->v-op ; inline
154 M: simd-128 vavg
155     dup simd-rep [ (simd-vavg)              ] [ call-next-method ] vv->v-op ; inline
156 M: simd-128 vmin
157     dup simd-rep [ (simd-vmin)              ] [ call-next-method ] vv->v-op ; inline
158 M: simd-128 vmax
159     dup simd-rep [ (simd-vmax)              ] [ call-next-method ] vv->v-op ; inline
160 M: simd-128 v.
161     dup simd-rep [ (simd-v.)                ] [ call-next-method ] vv->x-op ; inline
162 M: simd-128 vsad
163     dup simd-rep [ (simd-vsad)              ] [ call-next-method ] vv->x-op ; inline
164 M: simd-128 vsqrt
165     dup simd-rep [ (simd-vsqrt)             ] [ call-next-method ] v->v-op  ; inline
166 M: simd-128 sum
167     dup simd-rep [ (simd-sum)               ] [ call-next-method ] v->x-op  ; inline
168 M: simd-128 vabs
169     dup simd-rep [ (simd-vabs)              ] [ call-next-method ] v->v-op  ; inline
170 M: simd-128 vbitand
171     dup simd-rep [ (simd-vbitand)           ] [ call-next-method ] vv->v-op ; inline
172 M: simd-128 vbitandn
173     dup simd-rep [ (simd-vbitandn)          ] [ call-next-method ] vv->v-op ; inline
174 M: simd-128 vbitor
175     dup simd-rep [ (simd-vbitor)            ] [ call-next-method ] vv->v-op ; inline
176 M: simd-128 vbitxor
177     dup simd-rep [ (simd-vbitxor)           ] [ call-next-method ] vv->v-op ; inline
178 M: simd-128 vbitnot
179     dup simd-rep [ (simd-vbitnot)           ] [ call-next-method ] v->v-op  ; inline
180 M: simd-128 vand
181     dup simd-rep [ (simd-vand)              ] [ call-next-method ] vv->v-op ; inline
182 M: simd-128 vandn
183     dup simd-rep [ (simd-vandn)             ] [ call-next-method ] vv->v-op ; inline
184 M: simd-128 vor
185     dup simd-rep [ (simd-vor)               ] [ call-next-method ] vv->v-op ; inline
186 M: simd-128 vxor
187     dup simd-rep [ (simd-vxor)              ] [ call-next-method ] vv->v-op ; inline
188 M: simd-128 vnot
189     dup simd-rep [ (simd-vnot)              ] [ call-next-method ] v->v-op  ; inline
190 M: simd-128 vlshift
191     over simd-rep [ (simd-vlshift)           ] [ call-next-method ] vn->v-op ; inline
192 M: simd-128 vrshift
193     over simd-rep [ (simd-vrshift)           ] [ call-next-method ] vn->v-op ; inline
194 M: simd-128 hlshift
195     over simd-rep [ (simd-hlshift)           ] [ call-next-method ] vn->v-op ; inline
196 M: simd-128 hrshift
197     over simd-rep [ (simd-hrshift)           ] [ call-next-method ] vn->v-op ; inline
198 M: simd-128 vshuffle-elements
199     over simd-rep [ (simd-vshuffle-elements) ] [ call-next-method ] vx->v-op ; inline
200 M: simd-128 vshuffle2-elements
201     over simd-rep [ (simd-vshuffle2-elements) ] [ call-next-method ] vvx->v-op ; inline
202 M: simd-128 vshuffle-bytes
203     dup simd-rep [ (simd-vshuffle-bytes)    ] [ call-next-method ] vv'->v-op ; inline
204 M: simd-128 (vmerge-head)
205     dup simd-rep [ (simd-vmerge-head)       ] [ call-next-method ] vv->v-op ; inline
206 M: simd-128 (vmerge-tail)
207     dup simd-rep [ (simd-vmerge-tail)       ] [ call-next-method ] vv->v-op ; inline
208 M: simd-128 v<=
209     dup simd-rep [ (simd-v<=)               ] [ call-next-method ] vv->v-op ; inline
210 M: simd-128 v<
211     dup simd-rep [ (simd-v<)                ] [ call-next-method ] vv->v-op ; inline
212 M: simd-128 v=
213     dup simd-rep [ (simd-v=)                ] [ call-next-method ] vv->v-op ; inline
214 M: simd-128 v>
215     dup simd-rep [ (simd-v>)                ] [ call-next-method ] vv->v-op ; inline
216 M: simd-128 v>=
217     dup simd-rep [ (simd-v>=)               ] [ call-next-method ] vv->v-op ; inline
218 M: simd-128 vunordered?
219     dup simd-rep [ (simd-vunordered?)       ] [ call-next-method ] vv->v-op ; inline
220 M: simd-128 vany?
221     dup simd-rep [ (simd-vany?)             ] [ call-next-method ] v->x-op  ; inline
222 M: simd-128 vall?
223     dup simd-rep [ (simd-vall?)             ] [ call-next-method ] v->x-op  ; inline
224 M: simd-128 vnone?
225     dup simd-rep [ (simd-vnone?)            ] [ call-next-method ] v->x-op  ; inline
226
227 ! SIMD high-level specializations
228
229 M: simd-128 vbroadcast swap [ nth ] [ simd-with ] bi ; inline
230 M: simd-128 n+v [ simd-with ] keep v+ ; inline
231 M: simd-128 n-v [ simd-with ] keep v- ; inline
232 M: simd-128 n*v [ simd-with ] keep v* ; inline
233 M: simd-128 n/v [ simd-with ] keep v/ ; inline
234 M: simd-128 v+n over simd-with v+ ; inline
235 M: simd-128 v-n over simd-with v- ; inline
236 M: simd-128 v*n over simd-with v* ; inline
237 M: simd-128 v/n over simd-with v/ ; inline
238 M: simd-128 norm-sq dup v. assert-positive ; inline
239 M: simd-128 distance v- norm ; inline
240
241 M: simd-128 >pprint-sequence ;
242 M: simd-128 pprint* pprint-object ;
243
244 <PRIVATE
245
246 ! SIMD concrete type functor
247
248 FUNCTOR: define-simd-128 ( T -- )
249
250 A      DEFINES-CLASS ${T}
251 A-rep  IS            ${T}-rep
252 >A     DEFINES       >${T}
253 A-boa  DEFINES       ${T}-boa
254 A-with DEFINES       ${T}-with
255 A-cast DEFINES       ${T}-cast
256 A{     DEFINES       ${T}{
257
258 ELT     [ A-rep rep-component-type ]
259 N       [ A-rep rep-length ]
260 COERCER [ ELT c:c-type-class "coercer" word-prop [ ] or ]
261
262 BOA-EFFECT [ N "n" <array> { "v" } <effect> ]
263
264 WHERE
265
266 TUPLE: A < simd-128 ; final
267
268 M: A new-underlying    drop \ A boa ; inline
269 M: A simd-rep          drop A-rep ; inline
270 M: A simd-element-type drop ELT ; inline
271 M: A simd-with         drop A-with ; inline
272
273 M: A nth-unsafe
274     swap \ A-rep [ (simd-select) ] [ call-next-method ] vx->x-op ; inline
275 M: A set-nth-unsafe
276     [ ELT boolean>element ] 2dip
277     underlying>> ELT c:set-alien-element ; inline
278
279 : >A ( seq -- simd ) \ A new clone-like ; inline
280
281 M: A like drop dup \ A instance? [ >A ] unless ; inline
282
283 : A-with ( n -- v ) COERCER call \ A-rep (simd-with) \ A boa ; inline
284 : A-cast ( v -- v' ) underlying>> \ A boa ; inline
285
286 M: A length drop N ; inline
287
288 \ A-boa
289 [ COERCER N napply ] N {
290     { 2 [ [ A-rep (simd-gather-2) A boa ] ] }
291     { 4 [ [ A-rep (simd-gather-4) A boa ] ] }
292     [ \ A new '[ _ _ nsequence ] ]
293 } case compose
294 BOA-EFFECT define-inline
295
296 M: A pprint-delims drop \ A{ \ } ;
297 SYNTAX: A{ \ } [ >A ] parse-literal ;
298
299 INSTANCE: A sequence
300
301 c:<c-type>
302     byte-array >>class
303     A >>boxed-class
304     { A-rep alien-vector A boa } >quotation >>getter
305     {
306         [ dup simd-128? [ bad-simd-vector ] unless underlying>> ] 2dip
307         A-rep set-alien-vector
308     } >quotation >>setter
309     16 >>size
310     16 >>align
311     A-rep >>rep
312 \ A c:typedef
313
314 ;FUNCTOR
315
316 SYNTAX: SIMD-128:
317     scan-token define-simd-128 ;
318
319 PRIVATE>
320
321 >>
322
323 ! SIMD instances
324
325 SIMD-128: char-16
326 SIMD-128: uchar-16
327 SIMD-128: short-8
328 SIMD-128: ushort-8
329 SIMD-128: int-4
330 SIMD-128: uint-4
331 SIMD-128: longlong-2
332 SIMD-128: ulonglong-2
333 SIMD-128: float-4
334 SIMD-128: double-2
335
336 ! misc
337
338 M: simd-128 vshuffle ( u perm -- v )
339     vshuffle-bytes ; inline
340
341 M: uchar-16 v*hs+
342     uchar-16-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op short-8-cast ; inline
343 M: ushort-8 v*hs+
344     ushort-8-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op uint-4-cast ; inline
345 M: uint-4 v*hs+
346     uint-4-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op ulonglong-2-cast ; inline
347 M: char-16 v*hs+
348     char-16-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op short-8-cast ; inline
349 M: short-8 v*hs+
350     short-8-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op int-4-cast ; inline
351 M: int-4 v*hs+
352     int-4-rep [ (simd-v*hs+) ] [ call-next-method ] vv->v-op longlong-2-cast ; inline
353
354 { "math.vectors.simd" "mirrors" } "math.vectors.simd.mirrors" require-when