pixman-x86.c (4854B)
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 { 87 #if defined (__GNUC__) 88 *a = *b = *c = *d = 0; 89 __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 } 103 104 static cpu_features_t 105 detect_cpu_features (void) 106 { 107 uint32_t a, b, c, d; 108 cpu_features_t features = 0; 109 110 /* Get feature bits */ 111 pixman_cpuid (0x01, &a, &b, &c, &d); 112 if (d & (1 << 15)) 113 features |= X86_CMOV; 114 if (d & (1 << 23)) 115 features |= X86_MMX; 116 if (d & (1 << 25)) 117 features |= X86_SSE; 118 if (d & (1 << 26)) 119 features |= X86_SSE2; 120 if (c & (1 << 9)) 121 features |= X86_SSSE3; 122 123 /* Check for AMD specific features */ 124 if ((features & X86_MMX) && !(features & X86_SSE)) 125 { 126 char vendor[13]; 127 128 /* Get vendor string */ 129 memset (vendor, 0, sizeof vendor); 130 131 pixman_cpuid (0x00, &a, &b, &c, &d); 132 memcpy (vendor + 0, &b, 4); 133 memcpy (vendor + 4, &d, 4); 134 memcpy (vendor + 8, &c, 4); 135 136 if (strcmp (vendor, "AuthenticAMD") == 0 || 137 strcmp (vendor, "HygonGenuine") == 0 || 138 strcmp (vendor, "Geode by NSC") == 0) 139 { 140 pixman_cpuid (0x80000000, &a, &b, &c, &d); 141 if (a >= 0x80000001) 142 { 143 pixman_cpuid (0x80000001, &a, &b, &c, &d); 144 145 if (d & (1 << 22)) 146 features |= X86_MMX_EXTENSIONS; 147 } 148 } 149 } 150 151 return features; 152 } 153 154 #endif 155 156 static pixman_bool_t 157 have_feature (cpu_features_t feature) 158 { 159 static pixman_bool_t initialized; 160 static cpu_features_t features; 161 162 if (!initialized) 163 { 164 features = detect_cpu_features(); 165 initialized = TRUE; 166 } 167 168 return (features & feature) == feature; 169 } 170 171 #endif 172 173 pixman_implementation_t * 174 _pixman_x86_get_implementations (pixman_implementation_t *imp) 175 { 176 #define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS) 177 #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2) 178 #define SSSE3_BITS (X86_SSE | X86_SSE2 | X86_SSSE3) 179 180 #ifdef USE_X86_MMX 181 if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS)) 182 imp = _pixman_implementation_create_mmx (imp); 183 #endif 184 185 #ifdef USE_SSE2 186 if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS)) 187 imp = _pixman_implementation_create_sse2 (imp); 188 #endif 189 190 #ifdef USE_SSSE3 191 if (!_pixman_disabled ("ssse3") && have_feature (SSSE3_BITS)) 192 imp = _pixman_implementation_create_ssse3 (imp); 193 #endif 194 195 return imp; 196 }