os/ossrv/genericopenlibs/liboil/src/liboilcpu-x86.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/*
sl@0
     2
 * LIBOIL - Library of Optimized Inner Loops
sl@0
     3
 * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
sl@0
     4
 * All rights reserved.
sl@0
     5
 *
sl@0
     6
 * Redistribution and use in source and binary forms, with or without
sl@0
     7
 * modification, are permitted provided that the following conditions
sl@0
     8
 * are met:
sl@0
     9
 * 1. Redistributions of source code must retain the above copyright
sl@0
    10
 *    notice, this list of conditions and the following disclaimer.
sl@0
    11
 * 2. Redistributions in binary form must reproduce the above copyright
sl@0
    12
 *    notice, this list of conditions and the following disclaimer in the
sl@0
    13
 *    documentation and/or other materials provided with the distribution.
sl@0
    14
 * 
sl@0
    15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
sl@0
    16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
sl@0
    17
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sl@0
    18
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
sl@0
    19
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
sl@0
    20
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
sl@0
    21
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0
    22
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
sl@0
    23
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
sl@0
    24
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
sl@0
    25
 * POSSIBILITY OF SUCH DAMAGE.
sl@0
    26
 */
sl@0
    27
sl@0
    28
#ifdef HAVE_CONFIG_H
sl@0
    29
#include "config.h"
sl@0
    30
#endif
sl@0
    31
#include <liboil/liboilfunction.h>
sl@0
    32
#include <liboil/liboildebug.h>
sl@0
    33
#include <liboil/liboilcpu.h>
sl@0
    34
#include <liboil/liboilfault.h>
sl@0
    35
#include <liboil/liboilutils.h>
sl@0
    36
sl@0
    37
#ifdef HAVE_UNISTD_H
sl@0
    38
#include <unistd.h>
sl@0
    39
#endif
sl@0
    40
#include <fcntl.h>
sl@0
    41
#include <stdlib.h>
sl@0
    42
#include <string.h>
sl@0
    43
#include <stdio.h>
sl@0
    44
#include <setjmp.h>
sl@0
    45
#include <signal.h>
sl@0
    46
#ifdef HAVE_SYS_TIME_H
sl@0
    47
#include <sys/time.h>
sl@0
    48
#endif
sl@0
    49
#include <time.h>
sl@0
    50
sl@0
    51
#if defined(__FreeBSD__) || defined(__APPLE__)
sl@0
    52
#include <sys/types.h>
sl@0
    53
#include <sys/sysctl.h>
sl@0
    54
#endif
sl@0
    55
sl@0
    56
#ifdef __sun
sl@0
    57
#include <sys/auxv.h>
sl@0
    58
#endif
sl@0
    59
sl@0
    60
/***** i386, amd64 *****/
sl@0
    61
sl@0
    62
#if defined(__sun)
sl@0
    63
#define USE_I386_GETISAX
sl@0
    64
#else
sl@0
    65
#define USE_I386_CPUID
sl@0
    66
#endif
sl@0
    67
sl@0
    68
sl@0
    69
#ifdef USE_I386_CPUINFO
sl@0
    70
static void
sl@0
    71
