Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

Commit e36c713

Browse files
authored
[SYCL][ESIMD] Add test on simd bitwise not operator (#850)
1 parent 7794b50 commit e36c713

File tree

3 files changed

+266
-0
lines changed

3 files changed

+266
-0
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//===-- operator_bitwise_not.hpp - Functions for tests on simd assignment
2+
// operators. --------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// This file provides functions for tests on simd assignment operators.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#pragma once
16+
17+
#define ESIMD_TESTS_DISABLE_DEPRECATED_TEST_DESCRIPTION_FOR_LOGS
18+
19+
#include "../mutator.hpp"
20+
#include "../shared_element.hpp"
21+
#include "common.hpp"
22+
// For std::abs
23+
#include <cmath>
24+
25+
namespace esimd = sycl::ext::intel::esimd;
26+
27+
namespace esimd_test::api::functional::operators {
28+
29+
// Descriptor class for the case of calling bitwise not operator.
30+
struct bitwise_not_operator {
31+
static std::string get_description() { return "bitwise not"; }
32+
33+
template <typename DataT, int NumElems>
34+
static bool call_operator(const DataT *const ref_data,
35+
DataT *const source_simd_result,
36+
DataT *const operator_result) {
37+
auto simd_obj = esimd::simd<DataT, NumElems>();
38+
simd_obj.copy_from(ref_data);
39+
const auto bitwise_not_result = ~simd_obj;
40+
simd_obj.copy_to(source_simd_result);
41+
bitwise_not_result.copy_to(operator_result);
42+
return std::is_same_v<decltype(~simd_obj), esimd::simd<DataT, NumElems>>;
43+
}
44+
};
45+
46+
// Replace specific reference values to lower once.
47+
template <typename T> struct For_bitwise_not {
48+
For_bitwise_not() = default;
49+
50+
void operator()(T &val) {
51+
static_assert(!type_traits::is_sycl_floating_point_v<T>,
52+
"Invalid data type.");
53+
if constexpr (std::is_signed_v<T>) {
54+
// We could have UB for negative zero in different integral type
55+
// representations: two's complement, ones' complement and signed
56+
// magnitude.
57+
// See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2218.htm
58+
// Note that there is no check for UB with padding bits here, as it would
59+
// effectively disable any possible check for signed integer bitwise
60+
// operations.
61+
static const T max = value<T>::max();
62+
static const T lowest = value<T>::lowest();
63+
if (std::abs(lowest + 1) == (max - 1)) {
64+
// C11 standard mentions that it's possible to have a `0b100...0` value
65+
// as a trap value for twos' complement representation. In such case the
66+
// condition above would trigger for twos' complement representation
67+
// also.
68+
if (val == max) {
69+
// Would result in trap representation for signed magnitude
70+
val -= 1;
71+
} else if (val == 0) {
72+
// Would result in trap representation for ones' complement
73+
val = 1;
74+
}
75+
}
76+
} // signed integral types
77+
}
78+
};
79+
80+
// The main test routine.
81+
// Using functor class to be able to iterate over the pre-defined data types.
82+
template <typename TestCaseT, typename DataT, typename DimT> class run_test {
83+
static constexpr int NumElems = DimT::value;
84+
using TestDescriptionT = TestDescription<NumElems, TestCaseT>;
85+
86+
public:
87+
bool operator()(sycl::queue &queue, const std::string &data_type) {
88+
bool passed = true;
89+
std::vector<DataT> ref_data = generate_ref_data<DataT, NumElems>();
90+
91+
mutate(ref_data, For_bitwise_not<DataT>());
92+
93+
// If current number of elements is equal to one, then run test with each
94+
// one value from reference data.
95+
// If current number of elements is greater than one, then run tests with
96+
// whole reference data.
97+
if constexpr (NumElems == 1) {
98+
for (size_t i = 0; i < ref_data.size(); ++i) {
99+
passed = run_verification(queue, {ref_data[i]}, data_type);
100+
}
101+
} else {
102+
passed = run_verification(queue, ref_data, data_type);
103+
}
104+
return passed;
105+
}
106+
107+
private:
108+
bool run_verification(sycl::queue &queue, const std::vector<DataT> &ref_data,
109+
const std::string &data_type) {
110+
assert(ref_data.size() == NumElems &&
111+
"Reference data size is not equal to the simd vector length.");
112+
113+
bool passed = true;
114+
115+
shared_allocator<DataT> allocator(queue);
116+
shared_vector<DataT> shared_ref_data(ref_data.begin(), ref_data.end(),
117+
allocator);
118+
shared_vector<DataT> source_simd_result(NumElems, allocator);
119+
shared_vector<DataT> operator_result(NumElems, allocator);
120+
121+
shared_element<bool> is_correct_type(queue, true);
122+
123+
queue.submit([&](sycl::handler &cgh) {
124+
const DataT *const ref = shared_ref_data.data();
125+
DataT *const source_simd_result_data_ptr = source_simd_result.data();
126+
DataT *const operator_result_data_ptr = operator_result.data();
127+
auto is_correct_type_ptr = is_correct_type.data();
128+
129+
cgh.single_task<Kernel<DataT, NumElems, TestCaseT>>(
130+
[=]() SYCL_ESIMD_KERNEL {
131+
*is_correct_type_ptr =
132+
TestCaseT::template call_operator<DataT, NumElems>(
133+
ref, source_simd_result_data_ptr, operator_result_data_ptr);
134+
});
135+
});
136+
queue.wait_and_throw();
137+
138+
for (size_t i = 0; i < NumElems; ++i) {
139+
{
140+
const DataT &retrieved = source_simd_result[i];
141+
const DataT &expected = ref_data[i];
142+
if (!are_bitwise_equal(expected, retrieved)) {
143+
passed = false;
144+
log::fail(TestDescriptionT(data_type),
145+
"Unexpected source simd value at index ", i,
146+
", retrieved: ", retrieved, ", expected: ", expected);
147+
}
148+
}
149+
{
150+
const DataT &retrieved = operator_result[i];
151+
const DataT &expected = ~shared_ref_data[i];
152+
if (!are_bitwise_equal(expected, retrieved)) {
153+
passed = false;
154+
log::fail(TestDescriptionT(data_type),
155+
"Unexpected result value at index ", i,
156+
", retrieved: ", retrieved, ", expected: ", expected);
157+
}
158+
}
159+
}
160+
161+
if (!is_correct_type.value()) {
162+
passed = false;
163+
log::fail(TestDescriptionT(data_type),
164+
"Invalid return type for operator.");
165+
}
166+
167+
return passed;
168+
}
169+
};
170+
171+
} // namespace esimd_test::api::functional::operators
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//==------- operator_bitwise_not_sint.cpp - DPC++ ESIMD on-device test ----==//
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+
// REQUIRES: gpu, level_zero
9+
// XREQUIRES: gpu
10+
// TODO gpu and level_zero in REQUIRES due to only this platforms supported yet.
11+
// The current "REQUIRES" should be replaced with "gpu" only as mentioned in
12+
// "XREQUIRES".
13+
// UNSUPPORTED: cuda, hip
14+
// RUN: %clangxx -fsycl %s -fsycl-device-code-split=per_kernel -o %t.out
15+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
16+
//
17+
// Test for simd bitwise not operator.
18+
// The test creates source simd instance with reference data and invokes bitwise
19+
// not operator.
20+
// The test verifies that data from simd is not corrupted after calling bitwise
21+
// not operator, that bitwise not operator return type is as expected and
22+
// bitwise not operator result values are correct.
23+
//
24+
// IMPORTANT: ESIMD API currently supports bitwise not for signed integer types.
25+
// Though there is possibility of trap values and compiler optimizations in
26+
// general C++17, the llvm itself states that signed integer types are
27+
// guaranteed to be two's complement:
28+
// - https://llvm.org/docs/LangRef.html
29+
// - https://bugs.llvm.org/show_bug.cgi?id=950
30+
31+
#include "operator_bitwise_not.hpp"
32+
33+
using namespace esimd_test::api::functional;
34+
35+
int main(int, char **) {
36+
sycl::queue queue(esimd_test::ESIMDSelector{},
37+
esimd_test::createExceptionHandler());
38+
39+
bool passed = true;
40+
41+
const auto sint_types = get_tested_types<tested_types::sint>();
42+
const auto all_dims = get_all_dimensions();
43+
44+
// Running test for all sint types
45+
passed &= for_all_combinations<operators::run_test,
46+
operators::bitwise_not_operator>(
47+
sint_types, all_dims, queue);
48+
49+
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n");
50+
return passed ? 0 : 1;
51+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//==------- operator_bitwise_not_uint.cpp - DPC++ ESIMD on-device test ----==//
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+
// REQUIRES: gpu, level_zero
9+
// XREQUIRES: gpu
10+
// TODO gpu and level_zero in REQUIRES due to only this platforms supported yet.
11+
// The current "REQUIRES" should be replaced with "gpu" only as mentioned in
12+
// "XREQUIRES".
13+
// UNSUPPORTED: cuda, hip
14+
// RUN: %clangxx -fsycl %s -fsycl-device-code-split=per_kernel -o %t.out
15+
// RUN: %GPU_RUN_PLACEHOLDER %t.out
16+
//
17+
// Test for simd bitwise not operator.
18+
// The test creates source simd instance with reference data and invokes bitwise
19+
// not operator.
20+
// The test verifies that data from simd is not corrupted after calling bitwise
21+
// not operator, that bitwise not operator return type is as expected and
22+
// bitwise not operator result values are correct.
23+
24+
#include "operator_bitwise_not.hpp"
25+
26+
using namespace esimd_test::api::functional;
27+
28+
int main(int, char **) {
29+
sycl::queue queue(esimd_test::ESIMDSelector{},
30+
esimd_test::createExceptionHandler());
31+
32+
bool passed = true;
33+
34+
const auto uint_types = get_tested_types<tested_types::uint>();
35+
const auto all_dims = get_all_dimensions();
36+
37+
// Running test for all uint types
38+
passed &= for_all_combinations<operators::run_test,
39+
operators::bitwise_not_operator>(
40+
uint_types, all_dims, queue);
41+
42+
std::cout << (passed ? "=== Test passed\n" : "=== Test FAILED\n");
43+
return passed ? 0 : 1;
44+
}

0 commit comments

Comments
 (0)