orccpu-powerpc.c 4.71 KB
Newer Older
1
/*
David Schleef's avatar
David Schleef committed
2
 * LIBORC - Library of Optimized Inner Loops
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
David Schleef's avatar
David Schleef committed
31
#include <orc/orc.h>
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

#if defined(__linux__)
#include <linux/auxvec.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

#ifndef PPC_FEATURE_HAS_ALTIVEC
/* From linux-2.6/include/asm-powerpc/cputable.h */
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
#endif

#endif

48
#if defined(__FreeBSD__) || defined(__APPLE__)
49 50 51 52
#include <sys/types.h>
#include <sys/sysctl.h>
#endif

53 54 55 56 57
#if defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
#endif
58 59 60

/***** powerpc *****/

David Schleef's avatar
David Schleef committed
61
#if 0
62
static unsigned long
David Schleef's avatar
David Schleef committed
63
orc_profile_stamp_tb(void)
64 65 66 67 68
{
  unsigned long ts;
  __asm__ __volatile__("mftb %0\n" : "=r" (ts));
  return ts;
}
David Schleef's avatar
David Schleef committed
69
#endif
70

71
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__linux__)
72 73 74 75 76 77 78
static void
test_altivec (void * ignored)
{
  asm volatile ("vor v0, v0, v0\n");
}
#endif

79 80 81 82 83
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if defined(__APPLE__)
#define SYSCTL "hw.vectorunit"
#else
#define SYSCTL "hw.altivec"
84 85
#endif

86 87
static unsigned long
orc_check_altivec_sysctl_bsd (void)
88
{
89
  unsigned long cpu_flags = 0;
90 91 92 93
  int ret, vu;
  size_t len;

  len = sizeof(vu);
94
  ret = sysctlbyname(SYSCTL, &vu, &len, NULL, 0);
95
  if (!ret && vu) {
96
    cpu_flags |= ORC_TARGET_ALTIVEC_ALTIVEC;
97
  }
98 99

  return cpu_flags;
100 101 102
}
#endif

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
#if defined(__OpenBSD__)
static unsigned long
orc_check_altivec_sysctl_openbsd (void)
{
  unsigned long cpu_flags = 0;
  int mib[2], ret, vu;
  size_t len;

  mib[0] = CTL_MACHDEP;
  mib[1] = CPU_ALTIVEC;

  len = sizeof(vu);
  ret = sysctl(mib, 2, &vu, &len, NULL, 0);
  if (!ret && vu) {
    cpu_flags |= ORC_TARGET_ALTIVEC_ALTIVEC;
  }

  return cpu_flags;
}
#endif

124
#if defined(__linux__)
David Schleef's avatar
David Schleef committed
125 126
static unsigned long
orc_check_altivec_proc_auxv (void)
127
{
David Schleef's avatar
David Schleef committed
128
  unsigned long cpu_flags = 0;
129 130 131 132 133 134 135 136
  static int available = -1;
  int new_avail = 0;
  unsigned long buf[64];
  ssize_t count;
  int fd, i;

  /* Flags already set */
  if (available != -1) {
David Schleef's avatar
David Schleef committed
137
    return 0;
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
  }

  fd = open("/proc/self/auxv", O_RDONLY);
  if (fd < 0) {
    goto out;
  }

more:
  count = read(fd, buf, sizeof(buf));
  if (count < 0) {
    goto out_close;
  }

  for (i=0; i < (count / sizeof(unsigned long)); i += 2) {
    if (buf[i] == AT_HWCAP) {
      new_avail = !!(buf[i+1] & PPC_FEATURE_HAS_ALTIVEC);
      goto out_close;
    } else if (buf[i] == AT_NULL) {
      goto out_close;
    }
  }

  if (count == sizeof(buf)) {
    goto more;
  }

out_close:
  close(fd);

out:
  available = new_avail;
  if (available) {
David Schleef's avatar
David Schleef committed
170
    cpu_flags |= ORC_TARGET_ALTIVEC_ALTIVEC;
171
  }
David Schleef's avatar
David Schleef committed
172 173

  return cpu_flags;
174 175 176
}
#endif

177
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__linux__)
178
static void
David Schleef's avatar
David Schleef committed
179
orc_check_altivec_fault (void)
180
{
David Schleef's avatar
David Schleef committed
181 182 183 184
  orc_fault_check_enable ();
  if (orc_fault_check_try(test_altivec, NULL)) {
    ORC_DEBUG ("cpu flag altivec");
    orc_cpu_flags |= ORC_IMPL_FLAG_ALTIVEC;
185
  }
David Schleef's avatar
David Schleef committed
186
  orc_fault_check_disable ();
187 188 189 190
}
#endif

void
David Schleef's avatar
David Schleef committed
191
orc_cpu_detect_arch(void)
192
{
193 194
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
  orc_check_altivec_sysctl_bsd();
195 196
#elif defined(__OpenBSD__)
  orc_check_altivec_sysctl_openbsd();
197
#elif defined(__linux__)
David Schleef's avatar
David Schleef committed
198
  orc_check_altivec_proc_auxv();
199
#else
David Schleef's avatar
David Schleef committed
200
  orc_check_altivec_fault();
201 202
#endif

David Schleef's avatar
David Schleef committed
203
  //_orc_profile_stamp = orc_profile_stamp_tb;
204 205 206 207
}