-
Notifications
You must be signed in to change notification settings - Fork 797
[SYCL][ESIMD] Add support for local accessors to lsc API #10340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fbb2595
1d1176b
d6caa60
3a98a00
7abf48c
1629b5b
14efc8f
8e7ce4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -718,8 +718,10 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer_v<AccessorTy>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer_v<AccessorTy> && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
lsc_gather(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
__ESIMD_NS::simd<uint64_t, N> offsets, | ||
|
@@ -755,17 +757,31 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy, typename Toffset> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer_v<AccessorTy> && | ||
std::is_integral_v<Toffset> && | ||
!std::is_same_v<Toffset, uint64_t>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer_v<AccessorTy> && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
std::is_integral_v<Toffset> && !std::is_same_v<Toffset, uint64_t>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
lsc_gather(AccessorTy acc, __ESIMD_NS::simd<Toffset, N> offsets, | ||
__ESIMD_NS::simd_mask<N> pred = 1) { | ||
return lsc_gather<T, NElts, DS, L1H, L3H, N, AccessorTy>( | ||
acc, convert<uint64_t>(offsets), pred); | ||
} | ||
#endif | ||
|
||
template <typename T, int NElts = 1, | ||
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t< | ||
sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
lsc_gather(AccessorTy acc, __ESIMD_NS::simd<uint32_t, N> offsets, | ||
__ESIMD_NS::simd_mask<N> pred = 1) { | ||
return lsc_slm_gather<T, NElts, DS>( | ||
offsets + __ESIMD_DNS::localAccessorToOffset(acc), pred); | ||
} | ||
|
||
/// Accessor-based gather. | ||
/// Supported platforms: DG2, PVC | ||
/// VISA instruction: lsc_load.ugm | ||
|
@@ -791,8 +807,10 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer_v<AccessorTy>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer_v<AccessorTy> && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
lsc_gather(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
__ESIMD_NS::simd<uint64_t, N> offsets, | ||
|
@@ -833,10 +851,11 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy, typename Toffset> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer_v<AccessorTy> && | ||
std::is_integral_v<Toffset> && | ||
!std::is_same_v<Toffset, uint64_t>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer_v<AccessorTy> && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a note here: I created internal tracker for this issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The much better check is used for copy_to() and copy_from(), e.g. copy_from(): detail::is_sycl_accessor_with<
AccessorT, accessor_mode_cap::can_read,
sycl::access::target::device>::value) |
||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
std::is_integral_v<Toffset> && !std::is_same_v<Toffset, uint64_t>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
lsc_gather(AccessorTy acc, __ESIMD_NS::simd<Toffset, N> offsets, | ||
__ESIMD_NS::simd_mask<N> pred, | ||
__ESIMD_NS::simd<T, N * NElts> old_values) { | ||
|
@@ -845,6 +864,20 @@ lsc_gather(AccessorTy acc, __ESIMD_NS::simd<Toffset, N> offsets, | |
} | ||
#endif | ||
|
||
template <typename T, int NElts = 1, | ||
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t< | ||
sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>, | ||
__ESIMD_NS::simd<T, N * NElts>> | ||
lsc_gather(AccessorTy acc, __ESIMD_NS::simd<uint32_t, N> offsets, | ||
__ESIMD_NS::simd_mask<N> pred, | ||
__ESIMD_NS::simd<T, N * NElts> old_values) { | ||
return lsc_slm_gather<T, NElts, DS>( | ||
offsets + __ESIMD_DNS::localAccessorToOffset(acc), pred, old_values); | ||
} | ||
|
||
/// USM pointer transposed gather with 1 channel. | ||
/// Supported platforms: DG2, PVC | ||
/// VISA instruction: lsc_load.ugm | ||
|
@@ -1136,9 +1169,11 @@ template <typename T, int NElts, lsc_data_size DS = lsc_data_size::default_size, | |
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy, | ||
typename FlagsT = __ESIMD_DNS::dqword_element_aligned_tag> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>, | ||
__ESIMD_NS::simd<T, NElts>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>, | ||
__ESIMD_NS::simd<T, NElts>> | ||
lsc_block_load(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
uint64_t offset, | ||
|
@@ -1209,6 +1244,20 @@ lsc_block_load(AccessorTy acc, | |
#endif // !__ESIMD_FORCE_STATELESS_MEM | ||
} | ||
|
||
template <typename T, int NElts, lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy, | ||
typename FlagsT = __ESIMD_DNS::dqword_element_aligned_tag> | ||
__ESIMD_API std::enable_if_t< | ||
sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>, | ||
__ESIMD_NS::simd<T, NElts>> | ||
lsc_block_load(AccessorTy acc, uint32_t offset, | ||
__ESIMD_NS::simd_mask<1> pred = 1, FlagsT flags = FlagsT{}) { | ||
return lsc_slm_block_load<T, NElts, DS>( | ||
offset + __ESIMD_DNS::localAccessorToOffset(acc), pred); | ||
} | ||
|
||
/// A variation of lsc_block_load without predicate parameter to simplify use | ||
/// of alignment parameter | ||
/// | ||
|
@@ -1300,9 +1349,11 @@ template <typename T, int NElts, lsc_data_size DS = lsc_data_size::default_size, | |
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy, | ||
typename FlagsT = __ESIMD_DNS::dqword_element_aligned_tag> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>, | ||
__ESIMD_NS::simd<T, NElts>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>, | ||
__ESIMD_NS::simd<T, NElts>> | ||
lsc_block_load(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
uint64_t offset, | ||
|
@@ -1373,6 +1424,19 @@ lsc_block_load(AccessorTy acc, | |
#endif // !__ESIMD_FORCE_STATELESS_MEM | ||
} | ||
|
||
template <typename T, int NElts, lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy, | ||
typename FlagsT = __ESIMD_DNS::dqword_element_aligned_tag> | ||
__ESIMD_API std::enable_if_t< | ||
sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>, | ||
__ESIMD_NS::simd<T, NElts>> | ||
lsc_block_load(AccessorTy acc, uint32_t offset, __ESIMD_NS::simd_mask<1> pred, | ||
__ESIMD_NS::simd<T, NElts> old_values, FlagsT flags = FlagsT{}) { | ||
return lsc_slm_block_load<T, NElts, DS>( | ||
offset + __ESIMD_DNS::localAccessorToOffset(acc), pred, old_values); | ||
} | ||
/// USM pointer prefetch gather. | ||
/// Supported platforms: DG2, PVC | ||
/// VISA instruction: lsc_load.ugm | ||
|
@@ -1494,7 +1558,9 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>> | ||
lsc_prefetch(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
__ESIMD_NS::simd<uint64_t, N> offsets, | ||
|
@@ -1528,9 +1594,10 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy, typename Toffset> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value && | ||
std::is_integral_v<Toffset> && | ||
!std::is_same_v<Toffset, uint64_t>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
std::is_integral_v<Toffset> && !std::is_same_v<Toffset, uint64_t>> | ||
lsc_prefetch(AccessorTy acc, __ESIMD_NS::simd<Toffset, N> offsets, | ||
__ESIMD_NS::simd_mask<N> pred = 1) { | ||
lsc_prefetch<T, NElts, DS, L1H, L3H, N, AccessorTy>( | ||
|
@@ -1557,7 +1624,9 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>> | ||
lsc_prefetch(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
uint64_t offset | ||
|
@@ -1748,7 +1817,9 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>> | ||
lsc_scatter(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
__ESIMD_NS::simd<uint64_t, N> offsets, | ||
|
@@ -1786,16 +1857,31 @@ template <typename T, int NElts = 1, | |
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy, typename Toffset> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value && | ||
std::is_integral_v<Toffset> && | ||
!std::is_same_v<Toffset, uint64_t>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
std::is_integral_v<Toffset> && !std::is_same_v<Toffset, uint64_t>> | ||
lsc_scatter(AccessorTy acc, __ESIMD_NS::simd<Toffset, N> offsets, | ||
__ESIMD_NS::simd<T, N * NElts> vals, | ||
__ESIMD_NS::simd_mask<N> pred = 1) { | ||
lsc_scatter<T, NElts, DS, L1H, L3H, N, AccessorTy>( | ||
acc, convert<uint64_t>(offsets), vals, pred); | ||
} | ||
#endif | ||
|
||
template <typename T, int NElts = 1, | ||
lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
int N, typename AccessorTy> | ||
__ESIMD_API std::enable_if_t< | ||
sycl::detail::acc_properties::is_local_accessor_v<AccessorTy>> | ||
lsc_scatter(AccessorTy acc, __ESIMD_NS::simd<uint32_t, N> offsets, | ||
__ESIMD_NS::simd<T, N * NElts> vals, | ||
__ESIMD_NS::simd_mask<N> pred = 1) { | ||
lsc_slm_scatter<T, NElts, DS>( | ||
offsets + __ESIMD_DNS::localAccessorToOffset(acc), vals, pred); | ||
} | ||
|
||
/// USM pointer transposed scatter with 1 channel. | ||
/// Supported platforms: DG2, PVC | ||
/// VISA instruction: lsc_store.ugm | ||
|
@@ -1967,8 +2053,10 @@ template <typename T, int NElts, lsc_data_size DS = lsc_data_size::default_size, | |
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy, | ||
typename FlagsT = __ESIMD_DNS::dqword_element_aligned_tag> | ||
__ESIMD_API std::enable_if_t<!std::is_pointer<AccessorTy>::value && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>> | ||
__ESIMD_API std::enable_if_t< | ||
!std::is_pointer<AccessorTy>::value && | ||
!sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>> | ||
lsc_block_store(AccessorTy acc, | ||
#ifdef __ESIMD_FORCE_STATELESS_MEM | ||
uint64_t offset, | ||
|
@@ -2042,6 +2130,19 @@ lsc_block_store(AccessorTy acc, | |
#endif | ||
} | ||
|
||
template <typename T, int NElts, lsc_data_size DS = lsc_data_size::default_size, | ||
cache_hint L1H = cache_hint::none, cache_hint L3H = cache_hint::none, | ||
typename AccessorTy, | ||
typename FlagsT = __ESIMD_DNS::dqword_element_aligned_tag> | ||
__ESIMD_API std::enable_if_t< | ||
sycl::detail::acc_properties::is_local_accessor_v<AccessorTy> && | ||
__ESIMD_NS::is_simd_flag_type_v<FlagsT>> | ||
lsc_block_store(AccessorTy acc, uint32_t offset, | ||
__ESIMD_NS::simd<T, NElts> vals, FlagsT flags = FlagsT{}) { | ||
lsc_slm_block_store<T, NElts, DS>( | ||
offset + __ESIMD_DNS::localAccessorToOffset(acc), vals); | ||
} | ||
|
||
/// A variation of lsc_block_store without predicate parameter to simplify | ||
/// use of alignment parameter | ||
/// | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
//==- lsc_local_accessor_block_load_store.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-intel-pvc | ||
// RUN: %{build} -o %t.out | ||
// RUN: %{run} %t.out | ||
// | ||
// TODO: Enable the test when GPU driver is ready/fixed. | ||
// XFAIL: opencl || windows || gpu-intel-pvc | ||
turinevgeny marked this conversation as resolved.
Show resolved
Hide resolved
turinevgeny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// UNSUPPORTED: esimd_emulator | ||
// This test verifies usage of block_load/block_store for local_accessor. | ||
|
||
#include "../esimd_test_utils.hpp" | ||
|
||
#include <sycl/ext/intel/esimd.hpp> | ||
#include <sycl/sycl.hpp> | ||
|
||
#include <iostream> | ||
|
||
using namespace sycl; | ||
using namespace sycl::ext::intel::esimd; | ||
using namespace sycl::ext::intel::experimental::esimd; | ||
|
||
constexpr int VL = 16; | ||
|
||
template <typename T> | ||
bool test(queue Q, uint32_t LocalRange, uint32_t GlobalRange) { | ||
std::cout << "Running case: T=" << esimd_test::type_name<T>() << std::endl; | ||
|
||
// The test is going to use (LocalRange * VL) elements of T type. | ||
auto Dev = Q.get_device(); | ||
auto DeviceSLMSize = Dev.get_info<sycl::info::device::local_mem_size>(); | ||
if (DeviceSLMSize < LocalRange * VL * sizeof(T)) { | ||
// Report an error - the test needs a fix. | ||
std::cerr << "Error: Test needs more SLM memory than device has!" | ||
<< std::endl; | ||
return false; | ||
} | ||
|
||
T *Out = malloc_shared<T>(GlobalRange * VL, Q); | ||
for (int I = 0; I < GlobalRange * VL; I++) | ||
Out[I] = -1; | ||
|
||
try { | ||
nd_range<1> NDRange{range<1>{GlobalRange}, range<1>{LocalRange}}; | ||
Q.submit([&](handler &CGH) { | ||
auto LocalAcc = local_accessor<T, 1>(LocalRange * VL, CGH); | ||
|
||
CGH.parallel_for(NDRange, [=](nd_item<1> Item) SYCL_ESIMD_KERNEL { | ||
uint32_t GID = Item.get_global_id(0); | ||
uint32_t LID = Item.get_local_id(0); | ||
|
||
simd<int, VL> IntValues(GID * 100, 1); | ||
simd<T, VL> ValuesToSLM = IntValues; | ||
lsc_block_store(LocalAcc, LID * VL * sizeof(T), ValuesToSLM); | ||
|
||
Item.barrier(); | ||
|
||
if (LID == 0) { | ||
turinevgeny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (int LID = 0; LID < LocalRange; LID++) { | ||
simd<T, VL> ValuesFromSLM = | ||
lsc_block_load<T, VL>(LocalAcc, LID * VL * sizeof(T)); | ||
ValuesFromSLM.copy_to(Out + (GID + LID) * VL); | ||
} // end for (int LID = 0; LID < LocalRange; LID++) | ||
} // end if (LID == 0) | ||
}); | ||
}).wait(); | ||
} catch (sycl::exception const &e) { | ||
std::cout << "SYCL exception caught: " << e.what() << '\n'; | ||
free(Out, Q); | ||
return false; | ||
} | ||
|
||
bool Pass = true; | ||
for (int I = 0; I < GlobalRange * VL; I++) { | ||
int GID = I / VL; | ||
int LID = GID % LocalRange; | ||
int VecElementIndex = I % VL; | ||
|
||
T Expected = GID * 100 + VecElementIndex; | ||
T Computed = Out[I]; | ||
if (Computed != Expected) { | ||
std::cout << "Error: Out[" << I << "]:" << Computed << " != " << Expected | ||
<< ":[expected]" << std::endl; | ||
Pass = false; | ||
} | ||
} | ||
|
||
free(Out, Q); | ||
return Pass; | ||
} | ||
|
||
int main() { | ||
auto Q = queue{gpu_selector_v}; | ||
auto Dev = Q.get_device(); | ||
auto DeviceSLMSize = Dev.get_info<sycl::info::device::local_mem_size>(); | ||
std::cout << "Running on " << Dev.get_info<sycl::info::device::name>() | ||
<< ", Local memory size available : " << DeviceSLMSize << std::endl; | ||
|
||
constexpr uint32_t LocalRange = 16; | ||
constexpr uint32_t GlobalRange = LocalRange * 2; // 2 groups. | ||
|
||
bool Pass = true; | ||
Pass &= test<int>(Q, LocalRange, GlobalRange); | ||
Pass &= test<float>(Q, LocalRange, GlobalRange); | ||
|
||
std::cout << "Test result: " << (Pass ? "Pass" : "Fail") << std::endl; | ||
return Pass ? 0 : 1; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.