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