oil_cpu_i386_getflags_cpuinfo (char *cpuinfo)
sl@0
    72
{
sl@0
    73
  char *cpuinfo_flags;
sl@0
    74
  char **flags;
sl@0
    75
  char **f;
sl@0
    76
sl@0
    77
  cpuinfo_flags = get_tag_value (cpuinfo, "flags");
sl@0
    78
  if (cpuinfo_flags == NULL) {
sl@0
    79
    free (cpuinfo);
sl@0
    80
    return;
sl@0
    81
  }
sl@0
    82
sl@0
    83
  flags = strsplit(cpuinfo_flags);
sl@0
    84
  for (f = flags; *f; f++) {
sl@0
    85
    if (strcmp (*f, "cmov") == 0) {
sl@0
    86
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
    87
      oil_cpu_flags |= OIL_IMPL_FLAG_CMOV;
sl@0
    88
    }
sl@0
    89
    if (strcmp (*f, "mmx") == 0) {
sl@0
    90
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
    91
      oil_cpu_flags |= OIL_IMPL_FLAG_MMX;
sl@0
    92
    }
sl@0
    93
    if (strcmp (*f, "sse") == 0) {
sl@0
    94
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
    95
      oil_cpu_flags |= OIL_IMPL_FLAG_SSE;
sl@0
    96
    }
sl@0
    97
    if (strcmp (*f, "mmxext") == 0) {
sl@0
    98
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
    99
      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   100
    }
sl@0
   101
    if (strcmp (*f, "sse2") == 0) {
sl@0
   102
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
   103
      oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
sl@0
   104
      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   105
    }
sl@0
   106
    if (strcmp (*f, "3dnow") == 0) {
sl@0
   107
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
   108
      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOW;
sl@0
   109
    }
sl@0
   110
    if (strcmp (*f, "3dnowext") == 0) {
sl@0
   111
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
   112
      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOWEXT;
sl@0
   113
    }
sl@0
   114
    if (strcmp (*f, "sse3") == 0) {
sl@0
   115
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
   116
      oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
sl@0
   117
      oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
sl@0
   118
      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   119
    }
sl@0
   120
    if (strcmp (*f, "ssse3") == 0) {
sl@0
   121
      OIL_DEBUG ("cpu flag %s", *f);
sl@0
   122
      oil_cpu_flags |= OIL_IMPL_FLAG_SSSE3;
sl@0
   123
      oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
sl@0
   124
      oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
sl@0
   125
      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   126
    }
sl@0
   127
sl@0
   128
    free (*f);
sl@0
   129
  }
sl@0
   130
  free (flags);
sl@0
   131
  free (cpuinfo);
sl@0
   132
  free (cpuinfo_flags);
sl@0
   133
}
sl@0
   134
#endif
sl@0
   135
sl@0
   136
#ifdef HAVE_GCC_ASM      
sl@0
   137
static unsigned long
sl@0
   138
oil_profile_stamp_rdtsc(void)
sl@0
   139
{
sl@0
   140
	unsigned long ts;
sl@0
   141
	__asm__ __volatile__("rdtsc\n" : "=a" (ts) : : "edx");
sl@0
   142
	return ts;
sl@0
   143
}
sl@0
   144
#endif
sl@0
   145
sl@0
   146
#ifdef USE_I386_CPUID
sl@0
   147
#ifdef __i386__
sl@0
   148
static void
sl@0
   149
get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
sl@0
   150
{
sl@0
   151
/*               
sl@0
   152
  __asm__ (
sl@0
   153
      "  pushl %%ebx\n"
sl@0
   154
      "  cpuid\n"
sl@0
   155
      "  mov %%ebx, %%esi\n"
sl@0
   156
      "  popl %%ebx\n"
sl@0
   157
      : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d)
sl@0
   158
      : "0" (op));
sl@0
   159
*/  
sl@0
   160
}
sl@0
   161
#endif
sl@0
   162
sl@0
   163
#ifdef __amd64__
sl@0
   164
static void
sl@0
   165
