8843127e95b914381732124074c99af70d6de27e
[theora.git] / lib / x86_vc / mmxencfrag.c
1 /********************************************************************\r
2  *                                                                  *\r
3  * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *\r
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *\r
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\r
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *\r
7  *                                                                  *\r
8  * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009                *\r
9  * by the Xiph.Org Foundation http://www.xiph.org/                  *\r
10  *                                                                  *\r
11  ********************************************************************\r
12 \r
13   function:\r
14   last mod: $Id: dsp_mmx.c 14579 2008-03-12 06:42:40Z xiphmont $\r
15 \r
16  ********************************************************************/\r
17 #include <stddef.h>\r
18 #include "x86enc.h"\r
19 \r
20 #if defined(OC_X86_ASM)\r
21 \r
22 unsigned oc_enc_frag_sad_mmxext(const unsigned char *_src,\r
23  const unsigned char *_ref,int _ystride){\r
24   ptrdiff_t ret;\r
25   __asm{\r
26 #define SRC esi\r
27 #define REF edx\r
28 #define YSTRIDE ecx\r
29 #define YSTRIDE3 edi\r
30     mov YSTRIDE,_ystride\r
31     mov SRC,_src\r
32     mov REF,_ref\r
33     /*Load the first 4 rows of each block.*/\r
34     movq mm0,[SRC]\r
35     movq mm1,[REF]\r
36     movq mm2,[SRC][YSTRIDE]\r
37     movq mm3,[REF][YSTRIDE]\r
38     lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]\r
39     movq mm4,[SRC+YSTRIDE*2]\r
40     movq mm5,[REF+YSTRIDE*2]\r
41     movq mm6,[SRC+YSTRIDE3]\r
42     movq mm7,[REF+YSTRIDE3]\r
43     /*Compute their SADs and add them in mm0*/\r
44     psadbw mm0,mm1\r
45     psadbw mm2,mm3\r
46     lea SRC,[SRC+YSTRIDE*4]\r
47     paddw mm0,mm2\r
48     lea REF,[REF+YSTRIDE*4]\r
49     /*Load the next 3 rows as registers become available.*/\r
50     movq mm2,[SRC]\r
51     movq mm3,[REF]\r
52     psadbw mm4,mm5\r
53     psadbw mm6,mm7\r
54     paddw mm0,mm4\r
55     movq mm5,[REF+YSTRIDE]\r
56     movq mm4,[SRC+YSTRIDE]\r
57     paddw mm0,mm6\r
58     movq mm7,[REF+YSTRIDE*2]\r
59     movq mm6,[SRC+YSTRIDE*2]\r
60     /*Start adding their SADs to mm0*/\r
61     psadbw mm2,mm3\r
62     psadbw mm4,mm5\r
63     paddw mm0,mm2\r
64     psadbw mm6,mm7\r
65     /*Load last row as registers become available.*/\r
66     movq mm2,[SRC+YSTRIDE3]\r
67     movq mm3,[REF+YSTRIDE3]\r
68     /*And finish adding up their SADs.*/\r
69     paddw mm0,mm4\r
70     psadbw mm2,mm3\r
71     paddw mm0,mm6\r
72     paddw mm0,mm2\r
73     movd [ret],mm0\r
74 #undef SRC\r
75 #undef REF\r
76 #undef YSTRIDE\r
77 #undef YSTRIDE3\r
78   }\r
79   return (unsigned)ret;\r
80 }\r
81 \r
82 unsigned oc_enc_frag_sad_thresh_mmxext(const unsigned char *_src,\r
83  const unsigned char *_ref,int _ystride,unsigned _thresh){\r
84   /*Early termination is for suckers.*/\r
85   return oc_enc_frag_sad_mmxext(_src,_ref,_ystride);\r
86 }\r
87 \r
88 #define OC_SAD2_LOOP __asm{ \\r
89   /*We want to compute (mm0+mm1>>1) on unsigned bytes without overflow, but \\r
90      pavgb computes (mm0+mm1+1>>1). \\r
91    The latter is exactly 1 too large when the low bit of two corresponding \\r
92     bytes is only set in one of them. \\r
93    Therefore we pxor the operands, pand to mask out the low bits, and psubb to \\r
94     correct the output of pavgb.*/ \\r
95   __asm  movq mm6,mm0 \\r
96   __asm  lea REF1,[REF1+YSTRIDE*2] \\r
97   __asm  pxor mm0,mm1 \\r
98   __asm  pavgb mm6,mm1 \\r
99   __asm  lea REF2,[REF2+YSTRIDE*2] \\r
100   __asm  movq mm1,mm2 \\r
101   __asm  pand mm0,mm7 \\r
102   __asm  pavgb mm2,mm3 \\r
103   __asm  pxor mm1,mm3 \\r
104   __asm  movq mm3,[REF2+YSTRIDE] \\r
105   __asm  psubb mm6,mm0 \\r
106   __asm  movq mm0,[REF1] \\r
107   __asm  pand mm1,mm7 \\r
108   __asm  psadbw mm4,mm6 \\r
109   __asm  movd mm6,RET \\r
110   __asm  psubb mm2,mm1 \\r
111   __asm  movq mm1,[REF2] \\r
112   __asm  lea SRC,[SRC+YSTRIDE*2] \\r
113   __asm  psadbw mm5,mm2 \\r
114   __asm  movq mm2,[REF1+YSTRIDE] \\r
115   __asm  paddw mm5,mm4 \\r
116   __asm  movq mm4,[SRC] \\r
117   __asm  paddw mm6,mm5 \\r
118   __asm  movq mm5,[SRC+YSTRIDE] \\r
119   __asm  movd RET,mm6 \\r
120 }\r
121 \r
122 /*Same as above, but does not pre-load the next two rows.*/\r
123 #define OC_SAD2_TAIL __asm{ \\r
124   __asm  movq mm6,mm0 \\r
125   __asm  pavgb mm0,mm1 \\r
126   __asm  pxor mm6,mm1 \\r
127   __asm  movq mm1,mm2 \\r
128   __asm  pand mm6,mm7 \\r
129   __asm  pavgb mm2,mm3 \\r
130   __asm  pxor mm1,mm3 \\r
131   __asm  psubb mm0,mm6 \\r
132   __asm  pand mm1,mm7 \\r
133   __asm  psadbw mm4,mm0 \\r
134   __asm  psubb mm2,mm1 \\r
135   __asm  movd mm6,RET \\r
136   __asm  psadbw mm5,mm2 \\r
137   __asm  paddw mm5,mm4 \\r
138   __asm  paddw mm6,mm5 \\r
139   __asm  movd RET,mm6 \\r
140 }\r
141 \r
142 unsigned oc_enc_frag_sad2_thresh_mmxext(const unsigned char *_src,\r
143  const unsigned char *_ref1,const unsigned char *_ref2,int _ystride,\r
144  unsigned _thresh){\r
145   ptrdiff_t ret;\r
146   __asm{\r
147 #define REF1 ecx\r
148 #define REF2 edi\r
149 #define YSTRIDE esi\r
150 #define SRC edx\r
151 #define RET eax\r
152     mov YSTRIDE,_ystride\r
153     mov SRC,_src\r
154     mov REF1,_ref1\r
155     mov REF2,_ref2\r
156     movq mm0,[REF1]\r
157     movq mm1,[REF2]\r
158     movq mm2,[REF1+YSTRIDE]\r
159     movq mm3,[REF2+YSTRIDE]\r
160     xor RET,RET\r
161     movq mm4,[SRC]\r
162     pxor mm7,mm7\r
163     pcmpeqb mm6,mm6\r
164     movq mm5,[SRC+YSTRIDE]\r
165     psubb mm7,mm6\r
166     OC_SAD2_LOOP\r
167     OC_SAD2_LOOP\r
168     OC_SAD2_LOOP\r
169     OC_SAD2_TAIL\r
170     mov [ret],RET\r
171 #undef REF1\r
172 #undef REF2\r
173 #undef YSTRIDE\r
174 #undef SRC\r
175 #undef RET\r
176   }\r
177   return (unsigned)ret;\r
178 }\r
179 \r
180 /*Load an 8x4 array of pixel values from %[src] and %[ref] and compute their\r
181   16-bit difference in mm0...mm7.*/\r
182 #define OC_LOAD_SUB_8x4(_off) __asm{ \\r
183   __asm  movd mm0,[_off+SRC] \\r
184   __asm  movd mm4,[_off+REF] \\r
185   __asm  movd mm1,[_off+SRC+SRC_YSTRIDE] \\r
186   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
187   __asm  movd mm5,[_off+REF+REF_YSTRIDE] \\r
188   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
189   __asm  movd mm2,[_off+SRC] \\r
190   __asm  movd mm7,[_off+REF] \\r
191   __asm  movd mm3,[_off+SRC+SRC_YSTRIDE] \\r
192   __asm  movd mm6,[_off+REF+REF_YSTRIDE] \\r
193   __asm  punpcklbw mm0,mm4 \\r
194   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
195   __asm  punpcklbw mm4,mm4 \\r
196   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
197   __asm  psubw mm0,mm4 \\r
198   __asm  movd mm4,[_off+SRC] \\r
199   __asm  movq [_off*2+BUF],mm0 \\r
200   __asm  movd mm0,[_off+REF] \\r
201   __asm  punpcklbw mm1,mm5 \\r
202   __asm  punpcklbw mm5,mm5 \\r
203   __asm  psubw mm1,mm5 \\r
204   __asm  movd mm5,[_off+SRC+SRC_YSTRIDE] \\r
205   __asm  punpcklbw mm2,mm7 \\r
206   __asm  punpcklbw mm7,mm7 \\r
207   __asm  psubw mm2,mm7 \\r
208   __asm  movd mm7,[_off+REF+REF_YSTRIDE] \\r
209   __asm  punpcklbw mm3,mm6 \\r
210   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
211   __asm  punpcklbw mm6,mm6 \\r
212   __asm  psubw mm3,mm6 \\r
213   __asm  movd mm6,[_off+SRC] \\r
214   __asm  punpcklbw mm4,mm0 \\r
215   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
216   __asm  punpcklbw mm0,mm0 \\r
217   __asm  lea SRC,[SRC+SRC_YSTRIDE*2] \\r
218   __asm  psubw mm4,mm0 \\r
219   __asm  movd mm0,[_off+REF] \\r
220   __asm  punpcklbw mm5,mm7 \\r
221   __asm  neg SRC_YSTRIDE \\r
222   __asm  punpcklbw mm7,mm7 \\r
223   __asm  psubw mm5,mm7 \\r
224   __asm  movd mm7,[_off+SRC+SRC_YSTRIDE] \\r
225   __asm  punpcklbw mm6,mm0 \\r
226   __asm  lea REF,[REF+REF_YSTRIDE*2] \\r
227   __asm  punpcklbw mm0,mm0 \\r
228   __asm  neg REF_YSTRIDE \\r
229   __asm  psubw mm6,mm0 \\r
230   __asm  movd mm0,[_off+REF+REF_YSTRIDE] \\r
231   __asm  lea SRC,[SRC+SRC_YSTRIDE*8] \\r
232   __asm  punpcklbw mm7,mm0 \\r
233   __asm  neg SRC_YSTRIDE \\r
234   __asm  punpcklbw mm0,mm0 \\r
235   __asm  lea REF,[REF+REF_YSTRIDE*8] \\r
236   __asm  psubw mm7,mm0 \\r
237   __asm  neg REF_YSTRIDE \\r
238   __asm  movq mm0,[_off*2+BUF] \\r
239 }\r
240 \r
241 /*Load an 8x4 array of pixel values from %[src] into %%mm0...%%mm7.*/\r
242 #define OC_LOAD_8x4(_off) __asm{ \\r
243   __asm  movd mm0,[_off+SRC] \\r
244   __asm  movd mm1,[_off+SRC+YSTRIDE] \\r
245   __asm  movd mm2,[_off+SRC+YSTRIDE*2] \\r
246   __asm  pxor mm7,mm7 \\r
247   __asm  movd mm3,[_off+SRC+YSTRIDE3] \\r
248   __asm  punpcklbw mm0,mm7 \\r
249   __asm  movd mm4,[_off+SRC4] \\r
250   __asm  punpcklbw mm1,mm7 \\r
251   __asm  movd mm5,[_off+SRC4+YSTRIDE] \\r
252   __asm  punpcklbw mm2,mm7 \\r
253   __asm  movd mm6,[_off+SRC4+YSTRIDE*2] \\r
254   __asm  punpcklbw mm3,mm7 \\r
255   __asm  movd mm7,[_off+SRC4+YSTRIDE3] \\r
256   __asm  punpcklbw mm4,mm4 \\r
257   __asm  punpcklbw mm5,mm5 \\r
258   __asm  psrlw mm4,8 \\r
259   __asm  psrlw mm5,8 \\r
260   __asm  punpcklbw mm6,mm6 \\r
261   __asm  punpcklbw mm7,mm7 \\r
262   __asm  psrlw mm6,8 \\r
263   __asm  psrlw mm7,8 \\r
264 }\r
265 \r
266 /*Performs the first two stages of an 8-point 1-D Hadamard transform.\r
267   The transform is performed in place, except that outputs 0-3 are swapped with\r
268    outputs 4-7.\r
269   Outputs 2, 3, 6, and 7 from the second stage are negated (which allows us to\r
270    perform this stage in place with no temporary registers).*/\r
271 #define OC_HADAMARD_AB_8x4 __asm{ \\r
272   /*Stage A: \\r
273     Outputs 0-3 are swapped with 4-7 here.*/ \\r
274   __asm  paddw mm5,mm1 \\r
275   __asm  paddw mm6,mm2 \\r
276   __asm  paddw mm1,mm1 \\r
277   __asm  paddw mm2,mm2 \\r
278   __asm  psubw mm1,mm5 \\r
279   __asm  psubw mm2,mm6 \\r
280   __asm  paddw mm7,mm3 \\r
281   __asm  paddw mm4,mm0 \\r
282   __asm  paddw mm3,mm3 \\r
283   __asm  paddw mm0,mm0 \\r
284   __asm  psubw mm3,mm7 \\r
285   __asm  psubw mm0,mm4 \\r
286    /*Stage B:*/ \\r
287   __asm  paddw mm0,mm2 \\r
288   __asm  paddw mm1,mm3 \\r
289   __asm  paddw mm4,mm6 \\r
290   __asm  paddw mm5,mm7 \\r
291   __asm  paddw mm2,mm2 \\r
292   __asm  paddw mm3,mm3 \\r
293   __asm  paddw mm6,mm6 \\r
294   __asm  paddw mm7,mm7 \\r
295   __asm  psubw mm2,mm0 \\r
296   __asm  psubw mm3,mm1 \\r
297   __asm  psubw mm6,mm4 \\r
298   __asm  psubw mm7,mm5 \\r
299 }\r
300 \r
301 /*Performs the last stage of an 8-point 1-D Hadamard transform in place.\r
302   Outputs 1, 3, 5, and 7 are negated (which allows us to perform this stage in\r
303    place with no temporary registers).*/\r
304 #define OC_HADAMARD_C_8x4 __asm{ \\r
305   /*Stage C:*/ \\r
306   __asm  paddw mm0,mm1 \\r
307   __asm  paddw mm2,mm3 \\r
308   __asm  paddw mm4,mm5 \\r
309   __asm  paddw mm6,mm7 \\r
310   __asm  paddw mm1,mm1 \\r
311   __asm  paddw mm3,mm3 \\r
312   __asm  paddw mm5,mm5 \\r
313   __asm  paddw mm7,mm7 \\r
314   __asm  psubw mm1,mm0 \\r
315   __asm  psubw mm3,mm2 \\r
316   __asm  psubw mm5,mm4 \\r
317   __asm  psubw mm7,mm6 \\r
318 }\r
319 \r
320 /*Performs an 8-point 1-D Hadamard transform.\r
321   The transform is performed in place, except that outputs 0-3 are swapped with\r
322    outputs 4-7.\r
323   Outputs 1, 2, 5 and 6 are negated (which allows us to perform the transform\r
324    in place with no temporary registers).*/\r
325 #define OC_HADAMARD_8x4 __asm{ \\r
326   OC_HADAMARD_AB_8x4 \\r
327   OC_HADAMARD_C_8x4 \\r
328 }\r
329 \r
330 /*Performs the first part of the final stage of the Hadamard transform and\r
331    summing of absolute values.\r
332   At the end of this part, mm1 will contain the DC coefficient of the\r
333    transform.*/\r
334 #define OC_HADAMARD_C_ABS_ACCUM_A_8x4(_r6,_r7) __asm{ \\r
335   /*We use the fact that \\r
336       (abs(a+b)+abs(a-b))/2=max(abs(a),abs(b)) \\r
337      to merge the final butterfly with the abs and the first stage of \\r
338      accumulation. \\r
339     Thus we can avoid using pabsw, which is not available until SSSE3. \\r
340     Emulating pabsw takes 3 instructions, so the straightforward MMXEXT \\r
341      implementation would be (3+3)*8+7=55 instructions (+4 for spilling \\r
342      registers). \\r
343     Even with pabsw, it would be (3+1)*8+7=39 instructions (with no spills). \\r
344     This implementation is only 26 (+4 for spilling registers).*/ \\r
345   __asm  movq [_r7+BUF],mm7 \\r
346   __asm  movq [_r6+BUF],mm6 \\r
347   /*mm7={0x7FFF}x4 \\r
348     mm0=max(abs(mm0),abs(mm1))-0x7FFF*/ \\r
349   __asm  pcmpeqb mm7,mm7 \\r
350   __asm  movq mm6,mm0 \\r
351   __asm  psrlw mm7,1 \\r
352   __asm  paddw mm6,mm1 \\r
353   __asm  pmaxsw mm0,mm1 \\r
354   __asm  paddsw mm6,mm7 \\r
355   __asm  psubw mm0,mm6 \\r
356   /*mm2=max(abs(mm2),abs(mm3))-0x7FFF \\r
357     mm4=max(abs(mm4),abs(mm5))-0x7FFF*/ \\r
358   __asm  movq mm6,mm2 \\r
359   __asm  movq mm1,mm4 \\r
360   __asm  pmaxsw mm2,mm3 \\r
361   __asm  pmaxsw mm4,mm5 \\r
362   __asm  paddw mm6,mm3 \\r
363   __asm  paddw mm1,mm5 \\r
364   __asm  movq mm3,[_r7+BUF] \\r
365 }\r
366 \r
367 /*Performs the second part of the final stage of the Hadamard transform and\r
368    summing of absolute values.*/\r
369 #define OC_HADAMARD_C_ABS_ACCUM_B_8x4(_r6,_r7) __asm{ \\r
370   __asm  paddsw mm6,mm7 \\r
371   __asm  movq mm5,[_r6+BUF] \\r
372   __asm  paddsw mm1,mm7 \\r
373   __asm  psubw mm2,mm6 \\r
374   __asm  psubw mm4,mm1 \\r
375   /*mm7={1}x4 (needed for the horizontal add that follows) \\r
376     mm0+=mm2+mm4+max(abs(mm3),abs(mm5))-0x7FFF*/ \\r
377   __asm  movq mm6,mm3 \\r
378   __asm  pmaxsw mm3,mm5 \\r
379   __asm  paddw mm0,mm2 \\r
380   __asm  paddw mm6,mm5 \\r
381   __asm  paddw mm0,mm4 \\r
382   __asm  paddsw mm6,mm7 \\r
383   __asm  paddw mm0,mm3 \\r
384   __asm  psrlw mm7,14 \\r
385   __asm  psubw mm0,mm6 \\r
386 }\r
387 \r
388 /*Performs the last stage of an 8-point 1-D Hadamard transform, takes the\r
389    absolute value of each component, and accumulates everything into mm0.\r
390   This is the only portion of SATD which requires MMXEXT (we could use plain\r
391    MMX, but it takes 4 instructions and an extra register to work around the\r
392    lack of a pmaxsw, which is a pretty serious penalty).*/\r
393 #define OC_HADAMARD_C_ABS_ACCUM_8x4(_r6,_r7) __asm{ \\r
394   OC_HADAMARD_C_ABS_ACCUM_A_8x4(_r6,_r7) \\r
395   OC_HADAMARD_C_ABS_ACCUM_B_8x4(_r6,_r7) \\r
396 }\r
397 \r
398 /*Performs an 8-point 1-D Hadamard transform, takes the absolute value of each\r
399    component, and accumulates everything into mm0.\r
400   Note that mm0 will have an extra 4 added to each column, and that after\r
401    removing this value, the remainder will be half the conventional value.*/\r
402 #define OC_HADAMARD_ABS_ACCUM_8x4(_r6,_r7) __asm{ \\r
403   OC_HADAMARD_AB_8x4 \\r
404   OC_HADAMARD_C_ABS_ACCUM_8x4(_r6,_r7) \\r
405 }\r
406 \r
407 /*Performs two 4x4 transposes (mostly) in place.\r
408   On input, {mm0,mm1,mm2,mm3} contains rows {e,f,g,h}, and {mm4,mm5,mm6,mm7}\r
409    contains rows {a,b,c,d}.\r
410   On output, {0x40,0x50,0x60,0x70}+_off+BUF contains {e,f,g,h}^T, and\r
411    {mm4,mm5,mm6,mm7} contains the transposed rows {a,b,c,d}^T.*/\r
412 #define OC_TRANSPOSE_4x4x2(_off) __asm{ \\r
413   /*First 4x4 transpose:*/ \\r
414   __asm  movq [0x10+_off+BUF],mm5 \\r
415   /*mm0 = e3 e2 e1 e0 \\r
416     mm1 = f3 f2 f1 f0 \\r
417     mm2 = g3 g2 g1 g0 \\r
418     mm3 = h3 h2 h1 h0*/ \\r
419   __asm  movq mm5,mm2 \\r
420   __asm  punpcklwd mm2,mm3 \\r
421   __asm  punpckhwd mm5,mm3 \\r
422   __asm  movq mm3,mm0 \\r
423   __asm  punpcklwd mm0,mm1 \\r
424   __asm  punpckhwd mm3,mm1 \\r
425   /*mm0 = f1 e1 f0 e0 \\r
426     mm3 = f3 e3 f2 e2 \\r
427     mm2 = h1 g1 h0 g0 \\r
428     mm5 = h3 g3 h2 g2*/ \\r
429   __asm  movq mm1,mm0 \\r
430   __asm  punpckldq mm0,mm2 \\r
431   __asm  punpckhdq mm1,mm2 \\r
432   __asm  movq mm2,mm3 \\r
433   __asm  punpckhdq mm3,mm5 \\r
434   __asm  movq [0x40+_off+BUF],mm0 \\r
435   __asm  punpckldq mm2,mm5 \\r
436   /*mm0 = h0 g0 f0 e0 \\r
437     mm1 = h1 g1 f1 e1 \\r
438     mm2 = h2 g2 f2 e2 \\r
439     mm3 = h3 g3 f3 e3*/ \\r
440   __asm  movq mm5,[0x10+_off+BUF] \\r
441   /*Second 4x4 transpose:*/ \\r
442   /*mm4 = a3 a2 a1 a0 \\r
443     mm5 = b3 b2 b1 b0 \\r
444     mm6 = c3 c2 c1 c0 \\r
445     mm7 = d3 d2 d1 d0*/ \\r
446   __asm  movq mm0,mm6 \\r
447   __asm  punpcklwd mm6,mm7 \\r
448   __asm  movq [0x50+_off+BUF],mm1 \\r
449   __asm  punpckhwd mm0,mm7 \\r
450   __asm  movq mm7,mm4 \\r
451   __asm  punpcklwd mm4,mm5 \\r
452   __asm  movq [0x60+_off+BUF],mm2 \\r
453   __asm  punpckhwd mm7,mm5 \\r
454   /*mm4 = b1 a1 b0 a0 \\r
455     mm7 = b3 a3 b2 a2 \\r
456     mm6 = d1 c1 d0 c0 \\r
457     mm0 = d3 c3 d2 c2*/ \\r
458   __asm  movq mm5,mm4 \\r
459   __asm  punpckldq mm4,mm6 \\r
460   __asm  movq [0x70+_off+BUF],mm3 \\r
461   __asm  punpckhdq mm5,mm6 \\r
462   __asm  movq mm6,mm7 \\r
463   __asm  punpckhdq mm7,mm0 \\r
464   __asm  punpckldq mm6,mm0 \\r
465   /*mm4 = d0 c0 b0 a0 \\r
466     mm5 = d1 c1 b1 a1 \\r
467     mm6 = d2 c2 b2 a2 \\r
468     mm7 = d3 c3 b3 a3*/ \\r
469 }\r
470 \r
471 static unsigned oc_int_frag_satd_mmxext(unsigned *_dc,\r
472  const unsigned char *_src,int _src_ystride,\r
473  const unsigned char *_ref,int _ref_ystride){\r
474   OC_ALIGN8(ogg_int16_t buf[64]);\r
475   ogg_int16_t *bufp;\r
476   unsigned     ret1;\r
477   unsigned     ret2;\r
478   unsigned     dc;\r
479   bufp=buf;\r
480   __asm{\r
481 #define SRC esi\r
482 #define REF eax\r
483 #define SRC_YSTRIDE ecx\r
484 #define REF_YSTRIDE edx\r
485 #define BUF edi\r
486 #define RET eax\r
487 #define RET2 ecx\r
488 #define DC edx\r
489 #define DC_WORD dx\r
490     mov SRC,_src\r
491     mov SRC_YSTRIDE,_src_ystride\r
492     mov REF,_ref\r
493     mov REF_YSTRIDE,_ref_ystride\r
494     mov BUF,bufp\r
495     OC_LOAD_SUB_8x4(0x00)\r
496     OC_HADAMARD_8x4\r
497     OC_TRANSPOSE_4x4x2(0x00)\r
498     /*Finish swapping out this 8x4 block to make room for the next one.\r
499       mm0...mm3 have been swapped out already.*/\r
500     movq [0x00+BUF],mm4\r
501     movq [0x10+BUF],mm5\r
502     movq [0x20+BUF],mm6\r
503     movq [0x30+BUF],mm7\r
504     OC_LOAD_SUB_8x4(0x04)\r
505     OC_HADAMARD_8x4\r
506     OC_TRANSPOSE_4x4x2(0x08)\r
507     /*Here the first 4x4 block of output from the last transpose is the second\r
508        4x4 block of input for the next transform.\r
509       We have cleverly arranged that it already be in the appropriate place, so\r
510        we only have to do half the loads.*/\r
511     movq mm1,[0x10+BUF]\r
512     movq mm2,[0x20+BUF]\r
513     movq mm3,[0x30+BUF]\r
514     movq mm0,[0x00+BUF]\r
515     /*We split out the stages here so we can save the DC coefficient in the\r
516        middle.*/\r
517     OC_HADAMARD_AB_8x4\r
518     OC_HADAMARD_C_ABS_ACCUM_A_8x4(0x28,0x38)\r
519     movd DC,mm1\r
520     OC_HADAMARD_C_ABS_ACCUM_B_8x4(0x28,0x38)\r
521     /*Up to this point, everything fit in 16 bits (8 input + 1 for the\r
522        difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1\r
523        for the factor of two we dropped + 3 for the vertical accumulation).\r
524       Now we finally have to promote things to dwords.\r
525       We break this part out of OC_HADAMARD_ABS_ACCUM_8x4 to hide the long\r
526        latency of pmaddwd by starting the next series of loads now.*/\r
527     pmaddwd mm0,mm7\r
528     movq mm1,[0x50+BUF]\r
529     movq mm5,[0x58+BUF]\r
530     movq mm4,mm0\r
531     movq mm2,[0x60+BUF]\r
532     punpckhdq mm0,mm0\r
533     movq mm6,[0x68+BUF]\r
534     paddd mm4,mm0\r
535     movq mm3,[0x70+BUF]\r
536     movd RET2,mm4\r
537     movq mm7,[0x78+BUF]\r
538     /*The sums produced by OC_HADAMARD_ABS_ACCUM_8x4 each have an extra 4\r
539        added to them, and a factor of two removed; correct the final sum here.*/\r
540     lea RET,[RET+RET-32]\r
541     movq mm0,[0x40+BUF]\r
542     movq mm4,[0x48+BUF]\r
543     OC_HADAMARD_ABS_ACCUM_8x4(0x68,0x78)\r
544     pmaddwd mm0,mm7\r
545     /*Compute abs(dc).*/\r
546     movsx RET,DC_WORD\r
547     cdq\r
548     add RET2,RET2\r
549     add RET,DC\r
550     movq mm4,mm0\r
551     punpckhdq mm0,mm0\r
552     xor DC,RET\r
553     paddd mm4,mm0\r
554     sub RET2,DC\r
555     movd RET,mm4\r
556     lea RET,[RET2+RET*2-64]\r
557     mov ret1,RET\r
558     mov dc,DC\r
559 #undef SRC\r
560 #undef REF\r
561 #undef SRC_YSTRIDE\r
562 #undef REF_YSTRIDE\r
563 #undef BUF\r
564 #undef RET\r
565 #undef RET2\r
566 #undef DC\r
567 #undef DC_WORD\r
568   }\r
569   *_dc=dc;\r
570   return ret1;\r
571 }\r
572 \r
573 unsigned oc_enc_frag_satd_mmxext(unsigned *_dc,const unsigned char *_src,\r
574  const unsigned char *_ref,int _ystride){\r
575   return oc_int_frag_satd_mmxext(_dc,_src,_ystride,_ref,_ystride);\r
576 }\r
577 \r
578 \r
579 /*Our internal implementation of frag_copy2 takes an extra stride parameter so\r
580    we can share code with oc_enc_frag_satd2_mmxext().*/\r
581 static void oc_int_frag_copy2_mmxext(unsigned char *_dst,int _dst_ystride,\r
582  const unsigned char *_src1,const unsigned char *_src2,int _src_ystride){\r
583   __asm{\r
584     /*Load the first 3 rows.*/\r
585 #define DST_YSTRIDE edi\r
586 #define SRC_YSTRIDE esi\r
587 #define DST eax\r
588 #define SRC1 edx\r
589 #define SRC2 ecx\r
590     mov DST_YSTRIDE,_dst_ystride\r
591     mov SRC_YSTRIDE,_src_ystride\r
592     mov DST,_dst\r
593     mov SRC1,_src1\r
594     mov SRC2,_src2\r
595     movq mm0,[SRC1]\r
596     movq mm1,[SRC2]\r
597     movq mm2,[SRC1+SRC_YSTRIDE]\r
598     lea SRC1,[SRC1+SRC_YSTRIDE*2]\r
599     movq mm3,[SRC2+SRC_YSTRIDE]\r
600     lea SRC2,[SRC2+SRC_YSTRIDE*2]\r
601     pxor mm7,mm7\r
602     movq mm4,[SRC1]\r
603     pcmpeqb mm6,mm6\r
604     movq mm5,[SRC2]\r
605     /*mm7={1}x8.*/\r
606     psubb mm7,mm6\r
607     /*Start averaging mm0 and mm1 into mm6.*/\r
608     movq mm6,mm0\r
609     pxor mm0,mm1\r
610     pavgb mm6,mm1\r
611     /*mm1 is free, start averaging mm3 into mm2 using mm1.*/\r
612     movq mm1,mm2\r
613     pand mm0,mm7\r
614     pavgb mm2,mm3\r
615     pxor mm1,mm3\r
616     /*mm3 is free.*/\r
617     psubb mm6,mm0\r
618     /*mm0 is free, start loading the next row.*/\r
619     movq mm0,[SRC1+SRC_YSTRIDE]\r
620     /*Start averaging mm5 and mm4 using mm3.*/\r
621     movq mm3,mm4\r
622     /*mm6 [row 0] is done; write it out.*/\r
623     movq [DST],mm6\r
624     pand mm1,mm7\r
625     pavgb mm4,mm5\r
626     psubb mm2,mm1\r
627     /*mm1 is free, continue loading the next row.*/\r
628     movq mm1,[SRC2+SRC_YSTRIDE]\r
629     pxor mm3,mm5\r
630     lea SRC1,[SRC1+SRC_YSTRIDE*2]\r
631     /*mm2 [row 1] is done; write it out.*/\r
632     movq [DST+DST_YSTRIDE],mm2\r
633     pand mm3,mm7\r
634     /*Start loading the next row.*/\r
635     movq mm2,[SRC1]\r
636     lea DST,[DST+DST_YSTRIDE*2]\r
637     psubb mm4,mm3\r
638     lea SRC2,[SRC2+SRC_YSTRIDE*2]\r
639     /*mm4 [row 2] is done; write it out.*/\r
640     movq [DST],mm4\r
641     /*Continue loading the next row.*/\r
642     movq mm3,[SRC2]\r
643     /*Start averaging mm0 and mm1 into mm6.*/\r
644     movq mm6,mm0\r
645     pxor mm0,mm1\r
646     /*Start loading the next row.*/\r
647     movq mm4,[SRC1+SRC_YSTRIDE]\r
648     pavgb mm6,mm1\r
649     /*mm1 is free; start averaging mm3 into mm2 using mm1.*/\r
650     movq mm1,mm2\r
651     pand mm0,mm7\r
652     /*Continue loading the next row.*/\r
653     movq mm5,[SRC2+SRC_YSTRIDE]\r
654     pavgb mm2,mm3\r
655     lea SRC1,[SRC1+SRC_YSTRIDE*2]\r
656     pxor mm1,mm3\r
657     /*mm3 is free.*/\r
658     psubb mm6,mm0\r
659     /*mm0 is free, start loading the next row.*/\r
660     movq mm0,[SRC1]\r
661     /*Start averaging mm5 into mm4 using mm3.*/\r
662     movq mm3,mm4\r
663     /*mm6 [row 3] is done; write it out.*/\r
664     movq [DST+DST_YSTRIDE],mm6\r
665     pand mm1,mm7\r
666     lea SRC2,[SRC2+SRC_YSTRIDE*2]\r
667     pavgb mm4,mm5\r
668     lea DST,[DST+DST_YSTRIDE*2]\r
669     psubb mm2,mm1\r
670     /*mm1 is free; continue loading the next row.*/\r
671     movq mm1,[SRC2]\r
672     pxor mm3,mm5\r
673     /*mm2 [row 4] is done; write it out.*/\r
674     movq [DST],mm2\r
675     pand mm3,mm7\r
676     /*Start loading the next row.*/\r
677     movq mm2,[SRC1+SRC_YSTRIDE]\r
678     psubb mm4,mm3\r
679     /*Start averaging mm0 and mm1 into mm6.*/\r
680     movq mm6,mm0\r
681     /*Continue loading the next row.*/\r
682     movq mm3,[SRC2+SRC_YSTRIDE]\r
683     /*mm4 [row 5] is done; write it out.*/\r
684     movq [DST+DST_YSTRIDE],mm4\r
685     pxor mm0,mm1\r
686     pavgb mm6,mm1\r
687     /*mm4 is free; start averaging mm3 into mm2 using mm4.*/\r
688     movq mm4,mm2\r
689     pand mm0,mm7\r
690     pavgb mm2,mm3\r
691     pxor mm4,mm3\r
692     lea DST,[DST+DST_YSTRIDE*2]\r
693     psubb mm6,mm0\r
694     pand mm4,mm7\r
695     /*mm6 [row 6] is done, write it out.*/\r
696     movq [DST],mm6\r
697     psubb mm2,mm4\r
698     /*mm2 [row 7] is done, write it out.*/\r
699     movq [DST+DST_YSTRIDE],mm2\r
700 #undef SRC1\r
701 #undef SRC2\r
702 #undef SRC_YSTRIDE\r
703 #undef DST_YSTRIDE\r
704 #undef DST\r
705   }\r
706 }\r
707 \r
708 unsigned oc_enc_frag_satd2_mmxext(unsigned *_dc,const unsigned char *_src,\r
709  const unsigned char *_ref1,const unsigned char *_ref2,int _ystride){\r
710   OC_ALIGN8(unsigned char ref[64]);\r
711   oc_int_frag_copy2_mmxext(ref,8,_ref1,_ref2,_ystride);\r
712   return oc_int_frag_satd_mmxext(_dc,_src,_ystride,ref,8);\r
713 }\r
714 \r
715 unsigned oc_enc_frag_intra_satd_mmxext(unsigned *_dc,const unsigned char *_src,\r
716  int _ystride){\r
717   OC_ALIGN8(ogg_int16_t buf[64]);\r
718   ogg_int16_t *bufp;\r
719   unsigned     ret1;\r
720   unsigned     ret2;\r
721   unsigned     dc;\r
722   bufp=buf;\r
723   __asm{\r
724 #define SRC eax\r
725 #define SRC4 esi\r
726 #define BUF edi\r
727 #define YSTRIDE edx\r
728 #define YSTRIDE3 ecx\r
729 #define RET eax\r
730 #define RET2 ecx\r
731 #define DC edx\r
732 #define DC_WORD dx\r
733     mov SRC,_src\r
734     mov BUF,bufp\r
735     mov YSTRIDE,_ystride\r
736     /* src4 = src+4*ystride */\r
737     lea SRC4,[SRC+YSTRIDE*4]\r
738     /* ystride3 = 3*ystride */\r
739     lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]\r
740     OC_LOAD_8x4(0x00)\r
741     OC_HADAMARD_8x4\r
742     OC_TRANSPOSE_4x4x2(0x00)\r
743     /*Finish swapping out this 8x4 block to make room for the next one.\r
744       mm0...mm3 have been swapped out already.*/\r
745     movq [0x00+BUF],mm4\r
746     movq [0x10+BUF],mm5\r
747     movq [0x20+BUF],mm6\r
748     movq [0x30+BUF],mm7\r
749     OC_LOAD_8x4(0x04)\r
750     OC_HADAMARD_8x4\r
751     OC_TRANSPOSE_4x4x2(0x08)\r
752     /*Here the first 4x4 block of output from the last transpose is the second\r
753       4x4 block of input for the next transform.\r
754       We have cleverly arranged that it already be in the appropriate place, so\r
755       we only have to do half the loads.*/\r
756     movq mm1,[0x10+BUF]\r
757     movq mm2,[0x20+BUF]\r
758     movq mm3,[0x30+BUF]\r
759     movq mm0,[0x00+BUF]\r
760     /*We split out the stages here so we can save the DC coefficient in the\r
761       middle.*/\r
762     OC_HADAMARD_AB_8x4\r
763     OC_HADAMARD_C_ABS_ACCUM_A_8x4(0x28,0x38)\r
764     movd DC,mm1\r
765     OC_HADAMARD_C_ABS_ACCUM_B_8x4(0x28,0x38)\r
766     /*Up to this point, everything fit in 16 bits (8 input + 1 for the\r
767       difference + 2*3 for the two 8-point 1-D Hadamards - 1 for the abs - 1\r
768       for the factor of two we dropped + 3 for the vertical accumulation).\r
769       Now we finally have to promote things to dwords.\r
770       We break this part out of OC_HADAMARD_ABS_ACCUM_8x4 to hide the long\r
771       latency of pmaddwd by starting the next series of loads now.*/\r
772     pmaddwd mm0,mm7\r
773     movq mm1,[0x50+BUF]\r
774     movq mm5,[0x58+BUF]\r
775     movq mm2,[0x60+BUF]\r
776     movq mm4,mm0\r
777     movq mm6,[0x68+BUF]\r
778     punpckhdq mm0,mm0\r
779     movq mm3,[0x70+BUF]\r
780     paddd mm4,mm0\r
781     movq mm7,[0x78+BUF]\r
782     movd RET,mm4\r
783     movq mm0,[0x40+BUF]\r
784     movq mm4,[0x48+BUF]\r
785     OC_HADAMARD_ABS_ACCUM_8x4(0x68,0x78)\r
786     pmaddwd mm0,mm7\r
787     /*We assume that the DC coefficient is always positive (which is true,\r
788     because the input to the INTRA transform was not a difference).*/\r
789     movzx DC,DC_WORD\r
790     add RET,RET\r
791     sub RET, DC\r
792     movq mm4,mm0\r
793     punpckhdq mm0,mm0\r
794     paddd mm4,mm0\r
795     movd RET2,mm4\r
796     lea RET,[-64+RET+RET2*2]\r
797     mov [dc],DC\r
798     mov [ret1],RET\r
799 #undef SRC\r
800 #undef SRC4\r
801 #undef BUF\r
802 #undef YSTRIDE\r
803 #undef YSTRIDE3\r
804 #undef RET\r
805 #undef RET2\r
806 #undef DC\r
807 #undef DC_WORD\r
808   }\r
809   *_dc=dc;\r
810   return ret1;\r
811 }\r
812 \r
813 void oc_enc_frag_sub_mmx(ogg_int16_t _residue[64],\r
814  const unsigned char *_src, const unsigned char *_ref,int _ystride){\r
815   int i;\r
816   __asm  pxor mm7,mm7\r
817   for(i=4;i-->0;){\r
818     __asm{\r
819 #define SRC edx\r
820 #define YSTRIDE esi\r
821 #define RESIDUE eax\r
822 #define REF ecx\r
823       mov YSTRIDE,_ystride\r
824       mov RESIDUE,_residue\r
825       mov SRC,_src\r
826       mov REF,_ref\r
827       /*mm0=[src]*/\r
828       movq mm0,[SRC]\r
829       /*mm1=[ref]*/\r
830       movq mm1,[REF]\r
831       /*mm4=[src+ystride]*/\r
832       movq mm4,[SRC+YSTRIDE]\r
833       /*mm5=[ref+ystride]*/\r
834       movq mm5,[REF+YSTRIDE]\r
835       /*Compute [src]-[ref].*/\r
836       movq mm2,mm0\r
837       punpcklbw mm0,mm7\r
838       movq mm3,mm1\r
839       punpckhbw mm2,mm7\r
840       punpcklbw mm1,mm7\r
841       punpckhbw mm3,mm7\r
842       psubw mm0,mm1\r
843       psubw mm2,mm3\r
844       /*Compute [src+ystride]-[ref+ystride].*/\r
845       movq mm1,mm4\r
846       punpcklbw mm4,mm7\r
847       movq mm3,mm5\r
848       punpckhbw mm1,mm7\r
849       lea SRC,[SRC+YSTRIDE*2]\r
850       punpcklbw mm5,mm7\r
851       lea REF,[REF+YSTRIDE*2]\r
852       punpckhbw mm3,mm7\r
853       psubw mm4,mm5\r
854       psubw mm1,mm3\r
855       /*Write the answer out.*/\r
856       movq [RESIDUE+0x00],mm0\r
857       movq [RESIDUE+0x08],mm2\r
858       movq [RESIDUE+0x10],mm4\r
859       movq [RESIDUE+0x18],mm1\r
860       lea RESIDUE,[RESIDUE+0x20]\r
861       mov _residue,RESIDUE\r
862       mov _src,SRC\r
863       mov _ref,REF\r
864 #undef SRC\r
865 #undef YSTRIDE\r
866 #undef RESIDUE\r
867 #undef REF\r
868     }\r
869   }\r
870 }\r
871 \r
872 void oc_enc_frag_sub_128_mmx(ogg_int16_t _residue[64],\r
873  const unsigned char *_src,int _ystride){\r
874    __asm{\r
875 #define YSTRIDE edx\r
876 #define YSTRIDE3 edi\r
877 #define RESIDUE ecx\r
878 #define SRC eax\r
879     mov YSTRIDE,_ystride\r
880     mov RESIDUE,_residue\r
881     mov SRC,_src\r
882     /*mm0=[src]*/\r
883     movq mm0,[SRC]\r
884     /*mm1=[src+ystride]*/\r
885     movq mm1,[SRC+YSTRIDE]\r
886     /*mm6={-1}x4*/\r
887     pcmpeqw mm6,mm6\r
888     /*mm2=[src+2*ystride]*/\r
889     movq mm2,[SRC+YSTRIDE*2]\r
890     /*[ystride3]=3*[ystride]*/\r
891     lea YSTRIDE3,[YSTRIDE+YSTRIDE*2]\r
892     /*mm6={1}x4*/\r
893     psllw mm6,15\r
894     /*mm3=[src+3*ystride]*/\r
895     movq mm3,[SRC+YSTRIDE3]\r
896     /*mm6={128}x4*/\r
897     psrlw mm6,8\r
898     /*mm7=0*/ \r
899     pxor mm7,mm7\r
900     /*[src]=[src]+4*[ystride]*/\r
901     lea SRC,[SRC+YSTRIDE*4]\r
902     /*Compute [src]-128 and [src+ystride]-128*/\r
903     movq mm4,mm0\r
904     punpcklbw mm0,mm7\r
905     movq mm5,mm1\r
906     punpckhbw mm4,mm7\r
907     psubw mm0,mm6\r
908     punpcklbw mm1,mm7\r
909     psubw mm4,mm6\r
910     punpckhbw mm5,mm7\r
911     psubw mm1,mm6\r
912     psubw mm5,mm6\r
913     /*Write the answer out.*/\r
914     movq [RESIDUE+0x00],mm0\r
915     movq [RESIDUE+0x08],mm4\r
916     movq [RESIDUE+0x10],mm1\r
917     movq [RESIDUE+0x18],mm5\r
918     /*mm0=[src+4*ystride]*/\r
919     movq mm0,[SRC]\r
920     /*mm1=[src+5*ystride]*/\r
921     movq mm1,[SRC+YSTRIDE]\r
922     /*Compute [src+2*ystride]-128 and [src+3*ystride]-128*/\r
923     movq mm4,mm2\r
924     punpcklbw mm2,mm7\r
925     movq mm5,mm3\r
926     punpckhbw mm4,mm7\r
927     psubw mm2,mm6\r
928     punpcklbw mm3,mm7\r
929     psubw mm4,mm6\r
930     punpckhbw mm5,mm7\r
931     psubw mm3,mm6\r
932     psubw mm5,mm6\r
933     /*Write the answer out.*/\r
934     movq [RESIDUE+0x20],mm2\r
935     movq [RESIDUE+0x28],mm4\r
936     movq [RESIDUE+0x30],mm3\r
937     movq [RESIDUE+0x38],mm5\r
938     /*Compute [src+6*ystride]-128 and [src+7*ystride]-128*/\r
939     movq mm2,[SRC+YSTRIDE*2]\r
940     movq mm3,[SRC+YSTRIDE3]\r
941     movq mm4,mm0\r
942     punpcklbw mm0,mm7\r
943     movq mm5,mm1\r
944     punpckhbw mm4,mm7\r
945     psubw mm0,mm6\r
946     punpcklbw mm1,mm7\r
947     psubw mm4,mm6\r
948     punpckhbw mm5,mm7\r
949     psubw mm1,mm6\r
950     psubw mm5,mm6\r
951     /*Write the answer out.*/\r
952     movq [RESIDUE+0x40],mm0\r
953     movq [RESIDUE+0x48],mm4\r
954     movq [RESIDUE+0x50],mm1\r
955     movq [RESIDUE+0x58],mm5\r
956     /*Compute [src+6*ystride]-128 and [src+7*ystride]-128*/\r
957     movq mm4,mm2\r
958     punpcklbw mm2,mm7\r
959     movq mm5,mm3\r
960     punpckhbw mm4,mm7\r
961     psubw mm2,mm6\r
962     punpcklbw mm3,mm7\r
963     psubw mm4,mm6\r
964     punpckhbw mm5,mm7\r
965     psubw mm3,mm6\r
966     psubw mm5,mm6\r
967     /*Write the answer out.*/\r
968     movq [RESIDUE+0x60],mm2\r
969     movq [RESIDUE+0x68],mm4\r
970     movq [RESIDUE+0x70],mm3\r
971     movq [RESIDUE+0x78],mm5\r
972 #undef YSTRIDE\r
973 #undef YSTRIDE3\r
974 #undef RESIDUE\r
975 #undef SRC\r
976   }\r
977 }\r
978 \r
979 void oc_enc_frag_copy2_mmxext(unsigned char *_dst,\r
980  const unsigned char *_src1,const unsigned char *_src2,int _ystride){\r
981   oc_int_frag_copy2_mmxext(_dst,_ystride,_src1,_src2,_ystride);\r
982 }\r
983 \r
984 #endif\r