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