Skip to content

Commit 0f6bf76

Browse files
committed
Move add to v15 on x86
1 parent bbeeeb2 commit 0f6bf76

11 files changed

Lines changed: 575 additions & 418 deletions

File tree

include/xsimd/arch/common/xsimd_common_arithmetic.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define XSIMD_COMMON_ARITHMETIC_HPP
1414

1515
#include "../../types/xsimd_batch_constant.hpp"
16+
#include "../../v15/kernel_fwd.hpp"
1617
#include "./xsimd_common_details.hpp"
1718

1819
#include <complex>
@@ -363,7 +364,7 @@ namespace xsimd
363364
template <class A>
364365
XSIMD_INLINE batch<float, A> sadd(batch<float, A> const& self, batch<float, A> const& other, requires_arch<common>) noexcept
365366
{
366-
return add(self, other); // no saturated arithmetic on floating point numbers
367+
return kernel::add(self, other); // no saturated arithmetic on floating point numbers
367368
}
368369
template <class A, class T, class /*=std::enable_if_t<std::is_integral_v<T>>*/>
369370
XSIMD_INLINE batch<T, A> sadd(batch<T, A> const& self, batch<T, A> const& other, requires_arch<common>) noexcept
@@ -384,7 +385,7 @@ namespace xsimd
384385
template <class A>
385386
XSIMD_INLINE batch<double, A> sadd(batch<double, A> const& self, batch<double, A> const& other, requires_arch<common>) noexcept
386387
{
387-
return add(self, other); // no saturated arithmetic on floating point numbers
388+
return kernel::add(self, other); // no saturated arithmetic on floating point numbers
388389
}
389390

390391
// ssub

