/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-x86.c
Line | Count | Source (jump to first uncovered line) |
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 <pixman-config.h> |
24 | | #endif |
25 | | |
26 | | #include "pixman-private.h" |
27 | | |
28 | | #if defined(USE_X86_MMX) || defined (USE_SSE2) || defined (USE_SSSE3) |
29 | | |
30 | | /* The CPU detection code needs to be in a file not compiled with |
31 | | * "-mmmx -msse", as gcc would generate CMOV instructions otherwise |
32 | | * that would lead to SIGILL instructions on old CPUs that don't have |
33 | | * it. |
34 | | */ |
35 | | |
36 | | typedef enum |
37 | | { |
38 | | X86_MMX = (1 << 0), |
39 | | X86_MMX_EXTENSIONS = (1 << 1), |
40 | | X86_SSE = (1 << 2) | X86_MMX_EXTENSIONS, |
41 | | X86_SSE2 = (1 << 3), |
42 | | X86_CMOV = (1 << 4), |
43 | | X86_SSSE3 = (1 << 5) |
44 | | } cpu_features_t; |
45 | | |
46 | | #ifdef HAVE_GETISAX |
47 | | |
48 | | #include <sys/auxv.h> |
49 | | |
50 | | static cpu_features_t |
51 | | detect_cpu_features (void) |
52 | | { |
53 | | cpu_features_t features = 0; |
54 | | unsigned int result = 0; |
55 | | |
56 | | if (getisax (&result, 1)) |
57 | | { |
58 | | if (result & AV_386_CMOV) |
59 | | features |= X86_CMOV; |
60 | | if (result & AV_386_MMX) |
61 | | features |= X86_MMX; |
62 | | if (result & AV_386_AMD_MMX) |
63 | | features |= X86_MMX_EXTENSIONS; |
64 | | if (result & AV_386_SSE) |
65 | | features |= X86_SSE; |
66 | | if (result & AV_386_SSE2) |
67 | | features |= X86_SSE2; |
68 | | if (result & AV_386_SSSE3) |
69 | | features |= X86_SSSE3; |
70 | | } |
71 | | |
72 | | return features; |
73 | | } |
74 | | |
75 | | #else |
76 | | |
77 | | #if defined (__GNUC__) |
78 | | #include <cpuid.h> |
79 | | #elif defined(_MSC_VER) |
80 | | #include <intrin.h> |
81 | | #endif |
82 | | |
83 | | static void |
84 | | pixman_cpuid (uint32_t feature, |
85 | | uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) |
86 | 12 | { |
87 | 12 | #if defined (__GNUC__) |
88 | 12 | *a = *b = *c = *d = 0; |
89 | 12 | __get_cpuid(feature, a, b, c, d); |
90 | | #elif defined (_MSC_VER) |
91 | | int info[4]; |
92 | | |
93 | | __cpuid (info, feature); |
94 | | |
95 | | *a = info[0]; |
96 | | *b = info[1]; |
97 | | *c = info[2]; |
98 | | *d = info[3]; |
99 | | #else |
100 | | #error Unknown compiler |
101 | | #endif |
102 | 12 | } |
103 | | |
104 | | static cpu_features_t |
105 | | detect_cpu_features (void) |
106 | 12 | { |
107 | 12 | uint32_t a, b, c, d; |
108 | 12 | cpu_features_t features = 0; |
109 | | |
110 | | /* Get feature bits */ |
111 | 12 | pixman_cpuid (0x01, &a, &b, &c, &d); |
112 | 12 | if (d & (1 << 15)) |
113 | 12 | features |= X86_CMOV; |
114 | 12 | if (d & (1 << 23)) |
115 | 12 | features |= X86_MMX; |
116 | 12 | if (d & (1 << 25)) |
117 | 12 | features |= X86_SSE; |
118 | 12 | if (d & (1 << 26)) |
119 | 12 | features |= X86_SSE2; |
120 | 12 | if (c & (1 << 9)) |
121 | 12 | features |= X86_SSSE3; |
122 | | |
123 | | /* Check for AMD specific features */ |
124 | 12 | if ((features & X86_MMX) && !(features & X86_SSE)) |
125 | 0 | { |
126 | 0 | char vendor[13]; |
127 | | |
128 | | /* Get vendor string */ |
129 | 0 | memset (vendor, 0, sizeof vendor); |
130 | |
|
131 | 0 | pixman_cpuid (0x00, &a, &b, &c, &d); |
132 | 0 | memcpy (vendor + 0, &b, 4); |
133 | 0 | memcpy (vendor + 4, &d, 4); |
134 | 0 | memcpy (vendor + 8, &c, 4); |
135 | |
|
136 | 0 | if (strcmp (vendor, "AuthenticAMD") == 0 || |
137 | 0 | strcmp (vendor, "HygonGenuine") == 0 || |
138 | 0 | strcmp (vendor, "Geode by NSC") == 0) |
139 | 0 | { |
140 | 0 | pixman_cpuid (0x80000000, &a, &b, &c, &d); |
141 | 0 | if (a >= 0x80000001) |
142 | 0 | { |
143 | 0 | pixman_cpuid (0x80000001, &a, &b, &c, &d); |
144 | |
|
145 | 0 | if (d & (1 << 22)) |
146 | 0 | features |= X86_MMX_EXTENSIONS; |
147 | 0 | } |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | 12 | return features; |
152 | 12 | } |
153 | | |
154 | | #endif |
155 | | |
156 | | static pixman_bool_t |
157 | | have_feature (cpu_features_t feature) |
158 | 36 | { |
159 | 36 | static pixman_bool_t initialized; |
160 | 36 | static cpu_features_t features; |
161 | | |
162 | 36 | if (!initialized) |
163 | 12 | { |
164 | 12 | features = detect_cpu_features(); |
165 | 12 | initialized = TRUE; |
166 | 12 | } |
167 | | |
168 | 36 | return (features & feature) == feature; |
169 | 36 | } |
170 | | |
171 | | #endif |
172 | | |
173 | | pixman_implementation_t * |
174 | | _pixman_x86_get_implementations (pixman_implementation_t *imp) |
175 | 12 | { |
176 | 12 | #define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS) |
177 | 12 | #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2) |
178 | 12 | #define SSSE3_BITS (X86_SSE | X86_SSE2 | X86_SSSE3) |
179 | | |
180 | 12 | #ifdef USE_X86_MMX |
181 | 12 | if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS)) |
182 | 12 | imp = _pixman_implementation_create_mmx (imp); |
183 | 12 | #endif |
184 | | |
185 | 12 | #ifdef USE_SSE2 |
186 | 12 | if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS)) |
187 | 12 | imp = _pixman_implementation_create_sse2 (imp); |
188 | 12 | #endif |
189 | | |
190 | 12 | #ifdef USE_SSSE3 |
191 | 12 | if (!_pixman_disabled ("ssse3") && have_feature (SSSE3_BITS)) |
192 | 12 | imp = _pixman_implementation_create_ssse3 (imp); |
193 | 12 | #endif |
194 | | |
195 | 12 | return imp; |
196 | 12 | } |