55ea7371d3e72ed48c197ef6b389987389e1fe92
[ffmpeg.git] / libavcodec / ppc / dsputil_altivec.c
1 /*
2  * Copyright (c) 2002 Brian Foley
3  * Copyright (c) 2002 Dieter Shirley
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19  
20 #include "../dsputil.h"
21 #include "dsputil_altivec.h"
22
23 #if CONFIG_DARWIN
24 #include <sys/sysctl.h>
25 #endif
26
27 int pix_abs16x16_x2_altivec(uint8_t *pix1, uint8_t *pix2, int line_size)
28 {
29     int i;
30     int s __attribute__((aligned(16)));
31     const vector unsigned char zero = (const vector unsigned char)(0);
32     vector unsigned char *tv;
33     vector unsigned char pix1v, pix2v, pix2iv, avgv, t5;
34     vector unsigned int sad;
35     vector signed int sumdiffs;
36
37     s = 0;
38     sad = (vector unsigned int)(0);
39     for(i=0;i<16;i++) {
40         /*
41            Read unaligned pixels into our vectors. The vectors are as follows:
42            pix1v: pix1[0]-pix1[15]
43            pix2v: pix2[0]-pix2[15]      pix2iv: pix2[1]-pix2[16]
44         */
45         tv = (vector unsigned char *) pix1;
46         pix1v = vec_perm(tv[0], tv[1], vec_lvsl(0, pix1));
47         
48         tv = (vector unsigned char *) &pix2[0];
49         pix2v = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix2[0]));
50
51         tv = (vector unsigned char *) &pix2[1];
52         pix2iv = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix2[1]));
53
54         /* Calculate the average vector */
55         avgv = vec_avg(pix2v, pix2iv);
56
57         /* Calculate a sum of abs differences vector */
58         t5 = vec_sub(vec_max(pix1v, avgv), vec_min(pix1v, avgv));
59
60         /* Add each 4 pixel group together and put 4 results into sad */
61         sad = vec_sum4s(t5, sad);
62         
63         pix1 += line_size;
64         pix2 += line_size;
65     }
66     /* Sum up the four partial sums, and put the result into s */
67     sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
68     sumdiffs = vec_splat(sumdiffs, 3);
69     vec_ste(sumdiffs, 0, &s);
70
71     return s;
72 }
73
74 int pix_abs16x16_y2_altivec(uint8_t *pix1, uint8_t *pix2, int line_size)
75 {
76     int i;
77     int s __attribute__((aligned(16)));
78     const vector unsigned char zero = (const vector unsigned char)(0);
79     vector unsigned char *tv;
80     vector unsigned char pix1v, pix2v, pix3v, avgv, t5;
81     vector unsigned int sad;
82     vector signed int sumdiffs;
83     uint8_t *pix3 = pix2 + line_size;
84
85     s = 0;
86     sad = (vector unsigned int)(0);
87
88     /*
89        Due to the fact that pix3 = pix2 + line_size, the pix3 of one
90        iteration becomes pix2 in the next iteration. We can use this
91        fact to avoid a potentially expensive unaligned read, each
92        time around the loop.
93        Read unaligned pixels into our vectors. The vectors are as follows:
94        pix2v: pix2[0]-pix2[15]
95        Split the pixel vectors into shorts
96     */
97     tv = (vector unsigned char *) &pix2[0];
98     pix2v = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix2[0]));
99     
100     for(i=0;i<16;i++) {
101         /*
102            Read unaligned pixels into our vectors. The vectors are as follows:
103            pix1v: pix1[0]-pix1[15]
104            pix3v: pix3[0]-pix3[15]
105         */
106         tv = (vector unsigned char *) pix1;
107         pix1v = vec_perm(tv[0], tv[1], vec_lvsl(0, pix1));
108
109         tv = (vector unsigned char *) &pix3[0];
110         pix3v = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix3[0]));
111
112         /* Calculate the average vector */
113         avgv = vec_avg(pix2v, pix3v);
114
115         /* Calculate a sum of abs differences vector */
116         t5 = vec_sub(vec_max(pix1v, avgv), vec_min(pix1v, avgv));
117
118         /* Add each 4 pixel group together and put 4 results into sad */
119         sad = vec_sum4s(t5, sad);
120         
121         pix1 += line_size;
122         pix2v = pix3v;
123         pix3 += line_size;
124         
125     }
126     
127     /* Sum up the four partial sums, and put the result into s */
128     sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
129     sumdiffs = vec_splat(sumdiffs, 3);
130     vec_ste(sumdiffs, 0, &s);
131     return s;    
132 }
133
134 int pix_abs16x16_xy2_altivec(uint8_t *pix1, uint8_t *pix2, int line_size)
135 {
136     int i;
137     int s __attribute__((aligned(16)));
138     uint8_t *pix3 = pix2 + line_size;
139     const vector unsigned char zero = (const vector unsigned char)(0);
140     const vector unsigned short two = (const vector unsigned short)(2);
141     vector unsigned char *tv, avgv, t5;
142     vector unsigned char pix1v, pix2v, pix3v, pix2iv, pix3iv;
143     vector unsigned short pix2lv, pix2hv, pix2ilv, pix2ihv;
144     vector unsigned short pix3lv, pix3hv, pix3ilv, pix3ihv;
145     vector unsigned short avghv, avglv;
146     vector unsigned short t1, t2, t3, t4;
147     vector unsigned int sad;
148     vector signed int sumdiffs;
149
150     sad = (vector unsigned int)(0);
151     
152     s = 0;
153
154     /*
155        Due to the fact that pix3 = pix2 + line_size, the pix3 of one
156        iteration becomes pix2 in the next iteration. We can use this
157        fact to avoid a potentially expensive unaligned read, as well
158        as some splitting, and vector addition each time around the loop.
159        Read unaligned pixels into our vectors. The vectors are as follows:
160        pix2v: pix2[0]-pix2[15]  pix2iv: pix2[1]-pix2[16]
161        Split the pixel vectors into shorts
162     */
163     tv = (vector unsigned char *) &pix2[0];
164     pix2v = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix2[0]));
165
166     tv = (vector unsigned char *) &pix2[1];
167     pix2iv = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix2[1]));
168
169     pix2hv = (vector unsigned short) vec_mergeh(zero, pix2v);
170     pix2lv = (vector unsigned short) vec_mergel(zero, pix2v);
171     pix2ihv = (vector unsigned short) vec_mergeh(zero, pix2iv);
172     pix2ilv = (vector unsigned short) vec_mergel(zero, pix2iv);
173     t1 = vec_add(pix2hv, pix2ihv);
174     t2 = vec_add(pix2lv, pix2ilv);
175     
176     for(i=0;i<16;i++) {
177         /*
178            Read unaligned pixels into our vectors. The vectors are as follows:
179            pix1v: pix1[0]-pix1[15]
180            pix3v: pix3[0]-pix3[15]      pix3iv: pix3[1]-pix3[16]
181         */
182         tv = (vector unsigned char *) pix1;
183         pix1v = vec_perm(tv[0], tv[1], vec_lvsl(0, pix1));
184
185         tv = (vector unsigned char *) &pix3[0];
186         pix3v = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix3[0]));
187
188         tv = (vector unsigned char *) &pix3[1];
189         pix3iv = vec_perm(tv[0], tv[1], vec_lvsl(0, &pix3[1]));
190
191         /*
192           Note that Altivec does have vec_avg, but this works on vector pairs
193           and rounds up. We could do avg(avg(a,b),avg(c,d)), but the rounding
194           would mean that, for example, avg(3,0,0,1) = 2, when it should be 1.
195           Instead, we have to split the pixel vectors into vectors of shorts,
196           and do the averaging by hand.
197         */
198
199         /* Split the pixel vectors into shorts */
200         pix3hv = (vector unsigned short) vec_mergeh(zero, pix3v);
201         pix3lv = (vector unsigned short) vec_mergel(zero, pix3v);
202         pix3ihv = (vector unsigned short) vec_mergeh(zero, pix3iv);
203         pix3ilv = (vector unsigned short) vec_mergel(zero, pix3iv);
204
205         /* Do the averaging on them */
206         t3 = vec_add(pix3hv, pix3ihv);
207         t4 = vec_add(pix3lv, pix3ilv);
208
209         avghv = vec_sr(vec_add(vec_add(t1, t3), two), two);
210         avglv = vec_sr(vec_add(vec_add(t2, t4), two), two);
211
212         /* Pack the shorts back into a result */
213         avgv = vec_pack(avghv, avglv);
214
215         /* Calculate a sum of abs differences vector */
216         t5 = vec_sub(vec_max(pix1v, avgv), vec_min(pix1v, avgv));
217
218         /* Add each 4 pixel group together and put 4 results into sad */
219         sad = vec_sum4s(t5, sad);
220
221         pix1 += line_size;
222         pix3 += line_size;
223         /* Transfer the calculated values for pix3 into pix2 */
224         t1 = t3;
225         t2 = t4;
226     }
227     /* Sum up the four partial sums, and put the result into s */
228     sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
229     sumdiffs = vec_splat(sumdiffs, 3);
230     vec_ste(sumdiffs, 0, &s);
231
232     return s;
233 }
234
235 int pix_abs16x16_altivec(uint8_t *pix1, uint8_t *pix2, int line_size)
236 {
237     int i;
238     int s __attribute__((aligned(16)));
239     const vector unsigned int zero = (const vector unsigned int)(0);
240     vector unsigned char perm1, perm2, *pix1v, *pix2v;
241     vector unsigned char t1, t2, t3,t4, t5;
242     vector unsigned int sad;
243     vector signed int sumdiffs;
244     
245     sad = (vector unsigned int) (0);
246
247
248     for(i=0;i<16;i++) {
249         /* Read potentially unaligned pixels into t1 and t2 */
250         perm1 = vec_lvsl(0, pix1);
251         pix1v = (vector unsigned char *) pix1;
252         perm2 = vec_lvsl(0, pix2);
253         pix2v = (vector unsigned char *) pix2;
254         t1 = vec_perm(pix1v[0], pix1v[1], perm1);
255         t2 = vec_perm(pix2v[0], pix2v[1], perm2);
256        
257         /* Calculate a sum of abs differences vector */ 
258         t3 = vec_max(t1, t2);
259         t4 = vec_min(t1, t2);
260         t5 = vec_sub(t3, t4);
261         
262         /* Add each 4 pixel group together and put 4 results into sad */
263         sad = vec_sum4s(t5, sad);
264
265         pix1 += line_size;
266         pix2 += line_size;
267     }
268
269     /* Sum up the four partial sums, and put the result into s */
270     sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
271     sumdiffs = vec_splat(sumdiffs, 3);
272     vec_ste(sumdiffs, 0, &s);
273     
274     return s;
275 }
276
277 int pix_abs8x8_altivec(uint8_t *pix1, uint8_t *pix2, int line_size)
278 {
279     int i;
280     int s __attribute__((aligned(16)));
281     const vector unsigned int zero = (const vector unsigned int)(0);
282     vector unsigned char perm1, perm2, permclear, *pix1v, *pix2v;
283     vector unsigned char t1, t2, t3,t4, t5;
284     vector unsigned int sad;
285     vector signed int sumdiffs;
286
287     sad = (vector unsigned int)(0);
288     permclear = (vector unsigned char) (255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0);
289
290     for(i=0;i<8;i++) {
291         /* Read potentially unaligned pixels into t1 and t2
292            Since we're reading 16 pixels, and actually only want 8,
293            mask out the last 8 pixels. The 0s don't change the sum. */
294         perm1 = vec_lvsl(0, pix1);
295         pix1v = (vector unsigned char *) pix1;
296         perm2 = vec_lvsl(0, pix2);
297         pix2v = (vector unsigned char *) pix2;
298         t1 = vec_and(vec_perm(pix1v[0], pix1v[1], perm1), permclear);
299         t2 = vec_and(vec_perm(pix2v[0], pix2v[1], perm2), permclear);
300
301         /* Calculate a sum of abs differences vector */ 
302         t3 = vec_max(t1, t2);
303         t4 = vec_min(t1, t2);
304         t5 = vec_sub(t3, t4);
305
306         /* Add each 4 pixel group together and put 4 results into sad */
307         sad = vec_sum4s(t5, sad);
308
309         pix1 += line_size;
310         pix2 += line_size;
311     }
312
313     /* Sum up the four partial sums, and put the result into s */
314     sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
315     sumdiffs = vec_splat(sumdiffs, 3);
316     vec_ste(sumdiffs, 0, &s);
317
318     return s;
319 }
320
321 int pix_norm1_altivec(uint8_t *pix, int line_size)
322 {
323     int i;
324     int s __attribute__((aligned(16)));
325     const vector unsigned int zero = (const vector unsigned int)(0);
326     vector unsigned char *tv;
327     vector unsigned char pixv;
328     vector unsigned int sv;
329     vector signed int sum;
330     
331     sv = (vector unsigned int)(0);
332     
333     s = 0;
334     for (i = 0; i < 16; i++) {
335         /* Read in the potentially unaligned pixels */
336         tv = (vector unsigned char *) pix;
337         pixv = vec_perm(tv[0], tv[1], vec_lvsl(0, pix));
338
339         /* Square the values, and add them to our sum */
340         sv = vec_msum(pixv, pixv, sv);
341
342         pix += line_size;
343     }
344     /* Sum up the four partial sums, and put the result into s */
345     sum = vec_sums((vector signed int) sv, (vector signed int) zero);
346     sum = vec_splat(sum, 3);
347     vec_ste(sum, 0, &s);
348
349     return s;
350 }
351
352 /**
353  * Sum of Squared Errors for a 8x8 block.
354  * AltiVec-enhanced.
355  * It's the pix_abs8x8_altivec code above w/ squaring added.
356  */
357 int sse8_altivec(void *v, uint8_t *pix1, uint8_t *pix2, int line_size)
358 {
359     int i;
360     int s __attribute__((aligned(16)));
361     const vector unsigned int zero = (const vector unsigned int)(0);
362     vector unsigned char perm1, perm2, permclear, *pix1v, *pix2v;
363     vector unsigned char t1, t2, t3,t4, t5;
364     vector unsigned int sum;
365     vector signed int sumsqr;
366     
367     sum = (vector unsigned int)(0);
368     permclear = (vector unsigned char)(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
369     
370     for(i=0;i<8;i++) {
371         /* Read potentially unaligned pixels into t1 and t2
372            Since we're reading 16 pixels, and actually only want 8,
373            mask out the last 8 pixels. The 0s don't change the sum. */
374         perm1 = vec_lvsl(0, pix1);
375         pix1v = (vector unsigned char *) pix1;
376         perm2 = vec_lvsl(0, pix2);
377         pix2v = (vector unsigned char *) pix2;
378         t1 = vec_and(vec_perm(pix1v[0], pix1v[1], perm1), permclear);
379         t2 = vec_and(vec_perm(pix2v[0], pix2v[1], perm2), permclear);
380
381         /*
382           Since we want to use unsigned chars, we can take advantage
383           of the fact that abs(a-b)^2 = (a-b)^2.
384         */
385         
386         /* Calculate abs differences vector */ 
387         t3 = vec_max(t1, t2);
388         t4 = vec_min(t1, t2);
389         t5 = vec_sub(t3, t4);
390         
391         /* Square the values and add them to our sum */
392         sum = vec_msum(t5, t5, sum);
393         
394         pix1 += line_size;
395         pix2 += line_size;
396     }
397     
398     /* Sum up the four partial sums, and put the result into s */
399     sumsqr = vec_sums((vector signed int) sum, (vector signed int) zero);
400     sumsqr = vec_splat(sumsqr, 3);
401     vec_ste(sumsqr, 0, &s);
402     
403     return s;
404 }
405
406 /**
407  * Sum of Squared Errors for a 16x16 block.
408  * AltiVec-enhanced.
409  * It's the pix_abs16x16_altivec code above w/ squaring added.
410  */
411 int sse16_altivec(void *v, uint8_t *pix1, uint8_t *pix2, int line_size)
412 {
413     int i;
414     int s __attribute__((aligned(16)));
415     const vector unsigned int zero = (const vector unsigned int)(0);
416     vector unsigned char perm1, perm2, *pix1v, *pix2v;
417     vector unsigned char t1, t2, t3,t4, t5;
418     vector unsigned int sum;
419     vector signed int sumsqr;
420     
421     sum = (vector unsigned int)(0);
422     
423     for(i=0;i<16;i++) {
424         /* Read potentially unaligned pixels into t1 and t2 */
425         perm1 = vec_lvsl(0, pix1);
426         pix1v = (vector unsigned char *) pix1;
427         perm2 = vec_lvsl(0, pix2);
428         pix2v = (vector unsigned char *) pix2;
429         t1 = vec_perm(pix1v[0], pix1v[1], perm1);
430         t2 = vec_perm(pix2v[0], pix2v[1], perm2);
431
432         /*
433           Since we want to use unsigned chars, we can take advantage
434           of the fact that abs(a-b)^2 = (a-b)^2.
435         */
436         
437         /* Calculate abs differences vector */ 
438         t3 = vec_max(t1, t2);
439         t4 = vec_min(t1, t2);
440         t5 = vec_sub(t3, t4);
441         
442         /* Square the values and add them to our sum */
443         sum = vec_msum(t5, t5, sum);
444         
445         pix1 += line_size;
446         pix2 += line_size;
447     }
448     
449     /* Sum up the four partial sums, and put the result into s */
450     sumsqr = vec_sums((vector signed int) sum, (vector signed int) zero);
451     sumsqr = vec_splat(sumsqr, 3);
452     vec_ste(sumsqr, 0, &s);
453     
454     return s;
455 }
456
457 int pix_sum_altivec(UINT8 * pix, int line_size)
458 {
459     const vector unsigned int zero = (const vector unsigned int)(0);
460     vector unsigned char perm, *pixv;
461     vector unsigned char t1;
462     vector unsigned int sad;
463     vector signed int sumdiffs;
464
465     int i;
466     int s __attribute__((aligned(16)));
467     
468     sad = (vector unsigned int) (0);
469     
470     for (i = 0; i < 16; i++) {
471         /* Read the potentially unaligned 16 pixels into t1 */
472         perm = vec_lvsl(0, pix);
473         pixv = (vector unsigned char *) pix;
474         t1 = vec_perm(pixv[0], pixv[1], perm);
475
476         /* Add each 4 pixel group together and put 4 results into sad */
477         sad = vec_sum4s(t1, sad);
478         
479         pix += line_size;
480     }
481     
482     /* Sum up the four partial sums, and put the result into s */
483     sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
484     sumdiffs = vec_splat(sumdiffs, 3);
485     vec_ste(sumdiffs, 0, &s);
486     
487     return s;
488 }
489
490 void get_pixels_altivec(DCTELEM *restrict block, const UINT8 *pixels, int line_size)
491 {
492     int i;
493     vector unsigned char perm, bytes, *pixv;
494     const vector unsigned char zero = (const vector unsigned char) (0);
495     vector signed short shorts;
496
497     for(i=0;i<8;i++)
498     {
499         // Read potentially unaligned pixels.
500         // We're reading 16 pixels, and actually only want 8,
501         // but we simply ignore the extras.
502         perm = vec_lvsl(0, pixels);
503         pixv = (vector unsigned char *) pixels;
504         bytes = vec_perm(pixv[0], pixv[1], perm);
505
506         // convert the bytes into shorts
507         shorts = (vector signed short)vec_mergeh(zero, bytes);
508
509         // save the data to the block, we assume the block is 16-byte aligned
510         vec_st(shorts, i*16, (vector signed short*)block);
511
512         pixels += line_size;
513     }
514 }
515
516 void diff_pixels_altivec(DCTELEM *restrict block, const UINT8 *s1,
517         const UINT8 *s2, int stride)
518 {
519     int i;
520     vector unsigned char perm, bytes, *pixv;
521     const vector unsigned char zero = (const vector unsigned char) (0);
522     vector signed short shorts1, shorts2;
523
524     for(i=0;i<4;i++)
525     {
526         // Read potentially unaligned pixels
527         // We're reading 16 pixels, and actually only want 8,
528         // but we simply ignore the extras.
529         perm = vec_lvsl(0, s1);
530         pixv = (vector unsigned char *) s1;
531         bytes = vec_perm(pixv[0], pixv[1], perm);
532
533         // convert the bytes into shorts
534         shorts1 = (vector signed short)vec_mergeh(zero, bytes);
535
536         // Do the same for the second block of pixels
537         perm = vec_lvsl(0, s2);
538         pixv = (vector unsigned char *) s2;
539         bytes = vec_perm(pixv[0], pixv[1], perm);
540
541         // convert the bytes into shorts
542         shorts2 = (vector signed short)vec_mergeh(zero, bytes);
543
544         // Do the subtraction
545         shorts1 = vec_sub(shorts1, shorts2);
546
547         // save the data to the block, we assume the block is 16-byte aligned
548         vec_st(shorts1, 0, (vector signed short*)block);
549
550         s1 += stride;
551         s2 += stride;
552         block += 8;
553
554
555         // The code below is a copy of the code above... This is a manual
556         // unroll.
557
558         // Read potentially unaligned pixels
559         // We're reading 16 pixels, and actually only want 8,
560         // but we simply ignore the extras.
561         perm = vec_lvsl(0, s1);
562         pixv = (vector unsigned char *) s1;
563         bytes = vec_perm(pixv[0], pixv[1], perm);
564
565         // convert the bytes into shorts
566         shorts1 = (vector signed short)vec_mergeh(zero, bytes);
567
568         // Do the same for the second block of pixels
569         perm = vec_lvsl(0, s2);
570         pixv = (vector unsigned char *) s2;
571         bytes = vec_perm(pixv[0], pixv[1], perm);
572
573         // convert the bytes into shorts
574         shorts2 = (vector signed short)vec_mergeh(zero, bytes);
575
576         // Do the subtraction
577         shorts1 = vec_sub(shorts1, shorts2);
578
579         // save the data to the block, we assume the block is 16-byte aligned
580         vec_st(shorts1, 0, (vector signed short*)block);
581
582         s1 += stride;
583         s2 += stride;
584         block += 8;
585     }
586 }
587
588 int sad16x16_altivec(void *s, uint8_t *a, uint8_t *b, int stride) {
589   return pix_abs16x16_altivec(a,b,stride);
590 }
591
592 int sad8x8_altivec(void *s, uint8_t *a, uint8_t *b, int stride) {
593   return pix_abs8x8_altivec(a,b,stride);
594 }
595
596 void add_bytes_altivec(uint8_t *dst, uint8_t *src, int w) {
597 #if 0
598     int i;
599     for(i=0; i+7<w; i++){
600         dst[i+0] += src[i+0];
601         dst[i+1] += src[i+1];
602         dst[i+2] += src[i+2];
603         dst[i+3] += src[i+3];
604         dst[i+4] += src[i+4];
605         dst[i+5] += src[i+5];
606         dst[i+6] += src[i+6];
607         dst[i+7] += src[i+7];
608     }
609     for(; i<w; i++)
610         dst[i+0] += src[i+0];
611 #else
612     register int i;
613     register uint8_t *temp_src = src, *temp_dst = dst;
614     register vector unsigned char vdst, vsrc, temp1, temp2;
615     register vector unsigned char perm;
616     register int count = 0;
617
618     for (i = 0; (i < w) && ((unsigned long)temp_dst & 0x0000000F) ; i++)
619     {
620       dst[i] = src[i];
621       temp_src ++;
622       temp_dst ++;
623     }
624     /* temp_dst is a properly aligned pointer */
625     /* we still need to deal with ill-aligned src */
626     perm = vec_lvsl(0, temp_src);
627     temp1 = vec_ld(0, temp_src);
628     while ((i + 15) < w)
629     {
630       temp2 = vec_ld(count + 16, temp_src);
631       vdst = vec_ld(count, temp_dst);
632       vsrc = vec_perm(temp1, temp2, perm);
633       temp1 = temp2;
634       vdst = vec_add(vsrc, vdst);
635       vec_st(vdst, count, temp_dst);
636       count += 16;
637     }
638     for (; (i < w) ; i++)
639     {
640       dst[i] = src[i];
641     }
642 #endif
643 }
644
645 int has_altivec(void)
646 {
647 #if CONFIG_DARWIN
648     int sels[2] = {CTL_HW, HW_VECTORUNIT};
649     int has_vu = 0;
650     size_t len = sizeof(has_vu);
651     int err;
652
653     err = sysctl(sels, 2, &has_vu, &len, NULL, 0);
654
655     if (err == 0) return (has_vu != 0);
656 #endif
657     return 0;
658 }