Skip to content

[CUDA] make kernel stub ICF-proof #90155

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

Merged
merged 1 commit into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions clang/lib/CodeGen/CGCUDANV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,33 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
CGM.CreateRuntimeFunction(FTy, LaunchKernelName);
CGF.EmitCall(FI, CGCallee::forDirect(cudaLaunchKernelFn), ReturnValueSlot(),
LaunchKernelArgs);

// To prevent CUDA device stub functions from being merged by ICF in MSVC
// environment, create an unique global variable for each kernel and write to
// the variable in the device stub.
if (CGM.getContext().getTargetInfo().getCXXABI().isMicrosoft() &&
!CGF.getLangOpts().HIP) {
llvm::Function *KernelFunction = llvm::cast<llvm::Function>(Kernel);
std::string GlobalVarName = (KernelFunction->getName() + ".id").str();

llvm::GlobalVariable *HandleVar =
CGM.getModule().getNamedGlobal(GlobalVarName);
if (!HandleVar) {
HandleVar = new llvm::GlobalVariable(
CGM.getModule(), CGM.Int8Ty,
/*Constant=*/false, KernelFunction->getLinkage(),
llvm::ConstantInt::get(CGM.Int8Ty, 0), GlobalVarName);
HandleVar->setDSOLocal(KernelFunction->isDSOLocal());
HandleVar->setVisibility(KernelFunction->getVisibility());
if (KernelFunction->hasComdat())
HandleVar->setComdat(CGM.getModule().getOrInsertComdat(GlobalVarName));
}

CGF.Builder.CreateAlignedStore(llvm::ConstantInt::get(CGM.Int8Ty, 1),
HandleVar, CharUnits::One(),
/*IsVolatile=*/true);
}

CGF.EmitBranch(EndBlock);

CGF.EmitBlock(EndBlock);
Expand Down
101 changes: 61 additions & 40 deletions clang/test/CodeGenCUDA/kernel-stub-name.cu
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s \
// RUN: -fcuda-include-gpubinary %t -o - -x hip\
// RUN: | FileCheck -check-prefixes=CHECK,GNU %s
// RUN: | FileCheck -check-prefixes=CHECK,GNU,GNU-HIP,HIP %s

// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s \
// RUN: -fcuda-include-gpubinary %t -o - -x hip\
Expand All @@ -11,7 +11,12 @@
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm %s \
// RUN: -aux-triple amdgcn-amd-amdhsa -fcuda-include-gpubinary \
// RUN: %t -o - -x hip\
// RUN: | FileCheck -check-prefixes=CHECK,MSVC %s
// RUN: | FileCheck -check-prefixes=CHECK,MSVC,MSVC-HIP,HIP %s

// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm %s \
// RUN: -aux-triple nvptx64 -fcuda-include-gpubinary \
// RUN: %t -target-sdk-version=9.2 -o - \
// RUN: | FileCheck -check-prefixes=CHECK,MSVC,CUDA %s

// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm %s \
// RUN: -aux-triple amdgcn-amd-amdhsa -fcuda-include-gpubinary \
Expand All @@ -22,19 +27,23 @@

// Check kernel handles are emitted for non-MSVC target but not for MSVC target.

// GNU: @[[HCKERN:ckernel]] = constant ptr @[[CSTUB:__device_stub__ckernel]], align 8
// GNU: @[[HNSKERN:_ZN2ns8nskernelEv]] = constant ptr @[[NSSTUB:_ZN2ns23__device_stub__nskernelEv]], align 8
// GNU: @[[HTKERN:_Z10kernelfuncIiEvv]] = linkonce_odr constant ptr @[[TSTUB:_Z25__device_stub__kernelfuncIiEvv]], comdat, align 8
// GNU: @[[HDKERN:_Z11kernel_declv]] = external constant ptr, align 8
// GNU: @[[HTDKERN:_Z20template_kernel_declIiEvT_]] = external constant ptr, align 8

// MSVC: @[[HCKERN:ckernel]] = dso_local constant ptr @[[CSTUB:__device_stub__ckernel]], align 8
// MSVC: @[[HNSKERN:"\?nskernel@ns@@YAXXZ.*"]] = dso_local constant ptr @[[NSSTUB:"\?__device_stub__nskernel@ns@@YAXXZ"]], align 8
// MSVC: @[[HTKERN:"\?\?\$kernelfunc@H@@YAXXZ.*"]] = linkonce_odr dso_local constant ptr @[[TSTUB:"\?\?\$__device_stub__kernelfunc@H@@YAXXZ.*"]], comdat, align 8
// MSVC: @[[HDKERN:"\?kernel_decl@@YAXXZ.*"]] = external dso_local constant ptr, align 8
// MSVC: @[[HTDKERN:"\?\?\$template_kernel_decl@H@@YAXH.*"]] = external dso_local constant ptr, align 8
// GNU-HIP: @[[HCKERN:ckernel]] = constant ptr @[[CSTUB:__device_stub__ckernel]], align 8
// GNU-HIP: @[[HNSKERN:_ZN2ns8nskernelEv]] = constant ptr @[[NSSTUB:_ZN2ns23__device_stub__nskernelEv]], align 8
// GNU-HIP: @[[HTKERN:_Z10kernelfuncIiEvv]] = linkonce_odr constant ptr @[[TSTUB:_Z25__device_stub__kernelfuncIiEvv]], comdat, align 8
// GNU-HIP: @[[HDKERN:_Z11kernel_declv]] = external constant ptr, align 8
// GNU-HIP: @[[HTDKERN:_Z20template_kernel_declIiEvT_]] = external constant ptr, align 8

