mmx: compile on MIPS for Loongson MMI optimizations
[profile/ivi/pixman.git] / pixman / pixman-cpu.c
1 /*
2  * Copyright © 2000 SuSE, Inc.
3  * Copyright © 2007 Red Hat, Inc.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of SuSE not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  SuSE makes no representations about the
12  * suitability of this software for any purpose.  It is provided "as is"
13  * without express or implied warranty.
14  *
15  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <stdlib.h>
28
29 #if defined(USE_ARM_SIMD) && defined(_MSC_VER)
30 /* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
31 #include <windows.h>
32 #endif
33
34 #if defined(__APPLE__)
35 #include "TargetConditionals.h"
36 #endif
37
38 #include "pixman-private.h"
39
40 #ifdef USE_VMX
41
42 /* The CPU detection code needs to be in a file not compiled with
43  * "-maltivec -mabi=altivec", as gcc would try to save vector register
44  * across function calls causing SIGILL on cpus without Altivec/vmx.
45  */
46 static pixman_bool_t initialized = FALSE;
47 static volatile pixman_bool_t have_vmx = TRUE;
48
49 #ifdef __APPLE__
50 #include <sys/sysctl.h>
51
52 static pixman_bool_t
53 pixman_have_vmx (void)
54 {
55     if (!initialized)
56     {
57         size_t length = sizeof(have_vmx);
58         int error =
59             sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0);
60
61         if (error)
62             have_vmx = FALSE;
63
64         initialized = TRUE;
65     }
66     return have_vmx;
67 }
68
69 #elif defined (__OpenBSD__)
70 #include <sys/param.h>
71 #include <sys/sysctl.h>
72 #include <machine/cpu.h>
73
74 static pixman_bool_t
75 pixman_have_vmx (void)
76 {
77     if (!initialized)
78     {
79         int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC };
80         size_t length = sizeof(have_vmx);
81         int error =
82             sysctl (mib, 2, &have_vmx, &length, NULL, 0);
83
84         if (error != 0)
85             have_vmx = FALSE;
86
87         initialized = TRUE;
88     }
89     return have_vmx;
90 }
91
92 #elif defined (__linux__)
93 #include <sys/types.h>
94 #include <sys/stat.h>
95 #include <fcntl.h>
96 #include <unistd.h>
97 #include <stdio.h>
98 #include <linux/auxvec.h>
99 #include <asm/cputable.h>
100
101 static pixman_bool_t
102 pixman_have_vmx (void)
103 {
104     if (!initialized)
105     {
106         char fname[64];
107         unsigned long buf[64];
108         ssize_t count = 0;
109         pid_t pid;
110         int fd, i;
111
112         pid = getpid ();
113         snprintf (fname, sizeof(fname) - 1, "/proc/%d/auxv", pid);
114
115         fd = open (fname, O_RDONLY);
116         if (fd >= 0)
117         {
118             for (i = 0; i <= (count / sizeof(unsigned long)); i += 2)
119             {
120                 /* Read more if buf is empty... */
121                 if (i == (count / sizeof(unsigned long)))
122                 {
123                     count = read (fd, buf, sizeof(buf));
124                     if (count <= 0)
125                         break;
126                     i = 0;
127                 }
128
129                 if (buf[i] == AT_HWCAP)
130                 {
131                     have_vmx = !!(buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC);
132                     initialized = TRUE;
133                     break;
134                 }
135                 else if (buf[i] == AT_NULL)
136                 {
137                     break;
138                 }
139             }
140             close (fd);
141         }
142     }
143     if (!initialized)
144     {
145         /* Something went wrong. Assume 'no' rather than playing
146            fragile tricks with catching SIGILL. */
147         have_vmx = FALSE;
148         initialized = TRUE;
149     }
150
151     return have_vmx;
152 }
153
154 #else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */
155 #include <signal.h>
156 #include <setjmp.h>
157
158 static jmp_buf jump_env;
159
160 static void
161 vmx_test (int        sig,
162           siginfo_t *si,
163           void *     unused)
164 {
165     longjmp (jump_env, 1);
166 }
167
168 static pixman_bool_t
169 pixman_have_vmx (void)
170 {
171     struct sigaction sa, osa;
172     int jmp_result;
173
174     if (!initialized)
175     {
176         sa.sa_flags = SA_SIGINFO;
177         sigemptyset (&sa.sa_mask);
178         sa.sa_sigaction = vmx_test;
179         sigaction (SIGILL, &sa, &osa);
180         jmp_result = setjmp (jump_env);
181         if (jmp_result == 0)
182         {
183             asm volatile ( "vor 0, 0, 0" );
184         }
185         sigaction (SIGILL, &osa, NULL);
186         have_vmx = (jmp_result == 0);
187         initialized = TRUE;
188     }
189     return have_vmx;
190 }
191
192 #endif /* __APPLE__ */
193 #endif /* USE_VMX */
194
195 #if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT)
196
197 #if defined(_MSC_VER)
198
199 #if defined(USE_ARM_SIMD)
200 extern int pixman_msvc_try_arm_simd_op ();
201
202 pixman_bool_t
203 pixman_have_arm_simd (void)
204 {
205     static pixman_bool_t initialized = FALSE;
206     static pixman_bool_t have_arm_simd = FALSE;
207
208     if (!initialized)
209     {
210         __try {
211             pixman_msvc_try_arm_simd_op ();
212             have_arm_simd = TRUE;
213         } __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) {
214             have_arm_simd = FALSE;
215         }
216         initialized = TRUE;
217     }
218
219     return have_arm_simd;
220 }
221
222 #endif /* USE_ARM_SIMD */
223
224 #if defined(USE_ARM_NEON)
225 extern int pixman_msvc_try_arm_neon_op ();
226
227 pixman_bool_t
228 pixman_have_arm_neon (void)
229 {
230     static pixman_bool_t initialized = FALSE;
231     static pixman_bool_t have_arm_neon = FALSE;
232
233     if (!initialized)
234     {
235         __try
236         {
237             pixman_msvc_try_arm_neon_op ();
238             have_arm_neon = TRUE;
239         }
240         __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
241         {
242             have_arm_neon = FALSE;
243         }
244         initialized = TRUE;
245     }
246
247     return have_arm_neon;
248 }
249
250 #endif /* USE_ARM_NEON */
251
252 #elif (defined (__APPLE__) && defined(TARGET_OS_IPHONE)) /* iOS (iPhone/iPad/iPod touch) */
253
254 /* Detection of ARM NEON on iOS is fairly simple because iOS binaries
255  * contain separate executable images for each processor architecture.
256  * So all we have to do is detect the armv7 architecture build. The
257  * operating system automatically runs the armv7 binary for armv7 devices
258  * and the armv6 binary for armv6 devices.
259  */
260
261 pixman_bool_t
262 pixman_have_arm_simd (void)
263 {
264 #if defined(USE_ARM_SIMD)
265     return TRUE;
266 #else
267     return FALSE;
268 #endif
269 }
270
271 pixman_bool_t
272 pixman_have_arm_neon (void)
273 {
274 #if defined(USE_ARM_NEON) && defined(__ARM_NEON__)
275     /* This is an armv7 cpu build */
276     return TRUE;
277 #else
278     /* This is an armv6 cpu build */
279     return FALSE;
280 #endif
281 }
282
283 pixman_bool_t
284 pixman_have_arm_iwmmxt (void)
285 {
286 #if defined(USE_ARM_IWMMXT)
287     return FALSE;
288 #else
289     return FALSE;
290 #endif
291 }
292
293 #elif defined (__linux__) || defined(__ANDROID__) || defined(ANDROID) /* linux ELF or ANDROID */
294
295 static pixman_bool_t arm_has_v7 = FALSE;
296 static pixman_bool_t arm_has_v6 = FALSE;
297 static pixman_bool_t arm_has_vfp = FALSE;
298 static pixman_bool_t arm_has_neon = FALSE;
299 static pixman_bool_t arm_has_iwmmxt = FALSE;
300 static pixman_bool_t arm_tests_initialized = FALSE;
301
302 #if defined(__ANDROID__) || defined(ANDROID) /* Android device support */
303
304 #include <cpu-features.h>
305
306 static void
307 pixman_arm_read_auxv_or_cpu_features ()
308 {
309     AndroidCpuFamily cpu_family;
310     uint64_t cpu_features;
311
312     cpu_family = android_getCpuFamily();
313     cpu_features = android_getCpuFeatures();
314
315     if (cpu_family == ANDROID_CPU_FAMILY_ARM)
316     {
317         if (cpu_features & ANDROID_CPU_ARM_FEATURE_ARMv7)
318             arm_has_v7 = TRUE;
319         
320         if (cpu_features & ANDROID_CPU_ARM_FEATURE_VFPv3)
321             arm_has_vfp = TRUE;
322         
323         if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON)
324             arm_has_neon = TRUE;
325     }
326
327     arm_tests_initialized = TRUE;
328 }
329
330 #elif defined (__linux__) /* linux ELF */
331
332 #include <unistd.h>
333 #include <sys/types.h>
334 #include <sys/stat.h>
335 #include <sys/mman.h>
336 #include <fcntl.h>
337 #include <string.h>
338 #include <elf.h>
339
340 static void
341 pixman_arm_read_auxv_or_cpu_features ()
342 {
343     int fd;
344     Elf32_auxv_t aux;
345
346     fd = open ("/proc/self/auxv", O_RDONLY);
347     if (fd >= 0)
348     {
349         while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
350         {
351             if (aux.a_type == AT_HWCAP)
352             {
353                 uint32_t hwcap = aux.a_un.a_val;
354                 /* hardcode these values to avoid depending on specific
355                  * versions of the hwcap header, e.g. HWCAP_NEON
356                  */
357                 arm_has_vfp = (hwcap & 64) != 0;
358                 arm_has_iwmmxt = (hwcap & 512) != 0;
359                 /* this flag is only present on kernel 2.6.29 */
360                 arm_has_neon = (hwcap & 4096) != 0;
361             }
362             else if (aux.a_type == AT_PLATFORM)
363             {
364                 const char *plat = (const char*) aux.a_un.a_val;
365                 if (strncmp (plat, "v7l", 3) == 0)
366                 {
367                     arm_has_v7 = TRUE;
368                     arm_has_v6 = TRUE;
369                 }
370                 else if (strncmp (plat, "v6l", 3) == 0)
371                 {
372                     arm_has_v6 = TRUE;
373                 }
374             }
375         }
376         close (fd);
377     }
378
379     arm_tests_initialized = TRUE;
380 }
381
382 #endif /* Linux elf */
383
384 #if defined(USE_ARM_SIMD)
385 pixman_bool_t
386 pixman_have_arm_simd (void)
387 {
388     if (!arm_tests_initialized)
389         pixman_arm_read_auxv_or_cpu_features ();
390
391     return arm_has_v6;
392 }
393
394 #endif /* USE_ARM_SIMD */
395
396 #if defined(USE_ARM_NEON)
397 pixman_bool_t
398 pixman_have_arm_neon (void)
399 {
400     if (!arm_tests_initialized)
401         pixman_arm_read_auxv_or_cpu_features ();
402
403     return arm_has_neon;
404 }
405
406 #endif /* USE_ARM_NEON */
407
408 #if defined(USE_ARM_IWMMXT)
409 pixman_bool_t
410 pixman_have_arm_iwmmxt (void)
411 {
412     if (!arm_tests_initialized)
413         pixman_arm_read_auxv_or_cpu_features ();
414
415     return arm_has_iwmmxt;
416 }
417
418 #endif /* USE_ARM_IWMMXT */
419
420 #else /* !_MSC_VER && !Linux elf && !Android */
421
422 #define pixman_have_arm_simd() FALSE
423 #define pixman_have_arm_neon() FALSE
424 #define pixman_have_arm_iwmmxt() FALSE
425
426 #endif
427
428 #endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */
429
430 #if defined(USE_MIPS_DSPR2) || defined(USE_LOONGSON_MMI)
431
432 #if defined (__linux__) /* linux ELF */
433
434 static pixman_bool_t
435 pixman_have_mips_feature (const char *search_string)
436 {
437     const char *file_name = "/proc/cpuinfo";
438     /* Simple detection of MIPS features at runtime for Linux.
439      * It is based on /proc/cpuinfo, which reveals hardware configuration
440      * to user-space applications.  According to MIPS (early 2010), no similar
441      * facility is universally available on the MIPS architectures, so it's up
442      * to individual OSes to provide such.
443      */
444
445     char cpuinfo_line[256];
446
447     FILE *f = NULL;
448
449     if ((f = fopen (file_name, "r")) == NULL)
450         return FALSE;
451
452     while (fgets (cpuinfo_line, sizeof (cpuinfo_line), f) != NULL)
453     {
454         if (strstr (cpuinfo_line, search_string) != NULL)
455         {
456             fclose (f);
457             return TRUE;
458         }
459     }
460
461     fclose (f);
462
463     /* Did not find string in the proc file. */
464     return FALSE;
465 }
466
467 #if defined(USE_MIPS_DSPR2)
468 pixman_bool_t
469 pixman_have_mips_dspr2 (void)
470 {
471      /* Only currently available MIPS core that supports DSPr2 is 74K. */
472     return pixman_have_mips_feature ("MIPS 74K");
473 }
474 #endif
475
476 #if defined(USE_LOONGSON_MMI)
477 pixman_bool_t
478 pixman_have_loongson_mmi (void)
479 {
480     /* I really don't know if some Loongson CPUs don't have MMI. */
481     return pixman_have_mips_feature ("Loongson");
482 }
483 #endif
484
485 #else /* linux ELF */
486
487 #define pixman_have_mips_dspr2() FALSE
488 #define pixman_have_loongson_mmi() FALSE
489
490 #endif /* linux ELF */
491
492 #endif /* USE_MIPS_DSPR2 || USE_LOONGSON_MMI */
493
494 #if defined(USE_X86_MMX) || defined(USE_SSE2)
495 /* The CPU detection code needs to be in a file not compiled with
496  * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
497  * that would lead to SIGILL instructions on old CPUs that don't have
498  * it.
499  */
500 #if !defined(__amd64__) && !defined(__x86_64__) && !defined(_M_AMD64)
501
502 #ifdef HAVE_GETISAX
503 #include <sys/auxv.h>
504 #endif
505
506 typedef enum
507 {
508     NO_FEATURES = 0,
509     MMX = 0x1,
510     MMX_EXTENSIONS = 0x2,
511     SSE = 0x6,
512     SSE2 = 0x8,
513     CMOV = 0x10
514 } cpu_features_t;
515
516
517 static unsigned int
518 detect_cpu_features (void)
519 {
520     unsigned int features = 0;
521     unsigned int result = 0;
522
523 #ifdef HAVE_GETISAX
524     if (getisax (&result, 1))
525     {
526         if (result & AV_386_CMOV)
527             features |= CMOV;
528         if (result & AV_386_MMX)
529             features |= MMX;
530         if (result & AV_386_AMD_MMX)
531             features |= MMX_EXTENSIONS;
532         if (result & AV_386_SSE)
533             features |= SSE;
534         if (result & AV_386_SSE2)
535             features |= SSE2;
536     }
537 #else
538     char vendor[13];
539 #ifdef _MSC_VER
540     int vendor0 = 0, vendor1, vendor2;
541 #endif
542     vendor[0] = 0;
543     vendor[12] = 0;
544
545 #ifdef __GNUC__
546     /* see p. 118 of amd64 instruction set manual Vol3 */
547     /* We need to be careful about the handling of %ebx and
548      * %esp here. We can't declare either one as clobbered
549      * since they are special registers (%ebx is the "PIC
550      * register" holding an offset to global data, %esp the
551      * stack pointer), so we need to make sure they have their
552      * original values when we access the output operands.
553      */
554     __asm__ (
555         "pushf\n"
556         "pop %%eax\n"
557         "mov %%eax, %%ecx\n"
558         "xor $0x00200000, %%eax\n"
559         "push %%eax\n"
560         "popf\n"
561         "pushf\n"
562         "pop %%eax\n"
563         "mov $0x0, %%edx\n"
564         "xor %%ecx, %%eax\n"
565         "jz 1f\n"
566
567         "mov $0x00000000, %%eax\n"
568         "push %%ebx\n"
569         "cpuid\n"
570         "mov %%ebx, %%eax\n"
571         "pop %%ebx\n"
572         "mov %%eax, %1\n"
573         "mov %%edx, %2\n"
574         "mov %%ecx, %3\n"
575         "mov $0x00000001, %%eax\n"
576         "push %%ebx\n"
577         "cpuid\n"
578         "pop %%ebx\n"
579         "1:\n"
580         "mov %%edx, %0\n"
581         : "=r" (result),
582         "=m" (vendor[0]),
583         "=m" (vendor[4]),
584         "=m" (vendor[8])
585         :
586         : "%eax", "%ecx", "%edx"
587         );
588
589 #elif defined (_MSC_VER)
590
591     _asm {
592         pushfd
593         pop eax
594         mov ecx, eax
595         xor eax, 00200000h
596         push eax
597         popfd
598         pushfd
599         pop eax
600         mov edx, 0
601         xor eax, ecx
602         jz nocpuid
603
604         mov eax, 0
605         push ebx
606         cpuid
607         mov eax, ebx
608         pop ebx
609         mov vendor0, eax
610         mov vendor1, edx
611         mov vendor2, ecx
612         mov eax, 1
613         push ebx
614         cpuid
615         pop ebx
616     nocpuid:
617         mov result, edx
618     }
619     memmove (vendor + 0, &vendor0, 4);
620     memmove (vendor + 4, &vendor1, 4);
621     memmove (vendor + 8, &vendor2, 4);
622
623 #else
624 #   error unsupported compiler
625 #endif
626
627     features = 0;
628     if (result)
629     {
630         /* result now contains the standard feature bits */
631         if (result & (1 << 15))
632             features |= CMOV;
633         if (result & (1 << 23))
634             features |= MMX;
635         if (result & (1 << 25))
636             features |= SSE;
637         if (result & (1 << 26))
638             features |= SSE2;
639         if ((features & MMX) && !(features & SSE) &&
640             (strcmp (vendor, "AuthenticAMD") == 0 ||
641              strcmp (vendor, "Geode by NSC") == 0))
642         {
643             /* check for AMD MMX extensions */
644 #ifdef __GNUC__
645             __asm__ (
646                 "       push %%ebx\n"
647                 "       mov $0x80000000, %%eax\n"
648                 "       cpuid\n"
649                 "       xor %%edx, %%edx\n"
650                 "       cmp $0x1, %%eax\n"
651                 "       jge 2f\n"
652                 "       mov $0x80000001, %%eax\n"
653                 "       cpuid\n"
654                 "2:\n"
655                 "       pop %%ebx\n"
656                 "       mov %%edx, %0\n"
657                 : "=r" (result)
658                 :
659                 : "%eax", "%ecx", "%edx"
660                 );
661 #elif defined _MSC_VER
662             _asm {
663                 push ebx
664                 mov eax, 80000000h
665                 cpuid
666                 xor edx, edx
667                 cmp eax, 1
668                 jge notamd
669                 mov eax, 80000001h
670                 cpuid
671             notamd:
672                 pop ebx
673                 mov result, edx
674             }
675 #endif
676             if (result & (1 << 22))
677                 features |= MMX_EXTENSIONS;
678         }
679     }
680 #endif /* HAVE_GETISAX */
681
682     return features;
683 }
684
685 #ifdef USE_X86_MMX
686 static pixman_bool_t
687 pixman_have_mmx (void)
688 {
689     static pixman_bool_t initialized = FALSE;
690     static pixman_bool_t mmx_present;
691
692     if (!initialized)
693     {
694         unsigned int features = detect_cpu_features ();
695         mmx_present = (features & (MMX | MMX_EXTENSIONS)) == (MMX | MMX_EXTENSIONS);
696         initialized = TRUE;
697     }
698
699     return mmx_present;
700 }
701 #endif
702
703 #ifdef USE_SSE2
704 static pixman_bool_t
705 pixman_have_sse2 (void)
706 {
707     static pixman_bool_t initialized = FALSE;
708     static pixman_bool_t sse2_present;
709
710     if (!initialized)
711     {
712         unsigned int features = detect_cpu_features ();
713         sse2_present = (features & (MMX | MMX_EXTENSIONS | SSE | SSE2)) == (MMX | MMX_EXTENSIONS | SSE | SSE2);
714         initialized = TRUE;
715     }
716
717     return sse2_present;
718 }
719
720 #endif
721
722 #else /* __amd64__ */
723 #ifdef USE_X86_MMX
724 #define pixman_have_mmx() TRUE
725 #endif
726 #ifdef USE_SSE2
727 #define pixman_have_sse2() TRUE
728 #endif
729 #endif /* __amd64__ */
730 #endif
731
732 static pixman_bool_t
733 disabled (const char *name)
734 {
735     const char *env;
736
737     if ((env = getenv ("PIXMAN_DISABLE")))
738     {
739         do
740         {
741             const char *end;
742             int len;
743
744             if ((end = strchr (env, ' ')))
745                 len = end - env;
746             else
747                 len = strlen (env);
748
749             if (strlen (name) == len && strncmp (name, env, len) == 0)
750             {
751                 printf ("pixman: Disabled %s implementation\n", name);
752                 return TRUE;
753             }
754
755             env += len;
756         }
757         while (*env++);
758     }
759
760     return FALSE;
761 }
762
763 pixman_implementation_t *
764 _pixman_choose_implementation (void)
765 {
766     pixman_implementation_t *imp;
767
768     imp = _pixman_implementation_create_general();
769
770     if (!disabled ("fast"))
771         imp = _pixman_implementation_create_fast_path (imp);
772
773 #ifdef USE_X86_MMX
774     if (!disabled ("mmx") && pixman_have_mmx ())
775         imp = _pixman_implementation_create_mmx (imp);
776 #endif
777
778 #ifdef USE_SSE2
779     if (!disabled ("sse2") && pixman_have_sse2 ())
780         imp = _pixman_implementation_create_sse2 (imp);
781 #endif
782
783 #ifdef USE_ARM_SIMD
784     if (!disabled ("arm-simd") && pixman_have_arm_simd ())
785         imp = _pixman_implementation_create_arm_simd (imp);
786 #endif
787
788 #ifdef USE_ARM_IWMMXT
789     if (!disabled ("arm-iwmmxt") && pixman_have_arm_iwmmxt ())
790         imp = _pixman_implementation_create_mmx (imp);
791 #endif
792 #ifdef USE_LOONGSON_MMI
793     if (!disabled ("loongson-mmi") && pixman_have_loongson_mmi ())
794         imp = _pixman_implementation_create_mmx (imp);
795 #endif
796 #ifdef USE_ARM_NEON
797     if (!disabled ("arm-neon") && pixman_have_arm_neon ())
798         imp = _pixman_implementation_create_arm_neon (imp);
799 #endif
800
801 #ifdef USE_MIPS_DSPR2
802     if (!disabled ("mips-dspr2") && pixman_have_mips_dspr2 ())
803         imp = _pixman_implementation_create_mips_dspr2 (imp);
804 #endif
805
806 #ifdef USE_VMX
807     if (!disabled ("vmx") && pixman_have_vmx ())
808         imp = _pixman_implementation_create_vmx (imp);
809 #endif
810
811     imp = _pixman_implementation_create_noop (imp);
812
813     return imp;
814 }
815