1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <fenv.h> 6 7#include <zircon/compiler.h> 8#include <stdint.h> 9#include <x86intrin.h> 10 11#define ROUND_MASK (FE_DOWNWARD | FE_UPWARD | FE_TOWARDZERO) 12_Static_assert((ROUND_MASK << 3) == _MM_ROUND_MASK, ""); 13 14static inline uint16_t get_x87_sw(void) { 15 uint16_t sw; 16 __asm__("fnstsw %0" : "=a"(sw)); 17 return sw; 18} 19 20static inline uint16_t get_x87_cw(void) { 21 uint16_t cw; 22 __asm__("fnstcw %0" : "=m"(cw)); 23 return cw; 24} 25 26static inline void set_x87_cw(uint16_t cw) { 27 __asm__("fldcw %0" :: "m"(cw)); 28} 29 30int fegetround(void) { 31 return _MM_GET_ROUNDING_MODE() >> 3; 32} 33 34__LOCAL int __fesetround(int round) { 35 set_x87_cw((get_x87_cw() & ~ROUND_MASK) | round); 36 _MM_SET_ROUNDING_MODE(round << 3); 37 return 0; 38} 39 40int feclearexcept(int mask) { 41 uint16_t sw = get_x87_sw(); 42 if (sw & mask & FE_ALL_EXCEPT) 43 __asm__("fnclex"); 44 uint32_t mxcsr = _mm_getcsr(); 45 mxcsr |= sw & FE_ALL_EXCEPT; 46 if (mxcsr & mask & FE_ALL_EXCEPT) 47 _mm_setcsr(mxcsr & ~(mask & FE_ALL_EXCEPT)); 48 return 0; 49} 50 51int feraiseexcept(int mask) { 52 _mm_setcsr(_mm_getcsr() | (mask & FE_ALL_EXCEPT)); 53 return 0; 54} 55 56int fetestexcept(int mask) { 57 return (_mm_getcsr() | get_x87_sw()) & mask & FE_ALL_EXCEPT; 58} 59 60int fegetenv(fenv_t* env) { 61 __asm__("fnstenv %0\n" 62 "stmxcsr %1" : "=m"(*env), "=m"(env->__mxcsr)); 63 return 0; 64} 65 66static inline void install_fenv(const fenv_t* env) { 67 __asm__("fldenv %0\n" 68 "ldmxcsr %1" 69 :: "m"(*env), "m"(env->__mxcsr)); 70} 71 72int fesetenv(const fenv_t* env) { 73 install_fenv(likely(env != FE_DFL_ENV) ? env : 74 &(fenv_t){ 75 .__control_word = 0x37f, 76 .__tags = 0xffff, 77 .__mxcsr = 0x1f80, 78 }); 79 return 0; 80} 81