os/ossrv/genericopenlibs/liboil/src/liboilcpu-x86.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/genericopenlibs/liboil/src/liboilcpu-x86.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,354 @@
     1.4 +/*
     1.5 + * LIBOIL - Library of Optimized Inner Loops
     1.6 + * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
     1.7 + * All rights reserved.
     1.8 + *
     1.9 + * Redistribution and use in source and binary forms, with or without
    1.10 + * modification, are permitted provided that the following conditions
    1.11 + * are met:
    1.12 + * 1. Redistributions of source code must retain the above copyright
    1.13 + *    notice, this list of conditions and the following disclaimer.
    1.14 + * 2. Redistributions in binary form must reproduce the above copyright
    1.15 + *    notice, this list of conditions and the following disclaimer in the
    1.16 + *    documentation and/or other materials provided with the distribution.
    1.17 + * 
    1.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    1.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    1.20 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.21 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    1.22 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    1.23 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    1.24 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    1.25 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    1.26 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    1.27 + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    1.28 + * POSSIBILITY OF SUCH DAMAGE.
    1.29 + */
    1.30 +
    1.31 +#ifdef HAVE_CONFIG_H
    1.32 +#include "config.h"
    1.33 +#endif
    1.34 +#include <liboil/liboilfunction.h>
    1.35 +#include <liboil/liboildebug.h>
    1.36 +#include <liboil/liboilcpu.h>
    1.37 +#include <liboil/liboilfault.h>
    1.38 +#include <liboil/liboilutils.h>
    1.39 +
    1.40 +#ifdef HAVE_UNISTD_H
    1.41 +#include <unistd.h>
    1.42 +#endif
    1.43 +#include <fcntl.h>
    1.44 +#include <stdlib.h>
    1.45 +#include <string.h>
    1.46 +#include <stdio.h>
    1.47 +#include <setjmp.h>
    1.48 +#include <signal.h>
    1.49 +#ifdef HAVE_SYS_TIME_H
    1.50 +#include <sys/time.h>
    1.51 +#endif
    1.52 +#include <time.h>
    1.53 +
    1.54 +#if defined(__FreeBSD__) || defined(__APPLE__)
    1.55 +#include <sys/types.h>
    1.56 +#include <sys/sysctl.h>
    1.57 +#endif
    1.58 +
    1.59 +#ifdef __sun
    1.60 +#include <sys/auxv.h>
    1.61 +#endif
    1.62 +
    1.63 +/***** i386, amd64 *****/
    1.64 +
    1.65 +#if defined(__sun)
    1.66 +#define USE_I386_GETISAX
    1.67 +#else
    1.68 +#define USE_I386_CPUID
    1.69 +#endif
    1.70 +
    1.71 +
    1.72 +#ifdef USE_I386_CPUINFO
    1.73 +static void
    1.74 +oil_cpu_i386_getflags_cpuinfo (char *cpuinfo)
    1.75 +{
    1.76 +  char *cpuinfo_flags;
    1.77 +  char **flags;
    1.78 +  char **f;
    1.79 +
    1.80 +  cpuinfo_flags = get_tag_value (cpuinfo, "flags");
    1.81 +  if (cpuinfo_flags == NULL) {
    1.82 +    free (cpuinfo);
    1.83 +    return;
    1.84 +  }
    1.85 +
    1.86 +  flags = strsplit(cpuinfo_flags);
    1.87 +  for (f = flags; *f; f++) {
    1.88 +    if (strcmp (*f, "cmov") == 0) {
    1.89 +      OIL_DEBUG ("cpu flag %s", *f);
    1.90 +      oil_cpu_flags |= OIL_IMPL_FLAG_CMOV;
    1.91 +    }
    1.92 +    if (strcmp (*f, "mmx") == 0) {
    1.93 +      OIL_DEBUG ("cpu flag %s", *f);
    1.94 +      oil_cpu_flags |= OIL_IMPL_FLAG_MMX;
    1.95 +    }
    1.96 +    if (strcmp (*f, "sse") == 0) {
    1.97 +      OIL_DEBUG ("cpu flag %s", *f);
    1.98 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSE;
    1.99 +    }
   1.100 +    if (strcmp (*f, "mmxext") == 0) {
   1.101 +      OIL_DEBUG ("cpu flag %s", *f);
   1.102 +      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.103 +    }
   1.104 +    if (strcmp (*f, "sse2") == 0) {
   1.105 +      OIL_DEBUG ("cpu flag %s", *f);
   1.106 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
   1.107 +      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.108 +    }
   1.109 +    if (strcmp (*f, "3dnow") == 0) {
   1.110 +      OIL_DEBUG ("cpu flag %s", *f);
   1.111 +      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOW;
   1.112 +    }
   1.113 +    if (strcmp (*f, "3dnowext") == 0) {
   1.114 +      OIL_DEBUG ("cpu flag %s", *f);
   1.115 +      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOWEXT;
   1.116 +    }
   1.117 +    if (strcmp (*f, "sse3") == 0) {
   1.118 +      OIL_DEBUG ("cpu flag %s", *f);
   1.119 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
   1.120 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
   1.121 +      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.122 +    }
   1.123 +    if (strcmp (*f, "ssse3") == 0) {
   1.124 +      OIL_DEBUG ("cpu flag %s", *f);
   1.125 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSSE3;
   1.126 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
   1.127 +      oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
   1.128 +      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.129 +    }
   1.130 +
   1.131 +    free (*f);
   1.132 +  }
   1.133 +  free (flags);
   1.134 +  free (cpuinfo);
   1.135 +  free (cpuinfo_flags);
   1.136 +}
   1.137 +#endif
   1.138 +
   1.139 +#ifdef HAVE_GCC_ASM      
   1.140 +static unsigned long
   1.141 +oil_profile_stamp_rdtsc(void)
   1.142 +{
   1.143 +	unsigned long ts;
   1.144 +	__asm__ __volatile__("rdtsc\n" : "=a" (ts) : : "edx");
   1.145 +	return ts;
   1.146 +}
   1.147 +#endif
   1.148 +
   1.149 +#ifdef USE_I386_CPUID
   1.150 +#ifdef __i386__
   1.151 +static void
   1.152 +get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
   1.153 +{
   1.154 +/*               
   1.155 +  __asm__ (
   1.156 +      "  pushl %%ebx\n"
   1.157 +      "  cpuid\n"
   1.158 +      "  mov %%ebx, %%esi\n"
   1.159 +      "  popl %%ebx\n"
   1.160 +      : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d)
   1.161 +      : "0" (op));
   1.162 +*/  
   1.163 +}
   1.164 +#endif
   1.165 +
   1.166 +#ifdef __amd64__
   1.167 +static void
   1.168 +get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
   1.169 +{
   1.170 +  __asm__ (
   1.171 +      "  pushq %%rbx\n"
   1.172 +      "  cpuid\n"
   1.173 +      "  mov %%ebx, %%esi\n"
   1.174 +      "  popq %%rbx\n"
   1.175 +      : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d)
   1.176 +      : "0" (op));
   1.177 +}
   1.178 +#endif
   1.179 +
   1.180 +static void
   1.181 +test_cpuid (void *ignored)
   1.182 +{
   1.183 +  uint32_t eax, ebx, ecx, edx;
   1.184 +
   1.185 +  get_cpuid (0x00000000, &eax, &ebx, &ecx, &edx);
   1.186 +}
   1.187 +
   1.188 +static void
   1.189 +oil_cpu_detect_cpuid (void)
   1.190 +{
   1.191 +  uint32_t eax, ebx, ecx, edx;
   1.192 +  uint32_t level;
   1.193 +  char vendor[13] = { 0 };
   1.194 +  int ret;
   1.195 +
   1.196 +  oil_fault_check_enable ();
   1.197 +  ret = oil_fault_check_try(test_cpuid, NULL);
   1.198 +  oil_fault_check_disable ();
   1.199 +  if (!ret) {
   1.200 +    /* CPU thinks cpuid is an illegal instruction. */
   1.201 +    return;
   1.202 +  }
   1.203 +
   1.204 +  get_cpuid (0x00000000, &level, (uint32_t *)(vendor+0),
   1.205 +      (uint32_t *)(vendor+8), (uint32_t *)(vendor+4));
   1.206 +
   1.207 +  OIL_DEBUG("cpuid %d %s", level, vendor);
   1.208 +
   1.209 +  if (level < 1) {
   1.210 +    return;
   1.211 +  }
   1.212 +
   1.213 +  get_cpuid (0x00000001, &eax, &ebx, &ecx, &edx);
   1.214 +
   1.215 +#ifdef HAVE_GCC_ASM
   1.216 +  if (edx & (1<<4)) {
   1.217 +    _oil_profile_stamp = oil_profile_stamp_rdtsc;
   1.218 +  }
   1.219 +#endif
   1.220 +
   1.221 +  /* Intel flags */
   1.222 +  if (edx & (1<<15)) {
   1.223 +    oil_cpu_flags |= OIL_IMPL_FLAG_CMOV;
   1.224 +  }
   1.225 +  if (edx & (1<<23)) {
   1.226 +    oil_cpu_flags |= OIL_IMPL_FLAG_MMX;
   1.227 +  }
   1.228 +  if (edx & (1<<25)) {
   1.229 +    oil_cpu_flags |= OIL_IMPL_FLAG_SSE;
   1.230 +  }
   1.231 +  if (edx & (1<<26)) {
   1.232 +    oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
   1.233 +    oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.234 +  }
   1.235 +  if (ecx & (1<<0)) {
   1.236 +    oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
   1.237 +  }
   1.238 +  
   1.239 +  if (memcmp (vendor, "AuthenticAMD", 12) == 0) {
   1.240 +    get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
   1.241 +
   1.242 +    /* AMD flags */
   1.243 +    if (edx & (1<<22)) {
   1.244 +      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.245 +    }
   1.246 +    if (edx & (1<<31)) {
   1.247 +      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOW;
   1.248 +    }
   1.249 +    if (edx & (1<<30)) {
   1.250 +      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOWEXT;
   1.251 +    }
   1.252 +
   1.253 +    get_cpuid (0x80000005, &eax, &ebx, &ecx, &edx);
   1.254 +
   1.255 +    OIL_INFO("L1 D-cache: %d kbytes, %d-way, %d lines/tag, %d line size",
   1.256 +        (ecx>>24)&0xff, (ecx>>16)&0xff, (ecx>>8)&0xff, ecx&0xff);
   1.257 +    OIL_INFO("L1 I-cache: %d kbytes, %d-way, %d lines/tag, %d line size",
   1.258 +        (edx>>24)&0xff, (edx>>16)&0xff, (edx>>8)&0xff, edx&0xff);
   1.259 +
   1.260 +    get_cpuid (0x80000006, &eax, &ebx, &ecx, &edx);
   1.261 +    OIL_INFO("L2 cache: %d kbytes, %d assoc, %d lines/tag, %d line size",
   1.262 +        (ecx>>16)&0xffff, (ecx>>12)&0xf, (ecx>>8)&0xf, ecx&0xff);
   1.263 +  }
   1.264 +}
   1.265 +#endif
   1.266 +
   1.267 +#ifdef USE_I386_GETISAX
   1.268 +static void
   1.269 +oil_cpu_detect_getisax (void)
   1.270 +{
   1.271 +  uint_t ui;
   1.272 +
   1.273 +  getisax (&ui, 1);
   1.274 +
   1.275 +  if (ui & AV_386_CMOV) {
   1.276 +     oil_cpu_flags |= OIL_IMPL_FLAG_CMOV;
   1.277 +  }
   1.278 +  if (ui & AV_386_MMX) {
   1.279 +     oil_cpu_flags |= OIL_IMPL_FLAG_MMX;
   1.280 +  }
   1.281 +  if (ui & AV_386_SSE) {
   1.282 +     oil_cpu_flags |= OIL_IMPL_FLAG_SSE;
   1.283 +  }
   1.284 +  if (ui & AV_386_SSE2) {
   1.285 +     oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
   1.286 +     oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.287 +  }
   1.288 +  if (ui & AV_386_SSE3) {
   1.289 +     oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
   1.290 +  }
   1.291 +  if (ui & AV_386_AMD_3DNow) {
   1.292 +    oil_cpu_flags |= OIL_IMPL_FLAG_3DNOW;
   1.293 +  }
   1.294 +  if (ui & AV_386_AMD_3DNowx) {
   1.295 +    oil_cpu_flags |= OIL_IMPL_FLAG_3DNOWEXT;
   1.296 +  }
   1.297 +  if (ui & AV_386_AMD_MMX) {
   1.298 +    oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
   1.299 +  }
   1.300 +}
   1.301 +#endif
   1.302 +
   1.303 +/* Reduce the set of CPU capabilities detected by whatever detection mechanism
   1.304 + * was chosen, according to kernel limitations.  SSE requires kernel support for
   1.305 + * use.
   1.306 + */
   1.307 +static void
   1.308 +oil_cpu_detect_kernel_support (void)
   1.309 +{
   1.310 +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
   1.311 +  int ret, enabled;
   1.312 +  size_t len;
   1.313 +
   1.314 +  len = sizeof(enabled);
   1.315 +  ret = sysctlbyname("hw.instruction_sse", &enabled, &len, NULL, 0);
   1.316 +  if (ret || !enabled) {
   1.317 +    oil_cpu_flags &= ~(OIL_IMPL_FLAG_SSE | OIL_IMPL_FLAG_SSE2 |
   1.318 +		       OIL_IMPL_FLAG_MMXEXT | OIL_IMPL_FLAG_SSE3);
   1.319 +  }
   1.320 +#elif defined(__linux__)
   1.321 +  /*
   1.322 +   * Might also want to grow a check for the old RedHat + Linux 2.2
   1.323 +   * unmasked SSE FPU exception bug.  Other than that, if /proc/cpuinfo
   1.324 +   * reported SSE, then it's safe.
   1.325 +   */
   1.326 +#elif defined(__sun)
   1.327 +  /* Solaris is OK */
   1.328 +#elif defined(__NetBSD__)
   1.329 +  /* NetBSD is OK */
   1.330 +#else
   1.331 +   
   1.332 +  OIL_WARNING("Operating system is not known to support SSE.  "
   1.333 +      "Assuming it does, which might cause problems");
   1.334 +#if 0
   1.335 +  oil_cpu_flags &= ~(OIL_IMPL_FLAG_SSE | OIL_IMPL_FLAG_SSE2 |
   1.336 +		     OIL_IMPL_FLAG_MMXEXT | OIL_IMPL_FLAG_SSE3);
   1.337 +#endif
   1.338 +#endif
   1.339 +}
   1.340 +
   1.341 +void
   1.342 +oil_cpu_detect_arch(void)
   1.343 +{
   1.344 +#ifdef USE_I386_CPUID
   1.345 +  oil_cpu_detect_cpuid ();
   1.346 +#endif
   1.347 +#ifdef USE_I386_GETISAX
   1.348 +  oil_cpu_detect_getisax ();
   1.349 +#endif
   1.350 +#ifdef USE_I386_CPUINFO
   1.351 +  oil_cpu_detect_cpuinfo ();
   1.352 +#endif
   1.353 +
   1.354 +  oil_cpu_detect_kernel_support ();
   1.355 +}
   1.356 +
   1.357 +