This repository was archived by the owner on Mar 28, 2023. It is now read-only.
forked from llvm/llvm-test-suite
-
Notifications
You must be signed in to change notification settings - Fork 130
[SYCL][ESIMD] Add tests on simd vector move constructor #679
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
9775c8e
[SYCL][ESIMD] Add tests on simd vector move constructor
yuriykoch 71a3c3b
[SYCL][ESIMD] Ensure the move constructor invocation
yuriykoch 56b55df
[SYCL][ESIMD] Fix source type for simd move constructor
yuriykoch 0e296a0
[SYCL][ESIMD] Use parallel_for for simd<T,1> case
yuriykoch e974dde
[SYCL][ESIMD] Make flag usage in kernel more explicit
yuriykoch 9d78edc
[SYCL][ESIMD] Disable tests on simd move constructor
yuriykoch 796602b
[SYCL][ESIMD] Update test_proxy API signature
yuriykoch 241a933
[SYCL][ESIMD] Use the latest logger interface
yuriykoch 1e54ab1
[SYCL][ESIMD] Clarify multiple work items usage
yuriykoch 51a7965
[SYCL][ESIMD] Refactor the order of functions in file
yuriykoch 5a4f3ec
[SYCL][ESIMD] Remove unnecessary namespace using directive
yuriykoch 37e5e50
[SYCL][ESIMD] Enable test run
yuriykoch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
//==------- ctor_move.cpp - DPC++ ESIMD on-device test --------------------==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// REQUIRES: gpu, level_zero | ||
// XREQUIRES: gpu | ||
// TODO Remove the level_zero restriction once the test is supported on other | ||
// platforms | ||
// UNSUPPORTED: cuda, hip | ||
// RUN: %clangxx -fsycl %s -fsycl-device-code-split=per_kernel -o %t.out | ||
// RUN: %GPU_RUN_PLACEHOLDER %t.out | ||
// XFAIL: * | ||
// TODO Remove XFAIL once the simd vector provides move constructor | ||
// | ||
// Test for esimd move constructor | ||
// The test creates source simd instance with reference data and invokes move | ||
// constructor in different C++ contexts to create a new simd instance from the | ||
// source simd instance. It is expected for a new simd instance to store | ||
// bitwise same data as the one passed as the source simd constructor. | ||
|
||
// The following issues for simd<T,32> observed: | ||
// - freeze with T in {char, unsigned char, singned char}; | ||
// - runtime failure with T in {short, unsigned short}. | ||
// TODO Remove once the freeze is fixed | ||
#define SKIP_VECTOR_LEN_32 | ||
|
||
// The test proxy is used to verify the move constructor was called actually. | ||
#define __ESIMD_ENABLE_TEST_PROXY | ||
|
||
#include "common.hpp" | ||
#include <algorithm> | ||
#include <cassert> | ||
|
||
using namespace sycl::ext::intel::experimental::esimd; | ||
using namespace esimd_test::api::functional; | ||
|
||
// Uses the initializer C++ context to call simd move constructor | ||
struct initializer { | ||
static std::string get_description() { return "initializer"; } | ||
|
||
template <typename SimdT, typename ActionT> | ||
static void run(SimdT &&source, const ActionT &action) { | ||
static_assert( | ||
type_traits::is_nonconst_rvalue_reference_v<decltype(source)>); | ||
|
||
const auto instance = SimdT(std::move(source)); | ||
action(instance); | ||
} | ||
}; | ||
|
||
// Uses the variable declaration C++ context to call simd move constructor | ||
struct var_decl { | ||
static std::string get_description() { return "variable declaration"; } | ||
|
||
template <typename SimdT, typename ActionT> | ||
static void run(SimdT &&source, const ActionT &action) { | ||
static_assert( | ||
type_traits::is_nonconst_rvalue_reference_v<decltype(source)>); | ||
|
||
const auto instance(std::move(source)); | ||
action(instance); | ||
} | ||
}; | ||
|
||
// Uses the rvalue in expression C++ context to call simd move constructor | ||
struct rval_in_expr { | ||
static std::string get_description() { return "rvalue in expression"; } | ||
|
||
template <typename SimdT, typename ActionT> | ||
static void run(SimdT &&source, const ActionT &action) { | ||
static_assert( | ||
type_traits::is_nonconst_rvalue_reference_v<decltype(source)>); | ||
|
||
SimdT instance; | ||
instance = SimdT(std::move(source)); | ||
action(instance); | ||
} | ||
}; | ||
|
||
// Uses the function argument C++ context to call simd move constructor | ||
class const_ref { | ||
public: | ||
static std::string get_description() { return "const reference"; } | ||
|
||
template <typename SimdT, typename ActionT> | ||
static void run(SimdT &&source, const ActionT &action) { | ||
static_assert( | ||
type_traits::is_nonconst_rvalue_reference_v<decltype(source)>); | ||
|
||
action(SimdT(std::move(source))); | ||
} | ||
}; | ||
|
||
// The core test functionality. | ||
// Runs a TestCaseT, specific for each C++ context, for a simd<DataT,NumElems> | ||
// instance | ||
template <typename DataT, int NumElems, typename TestCaseT> class run_test { | ||
using KernelName = ctors::Kernel<DataT, NumElems, TestCaseT>; | ||
|
||
public: | ||
bool operator()(sycl::queue &queue, const std::string &data_type) { | ||
bool passed = true; | ||
bool was_moved = false; | ||
|
||
const shared_allocator<DataT> data_allocator(queue); | ||
const shared_allocator<int> flags_allocator(queue); | ||
const auto reference = generate_ref_data<DataT, NumElems>(); | ||
|
||
shared_vector<DataT> input(reference.cbegin(), reference.cend(), | ||
data_allocator); | ||
shared_vector<DataT> result(reference.size(), data_allocator); | ||
|
||
// We need a special handling for case of simd<T,1>, as we need to check | ||
// more than a single data value; therefore we need to loop over the | ||
// reference data to run test | ||
if constexpr (NumElems == 1) { | ||
const auto n_checks = input.size(); | ||
const sycl::range<1> range(n_checks); | ||
|
||
// We need a separate flag per each check to have a parallel_for possible, | ||
// because any concurrent access to the same memory location is UB, even | ||
// in case we are updating variable to the same value in multiple threads | ||
shared_vector<int> flags_storage(n_checks, flags_allocator); | ||
|
||
// Run check for each of the reference elements using a single work-item | ||
// per single element | ||
queue.submit([&](sycl::handler &cgh) { | ||
const DataT *const ptr_in = input.data(); | ||
const auto ptr_out = result.data(); | ||
const auto ptr_flags = flags_storage.data(); | ||
|
||
cgh.parallel_for<KernelName>( | ||
range, [=](sycl::id<1> id) SYCL_ESIMD_KERNEL { | ||
const auto work_item_index = id[0]; | ||
// Access a separate memory areas from each of the work items | ||
const DataT *const in = ptr_in + work_item_index; | ||
const auto out = ptr_out + work_item_index; | ||
const auto was_moved_flag = ptr_flags + work_item_index; | ||
*was_moved_flag = run_check(in, out); | ||
}); | ||
}); | ||
queue.wait_and_throw(); | ||
|
||
// Oversafe: verify the proper signature was called for every check | ||
was_moved = std::all_of(flags_storage.cbegin(), flags_storage.cend(), | ||
[](int flag) { return flag; }); | ||
} else { | ||
assert((input.size() == NumElems) && | ||
"Unexpected size of the input vector"); | ||
|
||
shared_vector<int> flags_storage(1, flags_allocator); | ||
|
||
queue.submit([&](sycl::handler &cgh) { | ||
const DataT *const in = input.data(); | ||
const auto out = result.data(); | ||
const auto was_moved_flag = flags_storage.data(); | ||
|
||
cgh.single_task<KernelName>( | ||
[=]() SYCL_ESIMD_KERNEL { *was_moved_flag = run_check(in, out); }); | ||
}); | ||
queue.wait_and_throw(); | ||
|
||
was_moved = flags_storage[0]; | ||
} | ||
|
||
if (!was_moved) { | ||
passed = false; | ||
|
||
// TODO: Make ITestDescription architecture more flexible | ||
std::string log_msg = "Failed for simd<"; | ||
log_msg += data_type + ", " + std::to_string(NumElems) + ">"; | ||
log_msg += ", with context: " + TestCaseT::get_description(); | ||
log_msg += ". A copy constructor instead of a move constructor was used."; | ||
|
||
log::note(log_msg); | ||
} else { | ||
for (size_t i = 0; i < reference.size(); ++i) { | ||
const auto &retrieved = result[i]; | ||
const auto &expected = reference[i]; | ||
|
||
if (!are_bitwise_equal(retrieved, expected)) { | ||
passed = false; | ||
|
||
log::fail(ctors::TestDescription<DataT, NumElems, TestCaseT>( | ||
i, retrieved, expected, data_type)); | ||
} | ||
} | ||
} | ||
|
||
return passed; | ||
} | ||
|
||
private: | ||
// The core check logic. | ||
// Uses USM pointers for input data and to store the data from the new simd | ||
// instance, so that we could check it later | ||
// Returns the flag that should be true only if the move constructor was | ||
// actually called, to differentiate with the copy constructor calls | ||
static bool run_check(const DataT *const in, DataT *const out) { | ||
bool was_moved = false; | ||
|
||
// Prepare the source simd to move | ||
simd<DataT, NumElems> source; | ||
source.copy_from(in); | ||
|
||
// Action to run over the simd move constructor result | ||
const auto action = [&](const simd<DataT, NumElems> &instance) { | ||
was_moved = instance.get_test_proxy().was_move_destination(); | ||
v-klochkov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
instance.copy_to(out); | ||
}; | ||
// Call the move constructor in the specific context and run action | ||
// directly over the simd move constructor result | ||
TestCaseT::template run(std::move(source), action); | ||
|
||
return was_moved; | ||
} | ||
}; | ||
|
||
int main(int, char **) { | ||
bool passed = true; | ||
const auto types = get_tested_types<tested_types::all>(); | ||
#ifdef SKIP_VECTOR_LEN_32 | ||
const auto dims = values_pack<1, 8, 16>(); | ||
#else | ||
const auto dims = get_all_dimensions(); | ||
#endif | ||
|
||
sycl::queue queue(esimd_test::ESIMDSelector{}, | ||
esimd_test::createExceptionHandler()); | ||
|
||
// Run for all combinations possible | ||
passed &= for_all_types_and_dims<run_test, initializer>(types, dims, queue); | ||
passed &= for_all_types_and_dims<run_test, var_decl>(types, dims, queue); | ||
passed &= for_all_types_and_dims<run_test, rval_in_expr>(types, dims, queue); | ||
passed &= for_all_types_and_dims<run_test, const_ref>(types, dims, queue); | ||
|
||
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n"); | ||
return passed ? 0 : 1; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.