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