Author: Oliver Hunt Date: 2026-09-06T22:47:58-07:00 New Revision: 2362eeb5f75560740146975e9eabe84c6bd25a0d
URL: https://github.com/llvm/llvm-project/commit/2362eeb5f75560740146975e9eabe84c6bd25a0d DIFF: https://github.com/llvm/llvm-project/commit/2362eeb5f75560740146975e9eabe84c6bd25a0d.diff LOG: [clang][Sema][CUDA,SPIRV] Instantiating function templates duplicates GPU attrs (#218582) A number of GPU related attributes were incorrectly falling back to the generic attribute instatiation logic which resulted in duplicating the attributes. The duplicates were also not correctly instantiated. This also exposed a failure to prevent duplicate addition in handleGlobalAttr as well. Added: clang/test/SemaCUDA/attr-instantiation-duplication-amdgpu.cu clang/test/SemaCUDA/attr-instantiation-duplication-spirv.cu Modified: clang/lib/Sema/SemaCUDA.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 553df2db01869..13aa06aa97399 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -1184,6 +1184,8 @@ void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD, template <typename AttrTy> static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, const FunctionDecl &TemplateFD) { + if (FD->hasAttr<AttrTy>()) + return; if (AttrTy *Attribute = TemplateFD.getAttr<AttrTy>()) { AttrTy *Clone = Attribute->clone(S.Context); Clone->setInherited(true); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 106605962171b..d4206acd060a0 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5450,15 +5450,23 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice) S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD; - if (AL.getKind() == ParsedAttr::AT_DeviceKernel) - D->addAttr(::new (S.Context) DeviceKernelAttr(S.Context, AL)); - else - D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL)); + switch (AL.getKind()) { + case ParsedAttr::AT_DeviceKernel: + if (!D->hasAttr<DeviceKernelAttr>()) + D->addAttr(::new (S.Context) DeviceKernelAttr(S.Context, AL)); + break; + case ParsedAttr::AT_CUDAGlobal: + if (!D->hasAttr<CUDAGlobalAttr>()) + D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL)); + break; + default: + llvm_unreachable("Unexpected attribute kind"); + } // In host compilation the kernel is emitted as a stub function, which is // a helper function for launching the kernel. The instructions in the helper // function has nothing to do with the source code of the kernel. Do not emit // debug info for the stub function to avoid confusing the debugger. - if (S.LangOpts.HIP && !S.LangOpts.CUDAIsDevice) + if (S.LangOpts.HIP && !S.LangOpts.CUDAIsDevice && !D->hasAttr<NoDebugAttr>()) D->addAttr(NoDebugAttr::CreateImplicit(S.Context)); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 27d5ff3496472..7668b75e836e4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -966,29 +966,34 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, dyn_cast<ReqdWorkGroupSizeAttr>(TmplAttr)) { instantiateDependentReqdWorkGroupSizeAttr(*this, TemplateArgs, *ReqdWorkGroupSize, New); + continue; } if (const auto *AMDGPUFlatWorkGroupSize = dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) { instantiateDependentAMDGPUFlatWorkGroupSizeAttr( *this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New); + continue; } if (const auto *AMDGPUFlatWorkGroupSize = dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) { instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New); + continue; } if (const auto *AMDGPUMaxNumWorkGroups = dyn_cast<AMDGPUMaxNumWorkGroupsAttr>(TmplAttr)) { instantiateDependentAMDGPUMaxNumWorkGroupsAttr( *this, TemplateArgs, *AMDGPUMaxNumWorkGroups, New); + continue; } if (const auto *CUDAClusterDims = dyn_cast<CUDAClusterDimsAttr>(TmplAttr)) { instantiateDependentCUDAClusterDimsAttr(*this, TemplateArgs, *CUDAClusterDims, New); + continue; } if (const auto *ParamAttr = dyn_cast<HLSLParamModifierAttr>(TmplAttr)) { diff --git a/clang/test/SemaCUDA/attr-instantiation-duplication-amdgpu.cu b/clang/test/SemaCUDA/attr-instantiation-duplication-amdgpu.cu new file mode 100644 index 0000000000000..eca9f36633512 --- /dev/null +++ b/clang/test/SemaCUDA/attr-instantiation-duplication-amdgpu.cu @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -triple amdgpu12.50-amd-amdhsa -fcuda-is-device -x hip -ast-dump -ast-dump-filter test_ %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -aux-triple amdgpu-amd-amdhsa -x hip -ast-dump -ast-dump-filter test_host_stub %s | FileCheck --check-prefix=HOST %s + +#include "Inputs/cuda.h" + +// CHECK: FunctionDecl {{.*}} test_flat_work_group_size 'void ()' explicit_instantiation_definition +// CHECK-NEXT: TemplateArgument integral '256' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: AMDGPUFlatWorkGroupSizeAttr +// CHECK-NEXT: IntegerLiteral {{.*}} 1 +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} N +// CHECK-NEXT: IntegerLiteral {{.*}} 256 +// CHECK-NEXT: CUDAGlobalAttr +// CHECK-EMPTY: +template <int N> +__attribute__((amdgpu_flat_work_group_size(1, N))) +__global__ void test_flat_work_group_size() {} +template __global__ void test_flat_work_group_size<256>(); + +// CHECK: FunctionDecl {{.*}} test_waves_per_eu 'void ()' explicit_instantiation_definition +// CHECK-NEXT: TemplateArgument integral '2' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: AMDGPUWavesPerEUAttr +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} N +// CHECK-NEXT: IntegerLiteral {{.*}} 2 +// CHECK-NEXT: <<<NULL>>> +// CHECK-NEXT: CUDAGlobalAttr +// CHECK-EMPTY: +template <int N> +__attribute__((amdgpu_waves_per_eu(N))) +__global__ void test_waves_per_eu() {} +template __global__ void test_waves_per_eu<2>(); + +// CHECK: FunctionDecl {{.*}} test_max_num_work_groups 'void ()' explicit_instantiation_definition +// CHECK-NEXT: TemplateArgument integral '8' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: AMDGPUMaxNumWorkGroupsAttr +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} N +// CHECK-NEXT: IntegerLiteral {{.*}} 8 +// CHECK-NEXT: <<<NULL>>> +// CHECK-NEXT: <<<NULL>>> +// CHECK-NEXT: CUDAGlobalAttr +// CHECK-EMPTY: +template <int N> +__attribute__((amdgpu_max_num_work_groups(N))) +__global__ void test_max_num_work_groups() {} +template __global__ void test_max_num_work_groups<8>(); + +// CHECK: FunctionDecl {{.*}} test_cluster_dims 'void ()' explicit_instantiation_definition +// CHECK-NEXT: TemplateArgument integral '4' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CUDAClusterDimsAttr +// CHECK-NEXT: ConstantExpr +// CHECK-NEXT: value: Int 4 +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} N +// CHECK-NEXT: IntegerLiteral {{.*}} 4 +// CHECK-NEXT: <<<NULL>>> +// CHECK-NEXT: <<<NULL>>> +// CHECK-NEXT: CUDAGlobalAttr +// CHECK-EMPTY: +template <int N> +__attribute__((cluster_dims(N))) +__global__ void test_cluster_dims() {} +template __global__ void test_cluster_dims<4>(); + +// HOST: FunctionDecl {{.*}} test_host_stub 'void ()' explicit_instantiation_definition +// HOST-NEXT: TemplateArgument integral '4' +// HOST-NEXT: CompoundStmt +// HOST-NEXT: CUDAGlobalAttr +// HOST-NEXT: NoDebugAttr {{.*}} Implicit +// HOST-EMPTY: +template <int N> +__global__ void test_host_stub() {} +template __global__ void test_host_stub<4>(); diff --git a/clang/test/SemaCUDA/attr-instantiation-duplication-spirv.cu b/clang/test/SemaCUDA/attr-instantiation-duplication-spirv.cu new file mode 100644 index 0000000000000..2ee045e163a9e --- /dev/null +++ b/clang/test/SemaCUDA/attr-instantiation-duplication-spirv.cu @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple spirv64-amd-amdhsa -fcuda-is-device -x hip -ast-dump -ast-dump-filter test_ %s | FileCheck %s + +#include "Inputs/cuda.h" + +// CHECK: FunctionDecl {{.*}} test_reqd_work_group_size 'void ()' explicit_instantiation_definition +// CHECK-NEXT: TemplateArgument integral '4' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: ReqdWorkGroupSizeAttr +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: NonTypeTemplateParmDecl {{.*}} N +// CHECK-NEXT: IntegerLiteral {{.*}} 4 +// CHECK-NEXT: IntegerLiteral {{.*}} 1 +// CHECK-NEXT: IntegerLiteral {{.*}} 1 +// CHECK-NEXT: CUDAGlobalAttr +// CHECK-EMPTY: +template <int N> +__attribute__((reqd_work_group_size(N, 1, 1))) +__global__ void test_reqd_work_group_size() {} +template __global__ void test_reqd_work_group_size<4>(); + +template <typename T> +__global__ void test_explicit_specialization() {} + +// CHECK: FunctionDecl {{.*}} test_explicit_specialization 'void ()' explicit_specialization +// CHECK-NEXT: TemplateArgument type 'int' +// CHECK-NEXT: BuiltinType {{.*}} 'int' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CUDAGlobalAttr +// CHECK-EMPTY: +template <> +__global__ void test_explicit_specialization<int>() {} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
