gfx/cairo/libpixman/src/pixman-cpu.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial