1
+ #include < cstdint>
2
+ #include < limits>
3
+ #include < type_traits>
4
+ #include < cstddef>
5
+ #include < algorithm>
6
+
7
+ #include < arcticdb/util/vector_common.hpp>
8
+
9
+ namespace arcticdb {
10
+
11
+ template <typename T>
12
+ using vector_type __attribute__ ((vector_size(64 ))) = T;
13
+
14
+ template <typename T>
15
+ class FloatMinFinder {
16
+ static_assert (is_supported_float<T>::value, " Type must be float or double" );
17
+ static_assert (std::is_floating_point_v<T>, " Type must be floating point" );
18
+
19
+ public:
20
+ static T find (const T* data, size_t n) {
21
+ using vec_t = vector_type<T>;
22
+
23
+ // Initialize min vector with infinity
24
+ vec_t vmin;
25
+ for (size_t i = 0 ; i < sizeof (vec_t )/sizeof (T); i++) {
26
+ reinterpret_cast <T*>(&vmin)[i] = std::numeric_limits<T>::infinity ();
27
+ }
28
+
29
+ // Process full vectors
30
+ const vec_t * vdata = reinterpret_cast <const vec_t *>(data);
31
+ const size_t elements_per_vector = sizeof (vec_t ) / sizeof (T);
32
+ const size_t vlen = n / elements_per_vector;
33
+
34
+ // Main SIMD loop
35
+ for (size_t i = 0 ; i < vlen; i++) {
36
+ vec_t v = vdata[i];
37
+ vmin = (v < vmin) ? v : vmin;
38
+ }
39
+
40
+ // Reduce vector to scalar
41
+ T min_val = std::numeric_limits<T>::infinity ();
42
+ const T* min_arr = reinterpret_cast <const T*>(&vmin);
43
+ for (size_t i = 0 ; i < elements_per_vector; i++) {
44
+ if (min_arr[i] == min_arr[i]) { // Not NaN
45
+ min_val = std::min (min_val, min_arr[i]);
46
+ }
47
+ }
48
+
49
+ // Handle remainder
50
+ const T* remain = data + (vlen * elements_per_vector);
51
+ for (size_t i = 0 ; i < n % elements_per_vector; i++) {
52
+ if (remain[i] == remain[i]) { // Not NaN
53
+ min_val = std::min (min_val, remain[i]);
54
+ }
55
+ }
56
+
57
+ return min_val;
58
+ }
59
+ };
60
+
61
+ template <typename T>
62
+ class FloatMaxFinder {
63
+ static_assert (is_supported_float<T>::value, " Type must be float or double" );
64
+ static_assert (std::is_floating_point_v<T>, " Type must be floating point" );
65
+
66
+ public:
67
+ static T find (const T* data, size_t n) {
68
+ using vec_t = vector_type<T>;
69
+
70
+ // Initialize max vector with negative infinity
71
+ vec_t vmax;
72
+ for (size_t i = 0 ; i < sizeof (vec_t )/sizeof (T); i++) {
73
+ reinterpret_cast <T*>(&vmax)[i] = -std::numeric_limits<T>::infinity ();
74
+ }
75
+
76
+ // Process full vectors
77
+ const vec_t * vdata = reinterpret_cast <const vec_t *>(data);
78
+ const size_t elements_per_vector = sizeof (vec_t ) / sizeof (T);
79
+ const size_t vlen = n / elements_per_vector;
80
+
81
+ // Main SIMD loop
82
+ for (size_t i = 0 ; i < vlen; i++) {
83
+ vec_t v = vdata[i];
84
+ vmax = (v > vmax) ? v : vmax;
85
+ }
86
+
87
+ // Reduce vector to scalar
88
+ T max_val = -std::numeric_limits<T>::infinity ();
89
+ const T* max_arr = reinterpret_cast <const T*>(&vmax);
90
+ for (size_t i = 0 ; i < elements_per_vector; i++) {
91
+ if (max_arr[i] == max_arr[i]) { // Not NaN
92
+ max_val = std::max (max_val, max_arr[i]);
93
+ }
94
+ }
95
+
96
+ // Handle remainder
97
+ const T* remain = data + (vlen * elements_per_vector);
98
+ for (size_t i = 0 ; i < n % elements_per_vector; i++) {
99
+ if (remain[i] == remain[i]) { // Not NaN
100
+ max_val = std::max (max_val, remain[i]);
101
+ }
102
+ }
103
+
104
+ return max_val;
105
+ }
106
+ };
107
+
108
+ template <typename T>
109
+ T find_float_min (const T *data, size_t n) {
110
+ return FloatMinFinder<T>::find (data, n);
111
+ }
112
+
113
+ template <typename T>
114
+ T find_float_max (const T *data, size_t n) {
115
+ return FloatMaxFinder<T>::find (data, n);
116
+ }
117
+
118
+ } // namespace arcticdb
0 commit comments