andrew@0: /* andrew@0: ** Copyright (C) 2001-2008 Erik de Castro Lopo andrew@0: ** andrew@0: ** This program is free software; you can redistribute it and/or modify andrew@0: ** it under the terms of the GNU Lesser General Public License as published by andrew@0: ** the Free Software Foundation; either version 2.1 of the License, or andrew@0: ** (at your option) any later version. andrew@0: ** andrew@0: ** This program is distributed in the hope that it will be useful, andrew@0: ** but WITHOUT ANY WARRANTY; without even the implied warranty of andrew@0: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrew@0: ** GNU Lesser General Public License for more details. andrew@0: ** andrew@0: ** You should have received a copy of the GNU Lesser General Public License andrew@0: ** along with this program; if not, write to the Free Software andrew@0: ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. andrew@0: */ andrew@0: andrew@0: /* Version 1.4 */ andrew@0: andrew@0: #ifndef FLOAT_CAST_HEADER andrew@0: #define FLOAT_CAST_HEADER andrew@0: andrew@0: /*============================================================================ andrew@0: ** On Intel Pentium processors (especially PIII and probably P4), converting andrew@0: ** from float to int is very slow. To meet the C specs, the code produced by andrew@0: ** most C compilers targeting Pentium needs to change the FPU rounding mode andrew@0: ** before the float to int conversion is performed. andrew@0: ** andrew@0: ** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It andrew@0: ** is this flushing of the pipeline which is so slow. andrew@0: ** andrew@0: ** Fortunately the ISO C99 specifications define the functions lrint, lrintf, andrew@0: ** llrint and llrintf which fix this problem as a side effect. andrew@0: ** andrew@0: ** On Unix-like systems, the configure process should have detected the andrew@0: ** presence of these functions. If they weren't found we have to replace them andrew@0: ** here with a standard C cast. andrew@0: */ andrew@0: andrew@0: /* andrew@0: ** The C99 prototypes for lrint and lrintf are as follows: andrew@0: ** andrew@0: ** long int lrintf (float x) ; andrew@0: ** long int lrint (double x) ; andrew@0: */ andrew@0: andrew@0: #include "config.h" andrew@0: andrew@0: /* andrew@0: ** The presence of the required functions are detected during the configure andrew@0: ** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in andrew@0: ** the config.h file. andrew@0: */ andrew@0: andrew@0: #define HAVE_LRINT_REPLACEMENT 0 andrew@0: andrew@0: #if (HAVE_LRINT && HAVE_LRINTF) andrew@0: andrew@0: /* andrew@0: ** These defines enable functionality introduced with the 1999 ISO C andrew@0: ** standard. They must be defined before the inclusion of math.h to andrew@0: ** engage them. If optimisation is enabled, these functions will be andrew@0: ** inlined. With optimisation switched off, you have to link in the andrew@0: ** maths library using -lm. andrew@0: */ andrew@0: andrew@0: #define _ISOC9X_SOURCE 1 andrew@0: #define _ISOC99_SOURCE 1 andrew@0: andrew@0: #define __USE_ISOC9X 1 andrew@0: #define __USE_ISOC99 1 andrew@0: andrew@0: #include andrew@0: andrew@0: #elif (defined (__CYGWIN__)) andrew@0: andrew@0: #include andrew@0: andrew@0: #undef HAVE_LRINT_REPLACEMENT andrew@0: #define HAVE_LRINT_REPLACEMENT 1 andrew@0: andrew@0: #undef lrint andrew@0: #undef lrintf andrew@0: andrew@0: #define lrint double2int andrew@0: #define lrintf float2int andrew@0: andrew@0: /* andrew@0: ** The native CYGWIN lrint and lrintf functions are buggy: andrew@0: ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html andrew@0: ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html andrew@0: ** and slow. andrew@0: ** These functions (pulled from the Public Domain MinGW math.h header) andrew@0: ** replace the native versions. andrew@0: */ andrew@0: andrew@0: static inline long double2int (double in) andrew@0: { long retval ; andrew@0: andrew@0: __asm__ __volatile__ andrew@0: ( "fistpl %0" andrew@0: : "=m" (retval) andrew@0: : "t" (in) andrew@0: : "st" andrew@0: ) ; andrew@0: andrew@0: return retval ; andrew@0: } /* double2int */ andrew@0: andrew@0: static inline long float2int (float in) andrew@0: { long retval ; andrew@0: andrew@0: __asm__ __volatile__ andrew@0: ( "fistpl %0" andrew@0: : "=m" (retval) andrew@0: : "t" (in) andrew@0: : "st" andrew@0: ) ; andrew@0: andrew@0: return retval ; andrew@0: } /* float2int */ andrew@0: andrew@0: #elif (defined (WIN32) || defined (_WIN32)) andrew@0: andrew@0: #undef HAVE_LRINT_REPLACEMENT andrew@0: #define HAVE_LRINT_REPLACEMENT 1 andrew@0: andrew@0: #include andrew@0: andrew@0: /* andrew@0: ** Win32 doesn't seem to have these functions. andrew@0: ** Therefore implement inline versions of these functions here. andrew@0: */ andrew@0: andrew@0: __inline long int andrew@0: lrint (double flt) andrew@0: { int intgr ; andrew@0: andrew@0: _asm andrew@0: { fld flt andrew@0: fistp intgr andrew@0: } ; andrew@0: andrew@0: return intgr ; andrew@0: } andrew@0: andrew@0: __inline long int andrew@0: lrintf (float flt) andrew@0: { int intgr ; andrew@0: andrew@0: _asm andrew@0: { fld flt andrew@0: fistp intgr andrew@0: } ; andrew@0: andrew@0: return intgr ; andrew@0: } andrew@0: andrew@0: #elif (defined (__MWERKS__) && defined (macintosh)) andrew@0: andrew@0: /* This MacOS 9 solution was provided by Stephane Letz */ andrew@0: andrew@0: #undef HAVE_LRINT_REPLACEMENT andrew@0: #define HAVE_LRINT_REPLACEMENT 1 andrew@0: #include andrew@0: andrew@0: #undef lrint andrew@0: #undef lrintf andrew@0: andrew@0: #define lrint double2int andrew@0: #define lrintf float2int andrew@0: andrew@0: inline int andrew@0: float2int (register float in) andrew@0: { long res [2] ; andrew@0: andrew@0: asm andrew@0: { fctiw in, in andrew@0: stfd in, res andrew@0: } andrew@0: return res [1] ; andrew@0: } /* float2int */ andrew@0: andrew@0: inline int andrew@0: double2int (register double in) andrew@0: { long res [2] ; andrew@0: andrew@0: asm andrew@0: { fctiw in, in andrew@0: stfd in, res andrew@0: } andrew@0: return res [1] ; andrew@0: } /* double2int */ andrew@0: andrew@0: #elif (defined (__MACH__) && defined (__APPLE__)) andrew@0: andrew@0: /* For Apple MacOSX. */ andrew@0: andrew@0: #undef HAVE_LRINT_REPLACEMENT andrew@0: #define HAVE_LRINT_REPLACEMENT 1 andrew@0: #include andrew@0: andrew@0: #undef lrint andrew@0: #undef lrintf andrew@0: andrew@0: #define lrint double2int andrew@0: #define lrintf float2int andrew@0: andrew@0: inline static long andrew@0: float2int (register float in) andrew@0: { int res [2] ; andrew@0: andrew@0: __asm__ __volatile__ andrew@0: ( "fctiw %1, %1\n\t" andrew@0: "stfd %1, %0" andrew@0: : "=m" (res) /* Output */ andrew@0: : "f" (in) /* Input */ andrew@0: : "memory" andrew@0: ) ; andrew@0: andrew@0: return res [1] ; andrew@0: } /* lrintf */ andrew@0: andrew@0: inline static long andrew@0: double2int (register double in) andrew@0: { int res [2] ; andrew@0: andrew@0: __asm__ __volatile__ andrew@0: ( "fctiw %1, %1\n\t" andrew@0: "stfd %1, %0" andrew@0: : "=m" (res) /* Output */ andrew@0: : "f" (in) /* Input */ andrew@0: : "memory" andrew@0: ) ; andrew@0: andrew@0: return res [1] ; andrew@0: } /* lrint */ andrew@0: andrew@0: #else andrew@0: #ifndef __sgi andrew@0: #warning "Don't have the functions lrint() and lrintf()." andrew@0: #warning "Replacing these functions with a standard C cast." andrew@0: #endif andrew@0: andrew@0: #include andrew@0: andrew@0: #define lrint(dbl) ((long) (dbl)) andrew@0: #define lrintf(flt) ((long) (flt)) andrew@0: andrew@0: #endif andrew@0: andrew@0: andrew@0: #endif /* FLOAT_CAST_HEADER */ andrew@0: