Skip to content

Commit 4c5d5b2

Browse files
committed
[SYCL][ESIMD] Add test proxy for move constructors
Because copy constructor works as the default fallback for every case with move constructor disabled or not provided, there is no way for a caller to differentiate between actual call to move constructor and copy constructor. Same goes for copy and move assignment operators. Therefore a test proxy is the only way left to check the move constructor and the move assignment works as expected. Signed-off-by: Yuriy Kochetkov <[email protected]>
1 parent db7ff53 commit 4c5d5b2

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

sycl/include/sycl/ext/intel/experimental/esimd/detail/simd_obj_impl.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <sycl/ext/intel/experimental/esimd/detail/intrin.hpp>
1414
#include <sycl/ext/intel/experimental/esimd/detail/memory_intrin.hpp>
1515
#include <sycl/ext/intel/experimental/esimd/detail/sycl_util.hpp>
16+
#include <sycl/ext/intel/experimental/esimd/detail/test_proxy.hpp>
1617
#include <sycl/ext/intel/experimental/esimd/detail/types.hpp>
1718
#include <sycl/ext/intel/experimental/esimd/simd_view.hpp>
1819

@@ -716,11 +717,17 @@ template <typename Ty, int N, class Derived, class SFINAE> class simd_obj_impl {
716717
__ESIMD_DEF_SIMD_OBJ_IMPL_OPASSIGN(/, /=, __ESIMD_ARITH_OP_FILTER)
717718
#undef __ESIMD_ARITH_OP_FILTER
718719

720+
// Getter for the test proxy member, if enabled
721+
__ESIMD_DECLARE_TEST_PROXY_ACCESS
722+
719723
private:
720724
// The underlying data for this vector.
721725
vector_type M_data;
722726

723727
protected:
728+
// The test proxy if enabled
729+
__ESIMD_DECLARE_TEST_PROXY
730+
724731
void set(const vector_type &Val) {
725732
#ifndef __SYCL_DEVICE_ONLY__
726733
M_data = Val;

sycl/include/sycl/ext/intel/experimental/esimd/detail/simd_view_impl.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#pragma once
1212

1313
#include <sycl/ext/intel/experimental/esimd/detail/intrin.hpp>
14+
#include <sycl/ext/intel/experimental/esimd/detail/test_proxy.hpp>
1415
#include <sycl/ext/intel/experimental/esimd/detail/types.hpp>
1516

1617
__SYCL_INLINE_NAMESPACE(cl) {
@@ -303,8 +304,12 @@ class simd_view_impl {
303304
Derived &operator=(const value_type &Val) { return write(Val); }
304305

305306
/// Move assignment operator.
306-
Derived &operator=(Derived &&Other) { return write(Other.read()); }
307+
Derived &operator=(Derived &&Other) {
308+
__esimd_move_test_proxy(Other);
309+
return write(Other.read());
310+
}
307311
simd_view_impl &operator=(simd_view_impl &&Other) {
312+
__esimd_move_test_proxy(Other);
308313
return write(Other.read());
309314
}
310315

@@ -492,10 +497,17 @@ class simd_view_impl {
492497
return read().all();
493498
}
494499

500+
public:
501+
// Getter for the test proxy member, if enabled
502+
__ESIMD_DECLARE_TEST_PROXY_ACCESS
503+
495504
protected:
496505
// The reference to the base object, which must be a simd object
497506
BaseTy &M_base;
498507

508+
// The test proxy if enabled
509+
__ESIMD_DECLARE_TEST_PROXY
510+
499511
// The region applied on the base object. Its type could be
500512
// - region1d_t
501513
// - region2d_t
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//==-------------- test_proxy.hpp - DPC++ Explicit SIMD API ----------------==//
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+
// Test proxy to differentiate move and copy constructor calls
9+
//===----------------------------------------------------------------------===//
10+
11+
#pragma once
12+
13+
#ifndef __ESIMD_ENABLE_TEST_PROXY
14+
15+
// No ABI-breaking changes by default
16+
#define __ESIMD_DECLARE_TEST_PROXY
17+
#define __ESIMD_DECLARE_TEST_PROXY_ACCESS
18+
#define __esimd_move_test_proxy(other)
19+
20+
#else
21+
22+
// Declare the class attribute
23+
//
24+
// We are using non static data member initialization approach to force
25+
// the value required. Initialization will take place even if no
26+
// default/copy/move constructor of the test_proxy class was explcitly
27+
// called by any of the user-defined constructors of the proxy target
28+
#define __ESIMD_DECLARE_TEST_PROXY \
29+
esimd::detail::test_proxy M_testProxy = esimd::detail::test_proxy();
30+
31+
// Declare the getter to access the proxy from the tests
32+
#define __ESIMD_DECLARE_TEST_PROXY_ACCESS \
33+
const auto &get_test_proxy() const { return M_testProxy; }
34+
35+
// Test proxy will be handled in a proper way by default/implicit move
36+
// constructors and move operators.
37+
// Still the user-defined constructors or move operators should explicitly state
38+
// what to do with each of class atributes, so a proper wrapper required
39+
#define __esimd_move_test_proxy(other) \
40+
do { \
41+
M_testProxy = std::move(other.M_testProxy); \
42+
} while (false);
43+
44+
__SYCL_INLINE_NAMESPACE(cl) {
45+
namespace sycl {
46+
namespace ext {
47+
namespace intel {
48+
namespace experimental {
49+
namespace esimd {
50+
namespace detail {
51+
52+
/// The test_proxy class.
53+
///
54+
/// This is a helper class for tests to differentiate between the copy
55+
/// constructor/assignment and the move constructor/assignment calls,
56+
/// as the copy constructor works as the default fallback for every case with
57+
/// move constructor disabled or not provided
58+
///
59+
/// The test proxy is enabled only if the __ESIMD_ENABLE_TEST_PROXY macro is
60+
/// defined.
61+
/// It is expected for the class with the test proxy (the class under test) to:
62+
/// - provide the get_test_proxy() method
63+
/// - properly handle moving the test_proxy member in user-defined move
64+
/// constructors and user-defined assignment operators
65+
///
66+
/// Therefore the following expression is expected to return `true` only if the
67+
/// move constructor or move operator was called for the instance of the class
68+
/// under test:
69+
/// instance.get_test_proxy().was_moved()
70+
///
71+
/// \ingroup sycl_esimd
72+
class test_proxy {
73+
// Define the default value to use for every constructor
74+
bool m_moved = false;
75+
76+
public:
77+
test_proxy() { __esimd_dbg_print(test_proxy()); }
78+
79+
test_proxy(const test_proxy &) {
80+
__esimd_dbg_print(test_proxy(const test_proxy &other));
81+
}
82+
test_proxy(test_proxy &&) {
83+
__esimd_dbg_print(test_proxy(test_proxy && other));
84+
m_moved = true;
85+
}
86+
test_proxy &operator=(const test_proxy &) {
87+
__esimd_dbg_print(test_proxy::operator=(const test_proxy &other));
88+
return *this;
89+
}
90+
test_proxy &operator=(test_proxy &&) {
91+
__esimd_dbg_print(test_proxy::operator=(test_proxy &&other));
92+
m_moved = true;
93+
return *this;
94+
}
95+
bool was_moved() const { return m_moved; }
96+
};
97+
98+
} // namespace detail
99+
} // namespace esimd
100+
} // namespace experimental
101+
} // namespace intel
102+
} // namespace ext
103+
} // namespace sycl
104+
} // __SYCL_INLINE_NAMESPACE(cl)
105+
106+
#endif // __ESIMD_ENABLE_TEST_PROXY

0 commit comments

Comments
 (0)