diff --git a/SYCL/ESIMD/double_grf.cpp b/SYCL/ESIMD/double_grf.cpp new file mode 100644 index 0000000000..47d31d1101 --- /dev/null +++ b/SYCL/ESIMD/double_grf.cpp @@ -0,0 +1,193 @@ +//==----------- double_grf.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 +// +//===----------------------------------------------------------------------===// +// This test verifies effect of +// set_kernel_properties(kernel_properties::use_double_grf); +// API call in device code: +// - ESIMD/SYCL splitting happens as usual +// - ESIMD module is further split into callgraphs for entry points requesting +// "double GRF" and callgraphs for entry points which are not +// - ESIMD device binary images requesting "double GRF" must be compiled with +// -doubleGRF option + +// REQUIRES: gpu-intel-pvc +// UNSUPPORTED: cuda || hip +// TODO/FIXME: esimd_emulator does not support online compilation that +// invokes 'piProgramBuild'/'piKernelCreate' +// UNSUPPORTED: esimd_emulator +// RUN: %clangxx -fsycl %s -o %t.out +// RUN: env SYCL_PI_TRACE=-1 %GPU_RUN_PLACEHOLDER %t.out 2>&1 %GPU_CHECK_PLACEHOLDER --check-prefixes=CHECK,CHECK-NO-VAR +// RUN: env SYCL_PROGRAM_COMPILE_OPTIONS="-g" SYCL_PI_TRACE=-1 %GPU_RUN_PLACEHOLDER %t.out 2>&1 %GPU_CHECK_PLACEHOLDER --check-prefixes=CHECK,CHECK-WITH-VAR + +#include "esimd_test_utils.hpp" + +#include +#include +#include + +using namespace cl::sycl; +using namespace sycl::ext::intel::esimd; +using namespace sycl::ext::intel::experimental::esimd; + +bool checkResult(const std::vector &A, int Inc) { + int err_cnt = 0; + unsigned Size = A.size(); + + for (unsigned i = 0; i < Size; ++i) { + if (A[i] != i + Inc) + if (++err_cnt < 10) + std::cerr << "failed at A[" << i << "]: " << A[i] << " != " << i + Inc + << "\n"; + } + + if (err_cnt > 0) { + std::cout << " pass rate: " + << ((float)(Size - err_cnt) / (float)Size) * 100.0f << "% (" + << (Size - err_cnt) << "/" << Size << ")\n"; + return false; + } + return true; +} + +// Make the double GRF request from non-inlineable function - compiler should +// mark the caller kernel as "double GRF" anyway. +__attribute__((noinline)) void double_grf_marker() { + set_kernel_properties(kernel_properties::use_double_grf); +} + +int main(void) { + constexpr unsigned Size = 32; + constexpr unsigned VL = 16; + + std::vector A(Size); + + for (unsigned i = 0; i < Size; ++i) { + A[i] = i; + } + + try { + buffer bufa(A.data(), range<1>(Size)); + queue q(gpu_selector{}, esimd_test::createExceptionHandler()); + + auto dev = q.get_device(); + std::cout << "Running on " << dev.get_info() << "\n"; + + auto e = q.submit([&](handler &cgh) { + auto PA = bufa.get_access(cgh); + cgh.parallel_for(Size, + [=](id<1> i) { PA[i] = PA[i] + 1; }); + }); + e.wait(); + } catch (cl::sycl::exception const &e) { + std::cout << "SYCL exception caught: " << e.what() << '\n'; + return 2; + } + + if (checkResult(A, 1)) { + std::cout << "SYCL kernel passed\n"; + } else { + std::cout << "SYCL kernel failed\n"; + return 1; + } + + try { + buffer bufa(A.data(), range<1>(Size)); + queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler()); + + auto dev = q.get_device(); + std::cout << "Running on " << dev.get_info() << "\n"; + + auto e = q.submit([&](handler &cgh) { + auto PA = bufa.get_access(cgh); + cgh.parallel_for(Size, [=](id<1> i) SYCL_ESIMD_KERNEL { + unsigned int offset = i * VL * sizeof(float); + simd va; + va.copy_from(PA, offset); + simd vc = va + 1; + vc.copy_to(PA, offset); + }); + }); + e.wait(); + } catch (cl::sycl::exception const &e) { + std::cout << "SYCL exception caught: " << e.what() << '\n'; + return 2; + } + + if (checkResult(A, 2)) { + std::cout << "ESIMD kernel passed\n"; + } else { + std::cout << "ESIMD kernel failed\n"; + return 1; + } + + try { + buffer bufa(A.data(), range<1>(Size)); + queue q(esimd_test::ESIMDSelector{}, esimd_test::createExceptionHandler()); + + auto dev = q.get_device(); + std::cout << "Running on " << dev.get_info() << "\n"; + + auto e = q.submit([&](handler &cgh) { + auto PA = bufa.get_access(cgh); + cgh.parallel_for( + Size, [=](id<1> i) SYCL_ESIMD_KERNEL { + double_grf_marker(); + unsigned int offset = i * VL * sizeof(float); + simd va; + va.copy_from(PA, offset); + simd vc = va + 1; + vc.copy_to(PA, offset); + }); + }); + e.wait(); + } catch (cl::sycl::exception const &e) { + std::cout << "SYCL exception caught: " << e.what() << '\n'; + return 2; + } + + if (checkResult(A, 3)) { + std::cout << "ESIMD double GRF kernel passed\n"; + } else { + std::cout << "ESIMD double GRF kernel failed\n"; + return 1; + } + + return 0; +} + +// Regular SYCL kernel is compiled without -vc-codegen option + +// CHECK-LABEL: ---> piProgramBuild( +// CHECK-NOT: -vc-codegen +// CHECK-WITH-VAR: -g +// CHECK-NOT: -vc-codegen +// CHECK: ) ---> pi_result : PI_SUCCESS +// CHECK-LABEL: ---> piKernelCreate( +// CHECK: : {{.*}}SyclKernel +// CHECK: ) ---> pi_result : PI_SUCCESS + +// For ESIMD kernels, -vc-codegen option is always preserved, +// regardless of SYCL_PROGRAM_COMPILE_OPTIONS value. + +// CHECK-LABEL: ---> piProgramBuild( +// CHECK-NO-VAR: -vc-codegen -disable-finalizer-msg +// CHECK-WITH-VAR: -g -vc-codegen -disable-finalizer-msg +// CHECK: ) ---> pi_result : PI_SUCCESS +// CHECK-LABEL: ---> piKernelCreate( +// CHECK: : {{.*}}EsimdKernel +// CHECK: ) ---> pi_result : PI_SUCCESS + +// Kernels requesting larger GRF are grouped into separate module and compiled +// with -doubleGRF regardless of SYCL_PROGRAM_COMPILE_OPTIONS value. + +// CHECK-LABEL: ---> piProgramBuild( +// CHECK-NO-VAR: -vc-codegen -disable-finalizer-msg -doubleGRF +// CHECK-WITH-VAR: -g -vc-codegen -disable-finalizer-msg -doubleGRF +// CHECK: ) ---> pi_result : PI_SUCCESS +// CHECK-LABEL: ---> piKernelCreate( +// CHECK: : {{.*}}EsimdKernelDoubleGRF +// CHECK: ) ---> pi_result : PI_SUCCESS