]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/experimental/simd/tests/loadstore.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / experimental / simd / tests / loadstore.cc
CommitLineData
a945c346 1// Copyright (C) 2020-2024 Free Software Foundation, Inc.
02e32295
MK
2//
3// This file is part of the GNU ISO C++ Library. This library is free
4// software; you can redistribute it and/or modify it under the
5// terms of the GNU General Public License as published by the
6// Free Software Foundation; either version 3, or (at your option)
7// any later version.
8//
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License along
15// with this library; see the file COPYING3. If not see
16// <http://www.gnu.org/licenses/>.
17
aa89c53c 18// expensive: * [1-9] * *
8f7ad986 19// timeout-factor: 2
073df3e7 20#include "bits/main.h"
02e32295
MK
21
22template <typename V, typename U>
23 void
24 load_store()
25 {
26 // types, tags, and constants
27 using T = typename V::value_type;
28 auto&& gen = make_vec<V>;
29 using std::experimental::element_aligned;
30 using std::experimental::vector_aligned;
31
32 // stride_alignment: consider V::size() == 6. The only reliable alignment is
33 // 2 * sizeof(U). I.e. if the first address is aligned to 8 * sizeof(U),
34 // then the next address is 6 * sizeof(U) larger, thus only aligned to 2 *
35 // sizeof(U).
36 // => the LSB determines the stride alignment
37 constexpr size_t stride_alignment = size_t(1) << __builtin_ctz(V::size());
38 using stride_aligned_t = std::conditional_t<
39 V::size() == stride_alignment, decltype(vector_aligned),
40 std::experimental::overaligned_tag<stride_alignment * sizeof(U)>>;
41 constexpr stride_aligned_t stride_aligned = {};
42 constexpr size_t alignment
43 = 2 * std::experimental::memory_alignment_v<V, U>;
44 constexpr auto overaligned = std::experimental::overaligned<alignment>;
45 const V indexes_from_0([](auto i) { return i; });
46 for (std::size_t i = 0; i < V::size(); ++i)
47 {
48 COMPARE(indexes_from_0[i], T(i));
49 }
50
51 // loads
52 cvt_inputs<T, U> test_values;
53
54 constexpr auto mem_size
55 = test_values.size() > 3 * V::size() ? test_values.size() : 3 * V::size();
56 alignas(std::experimental::memory_alignment_v<V, U> * 2) U mem[mem_size]
57 = {};
58 alignas(std::experimental::memory_alignment_v<V, T> * 2)
59 T reference[mem_size]
60 = {};
61 for (std::size_t i = 0; i < test_values.size(); ++i)
62 {
63 const U value = test_values[i];
64 mem[i] = value;
65 reference[i] = static_cast<T>(value);
66 }
67 for (std::size_t i = test_values.size(); i < mem_size; ++i)
68 {
69 mem[i] = U(i);
70 reference[i] = mem[i];
71 }
72
73 V x(&mem[V::size()], stride_aligned);
74 auto&& compare = [&](const std::size_t offset) {
75 static int n = 0;
76 const V ref(&reference[offset], element_aligned);
77 for (auto i = 0ul; i < V::size(); ++i)
78 {
79 if (is_conversion_undefined<T>(mem[i + offset]))
80 {
81 continue;
82 }
83 COMPARE(x[i], reference[i + offset])
84 << "\nbefore conversion: " << mem[i + offset]
85 << "\n offset = " << offset << "\n x = " << x
86 << "\nreference = " << ref << "\nx == ref = " << (x == ref)
87 << "\ncall no. " << n;
88 }
89 ++n;
90 };
91 compare(V::size());
92 x = V{mem, overaligned};
93 compare(0);
94 x = {&mem[1], element_aligned};
95 compare(1);
96
97 x.copy_from(&mem[V::size()], stride_aligned);
98 compare(V::size());
99 x.copy_from(&mem[1], element_aligned);
100 compare(1);
101 x.copy_from(mem, vector_aligned);
102 compare(0);
103
104 for (std::size_t i = 0; i < mem_size - V::size(); ++i)
105 {
106 x.copy_from(&mem[i], element_aligned);
107 compare(i);
108 }
109
110 for (std::size_t i = 0; i < test_values.size(); ++i)
111 {
112 mem[i] = U(i);
113 }
114 x = indexes_from_0;
115 using M = typename V::mask_type;
116 const M alternating_mask = make_mask<M>({0, 1});
117 where(alternating_mask, x).copy_from(&mem[V::size()], stride_aligned);
118
119 const V indexes_from_size = gen({T(V::size())}, 1);
120 COMPARE(x == indexes_from_size, alternating_mask)
121 << "x: " << x << "\nindexes_from_size: " << indexes_from_size;
122 COMPARE(x == indexes_from_0, !alternating_mask);
123 where(alternating_mask, x).copy_from(&mem[1], element_aligned);
124
125 const V indexes_from_1 = gen({1, 2, 3, 4}, 4);
126 COMPARE(x == indexes_from_1, alternating_mask);
127 COMPARE(x == indexes_from_0, !alternating_mask);
128 where(!alternating_mask, x).copy_from(mem, overaligned);
129 COMPARE(x == indexes_from_0, !alternating_mask);
130 COMPARE(x == indexes_from_1, alternating_mask);
131
132 x = where(alternating_mask, V()).copy_from(&mem[V::size()], stride_aligned);
133 COMPARE(x == indexes_from_size, alternating_mask);
134 COMPARE(x == 0, !alternating_mask);
135
136 x = where(!alternating_mask, V()).copy_from(&mem[1], element_aligned);
137 COMPARE(x == indexes_from_1, !alternating_mask);
138 COMPARE(x == 0, alternating_mask);
139
140 // stores
141 auto&& init_mem = [&mem](U init) {
142 for (auto i = mem_size; i; --i)
143 {
144 mem[i - 1] = init;
145 }
146 };
147 init_mem(-1);
148 x = indexes_from_1;
149 x.copy_to(&mem[V::size()], stride_aligned);
150 std::size_t i = 0;
151 for (; i < V::size(); ++i)
152 {
153 COMPARE(mem[i], U(-1)) << "i: " << i;
154 }
155 for (; i < 2 * V::size(); ++i)
156 {
157 COMPARE(mem[i], U(i - V::size() + 1)) << "i: " << i;
158 }
159 for (; i < 3 * V::size(); ++i)
160 {
161 COMPARE(mem[i], U(-1)) << "i: " << i;
162 }
163
164 init_mem(-1);
165 x.copy_to(&mem[1], element_aligned);
166 COMPARE(mem[0], U(-1));
167 for (i = 1; i <= V::size(); ++i)
168 {
169 COMPARE(mem[i], U(i));
170 }
171 for (; i < 3 * V::size(); ++i)
172 {
173 COMPARE(mem[i], U(-1));
174 }
175
176 init_mem(-1);
177 x.copy_to(mem, vector_aligned);
178 for (i = 0; i < V::size(); ++i)
179 {
180 COMPARE(mem[i], U(i + 1));
181 }
182 for (; i < 3 * V::size(); ++i)
183 {
184 COMPARE(mem[i], U(-1));
185 }
186
187 init_mem(-1);
188 where(alternating_mask, indexes_from_0)
189 .copy_to(&mem[V::size()], stride_aligned);
190 for (i = 0; i < V::size() + 1; ++i)
191 {
192 COMPARE(mem[i], U(-1));
193 }
194 for (; i < 2 * V::size(); i += 2)
195 {
196 COMPARE(mem[i], U(i - V::size()));
197 }
198 for (i = V::size() + 2; i < 2 * V::size(); i += 2)
199 {
200 COMPARE(mem[i], U(-1));
201 }
202 for (; i < 3 * V::size(); ++i)
203 {
204 COMPARE(mem[i], U(-1));
205 }
206 }
207
208template <typename V>
209 void
210 test()
211 {
212 load_store<V, long double>();
213 load_store<V, double>();
214 load_store<V, float>();
215 load_store<V, long long>();
216 load_store<V, unsigned long long>();
217 load_store<V, unsigned long>();
218 load_store<V, long>();
219 load_store<V, int>();
220 load_store<V, unsigned int>();
221 load_store<V, short>();
222 load_store<V, unsigned short>();
223 load_store<V, char>();
224 load_store<V, signed char>();
225 load_store<V, unsigned char>();
226 load_store<V, char32_t>();
227 load_store<V, char16_t>();
228 load_store<V, wchar_t>();
229 }