1 //===-- riscv floating point env manipulation functions ---------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H 10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H 11 12 #include "hdr/fenv_macros.h" 13 #include "hdr/types/fenv_t.h" 14 #include "src/__support/FPUtil/FPBits.h" 15 #include "src/__support/macros/attributes.h" // For LIBC_INLINE_ASM 16 #include "src/__support/macros/config.h" // For LIBC_INLINE 17 18 #include <stdint.h> 19 20 namespace LIBC_NAMESPACE_DECL { 21 namespace fputil { 22 23 struct FEnv { 24 // We will ignore RMM and DYN rounding modes. 25 static constexpr uint32_t TONEAREST = 0x0; 26 static constexpr uint32_t TOWARDZERO = 0x1; 27 static constexpr uint32_t DOWNWARD = 0x2; 28 static constexpr uint32_t UPWARD = 0x3; 29 30 // These are the bit locations of the corresponding exceptions in fcsr. 31 static constexpr uint32_t INEXACT = 0x1; 32 static constexpr uint32_t UNDERFLOW = 0x2; 33 static constexpr uint32_t OVERFLOW = 0x4; 34 static constexpr uint32_t DIVBYZERO = 0x8; 35 static constexpr uint32_t INVALID = 0x10; 36 get_frmFEnv37 LIBC_INLINE static uint32_t get_frm() { 38 unsigned int rm; 39 LIBC_INLINE_ASM("frrm %0\n\t" : "=r"(rm)); 40 return rm; 41 } 42 set_frmFEnv43 LIBC_INLINE static void set_frm(uint32_t rm) { 44 LIBC_INLINE_ASM("fsrm %0, %0\n\t" : "+r"(rm)); 45 } 46 get_fflagsFEnv47 LIBC_INLINE static uint32_t get_fflags() { 48 unsigned int flags; 49 LIBC_INLINE_ASM("frflags %0\n\t" : "=r"(flags)); 50 return flags; 51 } 52 set_fflagsFEnv53 LIBC_INLINE static void set_fflags(uint32_t flags) { 54 LIBC_INLINE_ASM("fsflags %0, %0\n\t" : "+r"(flags)); 55 } 56 get_fcsrFEnv57 LIBC_INLINE static uint32_t get_fcsr() { 58 unsigned int fcsr; 59 LIBC_INLINE_ASM("frcsr %0\n\t" : "=r"(fcsr)); 60 return fcsr; 61 } 62 set_fcsrFEnv63 LIBC_INLINE static void set_fcsr(uint32_t fcsr) { 64 LIBC_INLINE_ASM("fscsr %0, %0\n\t" : "+r"(fcsr)); 65 } 66 exception_bits_to_macroFEnv67 LIBC_INLINE static int exception_bits_to_macro(uint32_t status) { 68 return ((status & INVALID) ? FE_INVALID : 0) | 69 ((status & DIVBYZERO) ? FE_DIVBYZERO : 0) | 70 ((status & OVERFLOW) ? FE_OVERFLOW : 0) | 71 ((status & UNDERFLOW) ? FE_UNDERFLOW : 0) | 72 ((status & INEXACT) ? FE_INEXACT : 0); 73 } 74 exception_macro_to_bitsFEnv75 LIBC_INLINE static uint32_t exception_macro_to_bits(int except) { 76 return ((except & FE_INVALID) ? INVALID : 0) | 77 ((except & FE_DIVBYZERO) ? DIVBYZERO : 0) | 78 ((except & FE_OVERFLOW) ? OVERFLOW : 0) | 79 ((except & FE_UNDERFLOW) ? UNDERFLOW : 0) | 80 ((except & FE_INEXACT) ? INEXACT : 0); 81 } 82 }; 83 84 // Since RISCV does not have exception enable bits, we will just return 85 // the failure indicator. enable_except(int)86LIBC_INLINE int enable_except(int) { return -1; } 87 88 // Always succeed. disable_except(int)89LIBC_INLINE int disable_except(int) { return 0; } 90 91 // Always return "no exceptions enabled". get_except()92LIBC_INLINE int get_except() { return 0; } 93 clear_except(int excepts)94LIBC_INLINE int clear_except(int excepts) { 95 uint32_t flags = FEnv::get_fflags(); 96 uint32_t to_clear = FEnv::exception_macro_to_bits(excepts); 97 flags &= ~to_clear; 98 FEnv::set_fflags(flags); 99 return 0; 100 } 101 test_except(int excepts)102LIBC_INLINE int test_except(int excepts) { 103 uint32_t to_test = FEnv::exception_macro_to_bits(excepts); 104 uint32_t flags = FEnv::get_fflags(); 105 return FEnv::exception_bits_to_macro(flags & to_test); 106 } 107 set_except(int excepts)108LIBC_INLINE int set_except(int excepts) { 109 uint32_t flags = FEnv::get_fflags(); 110 FEnv::set_fflags(flags | FEnv::exception_macro_to_bits(excepts)); 111 return 0; 112 } 113 raise_except(int excepts)114LIBC_INLINE int raise_except(int excepts) { 115 // Since there are no traps, we just set the exception flags. 116 uint32_t flags = FEnv::get_fflags(); 117 FEnv::set_fflags(flags | FEnv::exception_macro_to_bits(excepts)); 118 return 0; 119 } 120 get_round()121LIBC_INLINE int get_round() { 122 uint32_t rm = FEnv::get_frm(); 123 switch (rm) { 124 case FEnv::TONEAREST: 125 return FE_TONEAREST; 126 case FEnv::DOWNWARD: 127 return FE_DOWNWARD; 128 case FEnv::UPWARD: 129 return FE_UPWARD; 130 case FEnv::TOWARDZERO: 131 return FE_TOWARDZERO; 132 default: 133 return -1; // Error value. 134 } 135 return 0; 136 } 137 set_round(int mode)138LIBC_INLINE int set_round(int mode) { 139 uint32_t rm; 140 switch (mode) { 141 case FE_TONEAREST: 142 rm = FEnv::TONEAREST; 143 break; 144 case FE_DOWNWARD: 145 rm = FEnv::DOWNWARD; 146 break; 147 case FE_UPWARD: 148 rm = FEnv::UPWARD; 149 break; 150 case FE_TOWARDZERO: 151 rm = FEnv::TOWARDZERO; 152 break; 153 default: 154 return -1; // To indicate failure 155 } 156 FEnv::set_frm(rm); 157 return 0; 158 } 159 get_env(fenv_t * envp)160LIBC_INLINE int get_env(fenv_t *envp) { 161 uint32_t *state = reinterpret_cast<uint32_t *>(envp); 162 *state = FEnv::get_fcsr(); 163 return 0; 164 } 165 set_env(const fenv_t * envp)166LIBC_INLINE int set_env(const fenv_t *envp) { 167 if (envp == FE_DFL_ENV) { 168 FEnv::set_frm(FEnv::TONEAREST); 169 FEnv::set_fflags(0); 170 return 0; 171 } 172 uint32_t status = *reinterpret_cast<const uint32_t *>(envp); 173 // We have to do the masking to preserve the reserved bits. 174 FEnv::set_fcsr((status & 0xFF) | (FEnv::get_fcsr() & 0xFFFFFF00)); 175 return 0; 176 } 177 178 } // namespace fputil 179 } // namespace LIBC_NAMESPACE_DECL 180 181 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H 182