================ @@ -0,0 +1,186 @@ +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-unknown-linux-gnu %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-LINUX %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple amdgcn-amd-amdhsa %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple nvptx-nvidia-cuda %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple nvptx64-nvidia-cuda %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spir64-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv32-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-unknown-linux-gnu -triple spirv64-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64-pc-windows-msvc %s -o - | FileCheck --check-prefixes=CHECK-HOST,CHECK-HOST-WINDOWS %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple amdgcn-amd-amdhsa %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-AMDGCN %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple nvptx-nvidia-cuda %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple nvptx64-nvidia-cuda %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-NVPTX %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spir64-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv32-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -aux-triple x86_64-pc-windows-msvc -triple spirv64-unknown-unknown %s -o - | FileCheck --check-prefixes=CHECK-DEVICE,CHECK-SPIR %s + +// Test the generation of SYCL kernel caller functions. These functions are +// generated from functions declared with the sycl_kernel_entry_point attribute +// and emited during device compilation. They are not emitted during device +// compilation. + +template <typename KernelName, typename KernelType> +[[clang::sycl_kernel_entry_point(KernelName)]] +void kernel_single_task(KernelType kernelFunc) { + kernelFunc(); +} + +struct single_purpose_kernel_name; +struct single_purpose_kernel { + void operator()() const {} +}; + +[[clang::sycl_kernel_entry_point(single_purpose_kernel_name)]] +void single_purpose_kernel_task(single_purpose_kernel kernelFunc) { + kernelFunc(); +} + +int main() { + int capture; + kernel_single_task<class lambda_kernel_name>( + [=]() { + (void) capture; + }); + single_purpose_kernel obj; + single_purpose_kernel_task(obj); +} + +// Verify that SYCL kernel caller functions are not emitted during host +// compilation. +// +// CHECK-HOST-NOT: _ZTS26single_purpose_kernel_name +// CHECK-HOST-NOT: _ZTSZ4mainE18lambda_kernel_name + +// Verify that sycl_kernel_entry_point attributed functions are not emitted +// during device compilation. +// +// CHECK-DEVICE-NOT: single_purpose_kernel_task +// CHECK-DEVICE-NOT: kernel_single_task + +// Verify that no code is generated for the bodies of sycl_kernel_entry_point +// attributed functions during host compilation. ODR-use of these functions may +// require them to be emitted, but they have no effect if called. +// +// CHECK-HOST-LINUX: define dso_local void @_Z26single_purpose_kernel_task21single_purpose_kernel() #[[LINUX_ATTR0:[0-9]+]] { +// CHECK-HOST-LINUX-NEXT: entry: +// CHECK-HOST-LINUX-NEXT: %kernelFunc = alloca %struct.single_purpose_kernel, align 1 +// CHECK-HOST-LINUX-NEXT: ret void ---------------- tahonermann wrote:
These functions may be called on the host. Any ODR-use (for a function template) suffices for the device-side entry point function to be emitted, but the common case is that such ODR-use will be due to a function call; that is what is done in the Intel SYCL library. When such calls occur, the function body is actually evaluated on the host; that is why the body is emitted as a no-op. This is what was established by https://github.com/llvm/llvm-project/pull/122379 per the following addition to `CodeGenFunction::EmitSimpleStmt()` in `clang/lib/CodeGen/CGStmt.cpp`: ``` 504 bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, 505 ArrayRef<const Attr *> Attrs) { ... 541 case Stmt::SYCLKernelCallStmtClass: 542 // SYCL kernel call statements are generated as wrappers around the body 543 // of functions declared with the sycl_kernel_entry_point attribute. Such 544 // functions are used to specify how a SYCL kernel (a function object) is 545 // to be invoked; the SYCL kernel call statement contains a transformed 546 // variation of the function body and is used to generate a SYCL kernel 547 // caller function; a function that serves as the device side entry point 548 // used to execute the SYCL kernel. The sycl_kernel_entry_point attributed 549 // function is invoked by host code in order to trigger emission of the 550 // device side SYCL kernel caller function and to generate metadata needed 551 // by SYCL run-time library implementations; the function is otherwise 552 // intended to have no effect. As such, the function body is not evaluated 553 // as part of the invocation during host compilation (and the function 554 // should not be called or emitted during device compilation); the SYCL 555 // kernel call statement is thus handled as a null statement for the 556 // purpose of code generation. 557 break; ... 560 } ``` https://github.com/llvm/llvm-project/pull/133030 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits