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 +