fenvc.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. fenvc.c
  9. Abstract:
  10. This module implements architecture-specific floating point support for the
  11. C library.
  12. Author:
  13. Evan Green 18-Jul-2014
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "../libcp.h"
  21. #include <fenv.h>
  22. #include <float.h>
  23. #include <string.h>
  24. //
  25. // ---------------------------------------------------------------- Definitions
  26. //
  27. #define FE_ROUNDINGMASK FE_TOWARDZERO
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. //
  32. // ----------------------------------------------- Internal Function Prototypes
  33. //
  34. unsigned int
  35. ClpGetFpscr (
  36. void
  37. );
  38. void
  39. ClpSetFpscr (
  40. unsigned int Value
  41. );
  42. //
  43. // -------------------------------------------------------------------- Globals
  44. //
  45. BOOL ClVfpSupported;
  46. //
  47. // ------------------------------------------------------------------ Functions
  48. //
  49. LIBC_API
  50. int
  51. fegetexceptflag (
  52. fexcept_t *Destination,
  53. int Mask
  54. )
  55. /*++
  56. Routine Description:
  57. This routine stores an implementation defined representation of the
  58. exception flags indicated by the given mask into the given destination.
  59. Arguments:
  60. Destination - Supplies a pointer where the implementation-defined
  61. representation of the current flags masked with the given value.
  62. Mask - Supplies a mask of the exceptions the caller is interested in. See
  63. FE_* definitions.
  64. Return Value:
  65. 0 on success.
  66. Non-zero on failure.
  67. --*/
  68. {
  69. fenv_t Environment;
  70. int Result;
  71. Result = fegetenv(&Environment);
  72. *Destination = Environment.Fpscr & FE_ALL_EXCEPT & Mask;
  73. return Result;
  74. }
  75. LIBC_API
  76. int
  77. fesetexceptflag (
  78. const fexcept_t *Source,
  79. int Mask
  80. )
  81. /*++
  82. Routine Description:
  83. This routine attempts to store an implementation-defined representation of
  84. the given floating point status flags into the current machine state. This
  85. function does not raise exceptions, it only sets the flags.
  86. Arguments:
  87. Source - Supplies a pointer to the implementation-defined representation of
  88. the floating point status to set.
  89. Mask - Supplies a mask of the exceptions to operate on. See FE_*
  90. definitions.
  91. Return Value:
  92. 0 on success.
  93. Non-zero on failure.
  94. --*/
  95. {
  96. fenv_t Environment;
  97. Mask &= FE_ALL_EXCEPT;
  98. fegetenv(&Environment);
  99. Environment.Fpscr |= Mask;
  100. return fesetenv(&Environment);
  101. }
  102. LIBC_API
  103. int
  104. feclearexcept (
  105. int Exceptions
  106. )
  107. /*++
  108. Routine Description:
  109. This routine attempts to clear the given floating point exceptions from the
  110. current machine state.
  111. Arguments:
  112. Exceptions - Supplies a mask of the exceptions to clear. See FE_*
  113. definitions.
  114. Return Value:
  115. 0 on success.
  116. Non-zero on failure.
  117. --*/
  118. {
  119. fenv_t Environment;
  120. Exceptions &= FE_ALL_EXCEPT;
  121. fegetenv(&Environment);
  122. Environment.Fpscr &= ~Exceptions;
  123. return fesetenv(&Environment);
  124. }
  125. LIBC_API
  126. int
  127. feraiseexcept (
  128. int Exceptions
  129. )
  130. /*++
  131. Routine Description:
  132. This routine attempts to raise the given supported floating point
  133. exceptions. The order in which these exceptions are raised is unspecified.
  134. Arguments:
  135. Exceptions - Supplies a mask of the exceptions to raise. See FE_*
  136. definitions.
  137. Return Value:
  138. 0 on success.
  139. Non-zero on failure.
  140. --*/
  141. {
  142. float Max;
  143. float Min;
  144. float One;
  145. float OneE32;
  146. volatile float Result;
  147. float Three;
  148. float Two;
  149. float Zero;
  150. One = 1.0;
  151. Two = 2.0;
  152. Three = 3.0;
  153. Zero = 0.0;
  154. Max = FLT_MAX;
  155. Min = FLT_MIN;
  156. OneE32 = 1.0e32F;
  157. if ((Exceptions & FE_INVALID) != 0) {
  158. Result = Zero / Zero;
  159. }
  160. if ((Exceptions & FE_DIVBYZERO) != 0) {
  161. Result = One / Zero;
  162. }
  163. if ((Exceptions & FE_OVERFLOW) != 0) {
  164. Result = Max + OneE32;
  165. }
  166. if ((Exceptions & FE_UNDERFLOW) != 0) {
  167. Result = Min / Two;
  168. }
  169. if ((Exceptions & FE_INEXACT) != 0) {
  170. Result = Two / Three;
  171. }
  172. if ((Exceptions & FE_DENORM) != 0) {
  173. Result = Min / Max;
  174. }
  175. //
  176. // Keep the compiler from complaining about an unused result.
  177. //
  178. (void)Result;
  179. return 0;
  180. }
  181. LIBC_API
  182. int
  183. fetestexcept (
  184. int Exceptions
  185. )
  186. /*++
  187. Routine Description:
  188. This routine determines which of a specified subset of the floating-point
  189. exceptions are currently set.
  190. Arguments:
  191. Exceptions - Supplies a mask of the exceptions to query. See FE_*
  192. definitions.
  193. Return Value:
  194. Returns the bitmask of which of the specified exceptions are currently
  195. raised.
  196. --*/
  197. {
  198. fexcept_t Status;
  199. fegetexceptflag(&Status, Exceptions);
  200. return (int)Status;
  201. }
  202. LIBC_API
  203. int
  204. fegetround (
  205. void
  206. )
  207. /*++
  208. Routine Description:
  209. This routine returns the current rounding direction of the floating point
  210. unit.
  211. Arguments:
  212. None.
  213. Return Value:
  214. Returns the current rounding mode on success. See FE_* definitions.
  215. Returns a negative number on failure.
  216. --*/
  217. {
  218. fenv_t Environment;
  219. int Result;
  220. Result = fegetenv(&Environment);
  221. if (Result != 0) {
  222. return Result;
  223. }
  224. return (Environment.Fpscr & FE_ROUNDINGMASK);
  225. }
  226. LIBC_API
  227. int
  228. fesetround (
  229. int Mode
  230. )
  231. /*++
  232. Routine Description:
  233. This routine attempts to set the rounding mode of the floating point unit.
  234. Arguments:
  235. Mode - Supplies the new mode to set. See FE_* definitions.
  236. Return Value:
  237. 0 on success.
  238. Non-zero on failure.
  239. --*/
  240. {
  241. fenv_t Environment;
  242. fegetenv(&Environment);
  243. Environment.Fpscr &= ~FE_ROUNDINGMASK;
  244. Environment.Fpscr |= Mode & FE_ROUNDINGMASK;
  245. return fesetenv(&Environment);
  246. }
  247. LIBC_API
  248. int
  249. feholdexcept (
  250. fenv_t *Environment
  251. )
  252. /*++
  253. Routine Description:
  254. This routine saves the current floating point environment, clears the
  255. status flags, and installs a non-stop (continue on floating-point
  256. exceptions) mode, if available, for all floating point exceptions.
  257. Arguments:
  258. Environment - Supplies a pointer where the environment will be returned.
  259. Return Value:
  260. 0 on success.
  261. Non-zero on failure.
  262. --*/
  263. {
  264. fenv_t EnvironmentCopy;
  265. fegetenv(Environment);
  266. memcpy(&EnvironmentCopy, Environment, sizeof(fenv_t));
  267. //
  268. // Clear the exception flags, and mask all exceptions.
  269. //
  270. EnvironmentCopy.Fpscr &= ~FE_ALL_EXCEPT;
  271. EnvironmentCopy.Fpscr &= ~(FE_ALL_EXCEPT << FE_EXCEPT_SHIFT);
  272. return fesetenv(&EnvironmentCopy);
  273. }
  274. LIBC_API
  275. int
  276. feupdateenv (
  277. fenv_t *Environment
  278. )
  279. /*++
  280. Routine Description:
  281. This routine saves the currently raised floating-point exceptions, loads
  282. the given floating-point environment, and then raises the saved floating
  283. point exceptions.
  284. Arguments:
  285. Environment - Supplies a pointer to the environment to load.
  286. Return Value:
  287. 0 on success.
  288. Non-zero on failure.
  289. --*/
  290. {
  291. int Exceptions;
  292. Exceptions = fetestexcept(FE_ALL_EXCEPT);
  293. fesetenv(Environment);
  294. return feraiseexcept(Exceptions);
  295. }
  296. LIBC_API
  297. int
  298. fegetenv (
  299. fenv_t *Environment
  300. )
  301. /*++
  302. Routine Description:
  303. This routine stores the current floating point machine environment into the
  304. given environment pointer.
  305. Arguments:
  306. Environment - Supplies the pointer to the environment to save the
  307. floating point context in.
  308. Return Value:
  309. 0 on success.
  310. Non-zero on failure.
  311. --*/
  312. {
  313. if (ClVfpSupported == FALSE) {
  314. ClVfpSupported = OsTestProcessorFeature(OsArmVfp);
  315. if (ClVfpSupported == FALSE) {
  316. return -1;
  317. }
  318. }
  319. Environment->Fpscr = ClpGetFpscr();
  320. return 0;
  321. }
  322. LIBC_API
  323. int
  324. fesetenv (
  325. const fenv_t *Environment
  326. )
  327. /*++
  328. Routine Description:
  329. This routine sets the current machine floating point environment to that of
  330. the given saved environment.
  331. Arguments:
  332. Environment - Supplies the pointer to the environment to load into the
  333. execution state.
  334. Return Value:
  335. 0 on success.
  336. Non-zero on failure.
  337. --*/
  338. {
  339. if (ClVfpSupported == FALSE) {
  340. ClVfpSupported = OsTestProcessorFeature(OsArmVfp);
  341. if (ClVfpSupported == FALSE) {
  342. return -1;
  343. }
  344. }
  345. ClpSetFpscr(Environment->Fpscr);
  346. return 0;
  347. }
  348. //
  349. // --------------------------------------------------------- Internal Functions
  350. //