// MSVC-HIP: @[[HCKERN:ckernel]] = dso_local constant ptr @[[CSTUB:__device_stub__ckernel]], align 8
// MSVC-HIP: @[[HNSKERN:"\?nskernel@ns@@YAXXZ.*"]] = dso_local constant ptr @[[NSSTUB:"\?__device_stub__nskernel@ns@@YAXXZ"]], align 8
// MSVC-HIP: @[[HTKERN:"\?\?\$kernelfunc@H@@YAXXZ.*"]] = linkonce_odr dso_local constant ptr @[[TSTUB:"\?\?\$__device_stub__kernelfunc@H@@YAXXZ.*"]], comdat, align 8
// MSVC-HIP: @[[HDKERN:"\?kernel_decl@@YAXXZ.*"]] = external dso_local constant ptr, align 8
// MSVC-HIP: @[[HTDKERN:"\?\?\$template_kernel_decl@H@@YAXH.*"]] = external dso_local constant ptr, align 8
extern "C" __global__ void ckernel() {}

// CUDA: @[[HCKERN:__device_stub__ckernel\.id]] = dso_local global i8 0
// CUDA: @[[HNSKERN:"\?__device_stub__nskernel@ns@@YAXXZ\.id"]] = dso_local global i8 0
// CUDA: @[[HTKERN:"\?\?\$__device_stub__kernelfunc@H@@YAXXZ\.id"]] = linkonce_odr dso_local global i8 0, comdat

namespace ns {
__global__ void nskernel() {}
} // namespace ns
Expand All @@ -60,18 +69,27 @@ extern "C" void launch(void *kern);

// Non-template kernel stub functions

// CHECK: define{{.*}}@[[CSTUB]]
// CHECK: call{{.*}}@hipLaunchByPtr{{.*}}@[[HCKERN]]
// HIP: define{{.*}}@[[CSTUB]]
// CUDA: define{{.*}}@[[CSTUB:__device_stub__ckernel]]
// HIP: call{{.*}}@hipLaunchByPtr{{.*}}@[[HCKERN]]
// CUDA: call{{.*}}@cudaLaunch{{.*}}@[[CSTUB]]
// CUDA: store volatile i8 1, ptr @[[HCKERN]], align 1
// CHECK: ret void

// CHECK: define{{.*}}@[[NSSTUB]]
// CHECK: call{{.*}}@hipLaunchByPtr{{.*}}@[[HNSKERN]]
// HIP: define{{.*}}@[[NSSTUB]]
// CUDA: define{{.*}}@[[NSSTUB:"\?__device_stub__nskernel@ns@@YAXXZ"]]
// HIP: call{{.*}}@hipLaunchByPtr{{.*}}@[[HNSKERN]]
// CUDA: call{{.*}}@cudaLaunch{{.*}}@[[NSSTUB]]
// CUDA: store volatile i8 1, ptr @[[HNSKERN]], align 1
// CHECK: ret void

// Check kernel stub is called for triple chevron.

