xref: /llvm-project/libcxx/test/std/experimental/simd/simd.class/simd_copy.pass.cpp (revision 7f845cba2ccc2ab637b8e40fbafb9f83a2d67c70)
1 //===----------------------------------------------------------------------===//
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 // UNSUPPORTED: c++03, c++11, c++14
10 
11 // Older versions of clang may encounter a backend error (see 0295c2ad):
12 //   Pass-by-value arguments with alignment greater than register width are not supported.
13 // XFAIL: target=powerpc{{.*}}-ibm-{{.*}} && clang-18
14 
15 // <experimental/simd>
16 //
17 // [simd.class]
18 // template<class U, class Flags> void copy_from(const U* mem, Flags);
19 // template<class U, class Flags> void copy_to(U* mem, Flags) const;
20 
21 #include "../test_utils.h"
22 
23 namespace ex = std::experimental::parallelism_v2;
24 
25 template <class T, class SimdAbi, std::size_t array_size>
26 struct ElementAlignedCopyFromHelper {
27   template <class U>
28   void operator()() const {
29     U buffer[array_size];
30     for (size_t i = 0; i < array_size; ++i)
31       buffer[i] = static_cast<U>(i);
32     ex::simd<T, SimdAbi> origin_simd;
33     origin_simd.copy_from(buffer, ex::element_aligned_tag());
34     assert_simd_values_equal(origin_simd, buffer);
35   }
36 };
37 
38 template <class T, class SimdAbi, std::size_t array_size>
39 struct VectorAlignedCopyFromHelper {
40   template <class U>
41   void operator()() const {
42     alignas(ex::memory_alignment_v<ex::simd<T, SimdAbi>, U>) U buffer[array_size];
43     for (size_t i = 0; i < array_size; ++i)
44       buffer[i] = static_cast<U>(i);
45     ex::simd<T, SimdAbi> origin_simd;
46     origin_simd.copy_from(buffer, ex::vector_aligned_tag());
47     assert_simd_values_equal(origin_simd, buffer);
48   }
49 };
50 
51 template <class T, class SimdAbi, std::size_t array_size>
52 struct OveralignedCopyFromHelper {
53   template <class U>
54   void operator()() const {
55     alignas(bit_ceil(sizeof(U) + 1)) U buffer[array_size];
56     for (size_t i = 0; i < array_size; ++i)
57       buffer[i] = static_cast<U>(i);
58     ex::simd<T, SimdAbi> origin_simd;
59     origin_simd.copy_from(buffer, ex::overaligned_tag<bit_ceil(sizeof(U) + 1)>());
60     assert_simd_values_equal(origin_simd, buffer);
61   }
62 };
63 
64 template <class T, std::size_t>
65 struct CheckSimdCopyFrom {
66   template <class SimdAbi>
67   void operator()() {
68     constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
69 
70     types::for_each(simd_test_types(), ElementAlignedCopyFromHelper<T, SimdAbi, array_size>());
71     types::for_each(simd_test_types(), VectorAlignedCopyFromHelper<T, SimdAbi, array_size>());
72     types::for_each(simd_test_types(), OveralignedCopyFromHelper<T, SimdAbi, array_size>());
73   }
74 };
75 
76 template <class T, class SimdAbi, std::size_t array_size>
77 struct ElementAlignedCopyToHelper {
78   template <class U>
79   void operator()() const {
80     U buffer[array_size];
81     ex::simd<T, SimdAbi> origin_simd([](T i) { return i; });
82     origin_simd.copy_to(buffer, ex::element_aligned_tag());
83     assert_simd_values_equal(origin_simd, buffer);
84   }
85 };
86 
87 template <class T, class SimdAbi, std::size_t array_size>
88 struct VectorAlignedCopyToHelper {
89   template <class U>
90   void operator()() const {
91     alignas(ex::memory_alignment_v<ex::simd<T, SimdAbi>, U>) U buffer[array_size];
92     ex::simd<T, SimdAbi> origin_simd([](T i) { return i; });
93     origin_simd.copy_to(buffer, ex::vector_aligned_tag());
94     assert_simd_values_equal(origin_simd, buffer);
95   }
96 };
97 
98 template <class T, class SimdAbi, std::size_t array_size>
99 struct OveralignedCopyToHelper {
100   template <class U>
101   void operator()() const {
102     alignas(bit_ceil(sizeof(U) + 1)) U buffer[array_size];
103     ex::simd<T, SimdAbi> origin_simd([](T i) { return i; });
104     origin_simd.copy_to(buffer, ex::overaligned_tag<bit_ceil(sizeof(U) + 1)>());
105     assert_simd_values_equal(origin_simd, buffer);
106   }
107 };
108 
109 template <class T, std::size_t>
110 struct CheckSimdCopyTo {
111   template <class SimdAbi>
112   void operator()() {
113     constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
114 
115     types::for_each(simd_test_types(), ElementAlignedCopyToHelper<T, SimdAbi, array_size>());
116     types::for_each(simd_test_types(), VectorAlignedCopyToHelper<T, SimdAbi, array_size>());
117     types::for_each(simd_test_types(), OveralignedCopyToHelper<T, SimdAbi, array_size>());
118   }
119 };
120 
121 template <class U, class T, class Flags, class SimdAbi = ex::simd_abi::compatible<T>, class = void>
122 struct has_copy_from : std::false_type {};
123 
124 template <class U, class T, class Flags, class SimdAbi>
125 struct has_copy_from<U,
126                      T,
127                      Flags,
128                      SimdAbi,
129                      std::void_t<decltype(std::declval<ex::simd<T, SimdAbi>>().copy_from(
130                          std::declval<const U*>(), std::declval<Flags>()))>> : std::true_type {};
131 
132 template <class U, class T, class Flags, class SimdAbi = ex::simd_abi::compatible<T>, class = void>
133 struct has_copy_to : std::false_type {};
134 
135 template <class U, class T, class Flags, class SimdAbi>
136 struct has_copy_to<
137     U,
138     T,
139     Flags,
140     SimdAbi,
141     std::void_t<decltype(std::declval<ex::simd<T, SimdAbi>>().copy_to(std::declval<U*>(), std::declval<Flags>()))>>
142     : std::true_type {};
143 
144 template <class T, std::size_t>
145 struct CheckSimdCopyTraits {
146   template <class SimdAbi>
147   void operator()() {
148     // These functions shall not participate in overload resolution unless
149     // is_simd_flag_type_v<Flags> is true, and
150     // U is a vectorizable type.
151     static_assert(has_copy_from<int, T, ex::element_aligned_tag, SimdAbi>::value);
152     static_assert(has_copy_to<int, T, ex::element_aligned_tag, SimdAbi>::value);
153 
154     // is_simd_flag_type_v<Flags> is false
155     static_assert(!has_copy_from<int, T, T, SimdAbi>::value);
156     static_assert(!has_copy_to<int, T, T, SimdAbi>::value);
157     static_assert(!has_copy_from<int, T, SimdAbi, SimdAbi>::value);
158     static_assert(!has_copy_to<int, T, SimdAbi, SimdAbi>::value);
159 
160     // U is not a vectorizable type.
161     static_assert(!has_copy_from<SimdAbi, T, ex::element_aligned_tag, SimdAbi>::value);
162     static_assert(!has_copy_to<SimdAbi, T, ex::element_aligned_tag, SimdAbi>::value);
163     static_assert(!has_copy_from<ex::element_aligned_tag, T, ex::element_aligned_tag, SimdAbi>::value);
164     static_assert(!has_copy_to<ex::element_aligned_tag, T, ex::element_aligned_tag, SimdAbi>::value);
165   }
166 };
167 
168 int main(int, char**) {
169   test_all_simd_abi<CheckSimdCopyFrom>();
170   test_all_simd_abi<CheckSimdCopyTo>();
171   test_all_simd_abi<CheckSimdCopyTraits>();
172   return 0;
173 }
174