1 /**
2  * KFR (http://kfrlib.com)
3  * Copyright (C) 2016  D Levin
4  * See LICENSE.txt for details
5  */
6 
7 #include <kfr/testo/testo.hpp>
8 
9 #include <kfr/base.hpp>
10 #include <kfr/io.hpp>
11 
12 using namespace kfr;
13 
14 namespace CMT_ARCH_NAME
15 {
16 
17 template <typename T>
builtin_add_overflow(T x,T y,T * r)18 bool builtin_add_overflow(T x, T y, T* r)
19 {
20 #if CMT_HAS_BUILTIN(__builtin_add_overflow) || defined CMT_COMPILER_GCC
21     return __builtin_add_overflow(x, y, r);
22 #else
23     *r = x + y;
24     return static_cast<long long>(x) + static_cast<long long>(y) != static_cast<long long>(*r);
25 #endif
26 }
27 template <>
builtin_add_overflow(u64 x,u64 y,u64 * r)28 bool builtin_add_overflow<u64>(u64 x, u64 y, u64* r)
29 {
30 #if CMT_HAS_BUILTIN(__builtin_uaddll_overflow) || defined CMT_COMPILER_GCC
31     return __builtin_uaddll_overflow(x, y, reinterpret_cast<unsigned long long*>(r));
32 #else
33     *r = x + y;
34     return x > 0xFFFFFFFFFFFFFFFFull - y;
35 #endif
36 }
37 template <>
builtin_add_overflow(i64 x,i64 y,i64 * r)38 bool builtin_add_overflow<i64>(i64 x, i64 y, i64* r)
39 {
40 #if CMT_HAS_BUILTIN(__builtin_saddll_overflow) || defined CMT_COMPILER_GCC
41     return __builtin_saddll_overflow(x, y, reinterpret_cast<long long*>(r));
42 #else
43     *r = x + y;
44     return !((x ^ y) & 0x8000000000000000ull) && ((*r ^ x) & 0x8000000000000000ull);
45 #endif
46 }
47 template <typename T>
builtin_sub_overflow(T x,T y,T * r)48 bool builtin_sub_overflow(T x, T y, T* r)
49 {
50 #if CMT_HAS_BUILTIN(__builtin_sub_overflow) || defined CMT_COMPILER_GCC
51     return __builtin_sub_overflow(x, y, r);
52 #else
53     *r = x - y;
54     return static_cast<long long>(x) - static_cast<long long>(y) != static_cast<long long>(*r);
55 #endif
56 }
57 template <>
builtin_sub_overflow(u64 x,u64 y,u64 * r)58 bool builtin_sub_overflow<u64>(u64 x, u64 y, u64* r)
59 {
60 #if CMT_HAS_BUILTIN(__builtin_usubll_overflow) || defined CMT_COMPILER_GCC
61     return __builtin_usubll_overflow(x, y, reinterpret_cast<unsigned long long*>(r));
62 #else
63     *r = x - y;
64     return x < y;
65 #endif
66 }
67 template <>
builtin_sub_overflow(i64 x,i64 y,i64 * r)68 bool builtin_sub_overflow<i64>(i64 x, i64 y, i64* r)
69 {
70 #if CMT_HAS_BUILTIN(__builtin_ssubll_overflow) || defined CMT_COMPILER_GCC
71     return __builtin_ssubll_overflow(x, y, reinterpret_cast<long long*>(r));
72 #else
73     *r = x - y;
74     return ((x ^ y) & 0x8000000000000000ull) && ((*r ^ x) & 0x8000000000000000ull);
75 #endif
76 }
77 //#endif
78 template <typename T>
ref_satadd(T x,T y)79 inline T ref_satadd(T x, T y)
80 {
81     T result;
82     if (builtin_add_overflow(x, y, &result))
83         return x < 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
84     else
85         return result;
86 }
87 
88 template <typename T>
ref_satsub(T x,T y)89 inline T ref_satsub(T x, T y)
90 {
91     T result;
92     if (builtin_sub_overflow(x, y, &result))
93         return x < y ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
94     else
95         return result;
96 }
97 
TEST(intrin_sqrt)98 TEST(intrin_sqrt)
99 {
100     testo::assert_is_same<decltype(kfr::sqrt(9)), fbase>();
101     testo::assert_is_same<decltype(kfr::intrinsics::sqrt(9)), fbase>();
102     testo::assert_is_same<decltype(kfr::sqrt(make_vector(9))), vec<fbase, 1>>();
103     testo::assert_is_same<decltype(kfr::sqrt(make_vector(9, 25))), vec<fbase, 2>>();
104     CHECK(kfr::sqrt(9) == fbase(3.0));
105     CHECK(kfr::sqrt(2) == fbase(1.4142135623730950488));
106     CHECK(kfr::sqrt(-9) == fbase(qnan));
107     CHECK(kfr::sqrt(make_vector(9)) == make_vector<fbase>(3.0));
108     CHECK(kfr::sqrt(make_vector(-9)) == make_vector<fbase>(qnan));
109     testo::matrix(named("type") = float_vector_types<vec>, named("value") = std::vector<int>{ 0, 2, 65536 },
110                   [](auto type, int value) {
111                       using T = typename decltype(type)::type;
112                       const T x(value);
113                       CHECK(kfr::sqrt(x) == apply([](auto x) -> decltype(x) { return std::sqrt(x); }, x));
114                   });
115 }
116 
TEST(intrin_satadd_satsub)117 TEST(intrin_satadd_satsub)
118 {
119     testo::matrix(named("type") = cconcat(signed_vector_types<vec>, unsigned_vector_types<vec>),
120                   [](auto type) {
121                       using T     = typename decltype(type)::type;
122                       using Tsub  = subtype<T>;
123                       const T min = std::numeric_limits<Tsub>::min();
124                       const T max = std::numeric_limits<Tsub>::max();
125                       CHECK(kfr::satadd(min, min) ==
126                             apply([](auto x, auto y) -> decltype(x) { return ref_satadd(x, y); }, min, min));
127                       CHECK(kfr::satadd(max, max) ==
128                             apply([](auto x, auto y) -> decltype(x) { return ref_satadd(x, y); }, max, max));
129                       CHECK(kfr::satadd(min, max) ==
130                             apply([](auto x, auto y) -> decltype(x) { return ref_satadd(x, y); }, min, max));
131                       CHECK(kfr::satadd(max, min) ==
132                             apply([](auto x, auto y) -> decltype(x) { return ref_satadd(x, y); }, max, min));
133 
134                       CHECK(kfr::satsub(min, min) ==
135                             apply([](auto x, auto y) -> decltype(x) { return ref_satsub(x, y); }, min, min));
136                       CHECK(kfr::satsub(max, max) ==
137                             apply([](auto x, auto y) -> decltype(x) { return ref_satsub(x, y); }, max, max));
138                       CHECK(kfr::satsub(min, max) ==
139                             apply([](auto x, auto y) -> decltype(x) { return ref_satsub(x, y); }, min, max));
140                       CHECK(kfr::satsub(max, min) ==
141                             apply([](auto x, auto y) -> decltype(x) { return ref_satsub(x, y); }, max, min));
142                   });
143 }
144 
TEST(intrin_any_all)145 TEST(intrin_any_all)
146 {
147     testo::matrix(named("type") = unsigned_vector_types<vec>, [](auto type) {
148         using T                = typename decltype(type)::type;
149         constexpr size_t width = widthof<T>();
150         using Tsub             = subtype<T>;
151         const auto x           = enumerate<Tsub, width>() == Tsub(0);
152         CHECK(any(x) == true);
153         if (width == 1)
154             CHECK(all(x) == true);
155         else
156             CHECK(all(x) == false);
157         const auto y = zerovector<Tsub, width>() == Tsub(127);
158         CHECK(all(y) == false);
159         CHECK(any(y) == false);
160         const auto z = zerovector<Tsub, width>() == Tsub(0);
161         CHECK(all(z) == true);
162         CHECK(any(z) == true);
163     });
164 }
165 
166 } // namespace CMT_ARCH_NAME
167 
168 #ifndef KFR_NO_MAIN
main()169 int main()
170 {
171     println(library_version(), " running on ", cpu_runtime());
172     return testo::run_all("", false);
173 }
174 #endif
175