include/xsimd/arch/utils/x86.hpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/****************************************************************************
2+
* Copyright (c) xsimd contributors *
3+
* *
4+
* Distributed under the terms of the BSD 3-Clause License. *
5+
* *
6+
* The full license is in the file LICENSE, distributed with this software. *
7+
****************************************************************************/
8+
9+
#ifndef XSIMD_ARCH_UTILS_AVX_HPP
10+
#define XSIMD_ARCH_UTILS_AVX_HPP
11+
12+
#include "../../config/xsimd_macros.hpp"
13+
#include "../../types/xsimd_batch.hpp"
14+
#include "../../types/xsimd_x86_registers.hpp"
15+
16+
#include <type_traits>
17+
18+
namespace xsimd::kernel::detail
19+
{
20+
template <class T, class A>
21+
using half_batch_t = make_sized_batch_t<T, batch<T, A>::size / 2>;
22+
23+
template <class T, class A>
24+
using half_arch_t = typename half_batch_t<T, A>::arch_type;
25+
26+
template <class T, class A2, class A1 = half_arch_t<T, A2>>
27+
XSIMD_INLINE batch<T, A1> lower_half(batch<T, A2> self) noexcept
28+
{
29+
if constexpr (sizeof(self) == 64)
30+
{
31+
if constexpr (std::is_same_v<T, float>)
32+
{
33+
return _mm512_castps512_ps256(self);
34+
}
35+
else if constexpr (std::is_same_v<T, double>)
36+
{
37+
return _mm512_castpd512_pd256(self);
38+
}
39+
else if constexpr (std::is_integral_v<T>)
40+
{
41+
return _mm512_castsi512_si256(self);
42+
}
43+
}
44+
else if constexpr (sizeof(self) == 32)
45+
{
46+
if constexpr (sizeof(self) == 32 && std::is_same_v<T, float>)
47+
{
48+
return _mm256_castps256_ps128(self);
49+
}
50+
else if constexpr (sizeof(self) == 32 && std::is_same_v<T, double>)
51+
{
52+
return _mm256_castpd256_pd128(self);
53+
}
54+
else if constexpr (sizeof(self) == 32 && std::is_integral_v<T>)
55+
{
56+
return _mm256_castsi256_si128(self);
57+
}
58+
}
59+
else
60+
{
61+
static_assert(false, "unsupported architecture conversion");
62+
}
63+
}
64+
65+
template <class T, class A2, class A1 = half_arch_t<T, A2>>
66+
XSIMD_INLINE batch<T, A1> upper_half(batch<T, A2> self) noexcept
67+
{
68+
if constexpr (sizeof(self) == 64)
69+
{
70+
if constexpr (std::is_same_v<T, float>)
71+
{
72+
// _mm512_extractf32x8_ps is AVX512DQ but the casts here are a noop
73+
return _mm256_castsi256_ps(_mm512_extracti64x4_epi64(_mm512_castps_si512(self), 1));
74+
}
75+
else if constexpr (std::is_same_v<T, double>)
76+
{
77+
return _mm512_extractf64x4_pd(self, 1);
78+
}
79+
else if constexpr (std::is_integral_v<T>)
80+
{
81+
return _mm512_extracti64x4_epi64(self, 1);
82+
}
83+
}
84+
else if constexpr (sizeof(self) == 32)
85+
{
86+
if constexpr (std::is_same_v<T, float>)
87+
{
88+
return _mm256_extractf128_ps(self, 1);
89+
}
90+
else if constexpr (std::is_same_v<T, double>)
91+
{
92+
return _mm256_extractf128_pd(self, 1);
93+
}
94+
else if constexpr (std::is_integral_v<T>)
95+
{
96+
return _mm256_extractf128_si256(self, 1);
97+
}
98+
}
99+
else
100+
{
101+
static_assert(false, "unsupported architecture conversion");
102+
}
103+
}
104+
105+
template <class T, class A2, class A1 = half_arch_t<T, A2>>
106+
XSIMD_INLINE batch<T, A2> merge_halves(batch<T, A1> low, batch<T, A1> high) noexcept
107+
{
108+
if constexpr (sizeof(batch<T, A2>) == 64)
109+
{
110+
if constexpr (std::is_same_v<T, float>)
111+
{
112+
// _mm512_insertf32x8 is AVX512DQ but the casts here are a noop
113+
auto const ld = _mm256_castps_pd(low);
114+
auto const lh = _mm256_castps_pd(high);
115+
return _mm512_castpd_ps(_mm512_insertf64x4(_mm512_castpd256_pd512(ld), lh, 1));
116+
}
117+
else if constexpr (std::is_same_v<T, double>)
118+
{
119+
return _mm512_insertf64x4(_mm512_castpd256_pd512(low), high, 1);
120+
}
121+
else if constexpr (std::is_integral_v<T>)
122+
{
123+
return _mm512_inserti64x4(_mm512_castsi256_si512(low), high, 1);
124+
}
125+
}
126+
if constexpr (sizeof(batch<T, A2>) == 32)
127+
{
128+
if constexpr (std::is_same_v<T, float>)
129+
{
130+
return _mm256_insertf128_ps(_mm256_castps128_ps256(low), high, 1);
131+
}
132+
else if constexpr (std::is_same_v<T, double>)
133+
{
134+
return _mm256_insertf128_pd(_mm256_castpd128_pd256(low), high, 1);
135+
}
136+
else if constexpr (std::is_integral_v<T>)
137+
{
138+
return _mm256_insertf128_si256(_mm256_castsi128_si256(low), high, 1);
139+
}
140+
}
141+
else
142+
{
143+
static_assert(false, "unsupported architecture conversion");
144+
}
145+
}
146+
147+
template <class A1, class T, class A2, class F>
148+
XSIMD_INLINE batch<T, A2> apply_on_halves_with_arch(F&& f, batch<T, A2> self) noexcept
149+
{
150+
auto low = f(lower_half<T, A2, A1>(self));
151+
auto high = f(upper_half<T, A2, A1>(self));
152+
return merge_halves<T, A2, A1>(low, high);
153+
}
154+
155+
template <class A1, class T, class A2, class F>
156+
XSIMD_INLINE batch<T, A2> apply_on_halves_with_arch(F&& f, batch<T, A2> lhs, batch<T, A2> rhs) noexcept
157+
{
158+
auto low = f(lower_half<T, A2, A1>(lhs), lower_half<T, A2, A1>(rhs));
159+
auto high = f(upper_half<T, A2, A1>(lhs), upper_half<T, A2, A1>(rhs));
160+
return merge_halves<T, A2, A1>(low, high);
161+
}
162+
163+
template <class T, class A2, class F>
164+
XSIMD_INLINE batch<T, A2> apply_on_halves(F&& f, batch<T, A2> self) noexcept
165+
{
166+
using A1 = half_arch_t<T, A2>;
167+
return apply_on_halves_with_arch<A1, T, A2, F>(std::forward<F>(f), self);
168+
}
169+
170+
template <class T, class A2, class F>
171+
XSIMD_INLINE batch<T, A2> apply_on_halves(F&& f, batch<T, A2> lhs, batch<T, A2> rhs) noexcept
172+
{
173+
using A1 = half_arch_t<T, A2>;
174+
return apply_on_halves_with_arch<A1, T, A2, F>(std::forward<F>(f), lhs, rhs);
175+
}
176+
}
177+
#endif

0 commit comments

Comments
 (0)