]> 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
7adcbafe 1// Copyright (C) 2020-2022 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
02e32295
MK
20#include "bits/verify.h"
21#include "bits/make_vec.h"
22#include "bits/conversions.h"
23
24template <typename V, typename U>
25 void
26 load_store()
27 {
28 // types, tags, and constants
29 using T = typename V::value_type;
30 auto&& gen = make_vec<V>;
31 using std::experimental::element_aligned;
32 using std::experimental::vector_aligned;
33
34 // stride_alignment: consider V::size() == 6. The only reliable alignment is
35 // 2 * sizeof(U). I.e. if the first address is aligned to 8 * sizeof(U),
36 // then the next address is 6 * sizeof(U) larger, thus only aligned to 2 *
37 // sizeof(U).
38 // => the LSB determines the stride alignment
39 constexpr size_t stride_alignment = size_t(1) << __builtin_ctz(V::size());
40 using stride_aligned_t = std::conditional_t<
41 V::size() == stride_alignment, decltype(vector_aligned),
42 std::experimental::overaligned_tag<stride_alignment * sizeof(U)>>;
43 constexpr stride_aligned_t stride_aligned = {};
44 constexpr size_t alignment
45 = 2 * std::experimental::memory_alignment_v<V, U>;
46 constexpr auto overaligned = std::experimental::overaligned<alignment>;
47 const V indexes_from_0([](auto i) { return i; });
48 for (std::size_t i = 0; i < V::size(); ++i)
49 {
50 COMPARE(indexes_from_0[i], T(i));
51 }
52
53 // loads
54 cvt_inputs<T, U> test_values;
55
56 constexpr auto mem_size
57 = test_values.size() > 3 * V::size() ? test_values.size() : 3 * V::size();
58 alignas(std::experimental::memory_alignment_v<V, U> * 2) U mem[mem_size]
59 = {};
60 alignas(std::experimental::memory_alignment_v<V, T> * 2)
61 T reference[mem_size]
62 = {};
63 for (std::size_t i = 0; i < test_values.size(); ++i)
64 {
65 const U value = test_values[i];
66 mem[i] = value;
67 reference[i] = static_cast<T>(value);
68 }
69 for (std::size_t i = test_values.size(); i < mem_size; ++i)
70 {
71 mem[i] = U(i);
72 reference[i] = mem[i];
73 }
74
75 V x(&mem[V::size()], stride_aligned);
76 auto&& compare = [&](const std::size_t offset) {
77 static int n = 0;
78 const V ref(&reference[offset], element_aligned);
79 for (auto i = 0ul; i < V::size(); ++i)
80 {
81 if (is_conversion_undefined<T>(mem[i + offset]))
82 {
83 continue;
84 }
85 COMPARE(x[i], reference[i + offset])
86 << "\nbefore conversion: " << mem[i + offset]
87 << "\n offset = " << offset << "\n x = " << x
88 << "\nreference = " << ref << "\nx == ref = " << (x == ref)
89 << "\ncall no. " << n;
90 }
91 ++n;
92 };
93 compare(V::size());
94 x = V{mem, overaligned};
95 compare(0);
96 x = {&mem[1], element_aligned};
97 compare(1);
98
99 x.copy_from(&mem[V::size()], stride_aligned);
100 compare(V::size());
101 x.copy_from(&mem[1], element_aligned);
102 compare(1);
103 x.copy_from(mem, vector_aligned);
104 compare(0);
105
106 for (std::size_t i = 0; i < mem_size - V::size(); ++i)
107 {
108 x.copy_from(&mem[i], element_aligned);
109 compare(i);
110 }
111
112 for (std::size_t i = 0; i < test_values.size(); ++i)
113 {
114 mem[i] = U(i);
115 }
116 x = indexes_from_0;
117 using M = typename V::mask_type;
118 const M alternating_mask = make_mask<M>({0, 1});
119 where(alternating_mask, x).copy_from(&mem[V::size()], stride_aligned);
120
121 const V indexes_from_size = gen({T(V::size())}, 1);
122 COMPARE(x == indexes_from_size, alternating_mask)
123 << "x: " << x << "\nindexes_from_size: " << indexes_from_size;
124 COMPARE(x == indexes_from_0, !alternating_mask);
125 where(alternating_mask, x).copy_from(&mem[1], element_aligned);
126
127 const V indexes_from_1 = gen({1, 2, 3, 4}, 4);
128 COMPARE(x == indexes_from_1, alternating_mask);
129 COMPARE(x == indexes_from_0, !alternating_mask);
130 where(!alternating_mask, x).copy_from(mem, overaligned);
131 COMPARE(x == indexes_from_0, !alternating_mask);
132 COMPARE(x == indexes_from_1, alternating_mask);
133
134 x = where(alternating_mask, V()).copy_from(&mem[V::size()], stride_aligned);
135 COMPARE(x == indexes_from_size, alternating_mask);
136 COMPARE(x == 0, !alternating_mask);
137
138 x = where(!alternating_mask, V()).copy_from(&mem[1], element_aligned);
139 COMPARE(x == indexes_from_1, !alternating_mask);
140 COMPARE(x == 0, alternating_mask);
141
142 // stores
143 auto&& init_mem = [&mem](U init) {
144 for (auto i = mem_size; i; --i)
145 {
146 mem[i - 1] = init;
147 }
148 };
149 init_mem(-1);
150 x = indexes_from_1;
151 x.copy_to(&mem[V::size()], stride_aligned);
152 std::size_t i = 0;
153 for (; i < V::size(); ++i)
154 {
155 COMPARE(mem[i], U(-1)) << "i: " << i;
156 }
157 for (; i < 2 * V::size(); ++i)
158 {
159 COMPARE(mem[i], U(i - V::size() + 1)) << "i: " << i;
160 }
161 for (; i < 3 * V::size(); ++i)
162 {
163 COMPARE(mem[i], U(-1)) << "i: " << i;
164 }
165
166 init_mem(-1);
167 x.copy_to(&mem[1], element_aligned);
168 COMPARE(mem[0], U(-1));
169 for (i = 1; i <= V::size(); ++i)
170 {
171 COMPARE(mem[i], U(i));
172 }
173 for (; i < 3 * V::size(); ++i)
174 {
175 COMPARE(mem[i], U(-1));
176 }
177
178 init_mem(-1);
179 x.copy_to(mem, vector_aligned);
180 for (i = 0; i < V::size(); ++i)
181 {
182 COMPARE(mem[i], U(i + 1));
183 }
184 for (; i < 3 * V::size(); ++i)
185 {
186 COMPARE(mem[i], U(-1));
187 }
188
189 init_mem(-1);
190 where(alternating_mask, indexes_from_0)
191 .copy_to(&mem[V::size()], stride_aligned);
192 for (i = 0; i < V::size() + 1; ++i)
193 {
194 COMPARE(mem[i], U(-1));
195 }
196 for (; i < 2 * V::size(); i += 2)
197 {
198 COMPARE(mem[i], U(i - V::size()));
199 }
200 for (i = V::size() + 2; i < 2 * V::size(); i += 2)
201 {
202 COMPARE(mem[i], U(-1));
203 }
204 for (; i < 3 * V::size(); ++i)
205 {
206 COMPARE(mem[i], U(-1));
207 }
208 }
209
210template <typename V>
211 void
212 test()
213 {
214 load_store<V, long double>();
215 load_store<V, double>();
216 load_store<V, float>();
217 load_store<V, long long>();
218 load_store<V, unsigned long long>();
219 load_store<V, unsigned long>();
220 load_store<V, long>();
221 load_store<V, int>();
222 load_store<V, unsigned int>();
223 load_store<V, short>();
224 load_store<V, unsigned short>();
225 load_store<V, char>();
226 load_store<V, signed char>();
227 load_store<V, unsigned char>();
228 load_store<V, char32_t>();
229 load_store<V, char16_t>();
230 load_store<V, wchar_t>();
231 }