aboutsummaryrefslogtreecommitdiff
path: root/libgomp/testsuite/libgomp.c++/target-flex-2003.C
diff options
context:
space:
mode:
Diffstat (limited to 'libgomp/testsuite/libgomp.c++/target-flex-2003.C')
-rw-r--r--libgomp/testsuite/libgomp.c++/target-flex-2003.C176
1 files changed, 176 insertions, 0 deletions
diff --git a/libgomp/testsuite/libgomp.c++/target-flex-2003.C b/libgomp/testsuite/libgomp.c++/target-flex-2003.C
new file mode 100644
index 0000000..8e8ca8e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-flex-2003.C
@@ -0,0 +1,176 @@
+/* { dg-additional-options "-std=c++20" } */
+
+/* bit_cast and memcpy */
+
+#include <bit>
+#include <cstring>
+
+#include "target-flex-common.h"
+
+struct S0
+{
+ int _v0;
+ char _v1;
+ long long _v2;
+};
+
+struct S1
+{
+ int _v0;
+ char _v1;
+ long long _v2;
+};
+
+bool test_bit_cast(int arg)
+{
+ bool ok;
+ S1 s1_out;
+ #pragma omp target map(from: ok, s1_out) map(to: arg)
+ {
+ bool inner_ok = true;
+ {
+ long long v = static_cast<long long>(arg + 42ll);
+ S0 s = {arg, 'a', v};
+ VERIFY (std::bit_cast<S1>(s)._v0 == arg);
+ VERIFY (std::bit_cast<S1>(s)._v1 == 'a');
+ VERIFY (std::bit_cast<S1>(s)._v2 == v);
+ s1_out = std::bit_cast<S1>(s);
+ }
+ end:
+ ok = inner_ok;
+ }
+ if (!ok)
+ return false;
+ long long v = static_cast<long long>(arg + 42ll);
+ VERIFY_NON_TARGET (std::bit_cast<S0>(s1_out)._v0 == arg);
+ VERIFY_NON_TARGET (std::bit_cast<S0>(s1_out)._v1 == 'a');
+ VERIFY_NON_TARGET (std::bit_cast<S0>(s1_out)._v2 == v);
+ return true;
+}
+
+
+struct OutStruct
+{
+ std::size_t _id;
+ void *_next;
+};
+
+struct Extendable1
+{
+ std::size_t _id;
+ void *_next;
+ int _v;
+};
+
+struct Extendable2
+{
+ std::size_t _id;
+ void *_next;
+ char _str[256];
+};
+
+struct Extendable3
+{
+ std::size_t _id;
+ void *_next;
+ const int *_nums;
+ std::size_t _size;
+};
+
+struct ExtendableUnknown
+{
+ std::size_t _id;
+ void *_next;
+};
+
+template<typename To, std::size_t Id>
+To *get_extendable(void *p)
+{
+ while (p != nullptr)
+ {
+ OutStruct out;
+ std::memcpy(&out, p, sizeof(OutStruct));
+ if (out._id == Id)
+ return static_cast<To *>(p);
+ p = out._next;
+ }
+ return nullptr;
+}
+
+bool test_memcpy(int arg, const int *nums, std::size_t nums_size)
+{
+ bool ok;
+ Extendable2 e2_out;
+ #pragma omp target map(from: ok, e2_out) map(to: arg, nums[:nums_size], nums_size)
+ {
+ bool inner_ok = true;
+ {
+ Extendable3 e3 = {3u, nullptr, nums, nums_size};
+ ExtendableUnknown u1 = {100u, &e3};
+ Extendable2 e2 = {2u, &u1, {'H', 'e', 'l', 'l', 'o', '!', '\000'}};
+ ExtendableUnknown u2 = {101u, &e2};
+ ExtendableUnknown u3 = {102u, &u2};
+ ExtendableUnknown u4 = {142u, &u3};
+ Extendable1 e1 = {1u, &u4, arg};
+
+ void *p = &e1;
+ while (p != nullptr)
+ {
+ /* You can always cast a pointer to a struct to a pointer to
+ the type of it's first member. */
+ switch (*static_cast<std::size_t *>(p))
+ {
+ case 1:
+ {
+ Extendable1 *e1_p = static_cast<Extendable1 *>(p);
+ p = e1_p->_next;
+ VERIFY (e1_p->_v == arg);
+ break;
+ }
+ case 2:
+ {
+ Extendable2 *e2_p = static_cast<Extendable2 *>(p);
+ p = e2_p->_next;
+ VERIFY (std::strcmp(e2_p->_str, "Hello!") == 0);
+ break;
+ }
+ case 3:
+ {
+ Extendable3 *e3_p = static_cast<Extendable3 *>(p);
+ p = e3_p->_next;
+ VERIFY (nums == e3_p->_nums);
+ VERIFY (nums_size == e3_p->_size);
+ break;
+ }
+ default:
+ {
+ /* Casting to a pointer to OutStruct invokes undefined
+ behavior though, memcpy is required to extract the _next
+ member. */
+ OutStruct out;
+ std::memcpy(&out, p, sizeof(OutStruct));
+ p = out._next;
+ }
+ }
+ }
+ Extendable2 *e2_p = get_extendable<Extendable2, 2u>(&e1);
+ VERIFY (e2_p != nullptr);
+ e2_out = *e2_p;
+ }
+ end:
+ ok = inner_ok;
+ }
+ if (!ok)
+ return false;
+ VERIFY_NON_TARGET (e2_out._id == 2u);
+ VERIFY_NON_TARGET (std::strcmp(e2_out._str, "Hello!") == 0);
+ return true;
+}
+
+int main()
+{
+ volatile int arg = 42;
+ int arr[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+ return test_bit_cast(arg)
+ && test_memcpy(arg, arr, 8) ? 0 : 1;
+}