// CHECK-LABEL: define{{.*}}@fun1()
// CHECK: call void @[[CSTUB]]()
// CHECK: call void @[[NSSTUB]]()
// CHECK: call void @[[TSTUB]]()
// HIP: call void @[[TSTUB]]()
// CUDA: call void @[[TSTUB:"\?\?\$__device_stub__kernelfunc@H@@YAXXZ.*"]]()
// GNU: call void @[[DSTUB:_Z26__device_stub__kernel_declv]]()
// GNU: call void @[[TDSTUB:_Z35__device_stub__template_kernel_declIiEvT_]](
// MSVC: call void @[[DSTUB:"\?__device_stub__kernel_decl@@YAXXZ"]]()
Expand All @@ -88,7 +106,10 @@ extern "C" void fun1(void) {
// Template kernel stub functions

// CHECK: define{{.*}}@[[TSTUB]]
// CHECK: call{{.*}}@hipLaunchByPtr{{.*}}@[[HTKERN]]
// HIP: call{{.*}}@hipLaunchByPtr{{.*}}@[[HTKERN]]
// CUDA: call{{.*}}@cudaLaunch{{.*}}@[[TSTUB]]
// CUDA: store volatile i8 1, ptr @[[HTKERN]], align 1
// CHECK: ret void

// Check declaration of stub function for external kernel.

Expand All @@ -98,11 +119,11 @@ extern "C" void fun1(void) {
// Check kernel handle is used for passing the kernel as a function pointer.

// CHECK-LABEL: define{{.*}}@fun2()
// CHECK: call void @launch({{.*}}[[HCKERN]]
// CHECK: call void @launch({{.*}}[[HNSKERN]]
// CHECK: call void @launch({{.*}}[[HTKERN]]
// CHECK: call void @launch({{.*}}[[HDKERN]]
// CHECK: call void @launch({{.*}}[[HTDKERN]]
// HIP: call void @launch({{.*}}[[HCKERN]]
// HIP: call void @launch({{.*}}[[HNSKERN]]
// HIP: call void @launch({{.*}}[[HTKERN]]
// HIP: call void @launch({{.*}}[[HDKERN]]
// HIP: call void @launch({{.*}}[[HTDKERN]]
extern "C" void fun2() {
launch((void *)ckernel);
launch((void *)ns::nskernel);
Expand All @@ -114,10 +135,10 @@ extern "C" void fun2() {
// Check kernel handle is used for assigning a kernel to a function pointer.

// CHECK-LABEL: define{{.*}}@fun3()
// CHECK: store ptr @[[HCKERN]], ptr @kernel_ptr, align 8
// CHECK: store ptr @[[HCKERN]], ptr @kernel_ptr, align 8
// CHECK: store ptr @[[HCKERN]], ptr @void_ptr, align 8
// CHECK: store ptr @[[HCKERN]], ptr @void_ptr, align 8
// HIP: store ptr @[[HCKERN]], ptr @kernel_ptr, align 8
// HIP: store ptr @[[HCKERN]], ptr @kernel_ptr, align 8
// HIP: store ptr @[[HCKERN]], ptr @void_ptr, align 8
// HIP: store ptr @[[HCKERN]], ptr @void_ptr, align 8
extern "C" void fun3() {
kernel_ptr = ckernel;
kernel_ptr = &ckernel;
Expand All @@ -129,11 +150,11 @@ extern "C" void fun3() {
// used with triple chevron.

// CHECK-LABEL: define{{.*}}@fun4()
// CHECK: store ptr @[[HCKERN]], ptr @kernel_ptr
// CHECK: call noundef i32 @{{.*hipConfigureCall}}
// CHECK: %[[HANDLE:.*]] = load ptr, ptr @kernel_ptr, align 8
// CHECK: %[[STUB:.*]] = load ptr, ptr %[[HANDLE]], align 8
// CHECK: call void %[[STUB]]()
// HIP: store ptr @[[HCKERN]], ptr @kernel_ptr
// HIP: call noundef i32 @{{.*hipConfigureCall}}
// HIP: %[[HANDLE:.*]] = load ptr, ptr @kernel_ptr, align 8
// HIP: %[[STUB:.*]] = load ptr, ptr %[[HANDLE]], align 8
// HIP: call void %[[STUB]]()
extern "C" void fun4() {
kernel_ptr = ckernel;
kernel_ptr<<<1,1>>>();
Expand All @@ -142,20 +163,20 @@ extern "C" void fun4() {
// Check kernel handle is passed to a function.

// CHECK-LABEL: define{{.*}}@fun5()
// CHECK: store ptr @[[HCKERN]], ptr @kernel_ptr
// CHECK: %[[HANDLE:.*]] = load ptr, ptr @kernel_ptr, align 8
// CHECK: call void @launch(ptr noundef %[[HANDLE]])
// HIP: store ptr @[[HCKERN]], ptr @kernel_ptr
// HIP: %[[HANDLE:.*]] = load ptr, ptr @kernel_ptr, align 8
// HIP: call void @launch(ptr noundef %[[HANDLE]])
extern "C" void fun5() {
kernel_ptr = ckernel;
launch((void *)kernel_ptr);
}

// Check kernel handle is registered.

// CHECK-LABEL: define{{.*}}@__hip_register_globals
// CHECK: call{{.*}}@__hipRegisterFunction{{.*}}@[[HCKERN]]{{.*}}@[[CKERN]]
// CHECK: call{{.*}}@__hipRegisterFunction{{.*}}@[[HNSKERN]]{{.*}}@[[NSKERN]]
// CHECK: call{{.*}}@__hipRegisterFunction{{.*}}@[[HTKERN]]{{.*}}@[[TKERN]]
// HIP-LABEL: define{{.*}}@__hip_register_globals
// HIP: call{{.*}}@__hipRegisterFunction{{.*}}@[[HCKERN]]{{.*}}@[[CKERN]]
// HIP: call{{.*}}@__hipRegisterFunction{{.*}}@[[HNSKERN]]{{.*}}@[[NSKERN]]
// HIP: call{{.*}}@__hipRegisterFunction{{.*}}@[[HTKERN]]{{.*}}@[[TKERN]]
// NEG-NOT: call{{.*}}@__hipRegisterFunction{{.*}}__device_stub
// NEG-NOT: call{{.*}}@__hipRegisterFunction{{.*}}kernel_decl
// NEG-NOT: call{{.*}}@__hipRegisterFunction{{.*}}template_kernel_decl