1 /* IA-32 floating point unit inline related functions. 2 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it> 3 Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com) 4 5 This file is part of the Parma Polyhedra Library (PPL). 6 7 The PPL is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published by the 9 Free Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 The PPL is distributed in the hope that it will be useful, but WITHOUT 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software Foundation, 19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. 20 21 For the most up-to-date information see the Parma Polyhedra Library 22 site: http://bugseng.com/products/ppl/ . */ 23 24 #ifndef PPL_fpu_ia32_inlines_hh 25 #define PPL_fpu_ia32_inlines_hh 1 26 27 #include <csetjmp> 28 #include <csignal> 29 30 #define FPU_INVALID 0x01 31 #define FPU_DIVBYZERO 0x04 32 #define FPU_OVERFLOW 0x08 33 #define FPU_UNDERFLOW 0x10 34 #define FPU_INEXACT 0x20 35 36 #define FPU_ALL_EXCEPT \ 37 (FPU_INEXACT | FPU_DIVBYZERO | FPU_UNDERFLOW | FPU_OVERFLOW | FPU_INVALID) 38 39 #define PPL_FPU_TONEAREST 0 40 #define PPL_FPU_DOWNWARD 0x400 41 #define PPL_FPU_UPWARD 0x800 42 #define PPL_FPU_TOWARDZERO 0xc00 43 44 #define FPU_ROUNDING_MASK 0xc00 45 46 #define SSE_INEXACT 0x20 47 48 #define PPL_FPU_CONTROL_DEFAULT_BASE 0x37f 49 #define PPL_SSE_CONTROL_DEFAULT_BASE 0x1f80 50 51 // This MUST be congruent with the definition of ROUND_DIRECT 52 #define PPL_FPU_CONTROL_DEFAULT \ 53 (PPL_FPU_CONTROL_DEFAULT_BASE | PPL_FPU_UPWARD) 54 #define PPL_SSE_CONTROL_DEFAULT \ 55 (PPL_SSE_CONTROL_DEFAULT_BASE | (PPL_FPU_UPWARD << 3)) 56 57 namespace Parma_Polyhedra_Library { 58 59 typedef struct { 60 unsigned short control_word; 61 unsigned short unused1; 62 unsigned short status_word; 63 unsigned short unused2; 64 unsigned short tags; 65 unsigned short unused3; 66 unsigned int eip; 67 unsigned short cs_selector; 68 unsigned int opcode:11; 69 unsigned int unused4:5; 70 unsigned int data_offset; 71 unsigned short data_selector; 72 unsigned short unused5; 73 } ia32_fenv_t; 74 75 inline int fpu_get_control()76fpu_get_control() { 77 unsigned short cw; 78 __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw) : : "memory"); 79 return cw; 80 } 81 82 inline void fpu_set_control(int c)83fpu_set_control(int c) { 84 unsigned short cw = static_cast<unsigned short>(c); 85 __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw) : "memory"); 86 } 87 88 inline int fpu_get_status()89fpu_get_status() { 90 unsigned short sw; 91 __asm__ __volatile__ ("fnstsw %0" : "=a" (sw) : : "memory"); 92 return sw; 93 } 94 95 inline void fpu_clear_status(unsigned short bits)96fpu_clear_status(unsigned short bits) { 97 /* There is no fldsw instruction */ 98 ia32_fenv_t env; 99 __asm__ __volatile__ ("fnstenv %0" : "=m" (env)); 100 env.status_word = static_cast<unsigned short>(env.status_word & ~bits); 101 __asm__ __volatile__ ("fldenv %0" : : "m" (env) : "memory"); 102 } 103 104 inline void fpu_clear_exceptions()105fpu_clear_exceptions() { 106 __asm__ __volatile__ ("fnclex" : /* No outputs. */ : : "memory"); 107 } 108 109 #ifdef PPL_FPMATH_MAY_USE_SSE 110 inline void sse_set_control(unsigned int cw)111sse_set_control(unsigned int cw) { 112 __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&cw) : "memory"); 113 } 114 115 inline unsigned int sse_get_control()116sse_get_control() { 117 unsigned int cw; 118 __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&cw) : : "memory"); 119 return cw; 120 } 121 #endif 122 123 inline void fpu_initialize_control_functions()124fpu_initialize_control_functions() { 125 #ifdef PPL_FPMATH_MAY_USE_SSE 126 extern void detect_sse_unit(); 127 detect_sse_unit(); 128 #endif 129 } 130 131 inline fpu_rounding_direction_type fpu_get_rounding_direction()132fpu_get_rounding_direction() { 133 return static_cast<fpu_rounding_direction_type>(fpu_get_control() & FPU_ROUNDING_MASK); 134 } 135 136 inline void fpu_set_rounding_direction(fpu_rounding_direction_type dir)137fpu_set_rounding_direction(fpu_rounding_direction_type dir) { 138 #ifdef PPL_FPMATH_MAY_USE_387 139 fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir); 140 #endif 141 #ifdef PPL_FPMATH_MAY_USE_SSE 142 extern bool have_sse_unit; 143 if (have_sse_unit) 144 sse_set_control(PPL_SSE_CONTROL_DEFAULT_BASE | (dir << 3)); 145 #endif 146 } 147 148 inline fpu_rounding_control_word_type fpu_save_rounding_direction(fpu_rounding_direction_type dir)149fpu_save_rounding_direction(fpu_rounding_direction_type dir) { 150 #ifdef PPL_FPMATH_MAY_USE_387 151 fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir); 152 #endif 153 #ifdef PPL_FPMATH_MAY_USE_SSE 154 extern bool have_sse_unit; 155 if (have_sse_unit) 156 sse_set_control(PPL_SSE_CONTROL_DEFAULT_BASE | (dir << 3)); 157 #endif 158 return static_cast<fpu_rounding_control_word_type>(0); 159 } 160 161 inline void fpu_reset_inexact()162fpu_reset_inexact() { 163 #ifdef PPL_FPMATH_MAY_USE_387 164 fpu_clear_exceptions(); 165 #endif 166 #ifdef PPL_FPMATH_MAY_USE_SSE 167 // NOTE: on entry to this function the current rounding mode 168 // has to be the default one. 169 extern bool have_sse_unit; 170 if (have_sse_unit) { 171 sse_set_control(PPL_SSE_CONTROL_DEFAULT); 172 } 173 #endif 174 } 175 176 inline void fpu_restore_rounding_direction(fpu_rounding_control_word_type)177fpu_restore_rounding_direction(fpu_rounding_control_word_type) { 178 #ifdef PPL_FPMATH_MAY_USE_387 179 fpu_set_control(PPL_FPU_CONTROL_DEFAULT); 180 #endif 181 #ifdef PPL_FPMATH_MAY_USE_SSE 182 extern bool have_sse_unit; 183 if (have_sse_unit) { 184 sse_set_control(PPL_SSE_CONTROL_DEFAULT); 185 } 186 #endif 187 } 188 189 inline int fpu_check_inexact()190fpu_check_inexact() { 191 #ifdef PPL_FPMATH_MAY_USE_387 192 if (fpu_get_status() & FPU_INEXACT) { 193 return 1; 194 } 195 #endif 196 #ifdef PPL_FPMATH_MAY_USE_SSE 197 extern bool have_sse_unit; 198 if (have_sse_unit && (sse_get_control() & SSE_INEXACT)) { 199 return 1; 200 } 201 #endif 202 return 0; 203 } 204 205 } // namespace Parma_Polyhedra_Library 206 207 #endif // !defined(PPL_fpu_ia32_inlines_hh) 208