cbe34bb5ed
From-SVN: r243994
363 lines
9.3 KiB
C
363 lines
9.3 KiB
C
/* Automatic switching between software and hardware IEEE 128-bit
|
||
floating-point emulation for PowerPC.
|
||
|
||
Copyright (C) 2016-2017 Free Software Foundation, Inc.
|
||
This file is part of the GNU C Library.
|
||
Contributed by Michael Meissner (meissner@linux.vnet.ibm.com)
|
||
Code is based on the main soft-fp library written by:
|
||
Richard Henderson (rth@cygnus.com) and
|
||
Jakub Jelinek (jj@ultra.linux.cz).
|
||
|
||
The GNU C Library is free software; you can redistribute it and/or
|
||
modify it under the terms of the GNU Lesser General Public
|
||
License as published by the Free Software Foundation; either
|
||
version 2.1 of the License, or (at your option) any later version.
|
||
|
||
In addition to the permissions in the GNU Lesser General Public
|
||
License, the Free Software Foundation gives you unlimited
|
||
permission to link the compiled version of this file into
|
||
combinations with other programs, and to distribute those
|
||
combinations without any restriction coming from the use of this
|
||
file. (The Lesser General Public License restrictions do apply in
|
||
other respects; for example, they cover modification of the file,
|
||
and distribution when not linked into a combine executable.)
|
||
|
||
The GNU C Library is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
Lesser General Public License for more details.
|
||
|
||
You should have received a copy of the GNU Lesser General Public
|
||
License along with the GNU C Library; if not, see
|
||
<http://www.gnu.org/licenses/>. */
|
||
|
||
#include <soft-fp.h>
|
||
#include <quad-float128.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <ctype.h>
|
||
|
||
#ifndef FLOAT128_HW_INSNS
|
||
#error "float128-ifunc.c needs access to ISA 3.0 instructions and ifunc"
|
||
#endif
|
||
|
||
#ifdef __FLOAT128_HARDWARE__
|
||
#error "This module must not be compiled with IEEE 128-bit hardware support"
|
||
#endif
|
||
|
||
#include <sys/auxv.h>
|
||
|
||
/* Use the namespace clean version of getauxval. However, not all versions of
|
||
sys/auxv.h declare it, so declare it here. This code is intended to be
|
||
temporary until a suitable version of __builtin_cpu_supports is added that
|
||
allows us to tell quickly if the machine supports IEEE 128-bit hardware. */
|
||
extern unsigned long __getauxval (unsigned long);
|
||
|
||
static int
|
||
have_ieee_hw_p (void)
|
||
{
|
||
static int ieee_hw_p = -1;
|
||
|
||
if (ieee_hw_p < 0)
|
||
{
|
||
char *p = (char *) __getauxval (AT_PLATFORM);
|
||
|
||
ieee_hw_p = 0;
|
||
|
||
/* Don't use atoi/strtol/strncmp/etc. These may require the normal
|
||
environment to be setup to set errno to 0, and the ifunc resolvers run
|
||
before the whole glibc environment is initialized. */
|
||
if (p && p[0] == 'p' && p[1] == 'o' && p[2] == 'w' && p[3] == 'e'
|
||
&& p[4] == 'r')
|
||
{
|
||
long n = 0;
|
||
char ch;
|
||
|
||
p += 5;
|
||
while ((ch = *p++) >= '0' && (ch <= '9'))
|
||
n = (n * 10) + (ch - '0');
|
||
|
||
if (n >= 9)
|
||
ieee_hw_p = 1;
|
||
}
|
||
}
|
||
|
||
return ieee_hw_p;
|
||
}
|
||
|
||
#define SW_OR_HW(SW, HW) (have_ieee_hw_p () ? HW : SW)
|
||
|
||
/* Resolvers. */
|
||
|
||
/* We do not provide ifunc resolvers for __fixkfti, __fixunskfti, __floattikf,
|
||
and __floatuntikf. There is no ISA 3.0 instruction that converts between
|
||
128-bit integer types and 128-bit IEEE floating point, or vice versa. So
|
||
use the emulator functions for these conversions. */
|
||
|
||
static void *__addkf3_resolve (void);
|
||
static void *__subkf3_resolve (void);
|
||
static void *__mulkf3_resolve (void);
|
||
static void *__divkf3_resolve (void);
|
||
static void *__negkf2_resolve (void);
|
||
static void *__eqkf2_resolve (void);
|
||
static void *__nekf2_resolve (void);
|
||
static void *__gekf2_resolve (void);
|
||
static void *__gtkf2_resolve (void);
|
||
static void *__lekf2_resolve (void);
|
||
static void *__ltkf2_resolve (void);
|
||
static void *__unordkf2_resolve (void);
|
||
static void *__extendsfkf2_resolve (void);
|
||
static void *__extenddfkf2_resolve (void);
|
||
static void *__trunckfsf2_resolve (void);
|
||
static void *__trunckfdf2_resolve (void);
|
||
static void *__fixkfsi_resolve (void);
|
||
static void *__fixkfdi_resolve (void);
|
||
static void *__fixunskfsi_resolve (void);
|
||
static void *__fixunskfdi_resolve (void);
|
||
static void *__floatsikf_resolve (void);
|
||
static void *__floatdikf_resolve (void);
|
||
static void *__floatunsikf_resolve (void);
|
||
static void *__floatundikf_resolve (void);
|
||
static void *__extendkftf2_resolve (void);
|
||
static void *__trunctfkf2_resolve (void);
|
||
|
||
static void *
|
||
__addkf3_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__addkf3_sw, __addkf3_hw);
|
||
}
|
||
|
||
static void *
|
||
__subkf3_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__subkf3_sw, __subkf3_hw);
|
||
}
|
||
|
||
static void *
|
||
__mulkf3_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__mulkf3_sw, __mulkf3_hw);
|
||
}
|
||
|
||
static void *
|
||
__divkf3_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__divkf3_sw, __divkf3_hw);
|
||
}
|
||
|
||
static void *
|
||
__negkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__negkf2_sw, __negkf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__floatsikf_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__floatsikf_sw, __floatsikf_hw);
|
||
}
|
||
|
||
static void *
|
||
__floatdikf_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__floatdikf_sw, __floatdikf_hw);
|
||
}
|
||
|
||
static void *
|
||
__floatunsikf_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__floatunsikf_sw, __floatunsikf_hw);
|
||
}
|
||
|
||
static void *
|
||
__floatundikf_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__floatundikf_sw, __floatundikf_hw);
|
||
}
|
||
|
||
static void *
|
||
__fixkfsi_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__fixkfsi_sw, __fixkfsi_hw);
|
||
}
|
||
|
||
static void *
|
||
__fixkfdi_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__fixkfdi_sw, __fixkfdi_hw);
|
||
}
|
||
|
||
static void *
|
||
__fixunskfsi_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__fixunskfsi_sw, __fixunskfsi_hw);
|
||
}
|
||
|
||
static void *
|
||
__fixunskfdi_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__fixunskfdi_sw, __fixunskfdi_hw);
|
||
}
|
||
|
||
static void *
|
||
__extendsfkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__extendsfkf2_sw, __extendsfkf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__extenddfkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__extenddfkf2_sw, __extenddfkf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__trunckfsf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__trunckfsf2_sw, __trunckfsf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__trunckfdf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__trunckfdf2_sw, __trunckfdf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__extendkftf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__extendkftf2_sw, __extendkftf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__trunctfkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__trunctfkf2_sw, __trunctfkf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__eqkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__eqkf2_sw, __eqkf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__gekf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__gekf2_sw, __gekf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__lekf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__lekf2_sw, __lekf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__unordkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__unordkf2_sw, __unordkf2_hw);
|
||
}
|
||
|
||
/* Resolve __nekf2, __gtkf2, __ltkf2 like __eqkf2, __gekf2, and __lekf2, since
|
||
the functions return the same values. */
|
||
|
||
static void *
|
||
__nekf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__eqkf2_sw, __eqkf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__gtkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__gekf2_sw, __gekf2_hw);
|
||
}
|
||
|
||
static void *
|
||
__ltkf2_resolve (void)
|
||
{
|
||
return (void *) SW_OR_HW (__lekf2_sw, __lekf2_hw);
|
||
}
|
||
|
||
|
||
|
||
/* Ifunc definitions. */
|
||
TFtype __addkf3 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__addkf3_resolve")));
|
||
|
||
TFtype __subkf3 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__subkf3_resolve")));
|
||
|
||
TFtype __mulkf3 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__mulkf3_resolve")));
|
||
|
||
TFtype __divkf3 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__divkf3_resolve")));
|
||
|
||
TFtype __negkf2 (TFtype)
|
||
__attribute__ ((__ifunc__ ("__negkf2_resolve")));
|
||
|
||
CMPtype __eqkf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__eqkf2_resolve")));
|
||
|
||
CMPtype __nekf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__nekf2_resolve")));
|
||
|
||
CMPtype __gekf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__gekf2_resolve")));
|
||
|
||
CMPtype __gtkf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__gtkf2_resolve")));
|
||
|
||
CMPtype __lekf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__lekf2_resolve")));
|
||
|
||
CMPtype __ltkf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__ltkf2_resolve")));
|
||
|
||
CMPtype __unordkf2 (TFtype, TFtype)
|
||
__attribute__ ((__ifunc__ ("__unordkf2_resolve")));
|
||
|
||
TFtype __extendsfkf2 (float)
|
||
__attribute__ ((__ifunc__ ("__extendsfkf2_resolve")));
|
||
|
||
TFtype __extenddfkf2 (double)
|
||
__attribute__ ((__ifunc__ ("__extenddfkf2_resolve")));
|
||
|
||
float __trunckfsf2 (TFtype)
|
||
__attribute__ ((__ifunc__ ("__trunckfsf2_resolve")));
|
||
|
||
double __trunckfdf2 (TFtype)
|
||
__attribute__ ((__ifunc__ ("__trunckfdf2_resolve")));
|
||
|
||
SItype_ppc __fixkfsi (TFtype)
|
||
__attribute__ ((__ifunc__ ("__fixkfsi_resolve")));
|
||
|
||
DItype_ppc __fixkfdi (TFtype)
|
||
__attribute__ ((__ifunc__ ("__fixkfdi_resolve")));
|
||
|
||
USItype_ppc __fixunskfsi (TFtype)
|
||
__attribute__ ((__ifunc__ ("__fixunskfsi_resolve")));
|
||
|
||
UDItype_ppc __fixunskfdi (TFtype)
|
||
__attribute__ ((__ifunc__ ("__fixunskfdi_resolve")));
|
||
|
||
TFtype __floatsikf (SItype_ppc)
|
||
__attribute__ ((__ifunc__ ("__floatsikf_resolve")));
|
||
|
||
TFtype __floatdikf (DItype_ppc)
|
||
__attribute__ ((__ifunc__ ("__floatdikf_resolve")));
|
||
|
||
TFtype __floatunsikf (USItype_ppc)
|
||
__attribute__ ((__ifunc__ ("__floatunsikf_resolve")));
|
||
|
||
TFtype __floatundikf (UDItype_ppc)
|
||
__attribute__ ((__ifunc__ ("__floatundikf_resolve")));
|
||
|
||
IBM128_TYPE __extendkftf2 (TFtype)
|
||
__attribute__ ((__ifunc__ ("__extendkftf2_resolve")));
|
||
|
||
TFtype __trunctfkf2 (IBM128_TYPE)
|
||
__attribute__ ((__ifunc__ ("__trunctfkf2_resolve")));
|