PPL  0.12.1
fpu-ia32.inlines.hh
Go to the documentation of this file.
00001 /* IA-32 floating point unit inline related functions.
00002    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00003    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00004 
00005 This file is part of the Parma Polyhedra Library (PPL).
00006 
00007 The PPL is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 The PPL is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software Foundation,
00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00020 
00021 For the most up-to-date information see the Parma Polyhedra Library
00022 site: http://bugseng.com/products/ppl/ . */
00023 
00024 #ifndef PPL_fpu_ia32_inlines_hh
00025 #define PPL_fpu_ia32_inlines_hh 1
00026 
00027 #include <csetjmp>
00028 #include <csignal>
00029 
00030 #define FPU_INVALID       0x01
00031 #define FPU_DIVBYZERO     0x04
00032 #define FPU_OVERFLOW      0x08
00033 #define FPU_UNDERFLOW     0x10
00034 #define FPU_INEXACT       0x20
00035 
00036 #define FPU_ALL_EXCEPT \
00037   (FPU_INEXACT | FPU_DIVBYZERO | FPU_UNDERFLOW | FPU_OVERFLOW | FPU_INVALID)
00038 
00039 #define PPL_FPU_TONEAREST     0
00040 #define PPL_FPU_DOWNWARD      0x400
00041 #define PPL_FPU_UPWARD        0x800
00042 #define PPL_FPU_TOWARDZERO    0xc00
00043 
00044 #define FPU_ROUNDING_MASK 0xc00
00045 
00046 #define SSE_INEXACT       0x20
00047 
00048 #define PPL_FPU_CONTROL_DEFAULT_BASE 0x37f
00049 #define PPL_SSE_CONTROL_DEFAULT_BASE 0x1f80
00050 
00051 // This MUST be congruent with the definition of ROUND_DIRECT
00052 #define PPL_FPU_CONTROL_DEFAULT \
00053   (PPL_FPU_CONTROL_DEFAULT_BASE | PPL_FPU_UPWARD)
00054 #define PPL_SSE_CONTROL_DEFAULT \
00055   (PPL_SSE_CONTROL_DEFAULT_BASE | (PPL_FPU_UPWARD << 3))
00056 
00057 namespace Parma_Polyhedra_Library {
00058 
00059 typedef struct {
00060   unsigned short control_word;
00061   unsigned short unused1;
00062   unsigned short status_word;
00063   unsigned short unused2;
00064   unsigned short tags;
00065   unsigned short unused3;
00066   unsigned int eip;
00067   unsigned short cs_selector;
00068   unsigned int opcode:11;
00069   unsigned int unused4:5;
00070   unsigned int data_offset;
00071   unsigned short data_selector;
00072   unsigned short unused5;
00073 } ia32_fenv_t;
00074 
00075 inline int
00076 fpu_get_control() {
00077   unsigned short cw;
00078   __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw) : : "memory");
00079   return cw;
00080 }
00081 
00082 inline void
00083 fpu_set_control(int c) {
00084   unsigned short cw = static_cast<unsigned short>(c);
00085   __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw) : "memory");
00086 }
00087 
00088 inline int
00089 fpu_get_status() {
00090   unsigned short sw;
00091   __asm__ __volatile__ ("fnstsw %0" : "=a" (sw) : : "memory");
00092   return sw;
00093 }
00094 
00095 inline void
00096 fpu_clear_status(unsigned short bits) {
00097   /* There is no fldsw instruction */
00098   ia32_fenv_t env;
00099   __asm__ __volatile__ ("fnstenv %0" : "=m" (env));
00100   env.status_word = static_cast<unsigned short>(env.status_word & ~bits);
00101   __asm__ __volatile__ ("fldenv %0" : : "m" (env) : "memory");
00102 }
00103 
00104 inline void
00105 fpu_clear_exceptions() {
00106   __asm__ __volatile__ ("fnclex" : /* No outputs.  */ : : "memory");
00107 }
00108 
00109 #ifdef PPL_FPMATH_MAY_USE_SSE
00110 inline void
00111 sse_set_control(unsigned int cw) {
00112   __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&cw) : "memory");
00113 }
00114 
00115 inline unsigned int
00116 sse_get_control() {
00117   unsigned int cw;
00118   __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&cw) : : "memory");
00119   return cw;
00120 }
00121 #endif
00122 
00123 inline void
00124 fpu_initialize_control_functions() {
00125 #ifdef PPL_FPMATH_MAY_USE_SSE
00126   extern void detect_sse_unit();
00127   detect_sse_unit();
00128 #endif
00129 }
00130 
00131 inline fpu_rounding_direction_type
00132 fpu_get_rounding_direction() {
00133   return static_cast<fpu_rounding_direction_type>(fpu_get_control() & FPU_ROUNDING_MASK);
00134 }
00135 
00136 inline void
00137 fpu_set_rounding_direction(fpu_rounding_direction_type dir) {
00138 #ifdef PPL_FPMATH_MAY_USE_387
00139   fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir);
00140 #endif
00141 #ifdef PPL_FPMATH_MAY_USE_SSE
00142   extern bool have_sse_unit;
00143   if (have_sse_unit)
00144     sse_set_control(PPL_SSE_CONTROL_DEFAULT_BASE | (dir << 3));
00145 #endif
00146 }
00147 
00148 inline fpu_rounding_control_word_type
00149 fpu_save_rounding_direction(fpu_rounding_direction_type dir) {
00150 #ifdef PPL_FPMATH_MAY_USE_387
00151   fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir);
00152 #endif
00153 #ifdef PPL_FPMATH_MAY_USE_SSE
00154   extern bool have_sse_unit;
00155   if (have_sse_unit)
00156     sse_set_control(PPL_SSE_CONTROL_DEFAULT_BASE | (dir << 3));
00157 #endif
00158   return static_cast<fpu_rounding_control_word_type>(0);
00159 }
00160 
00161 inline void
00162 fpu_reset_inexact() {
00163 #ifdef PPL_FPMATH_MAY_USE_387
00164   fpu_clear_exceptions();
00165 #endif
00166 #ifdef PPL_FPMATH_MAY_USE_SSE
00167   // NOTE: on entry to this function the current rounding mode
00168   // has to be the default one.
00169   extern bool have_sse_unit;
00170   if (have_sse_unit)
00171     sse_set_control(PPL_SSE_CONTROL_DEFAULT);
00172 #endif
00173 }
00174 
00175 inline void
00176 fpu_restore_rounding_direction(fpu_rounding_control_word_type) {
00177 #ifdef PPL_FPMATH_MAY_USE_387
00178   fpu_set_control(PPL_FPU_CONTROL_DEFAULT);
00179 #endif
00180 #ifdef PPL_FPMATH_MAY_USE_SSE
00181   extern bool have_sse_unit;
00182   if (have_sse_unit)
00183     sse_set_control(PPL_SSE_CONTROL_DEFAULT);
00184 #endif
00185 }
00186 
00187 inline int
00188 fpu_check_inexact() {
00189 #ifdef PPL_FPMATH_MAY_USE_387
00190   if (fpu_get_status() & FPU_INEXACT)
00191     return 1;
00192 #endif
00193 #ifdef PPL_FPMATH_MAY_USE_SSE
00194   extern bool have_sse_unit;
00195   if (have_sse_unit && (sse_get_control() & SSE_INEXACT))
00196     return 1;
00197 #endif
00198   return 0;
00199 }
00200 
00201 } // namespace Parma_Polyhedra_Library
00202 
00203 #endif // !defined(PPL_fpu_ia32_inlines_hh)