1 //===-- Exhaustive test template for math 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 #include <atomic>
10 #include <fenv.h>
11 #include <functional>
12 #include <iostream>
13 #include <mutex>
14 #include <sstream>
15 #include <thread>
16 #include <vector>
17 
18 #include "src/__support/FPUtil/FPBits.h"
19 
20 #include "exhaustive_test.h"
21 
22 template <typename T, typename FloatType>
test_full_range(T start,T stop,mpfr::RoundingMode rounding)23 void LlvmLibcExhaustiveTest<T, FloatType>::test_full_range(
24     T start, T stop, mpfr::RoundingMode rounding) {
25   int n_threads = std::thread::hardware_concurrency();
26   std::vector<std::thread> thread_list;
27   std::mutex mx_cur_val;
28   int current_percent = -1;
29   T current_value = start;
30   std::atomic<uint64_t> failed(0);
31   for (int i = 0; i < n_threads; ++i) {
32     thread_list.emplace_back([&, this]() {
33       while (true) {
34         T range_begin, range_end;
35         int new_percent = -1;
36         {
37           std::lock_guard<std::mutex> lock(mx_cur_val);
38           if (current_value == stop)
39             return;
40 
41           range_begin = current_value;
42           if (stop >= increment && stop - increment >= current_value) {
43             range_end = current_value + increment;
44           } else
45             range_end = stop;
46           current_value = range_end;
47           int pc = 100.0 * double(range_end - start) / double(stop - start);
48           if (current_percent != pc) {
49             new_percent = pc;
50             current_percent = pc;
51           }
52         }
53         if (new_percent >= 0) {
54           std::stringstream msg;
55           msg << new_percent << "% is in process     \r";
56           std::cout << msg.str() << std::flush;
57           ;
58         }
59 
60         bool check_passed = check(range_begin, range_end, rounding);
61         if (!check_passed) {
62           std::stringstream msg;
63           msg << "Test failed in range: " << std::dec << range_begin << " to "
64               << range_end << " [0x" << std::hex << range_begin << ", 0x"
65               << range_end << "), [" << std::hexfloat
66               << static_cast<FloatType>(__llvm_libc::fputil::FPBits<FloatType>(
67                      static_cast<T>(range_begin)))
68               << ", "
69               << static_cast<FloatType>(
70                      __llvm_libc::fputil::FPBits<FloatType>(range_end))
71               << ") " << std::endl;
72           std::cerr << msg.str() << std::flush;
73 
74           failed.fetch_add(1);
75         }
76       }
77     });
78   }
79 
80   for (auto &thread : thread_list) {
81     if (thread.joinable()) {
82       thread.join();
83     }
84   }
85   std::cout << std::endl;
86   std::cout << "Test " << ((failed > 0) ? "FAILED" : "PASSED") << std::endl;
87 }
88 
89 template void
90     LlvmLibcExhaustiveTest<uint32_t>::test_full_range(uint32_t, uint32_t,
91                                                       mpfr::RoundingMode);
92 template void LlvmLibcExhaustiveTest<uint64_t, double>::test_full_range(
93     uint64_t, uint64_t, mpfr::RoundingMode);
94