1 //===-- TestMatchers.cpp ----------------------------------------*- 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 #include "TestHelpers.h" 10 11 #include "FPBits.h" 12 13 #include <fenv.h> 14 #include <memory> 15 #include <setjmp.h> 16 #include <signal.h> 17 #include <string> 18 19 namespace __llvm_libc { 20 namespace fputil { 21 namespace testing { 22 23 // Return the first N hex digits of an integer as a string in upper case. 24 template <typename T> 25 cpp::EnableIfType<cpp::IsIntegral<T>::Value, std::string> 26 uintToHex(T X, size_t Length = sizeof(T) * 2) { 27 std::string s(Length, '0'); 28 29 for (auto it = s.rbegin(), end = s.rend(); it != end; ++it, X >>= 4) { 30 unsigned char Mod = static_cast<unsigned char>(X) & 15; 31 *it = (Mod < 10 ? '0' + Mod : 'a' + Mod - 10); 32 } 33 34 return s; 35 } 36 37 template <typename ValType> 38 cpp::EnableIfType<cpp::IsFloatingPointType<ValType>::Value, void> 39 describeValue(const char *label, ValType value, 40 testutils::StreamWrapper &stream) { 41 stream << label; 42 43 FPBits<ValType> bits(value); 44 if (bits.isNaN()) { 45 stream << "(NaN)"; 46 } else if (bits.isInf()) { 47 if (bits.getSign()) 48 stream << "(-Infinity)"; 49 else 50 stream << "(+Infinity)"; 51 } else { 52 constexpr int exponentWidthInHex = 53 (fputil::ExponentWidth<ValType>::value - 1) / 4 + 1; 54 constexpr int mantissaWidthInHex = 55 (fputil::MantissaWidth<ValType>::value - 1) / 4 + 1; 56 57 stream << "Sign: " << (bits.getSign() ? '1' : '0') << ", " 58 << "Exponent: 0x" 59 << uintToHex<uint16_t>(bits.getUnbiasedExponent(), 60 exponentWidthInHex) 61 << ", " 62 << "Mantissa: 0x" 63 << uintToHex<typename fputil::FPBits<ValType>::UIntType>( 64 bits.getMantissa(), mantissaWidthInHex); 65 } 66 67 stream << '\n'; 68 } 69 70 template void describeValue<float>(const char *, float, 71 testutils::StreamWrapper &); 72 template void describeValue<double>(const char *, double, 73 testutils::StreamWrapper &); 74 template void describeValue<long double>(const char *, long double, 75 testutils::StreamWrapper &); 76 77 #if defined(_WIN32) 78 #define sigjmp_buf jmp_buf 79 #define sigsetjmp(buf, save) setjmp(buf) 80 #define siglongjmp(buf, val) longjmp(buf, val) 81 #endif 82 83 static thread_local sigjmp_buf jumpBuffer; 84 static thread_local bool caughtExcept; 85 86 static void sigfpeHandler(int sig) { 87 caughtExcept = true; 88 siglongjmp(jumpBuffer, -1); 89 } 90 91 FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) { 92 auto oldSIGFPEHandler = signal(SIGFPE, &sigfpeHandler); 93 std::unique_ptr<FunctionCaller> funcUP(func); 94 95 caughtExcept = false; 96 fenv_t oldEnv; 97 fegetenv(&oldEnv); 98 if (sigsetjmp(jumpBuffer, 1) == 0) 99 funcUP->call(); 100 // We restore the previous floating point environment after 101 // the call to the function which can potentially raise SIGFPE. 102 fesetenv(&oldEnv); 103 signal(SIGFPE, oldSIGFPEHandler); 104 exceptionRaised = caughtExcept; 105 } 106 107 } // namespace testing 108 } // namespace fputil 109 } // namespace __llvm_libc 110