mmx: add and use expand_4xpacked565 function
[profile/ivi/pixman.git] / pixman / loongson-mmintrin.h
1 /* The gcc-provided loongson intrinsic functions are way too fucking broken
2  * to be of any use, otherwise I'd use them.
3  *
4  * - The hardware instructions are very similar to MMX or iwMMXt. Certainly
5  *   close enough that they could have implemented the _mm_*-style intrinsic
6  *   interface and had a ton of optimized code available to them. Instead they
7  *   implemented something much, much worse.
8  *
9  * - pshuf takes a dead first argument, causing extra instructions to be
10  *   generated.
11  *
12  * - There are no 64-bit shift or logical intrinsics, which means you have
13  *   to implement them with inline assembly, but this is a nightmare because
14  *   gcc doesn't understand that the integer vector datatypes are actually in
15  *   floating-point registers, so you end up with braindead code like
16  *
17  *      punpcklwd       $f9,$f9,$f5
18  *          dmtc1       v0,$f8
19  *      punpcklwd       $f19,$f19,$f5
20  *          dmfc1       t9,$f9
21  *          dmtc1       v0,$f9
22  *          dmtc1       t9,$f20
23  *          dmfc1       s0,$f19
24  *      punpcklbh       $f20,$f20,$f2
25  *
26  *   where crap just gets copied back and forth between integer and floating-
27  *   point registers ad nauseum.
28  *
29  * Instead of trying to workaround the problems from these crap intrinsics, I
30  * just implement the _mm_* intrinsics needed for pixman-mmx.c using inline
31  * assembly.
32  */
33
34 #include <stdint.h>
35
36 /* vectors are stored in 64-bit floating-point registers */
37 typedef double __m64;
38 /* having a 32-bit datatype allows us to use 32-bit loads in places like load8888 */
39 typedef float  __m32;
40
41 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
42 _mm_setzero_si64 (void)
43 {
44         return 0.0;
45 }
46
47 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
48 _mm_adds_pu16 (__m64 __m1, __m64 __m2)
49 {
50         __m64 ret;
51         asm("paddush %0, %1, %2\n\t"
52            : "=f" (ret)
53            : "f" (__m1), "f" (__m2)
54         );
55         return ret;
56 }
57
58 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
59 _mm_adds_pu8 (__m64 __m1, __m64 __m2)
60 {
61         __m64 ret;
62         asm("paddusb %0, %1, %2\n\t"
63            : "=f" (ret)
64            : "f" (__m1), "f" (__m2)
65         );
66         return ret;
67 }
68
69 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
70 _mm_and_si64 (__m64 __m1, __m64 __m2)
71 {
72         __m64 ret;
73         asm("and %0, %1, %2\n\t"
74            : "=f" (ret)
75            : "f" (__m1), "f" (__m2)
76         );
77         return ret;
78 }
79
80 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
81 _mm_cmpeq_pi32 (__m64 __m1, __m64 __m2)
82 {
83         __m64 ret;
84         asm("pcmpeqw %0, %1, %2\n\t"
85            : "=f" (ret)
86            : "f" (__m1), "f" (__m2)
87         );
88         return ret;
89 }
90
91 extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
92 _mm_empty (void)
93 {
94
95 }
96
97 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
98 _mm_madd_pi16 (__m64 __m1, __m64 __m2)
99 {
100         __m64 ret;
101         asm("pmaddhw %0, %1, %2\n\t"
102            : "=f" (ret)
103            : "f" (__m1), "f" (__m2)
104         );
105         return ret;
106 }
107
108 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
109 _mm_mulhi_pu16 (__m64 __m1, __m64 __m2)
110 {
111         __m64 ret;
112         asm("pmulhuh %0, %1, %2\n\t"
113            : "=f" (ret)
114            : "f" (__m1), "f" (__m2)
115         );
116         return ret;
117 }
118
119 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
120 _mm_mullo_pi16 (__m64 __m1, __m64 __m2)
121 {
122         __m64 ret;
123         asm("pmullh %0, %1, %2\n\t"
124            : "=f" (ret)
125            : "f" (__m1), "f" (__m2)
126         );
127         return ret;
128 }
129
130 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
131 _mm_or_si64 (__m64 __m1, __m64 __m2)
132 {
133         __m64 ret;
134         asm("or %0, %1, %2\n\t"
135            : "=f" (ret)
136            : "f" (__m1), "f" (__m2)
137         );
138         return ret;
139 }
140
141 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
142 _mm_packs_pu16 (__m64 __m1, __m64 __m2)
143 {
144         __m64 ret;
145         asm("packushb %0, %1, %2\n\t"
146            : "=f" (ret)
147            : "f" (__m1), "f" (__m2)
148         );
149         return ret;
150 }
151
152 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
153 _mm_shuffle_pi16 (__m64 __m, int64_t __n)
154 {
155         __m64 ret;
156         asm("pshufh %0, %1, %2\n\t"
157             : "=f" (ret)
158             : "f" (__m), "f" (*(__m64 *)&__n)
159         );
160         return ret;
161 }
162
163 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
164 _mm_slli_pi16 (__m64 __m, int64_t __count)
165 {
166         __m64 ret;
167         asm("psllh  %0, %1, %2\n\t"
168            : "=f" (ret)
169            : "f" (__m), "f" (*(__m64 *)&__count)
170         );
171         return ret;
172 }
173 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
174 _mm_slli_si64 (__m64 __m, int64_t __count)
175 {
176         __m64 ret;
177         asm("dsll  %0, %1, %2\n\t"
178            : "=f" (ret)
179            : "f" (__m), "f" (*(__m64 *)&__count)
180         );
181         return ret;
182 }
183
184 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
185 _mm_srli_pi16 (__m64 __m, int64_t __count)
186 {
187         __m64 ret;
188         asm("psrlh %0, %1, %2\n\t"
189            : "=f" (ret)
190            : "f" (__m), "f" (*(__m64 *)&__count)
191         );
192         return ret;
193 }
194
195 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
196 _mm_srli_si64 (__m64 __m, int64_t __count)
197 {
198         __m64 ret;
199         asm("dsrl  %0, %1, %2\n\t"
200            : "=f" (ret)
201            : "f" (__m), "f" (*(__m64 *)&__count)
202         );
203         return ret;
204 }
205
206 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
207 _mm_unpackhi_pi8 (__m64 __m1, __m64 __m2)
208 {
209         __m64 ret;
210         asm("punpckhbh %0, %1, %2\n\t"
211            : "=f" (ret)
212            : "f" (__m1), "f" (__m2)
213         );
214         return ret;
215 }
216
217 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
218 _mm_unpackhi_pi16 (__m64 __m1, __m64 __m2)
219 {
220         __m64 ret;
221         asm("punpckhhw %0, %1, %2\n\t"
222            : "=f" (ret)
223            : "f" (__m1), "f" (__m2)
224         );
225         return ret;
226 }
227
228 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
229 _mm_unpacklo_pi8 (__m64 __m1, __m64 __m2)
230 {
231         __m64 ret;
232         asm("punpcklbh %0, %1, %2\n\t"
233            : "=f" (ret)
234            : "f" (__m1), "f" (__m2)
235         );
236         return ret;
237 }
238
239 /* Since punpcklbh doesn't care about the high 32-bits, we use the __m32 datatype which
240  * allows load8888 to use 32-bit loads */
241 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
242 _mm_unpacklo_pi8_f (__m32 __m1, __m64 __m2)
243 {
244         __m64 ret;
245         asm("punpcklbh %0, %1, %2\n\t"
246            : "=f" (ret)
247            : "f" (__m1), "f" (__m2)
248         );
249         return ret;
250 }
251
252 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
253 _mm_unpacklo_pi16 (__m64 __m1, __m64 __m2)
254 {
255         __m64 ret;
256         asm("punpcklhw %0, %1, %2\n\t"
257            : "=f" (ret)
258            : "f" (__m1), "f" (__m2)
259         );
260         return ret;
261 }
262
263 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
264 _mm_xor_si64 (__m64 __m1, __m64 __m2)
265 {
266         __m64 ret;
267         asm("xor %0, %1, %2\n\t"
268            : "=f" (ret)
269            : "f" (__m1), "f" (__m2)
270         );
271         return ret;
272 }
273
274 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
275 loongson_extract_pi16 (__m64 __m, int64_t __pos)
276 {
277         __m64 ret;
278         asm("pextrh %0, %1, %2\n\t"
279            : "=f" (ret)
280            : "f" (__m), "f" (*(__m64 *)&__pos)
281         );
282         return ret;
283 }
284
285 extern __inline __m64 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
286 loongson_insert_pi16 (__m64 __m1, __m64 __m2, int64_t __pos)
287 {
288         __m64 ret;
289         asm("pinsrh_%3 %0, %1, %2\n\t"
290            : "=f" (ret)
291            : "f" (__m1), "f" (__m2), "i" (__pos)
292         );
293         return ret;
294 }