get_cpuid (uint32_t op, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
sl@0
   166
{
sl@0
   167
  __asm__ (
sl@0
   168
      "  pushq %%rbx\n"
sl@0
   169
      "  cpuid\n"
sl@0
   170
      "  mov %%ebx, %%esi\n"
sl@0
   171
      "  popq %%rbx\n"
sl@0
   172
      : "=a" (*a), "=S" (*b), "=c" (*c), "=d" (*d)
sl@0
   173
      : "0" (op));
sl@0
   174
}
sl@0
   175
#endif
sl@0
   176
sl@0
   177
static void
sl@0
   178
test_cpuid (void *ignored)
sl@0
   179
{
sl@0
   180
  uint32_t eax, ebx, ecx, edx;
sl@0
   181
sl@0
   182
  get_cpuid (0x00000000, &eax, &ebx, &ecx, &edx);
sl@0
   183
}
sl@0
   184
sl@0
   185
static void
sl@0
   186
oil_cpu_detect_cpuid (void)
sl@0
   187
{
sl@0
   188
  uint32_t eax, ebx, ecx, edx;
sl@0
   189
  uint32_t level;
sl@0
   190
  char vendor[13] = { 0 };
sl@0
   191
  int ret;
sl@0
   192
sl@0
   193
  oil_fault_check_enable ();
sl@0
   194
  ret = oil_fault_check_try(test_cpuid, NULL);
sl@0
   195
  oil_fault_check_disable ();
sl@0
   196
  if (!ret) {
sl@0
   197
    /* CPU thinks cpuid is an illegal instruction. */
sl@0
   198
    return;
sl@0
   199
  }
sl@0
   200
sl@0
   201
  get_cpuid (0x00000000, &level, (uint32_t *)(vendor+0),
sl@0
   202
      (uint32_t *)(vendor+8), (uint32_t *)(vendor+4));
sl@0
   203
sl@0
   204
  OIL_DEBUG("cpuid %d %s", level, vendor);
sl@0
   205
sl@0
   206
  if (level < 1) {
sl@0
   207
    return;
sl@0
   208
  }
sl@0
   209
sl@0
   210
  get_cpuid (0x00000001, &eax, &ebx, &ecx, &edx);
sl@0
   211
sl@0
   212
#ifdef HAVE_GCC_ASM
sl@0
   213
  if (edx & (1<<4)) {
sl@0
   214
    _oil_profile_stamp = oil_profile_stamp_rdtsc;
sl@0
   215
  }
sl@0
   216
#endif
sl@0
   217
sl@0
   218
  /* Intel flags */
sl@0
   219
  if (edx & (1<<15)) {
sl@0
   220
    oil_cpu_flags |= OIL_IMPL_FLAG_CMOV;
sl@0
   221
  }
sl@0
   222
  if (edx & (1<<23)) {
sl@0
   223
    oil_cpu_flags |= OIL_IMPL_FLAG_MMX;
sl@0
   224
  }
sl@0
   225
  if (edx & (1<<25)) {
sl@0
   226
    oil_cpu_flags |= OIL_IMPL_FLAG_SSE;
sl@0
   227
  }
sl@0
   228
  if (edx & (1<<26)) {
sl@0
   229
    oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
sl@0
   230
    oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   231
  }
sl@0
   232
  if (ecx & (1<<0)) {
sl@0
   233
    oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
sl@0
   234
  }
sl@0
   235
  
sl@0
   236
  if (memcmp (vendor, "AuthenticAMD", 12) == 0) {
sl@0
   237
    get_cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
sl@0
   238
sl@0
   239
    /* AMD flags */
sl@0
   240
    if (edx & (1<<22)) {
sl@0
   241
      oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   242
    }
sl@0
   243
    if (edx & (1<<31)) {
sl@0
   244
      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOW;
sl@0
   245
    }
sl@0
   246
    if (edx & (1<<30)) {
sl@0
   247
      oil_cpu_flags |= OIL_IMPL_FLAG_3DNOWEXT;
sl@0
   248
    }
sl@0
   249
sl@0
   250
    get_cpuid (0x80000005, &eax, &ebx, &ecx, &edx);
sl@0
   251
sl@0
   252
    OIL_INFO("L1 D-cache: %d kbytes, %d-way, %d lines/tag, %d line size",
sl@0
   253
        (ecx>>24)&0xff, (ecx>>16)&0xff, (ecx>>8)&0xff, ecx&0xff);
sl@0
   254
    OIL_INFO("L1 I-cache: %d kbytes, %d-way, %d lines/tag, %d line size",
sl@0
   255
        (edx>>24)&0xff, (edx>>16)&0xff, (edx>>8)&0xff, edx&0xff);
sl@0
   256
sl@0
   257
    get_cpuid (0x80000006, &eax, &ebx, &ecx, &edx);
sl@0
   258
    OIL_INFO("L2 cache: %d kbytes, %d assoc, %d lines/tag, %d line size",
sl@0
   259
        (ecx>>16)&0xffff, (ecx>>12)&0xf, (ecx>>8)&0xf, ecx&0xff);
sl@0
   260
  }
sl@0
   261
}
sl@0
   262
#endif
sl@0
   263
sl@0
   264
#ifdef USE_I386_GETISAX
sl@0
   265
static void
sl@0
   266
oil_cpu_detect_getisax (void)
sl@0
   267
{
sl@0
   268
  uint_t ui;
sl@0
   269
sl@0
   270
  getisax (&ui, 1);
sl@0
   271
sl@0
   272
  if (ui & AV_386_CMOV) {
sl@0
   273
     oil_cpu_flags |= OIL_IMPL_FLAG_CMOV;
sl@0
   274
  }
sl@0
   275
  if (ui & AV_386_MMX) {
sl@0
   276
     oil_cpu_flags |= OIL_IMPL_FLAG_MMX;
sl@0
   277
  }
sl@0
   278
  if (ui & AV_386_SSE) {
sl@0
   279
     oil_cpu_flags |= OIL_IMPL_FLAG_SSE;
sl@0
   280
  }
sl@0
   281
  if (ui & AV_386_SSE2) {
sl@0
   282
     oil_cpu_flags |= OIL_IMPL_FLAG_SSE2;
sl@0
   283
     oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   284
  }
sl@0
   285
  if (ui & AV_386_SSE3) {
sl@0
   286
     oil_cpu_flags |= OIL_IMPL_FLAG_SSE3;
sl@0
   287
  }
sl@0
   288
  if (ui & AV_386_AMD_3DNow) {
sl@0
   289
    oil_cpu_flags |= OIL_IMPL_FLAG_3DNOW;
sl@0
   290
  }
sl@0
   291
  if (ui & AV_386_AMD_3DNowx) {
sl@0
   292
    oil_cpu_flags |= OIL_IMPL_FLAG_3DNOWEXT;
sl@0
   293
  }
sl@0
   294
  if (ui & AV_386_AMD_MMX) {
sl@0
   295
    oil_cpu_flags |= OIL_IMPL_FLAG_MMXEXT;
sl@0
   296
  }
sl@0
   297
}
sl@0
   298
#endif
sl@0
   299
sl@0
   300
/* Reduce the set of CPU capabilities detected by whatever detection mechanism
sl@0
   301
 * was chosen, according to kernel limitations.  SSE requires kernel support for
sl@0
   302
 * use.
sl@0
   303
 */
sl@0
   304
static void
sl@0
   305
oil_cpu_detect_kernel_support (void)
sl@0
   306
{
sl@0
   307
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
sl@0
   308
  int ret, enabled;
sl@0
   309
  size_t len;
sl@0
   310
sl@0
   311
  len = sizeof(enabled);
sl@0
   312
  ret = sysctlbyname("hw.instruction_sse", &enabled, &len, NULL, 0);
sl@0
   313
  if (ret || !enabled) {
sl@0
   314
    oil_cpu_flags &= ~(OIL_IMPL_FLAG_SSE | OIL_IMPL_FLAG_SSE2 |
sl@0
   315
		       OIL_IMPL_FLAG_MMXEXT | OIL_IMPL_FLAG_SSE3);
sl@0
   316
  }
sl@0
   317
#elif defined(__linux__)
sl@0
   318
  /*
sl@0
   319
   * Might also want to grow a check for the old RedHat + Linux 2.2
sl@0
   320
   * unmasked SSE FPU exception bug.  Other than that, if /proc/cpuinfo
sl@0
   321
   * reported SSE, then it's safe.
sl@0
   322
   */
sl@0
   323
#elif defined(__sun)
sl@0
   324
  /* Solaris is OK */
sl@0
   325
#elif defined(__NetBSD__)
sl@0
   326
  /* NetBSD is OK */
sl@0
   327
#else
sl@0
   328
   
sl@0
   329
  OIL_WARNING("Operating system is not known to support SSE.  "
sl@0
   330
      "Assuming it does, which might cause problems");
sl@0
   331
#if 0
sl@0
   332
  oil_cpu_flags &= ~(OIL_IMPL_FLAG_SSE | OIL_IMPL_FLAG_SSE2 |
sl@0
   333
		     OIL_IMPL_FLAG_MMXEXT | OIL_IMPL_FLAG_SSE3);
sl@0
   334
#endif
sl@0
   335
#endif
sl@0
   336
}
sl@0
   337
sl@0
   338
void
sl@0
   339
oil_cpu_detect_arch(void)
sl@0
   340
{
sl@0
   341
#ifdef USE_I386_CPUID
sl@0
   342
  oil_cpu_detect_cpuid ();
sl@0
   343
#endif
sl@0
   344
#ifdef USE_I386_GETISAX
sl@0
   345
  oil_cpu_detect_getisax ();
sl@0
   346
#endif
sl@0
   347
#ifdef USE_I386_CPUINFO
sl@0
   348
  oil_cpu_detect_cpuinfo ();
sl@0
   349
#endif
sl@0
   350
sl@0
   351
  oil_cpu_detect_kernel_support ();
sl@0
   352
}
sl@0
   353
sl@0
   354