diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 8f238f3a93a83..227c018399b0d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1262,7 +1262,7 @@ def LoopUnrollHint : InheritableAttr { def IntelReqdSubGroupSize: InheritableAttr { let Spellings = [GNU<"intel_reqd_sub_group_size">, CXX11<"cl", "intel_reqd_sub_group_size">]; - let Args = [UnsignedArgument<"SubGroupSize">]; + let Args = [ExprArgument<"SubGroupSize">]; let Subjects = SubjectList<[Function, CXXMethod], ErrorDiag>; let Documentation = [IntelReqdSubGroupSizeDocs]; let LangOpts = [OpenCL, SYCLIsDevice, SYCLIsHost]; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6233e982506f7..3634b90ead684 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9917,6 +9917,10 @@ class Sema final { bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); + // Adds an intel_reqd_sub_group_size attribute to a particular declaration. + void addIntelReqdSubGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, + Expr *E); + //===--------------------------------------------------------------------===// // C++ Coroutines TS // diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 37aa19c012b17..246e3cd27373e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -574,8 +574,14 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, if (const IntelReqdSubGroupSizeAttr *A = FD->getAttr()) { + llvm::APSInt ArgVal(32); + llvm::LLVMContext &Context = getLLVMContext(); + bool IsValid = A->getSubGroupSize()->isIntegerConstantExpr( + ArgVal, FD->getASTContext()); + assert(IsValid && "Not an integer constant expression"); + (void)IsValid; llvm::Metadata *AttrMDArgs[] = { - llvm::ConstantAsMetadata::get(Builder.getInt32(A->getSubGroupSize()))}; + llvm::ConstantAsMetadata::get(Builder.getInt32(ArgVal.getSExtValue()))}; Fn->setMetadata("intel_reqd_sub_group_size", llvm::MDNode::get(Context, AttrMDArgs)); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 61a51918befd4..37b808904210c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2980,27 +2980,41 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { } // Handles intel_reqd_sub_group_size. +void Sema::addIntelReqdSubGroupSizeAttr(Decl *D, + const AttributeCommonInfo &Attr, + Expr *E) { + if (!E) + return; + + if (!E->isInstantiationDependent()) { + llvm::APSInt ArgVal(32); + if (!E->isIntegerConstantExpr(ArgVal, getASTContext())) { + Diag(E->getExprLoc(), diag::err_attribute_argument_type) + << Attr.getAttrName() << AANT_ArgumentIntegerConstant + << E->getSourceRange(); + return; + } + int32_t ArgInt = ArgVal.getSExtValue(); + if (ArgInt <= 0) { + Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer) + << Attr.getAttrName() << /*positive*/ 0; + return; + } + } + + D->addAttr(::new (Context) IntelReqdSubGroupSizeAttr(Context, Attr, E)); +} + static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { if (S.LangOpts.SYCLIsHost) return; - uint32_t SGSize; - const Expr *E = AL.getArgAsExpr(0); - if (!checkUInt32Argument(S, AL, E, SGSize)) - return; - if (SGSize == 0) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) - << AL << E->getSourceRange(); - return; - } + Expr *E = AL.getArgAsExpr(0); - IntelReqdSubGroupSizeAttr *Existing = - D->getAttr(); - if (Existing && Existing->getSubGroupSize() != SGSize) + if (D->getAttr()) S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; - D->addAttr(::new (S.Context) - IntelReqdSubGroupSizeAttr(S.Context, AL, SGSize)); + S.addIntelReqdSubGroupSizeAttr(D, AL, E); } // Handles num_simd_work_items. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index c9401264140e6..fd837856e37ae 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -579,6 +579,17 @@ static void instantiateSYCLIntelPipeIOAttr( S.addSYCLIntelPipeIOAttr(New, *Attr, Result.getAs()); } +static void instantiateIntelReqdSubGroupSizeAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const IntelReqdSubGroupSizeAttr *Attr, Decl *New) { + // The SubGroupSize expression is a constant expression. + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ExprResult Result = S.SubstExpr(Attr->getSubGroupSize(), TemplateArgs); + if (!Result.isInvalid()) + S.addIntelReqdSubGroupSizeAttr(New, *Attr, Result.getAs()); +} + void Sema::InstantiateAttrsForDecl( const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -721,7 +732,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, instantiateSYCLIntelPipeIOAttr(*this, TemplateArgs, SYCLIntelPipeIO, New); continue; } - + if (const auto *IntelReqdSubGroupSize = + dyn_cast(TmplAttr)) { + instantiateIntelReqdSubGroupSizeAttr(*this, TemplateArgs, + IntelReqdSubGroupSize, New); + continue; + } // Existing DLL attribute on the instantiation takes precedence. if (TmplAttr->getKind() == attr::DLLExport || TmplAttr->getKind() == attr::DLLImport) { diff --git a/clang/test/CodeGenSYCL/reqd-sub-group-size.cpp b/clang/test/CodeGenSYCL/reqd-sub-group-size.cpp index f290ca4757c1d..d95b97180b3f6 100644 --- a/clang/test/CodeGenSYCL/reqd-sub-group-size.cpp +++ b/clang/test/CodeGenSYCL/reqd-sub-group-size.cpp @@ -14,6 +14,12 @@ class Functor { } }; +template +class Functor5 { +public: + [[cl::intel_reqd_sub_group_size(SIZE)]] void operator()() {} +}; + template __attribute__((sycl_kernel)) void kernel(Func kernelFunc) { kernelFunc(); @@ -28,12 +34,16 @@ void bar() { kernel( []() [[cl::intel_reqd_sub_group_size(4)]] {}); + + Functor5<2> f5; + kernel(f5); } // CHECK: define spir_kernel void @{{.*}}kernel_name1() {{.*}} !intel_reqd_sub_group_size ![[SGSIZE16:[0-9]+]] // CHECK: define spir_kernel void @{{.*}}kernel_name2() {{.*}} !intel_reqd_sub_group_size ![[SGSIZE8:[0-9]+]] // CHECK: define spir_kernel void @{{.*}}kernel_name3() {{.*}} !intel_reqd_sub_group_size ![[SGSIZE4:[0-9]+]] +// CHECK: define spir_kernel void @{{.*}}kernel_name4() {{.*}} !intel_reqd_sub_group_size ![[SGSIZE2:[0-9]+]] // CHECK: ![[SGSIZE16]] = !{i32 16} // CHECK: ![[SGSIZE8]] = !{i32 8} // CHECK: ![[SGSIZE4]] = !{i32 4} - +// CHECK: ![[SGSIZE2]] = !{i32 2} diff --git a/clang/test/SemaOpenCL/invalid-kernel-attrs.cl b/clang/test/SemaOpenCL/invalid-kernel-attrs.cl index daa8fa07f68dd..cc68fe41e5416 100644 --- a/clang/test/SemaOpenCL/invalid-kernel-attrs.cl +++ b/clang/test/SemaOpenCL/invalid-kernel-attrs.cl @@ -35,8 +35,11 @@ kernel __attribute__((reqd_work_group_size(1,0,2))) void kernel12(){} // expecte kernel __attribute__((reqd_work_group_size(0,1,2))) void kernel13(){} // expected-error {{'reqd_work_group_size' attribute must be greater than 0}} __attribute__((intel_reqd_sub_group_size(8))) void kernel14(){} // expected-error {{attribute 'intel_reqd_sub_group_size' can only be applied to an OpenCL kernel}} -kernel __attribute__((intel_reqd_sub_group_size(0))) void kernel15(){} // expected-error {{'intel_reqd_sub_group_size' attribute must be greater than 0}} -kernel __attribute__((intel_reqd_sub_group_size(8))) __attribute__((intel_reqd_sub_group_size(16))) void kernel16() {} //expected-warning{{attribute 'intel_reqd_sub_group_size' is already applied with different parameters}} +kernel __attribute__((intel_reqd_sub_group_size(0))) void kernel15() {} // expected-error {{'intel_reqd_sub_group_size' attribute requires a positive integral compile time constant expression}} + +kernel __attribute__((intel_reqd_sub_group_size(-1))) void kernel16() {} // expected-error {{'intel_reqd_sub_group_size' attribute requires a positive integral compile time constant expression}} + +kernel __attribute__((intel_reqd_sub_group_size(8))) __attribute__((intel_reqd_sub_group_size(16))) void kernel17() {} //expected-warning{{attribute 'intel_reqd_sub_group_size' is already applied with different parameters}} __kernel __attribute__((work_group_size_hint(8,-16,32))) void neg1() {} //expected-error{{'work_group_size_hint' attribute requires a non-negative integral compile time constant expression}} __kernel __attribute__((reqd_work_group_size(8,16,-32))) void neg2(){} // expected-error{{'reqd_work_group_size' attribute requires a non-negative integral compile time constant expression}} diff --git a/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp b/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp index 1e8298f27d5b3..76dfcb6a8d099 100644 --- a/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp +++ b/clang/test/SemaSYCL/reqd-sub-group-size-device.cpp @@ -49,8 +49,11 @@ void bar() { } // CHECK: FunctionDecl {{.*}} {{.*}}kernel_name1 -// CHECK: IntelReqdSubGroupSizeAttr {{.*}} 16 +// CHECK: IntelReqdSubGroupSizeAttr {{.*}} +// CHECK-NEXT: IntegerLiteral{{.*}}16{{$}} // CHECK: FunctionDecl {{.*}} {{.*}}kernel_name2 -// CHECK: IntelReqdSubGroupSizeAttr {{.*}} 4 +// CHECK: IntelReqdSubGroupSizeAttr {{.*}} +// CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // CHECK: FunctionDecl {{.*}} {{.*}}kernel_name5 -// CHECK: IntelReqdSubGroupSizeAttr {{.*}} 2 +// CHECK: IntelReqdSubGroupSizeAttr {{.*}} +// CHECK-NEXT: IntegerLiteral{{.*}}2{{$}} diff --git a/clang/test/SemaSYCL/sycl-device-reqd-sub-group-size-template.cpp b/clang/test/SemaSYCL/sycl-device-reqd-sub-group-size-template.cpp new file mode 100644 index 0000000000000..4f68326b8a485 --- /dev/null +++ b/clang/test/SemaSYCL/sycl-device-reqd-sub-group-size-template.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -ast-dump -verify -pedantic %s | FileCheck %s + +// Test that checkes template parameter support for 'intel_reqd_sub_group_size' attribute on sycl device. + +template +class KernelFunctor { +public: + //expected-error@+1{{'intel_reqd_sub_group_size' attribute requires a positive integral compile time constant expression}} + [[cl::intel_reqd_sub_group_size(SIZE)]] void operator()() {} +}; + +int main() { + //expected-note@+1{{in instantiation of template class 'KernelFunctor<-1>' requested here}} + KernelFunctor<-1>(); + // no error expected + KernelFunctor<10>(); +} + +// CHECK: ClassTemplateDecl {{.*}} {{.*}} KernelFunctor +// CHECK: ClassTemplateSpecializationDecl {{.*}} {{.*}} class KernelFunctor definition +// CHECK: CXXRecordDecl {{.*}} {{.*}} implicit class KernelFunctor +// CHECK: IntelReqdSubGroupSizeAttr {{.*}} +// CHECK: SubstNonTypeTemplateParmExpr {{.*}} +// CHECK-NEXT: IntegerLiteral{{.*}}10{{$}}