|
PPL
0.12.1
|
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)