From 80491c3872a54d52c612bb3167eee5256d8d82be Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Mon, 9 Sep 2024 09:21:25 -0700 Subject: [PATCH 01/16] [clang][SYCL] Allow structs as free function kernel arguments --- clang/lib/Sema/SemaSYCL.cpp | 141 ++++++++++++++---- sycl/a.out | Bin 0 -> 280776 bytes .../free_function_kernels.cpp | 59 ++++++++ sycl/test/extensions/free_function_errors.cpp | 2 - 4 files changed, 175 insertions(+), 27 deletions(-) create mode 100755 sycl/a.out diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d0030036aacf8..26f094af1dbb3 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1263,6 +1263,12 @@ class KernelObjVisitor { std::initializer_list{(result = result && tn(BD, BDTy), 0)...}; return result; } + template + bool handleField(ParmVarDecl *PD, QualType PDTy, Tn &&... tn) { + bool result = true; + std::initializer_list{(result = result && tn(PD, PDTy), 0)...}; + return result; + } // This definition using std::bind is necessary because of a gcc 7.x bug. #define KF_FOR_EACH(FUNC, Item, Qt) \ @@ -1443,9 +1449,12 @@ class KernelObjVisitor { HandlerTys &...Handlers) { if (isSyclSpecialType(ParamTy, SemaSYCLRef)) KP_FOR_EACH(handleOtherType, Param, ParamTy); - else if (ParamTy->isStructureOrClassType()) - KP_FOR_EACH(handleOtherType, Param, ParamTy); - else if (ParamTy->isUnionType()) + else if (ParamTy->isStructureOrClassType()) { + if (KF_FOR_EACH(handleStructType, Param, ParamTy)) { + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + visitRecord(RD, Param, RD, ParamTy, Handlers...); + } + } else if (ParamTy->isUnionType()) KP_FOR_EACH(handleOtherType, Param, ParamTy); else if (ParamTy->isReferenceType()) KP_FOR_EACH(handleOtherType, Param, ParamTy); @@ -1957,8 +1966,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleStructType(ParmVarDecl *PD, QualType ParamTy) final { - Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; - IsInvalid = true; + // TODO check requirements defined by the spec here. return isValid(); } @@ -2037,14 +2045,12 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + ++StructFieldDepth; return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + --StructFieldDepth; return true; } @@ -2162,8 +2168,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool handlePointerType(ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + PointerStack.back() = targetRequiresNewType(SemaSYCLRef.getASTContext()); return true; } @@ -2194,8 +2199,8 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + CollectionStack.push_back(false); + PointerStack.push_back(false); return true; } @@ -2221,10 +2226,22 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { return true; } - bool leaveStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { - // TODO - unsupportedFreeFunctionParamType(); + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + assert(RD && "should not be null."); + if (CollectionStack.pop_back_val()) { + if (!RD->hasAttr()) + RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( + SemaSYCLRef.getASTContext())); + CollectionStack.back() = true; + PointerStack.pop_back(); + } else if (PointerStack.pop_back_val()) { + PointerStack.back() = true; + if (!RD->hasAttr()) + RD->addAttr(SYCLGenerateNewTypeAttr::CreateImplicit( + SemaSYCLRef.getASTContext())); + } return true; } @@ -2974,8 +2991,15 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) final { - // TODO - unsupportedFreeFunctionParamType(); + // This is a field which should not be decomposed. + CXXRecordDecl *FieldRecordDecl = ParamTy->getAsCXXRecordDecl(); + assert(FieldRecordDecl && "Type must be a C++ record type"); + // Check if we need to generate a new type for this record, + // i.e. this record contains pointers. + if (FieldRecordDecl->hasAttr()) + addParam(PD, GenerateNewRecordType(FieldRecordDecl)); + else + addParam(PD, ParamTy); return true; } @@ -3204,7 +3228,7 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { // TODO - unsupportedFreeFunctionParamType(); + addParam(ParamTy); return true; } @@ -4212,6 +4236,59 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return DRE; } + Expr *createGetAddressOf(Expr *E) { + return UnaryOperator::Create( + SemaSYCLRef.getASTContext(), E, UO_AddrOf, + SemaSYCLRef.getASTContext().getPointerType(E->getType()), VK_PRValue, + OK_Ordinary, SourceLocation(), false, + SemaSYCLRef.SemaRef.CurFPFeatureOverrides()); + } + + Expr *createDerefOp(Expr *E) { + return UnaryOperator::Create(SemaSYCLRef.getASTContext(), E, UO_Deref, + E->getType()->getPointeeType(), VK_LValue, + OK_Ordinary, SourceLocation(), false, + SemaSYCLRef.SemaRef.CurFPFeatureOverrides()); + } + + Expr *createReinterpretCastExpr(Expr *E, QualType To) { + return CXXReinterpretCastExpr::Create( + SemaSYCLRef.getASTContext(), To, VK_PRValue, CK_BitCast, E, + /*Path=*/nullptr, + SemaSYCLRef.getASTContext().getTrivialTypeSourceInfo(To), + SourceLocation(), SourceLocation(), SourceRange()); + } + + // TODO think about the name here + Expr *createReferenceToLocalStructCopy(ParmVarDecl *OrigFunctionParameter) { + ParmVarDecl *FreeFunctionParameter = + DeclCreator.getParamVarDeclsForCurrentField()[0]; + + QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); + Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( + FreeFunctionParameter, FreeFunctionParamType, VK_LValue, + FreeFunctionSrcLoc); + DRE = SemaSYCLRef.SemaRef.DefaultLvalueConversion(DRE).get(); + + // VarDecl *VD = createObjClone(S.getASTContext(), DC.getKernelDecl(), Obj); + assert(OrigFunctionParameter && "no parameter?"); + + CXXRecordDecl *RD = OrigFunctionParameter->getType()->getAsCXXRecordDecl(); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + SemaSYCLRef.getASTContext(), OrigFunctionParameter); + + if (RD->hasAttr()) { + DRE = createReinterpretCastExpr( + createGetAddressOf(DRE), SemaSYCLRef.getASTContext().getPointerType( + OrigFunctionParameter->getType())); + DRE = createDerefOp(DRE); + } + + ExprResult ArgE = SemaSYCLRef.SemaRef.PerformCopyInitialization( + Entity, SourceLocation(), DRE, false, false); + return ArgE.getAs(); + } + // For a free function such as: // void f(int i, int* p, struct Simple S) { ... } // @@ -4299,10 +4376,10 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + Expr *TempCopy = createReferenceToLocalStructCopy(PD); + ArgExprs.push_back(TempCopy); return true; } @@ -4589,7 +4666,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { // TODO - unsupportedFreeFunctionParamType(); + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); return true; } @@ -5435,6 +5512,7 @@ void SemaSYCL::MarkDevices() { void SemaSYCL::ProcessFreeFunction(FunctionDecl *FD) { if (isFreeFunction(*this, FD)) { + SyclKernelDecompMarker DecompMarker(*this); SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); @@ -5443,7 +5521,8 @@ void SemaSYCL::ProcessFreeFunction(FunctionDecl *FD) { DiagnosingSYCLKernel = true; // Check parameters of free function. - Visitor.VisitFunctionParameters(FD, FieldChecker, UnionChecker); + Visitor.VisitFunctionParameters(FD, FieldChecker, UnionChecker, + DecompMarker); DiagnosingSYCLKernel = false; @@ -5889,6 +5968,14 @@ class SYCLFwdDeclEmitter void VisitPackTemplateArgument(const TemplateArgument &TA) { VisitTemplateArgs(TA.getPackAsArray()); } + + void VisitFunctionProtoType(const FunctionProtoType *T) { + for (const auto Ty : T->getParamTypes()) + Visit(Ty.getCanonicalType()); + // So far this visitor method is only used for free function kernels whose + // return type is void anyway, so it is not visited. Otherwise, add if + // required. + } }; class SYCLKernelNameTypePrinter @@ -6325,10 +6412,14 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { for (const KernelDesc &K : KernelDescs) { if (!isFreeFunction(S, K.SyclKernel)) continue; - ++FreeFunctionCount; // Generate forward declaration for free function. O << "\n// Definition of " << K.Name << " as a free function kernel\n"; + + O << "// Forward declarations of kernel argument types:\n"; + FwdDeclEmitter.Visit(K.SyclKernel->getType()); + O << "\n"; + if (K.SyclKernel->getLanguageLinkage() == CLanguageLinkage) O << "extern \"C\" "; std::string ParmList; diff --git a/sycl/a.out b/sycl/a.out new file mode 100755 index 0000000000000000000000000000000000000000..ce6822b5bf78224336cce3e29193ed2aaef072a9 GIT binary patch literal 280776 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 +void ff_4(KArg Arg) { + int(&ptr2D)[4][4] = *reinterpret_cast(Arg.ptr); + nd_item<2> Item = ext::oneapi::this_work_item::get_nd_item<2>(); + id<2> GId = Item.get_global_id(); + id<2> LId = Item.get_local_id(); + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + Arg.start; +} + +bool test_4(queue Queue) { + constexpr int Range = 16; + int *usmPtr = malloc_shared(Range, Queue); + int value = 55; + int Result[Range] = {55, 56, 55, 56, 56, 57, 56, 57, + 55, 56, 55, 56, 56, 57, 56, 57}; + nd_range<2> R2{range<2>{4, 4}, range<2>{2, 2}}; + + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.parallel_for(R2, [=](nd_item<2> Item) { + int(&ptr2D)[4][4] = *reinterpret_cast(usmPtr); + id<2> GId = Item.get_global_id(); + id<2> LId = Item.get_local_id(); + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + value; + }); + }); + Queue.wait(); + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 4a: " << (PassA ? "PASS" : "FAIL") << std::endl; + + bool PassB = false; +#ifndef __SYCL_DEVICE_ONLY__ + kernel_bundle Bundle = + get_kernel_bundle(Queue.get_context()); + kernel_id Kernel_id = ext::oneapi::experimental::get_kernel_id<( + void (*)(KArg))ff_4>(); + kernel Kernel = Bundle.get_kernel(Kernel_id); + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.set_arg(0, KArg(usmPtr, value)); + Handler.parallel_for(R2, Kernel); + }); + Queue.wait(); + PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 4b: " << (PassB ? "PASS" : "FAIL") << std::endl; + + free(usmPtr, Queue); +#endif + return PassA && PassB; +} + int main() { queue Queue; @@ -265,6 +323,7 @@ int main() { Pass &= test_1(Queue); Pass &= test_2(Queue); Pass &= test_3(Queue); + Pass &= test_4(Queue); return Pass ? 0 : 1; } diff --git a/sycl/test/extensions/free_function_errors.cpp b/sycl/test/extensions/free_function_errors.cpp index 344bf17bdcc32..1838ec9ec072e 100755 --- a/sycl/test/extensions/free_function_errors.cpp +++ b/sycl/test/extensions/free_function_errors.cpp @@ -25,7 +25,6 @@ union U { using accType = accessor; -// expected-error@+3 {{'struct S' cannot be used as the type of a kernel parameter}} SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::single_task_kernel)) void ff(struct S s) {} @@ -40,7 +39,6 @@ SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::single_task_kernel)) void ff(accType acc) {} -// expected-error@+3 {{'std::array' cannot be used as the type of a kernel parameter}} SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::single_task_kernel)) void ff(std::array a) {} From 3fbb50c5651a5eb75dcaba8e9a67dc1cbfaf7a46 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 02:12:11 -0700 Subject: [PATCH 02/16] Add AST test --- .../SemaSYCL/free_function_kernel_params.cpp | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 6f73d6f172aa6..758a4fcc6b32a 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -ast-dump \ // RUN: %s -o - | FileCheck %s // This test checks parameter rewriting for free functions with parameters -// of type scalar and pointer. +// of type scalar, pointer and non-decomposed struct. #include "sycl.hpp" @@ -55,3 +55,119 @@ template void ff_3(int* ptr, int start, int end); // CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_start' 'int' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' // CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_end' 'int' + +struct NoPointers { + int f; +}; + +struct Pointers { + int * a; + float * b; +}; + +struct Agg { + NoPointers F1; + int F2; + int *F3; + Pointers F4; +}; + +struct Agg1 { + NoPointers F1; + int F2; +}; + +struct Derived : Agg { + int a; +}; + +class Derived1 : Pointers { + int a; +}; + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_4(NoPointers S1, Pointers S2, Agg S3) { +} +// CHECK: FunctionDecl {{.*}}__sycl_kernel{{.*}}'void (NoPointers, __generated_Pointers, __generated_Agg)' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S1 'NoPointers' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S2 '__generated_Pointers' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S3 '__generated_Agg' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CallExpr +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(NoPointers, Pointers, Agg)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (NoPointers, Pointers, Agg)' lvalue Function {{.*}} 'ff_4' 'void (NoPointers, Pointers, Agg)' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'NoPointers' 'void (const NoPointers &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const NoPointers' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'NoPointers' lvalue ParmVar {{.*}} '__arg_S1' 'NoPointers' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Pointers' 'void (const Pointers &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Pointers' lvalue +// CHECK-NEXT: UnaryOperator {{.*}} 'Pointers' lvalue prefix '*' cannot overflow +// CHECK-NEXT: CXXReinterpretCastExpr {{.*}} 'Pointers *' reinterpret_cast +// CHECK-NEXT: UnaryOperator {{.*}} '__generated_Pointers *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr {{.*}} '__generated_Pointers' lvalue ParmVar {{.*}} '__arg_S2' '__generated_Pointers' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Agg' 'void (const Agg &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Agg' lvalue +// CHECK-NEXT: UnaryOperator {{.*}} 'Agg' lvalue prefix '*' cannot overflow +// CHECK-NEXT: CXXReinterpretCastExpr {{.*}} 'Agg *' reinterpret_cast +// CHECK-NEXT: UnaryOperator {{.*}} '__generated_Agg *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr {{.*}} '__generated_Agg' lvalue ParmVar {{.*}} '__arg_S3' '__generated_Agg' + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_5(Agg1 S1, Derived S2, Derived1 S3) { +} +// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_54Agg17Derived8Derived1 'void (Agg1, __generated_Derived, __generated_Derived1)' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S1 'Agg1' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S2 '__generated_Derived' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S3 '__generated_Derived1' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CallExpr +// CHECK-NEXT: ImplicitCastExpr{{.*}}'void (*)(Agg1, Derived, Derived1)' +// CHECK-NEXT: DeclRefExpr{{.*}}'void (Agg1, Derived, Derived1)' lvalue Function {{.*}} 'ff_5' 'void (Agg1, Derived, Derived1)' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Agg1' 'void (const Agg1 &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Agg1' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'Agg1' lvalue ParmVar {{.*}} '__arg_S1' 'Agg1' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Derived' 'void (const Derived &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Derived' lvalue +// CHECK-NEXT: UnaryOperator {{.*}} 'Derived' lvalue prefix '*' cannot overflow +// CHECK-NEXT: CXXReinterpretCastExpr {{.*}} 'Derived *' reinterpret_cast +// CHECK-NEXT: UnaryOperator {{.*}} '__generated_Derived *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr {{.*}} '__generated_Derived' lvalue ParmVar {{.*}} '__arg_S2' '__generated_Derived' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Derived1' 'void (const Derived1 &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Derived1' lvalue +// CHECK-NEXT: UnaryOperator {{.*}} 'Derived1' lvalue prefix '*' cannot overflow +// CHECK-NEXT: CXXReinterpretCastExpr {{.*}} 'Derived1 *' reinterpret_cast +// CHECK-NEXT: UnaryOperator {{.*}} '__generated_Derived1 *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr {{.*}} '__generated_Derived1' lvalue ParmVar {{.*}} '__arg_S3' '__generated_Derived1' + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] + void ff_6(T1 S1, T2 S2, int end) { +} + +// Explicit instantiation. +template void ff_6(Agg S1, Derived1 S2, int); +// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_6I3Agg8Derived1EvT_T0_i 'void (__generated_Agg, __generated_Derived1, int)' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S1 '__generated_Agg' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S2 '__generated_Derived1' +// CHECK-NEXT: ParmVarDecl {{.*}} used __arg_end 'int' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(Agg, Derived1, int)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (Agg, Derived1, int)' lvalue Function {{.*}} 'ff_6' 'void (Agg, Derived1, int)' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Agg' 'void (const Agg &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Agg' lvalue +// CHECK-NEXT: UnaryOperator {{.*}} 'Agg' lvalue prefix '*' cannot overflow +// CHECK-NEXT: CXXReinterpretCastExpr {{.*}} 'Agg *' reinterpret_cast +// CHECK-NEXT: UnaryOperator {{.*}} '__generated_Agg *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr {{.*}} '__generated_Agg' lvalue ParmVar {{.*}} '__arg_S1' '__generated_Agg' +// CHECK-NEXT: CXXConstructExpr {{.*}} 'Derived1' 'void (const Derived1 &) noexcept' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const Derived1' lvalue +// CHECK-NEXT: UnaryOperator {{.*}} 'Derived1' lvalue prefix '*' cannot overflow +// CHECK-NEXT: CXXReinterpretCastExpr {{.*}} 'Derived1 *' reinterpret_cast +// CHECK-NEXT: UnaryOperator {{.*}} '__generated_Derived1 *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr {{.*}} '__generated_Derived1' lvalue ParmVar {{.*}} '__arg_S2' '__generated_Derived1' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_end' 'int' From 3e5332ea71aa0d2f02e1935aea6b128d9a1c3113 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 02:45:19 -0700 Subject: [PATCH 03/16] Add test for integration header generation, extend e2e test --- clang/lib/Sema/SemaSYCL.cpp | 19 ++- .../CodeGenSYCL/free_function_int_header.cpp | 122 ++++++++++++++++-- sycl/a.out | Bin 280776 -> 0 bytes .../free_function_kernels.cpp | 57 ++++++++ 4 files changed, 185 insertions(+), 13 deletions(-) delete mode 100755 sycl/a.out diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 26f094af1dbb3..7e71466f46c64 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1966,7 +1966,13 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleStructType(ParmVarDecl *PD, QualType ParamTy) final { - // TODO check requirements defined by the spec here. + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + if (RD->isLambda()) { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) + << ParamTy; + IsInvalid = true; + } + // TODO check that the type is defined at namespace scope. return isValid(); } @@ -2045,12 +2051,16 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ++StructFieldDepth; + // TODO manipulate struct depth once special types are supported for free + // function kernels. + // ++StructFieldDepth; return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - --StructFieldDepth; + // TODO manipulate struct depth once special types are supported for free + // function kernels. + // --StructFieldDepth; return true; } @@ -6416,7 +6426,8 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { // Generate forward declaration for free function. O << "\n// Definition of " << K.Name << " as a free function kernel\n"; - O << "// Forward declarations of kernel argument types:\n"; + O << "\n"; + O << "// Forward declarations of kernel and its argument types:\n"; FwdDeclEmitter.Visit(K.SyclKernel->getType()); O << "\n"; diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index ab61b06d66728..147b4ff903418 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown -sycl-std=2020 -fsycl-int-header=%t.h %s // RUN: FileCheck -input-file=%t.h %s // -// This test checks integration header contents for free functions with scalar -// and pointer parameters. +// This test checks integration header contents for free functions with scalar, +// pointer and non-decomposed struct parameters. #include "mock_properties.hpp" #include "sycl.hpp" @@ -43,12 +43,47 @@ template <> void ff_3(double *ptr, double start, double end) { ptr[i] = end; } +struct NoPointers { + int f; +}; + +struct Pointers { + int * a; + float * b; +}; + +struct Agg { + NoPointers F1; + int F2; + int *F3; + Pointers F4; +}; + +struct Derived : Agg { + int a; +}; + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_4(NoPointers S1, Pointers S2, Agg S3) { +} + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] + void ff_6(T1 S1, T2 S2, int end) { +} + +template void ff_6(Agg S1, Derived S2, int); + // CHECK: const char* const kernel_names[] = { // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piiii // CHECK-NEXT: {{.*}}__sycl_kernel_ff_3IiEvPT_S0_S0_ // CHECK-NEXT: {{.*}}__sycl_kernel_ff_3IfEvPT_S0_S0_ // CHECK-NEXT: {{.*}}__sycl_kernel_ff_3IdEvPT_S0_S0_ +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_410NoPointers8Pointers3Agg +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_6I3Agg7DerivedEvT_T0_i // CHECK-NEXT: "" // CHECK-NEXT: }; @@ -79,11 +114,22 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 16 }, +// CHECK: //--- _Z18__sycl_kernel_ff_410NoPointers8Pointers3Agg +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 16, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 32, 20 }, + +// CHECK: //--- _Z18__sycl_kernel_ff_6I3Agg7DerivedEvT_T0_i +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 32, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 40, 32 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 72 }, + // CHECK: { kernel_param_kind_t::kind_invalid, -987654321, -987654321 }, // CHECK-NEXT: }; // CHECK: Definition of _Z18__sycl_kernel_ff_2Piii as a free function kernel -// CHECK-NEXT: void ff_2(int *ptr, int start, int end); +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: void ff_2(int *ptr, int start, int end); // CHECK-NEXT: static constexpr auto __sycl_shim1() { // CHECK-NEXT: return (void (*)(int *, int, int))ff_2; // CHECK-NEXT: } @@ -99,7 +145,8 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: } // CHECK: Definition of _Z18__sycl_kernel_ff_2Piiii as a free function kernel -// CHECK-NEXT: void ff_2(int *ptr, int start, int end, int value); +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: void ff_2(int *ptr, int start, int end, int value); // CHECK-NEXT: static constexpr auto __sycl_shim2() { // CHECK-NEXT: return (void (*)(int *, int, int, int))ff_2; // CHECK-NEXT: } @@ -115,7 +162,8 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: } // CHECK: Definition of _Z18__sycl_kernel_ff_3IiEvPT_S0_S0_ as a free function kernel -// CHECK-NEXT: template void ff_3(T *ptr, T start, T end); +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: template void ff_3(T *ptr, T start, T end); // CHECK-NEXT: static constexpr auto __sycl_shim3() { // CHECK-NEXT: return (void (*)(int *, int, int))ff_3; // CHECK-NEXT: } @@ -129,9 +177,10 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; // CHECK-NEXT: } - + // CHECK: Definition of _Z18__sycl_kernel_ff_3IfEvPT_S0_S0_ as a free function kernel -// CHECK-NEXT: template void ff_3(T *ptr, T start, T end); +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: template void ff_3(T *ptr, T start, T end); // CHECK-NEXT: static constexpr auto __sycl_shim4() { // CHECK-NEXT: return (void (*)(float *, float, float))ff_3; // CHECK-NEXT: } @@ -147,7 +196,8 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: } // CHECK: Definition of _Z18__sycl_kernel_ff_3IdEvPT_S0_S0_ as a free function kernel -// CHECK-NEXT: template void ff_3(T *ptr, T start, T end); +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: template void ff_3(T *ptr, T start, T end); // CHECK-NEXT: static constexpr auto __sycl_shim5() { // CHECK-NEXT: return (void (*)(double *, double, double))ff_3; // CHECK-NEXT: } @@ -162,6 +212,44 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: }; // CHECK-NEXT: } +// CHECK: Definition of _Z18__sycl_kernel_ff_410NoPointers8Pointers3Agg as a free function kernel +// CHECK: Forward declarations of kernel and its argument types: +// CHECK-NEXT: struct NoPointers; +// CHECK-NEXT: struct Pointers; +// CHECK-NEXT: struct Agg; +// CHECK: void ff_4(NoPointers S1, Pointers S2, Agg S3); +// CHECK-NEXT: static constexpr auto __sycl_shim6() { +// CHECK-NEXT: return (void (*)(struct NoPointers, struct Pointers, struct Agg))ff_4; +// CHECK-NEXT: } +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim6()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim6()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: } + +// CHECK: Definition of _Z18__sycl_kernel_ff_6I3Agg7DerivedEvT_T0_i as a free function kernel +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: struct Derived; +// CHECK: template void ff_6(T1 S1, T2 S2, int end); +// CHECK-NEXT: static constexpr auto __sycl_shim7() { +// CHECK-NEXT: return (void (*)(struct Agg, struct Derived, int))ff_6; +// CHECK-NEXT: } +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim7()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim7()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: } + // CHECK: #include // CHECK: Definition of kernel_id of _Z18__sycl_kernel_ff_2Piii @@ -201,5 +289,21 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: template <> // CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim5()>() { // CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z18__sycl_kernel_ff_3IdEvPT_S0_S0_"}); -// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } + +// CHECK: Definition of kernel_id of _Z18__sycl_kernel_ff_410NoPointers8Pointers3Agg +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim6()>() { +// CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z18__sycl_kernel_ff_410NoPointers8Pointers3Agg"}); +// CHECK-NEXT: } +// CHECK-NEXT: } + +// CHECK: Definition of kernel_id of _Z18__sycl_kernel_ff_6I3Agg7DerivedEvT_T0_i +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim7()>() { +// CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z18__sycl_kernel_ff_6I3Agg7DerivedEvT_T0_i"}); +// CHECK-NEXT: } // CHECK-NEXT: } diff --git a/sycl/a.out b/sycl/a.out deleted file mode 100755 index ce6822b5bf78224336cce3e29193ed2aaef072a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 280776 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 +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( + (ext::oneapi::experimental::nd_range_kernel<2>)) +void ff_5(T Arg) { + int(&ptr2D)[4][4] = *reinterpret_cast(Arg.ptr); + nd_item<2> Item = ext::oneapi::this_work_item::get_nd_item<2>(); + id<2> GId = Item.get_global_id(); + id<2> LId = Item.get_local_id(); + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + Arg.start; +} + +// Explicit instantiation with "KArg". +template void ff_5(KArg Arg); + +bool test_5(queue Queue) { + constexpr int Range = 16; + int *usmPtr = malloc_shared(Range, Queue); + int value = 55; + int Result[Range] = {55, 56, 55, 56, 56, 57, 56, 57, + 55, 56, 55, 56, 56, 57, 56, 57}; + nd_range<2> R2{range<2>{4, 4}, range<2>{2, 2}}; + + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.parallel_for(R2, [=](nd_item<2> Item) { + int(&ptr2D)[4][4] = *reinterpret_cast(usmPtr); + id<2> GId = Item.get_global_id(); + id<2> LId = Item.get_local_id(); + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + value; + }); + }); + Queue.wait(); + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 5a: " << (PassA ? "PASS" : "FAIL") << std::endl; + + bool PassB = false; +#ifndef __SYCL_DEVICE_ONLY__ + kernel_bundle Bundle = + get_kernel_bundle(Queue.get_context()); + kernel_id Kernel_id = ext::oneapi::experimental::get_kernel_id<( + void (*)(KArg))ff_5>(); + kernel Kernel = Bundle.get_kernel(Kernel_id); + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.set_arg(0, KArg(usmPtr, value)); + Handler.parallel_for(R2, Kernel); + }); + Queue.wait(); + PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 5b: " << (PassB ? "PASS" : "FAIL") << std::endl; + + free(usmPtr, Queue); +#endif + return PassA && PassB; +} + int main() { queue Queue; @@ -324,6 +380,7 @@ int main() { Pass &= test_2(Queue); Pass &= test_3(Queue); Pass &= test_4(Queue); + Pass &= test_5(Queue); return Pass ? 0 : 1; } From c8bf832c626d2735e9ef2d43785d5e1e1ea5b66d Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 03:34:54 -0700 Subject: [PATCH 04/16] Maybe fix test on win --- clang/test/SemaSYCL/free_function_kernel_params.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 758a4fcc6b32a..2de4f896a1513 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -117,7 +117,7 @@ __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void ff_5(Agg1 S1, Derived S2, Derived1 S3) { } -// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_54Agg17Derived8Derived1 'void (Agg1, __generated_Derived, __generated_Derived1)' +// CHECK: FunctionDecl {{.*}}__sycl_kernel{{.*}}'void (Agg1, __generated_Derived, __generated_Derived1)' // CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S1 'Agg1' // CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S2 '__generated_Derived' // CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S3 '__generated_Derived1' @@ -149,7 +149,7 @@ __attribute__((sycl_device)) // Explicit instantiation. template void ff_6(Agg S1, Derived1 S2, int); -// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_6I3Agg8Derived1EvT_T0_i 'void (__generated_Agg, __generated_Derived1, int)' +// CHECK: FunctionDecl {{.*}}__sycl_kernel{{.*}}'void (__generated_Agg, __generated_Derived1, int)' // CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S1 '__generated_Agg' // CHECK-NEXT: ParmVarDecl {{.*}} used __arg_S2 '__generated_Derived1' // CHECK-NEXT: ParmVarDecl {{.*}} used __arg_end 'int' From 95cfe1587849b3ebbdbc28f74929f144eb399d69 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 03:42:44 -0700 Subject: [PATCH 05/16] Clean up SemaSYCL --- clang/lib/Sema/SemaSYCL.cpp | 40 ++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 7e71466f46c64..e29d1a3bb17fa 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2209,7 +2209,9 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - CollectionStack.push_back(false); + // TODO handle decomposition once special type arguments are supported + // for free function kernels. + // CollectionStack.push_back(false); PointerStack.push_back(false); return true; } @@ -2240,13 +2242,15 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { QualType ParamTy) final { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); assert(RD && "should not be null."); - if (CollectionStack.pop_back_val()) { - if (!RD->hasAttr()) - RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( - SemaSYCLRef.getASTContext())); - CollectionStack.back() = true; - PointerStack.pop_back(); - } else if (PointerStack.pop_back_val()) { + // TODO handle decomposition once special type arguments are supported + // for free function kernels. + // if (CollectionStack.pop_back_val()) { + // if (!RD->hasAttr()) + // RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( + // SemaSYCLRef.getASTContext())); + // CollectionStack.back() = true; + // PointerStack.pop_back(); + if (PointerStack.pop_back_val()) { PointerStack.back() = true; if (!RD->hasAttr()) RD->addAttr(SYCLGenerateNewTypeAttr::CreateImplicit( @@ -4228,7 +4232,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // Creates a DeclRefExpr to the ParmVar that represents the current pointer // parameter. - Expr *createPointerParamReferenceExpr(QualType PointerTy, bool Wrapped) { + Expr *createPointerParamReferenceExpr(QualType PointerTy) { ParmVarDecl *FreeFunctionParameter = DeclCreator.getParamVarDeclsForCurrentField()[0]; @@ -4269,18 +4273,9 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SourceLocation(), SourceLocation(), SourceRange()); } - // TODO think about the name here - Expr *createReferenceToLocalStructCopy(ParmVarDecl *OrigFunctionParameter) { - ParmVarDecl *FreeFunctionParameter = - DeclCreator.getParamVarDeclsForCurrentField()[0]; + Expr *createStructTemporary(ParmVarDecl *OrigFunctionParameter) { + Expr *DRE = createParamReferenceExpr(); - QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); - Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - FreeFunctionParameter, FreeFunctionParamType, VK_LValue, - FreeFunctionSrcLoc); - DRE = SemaSYCLRef.SemaRef.DefaultLvalueConversion(DRE).get(); - - // VarDecl *VD = createObjClone(S.getASTContext(), DC.getKernelDecl(), Obj); assert(OrigFunctionParameter && "no parameter?"); CXXRecordDecl *RD = OrigFunctionParameter->getType()->getAsCXXRecordDecl(); @@ -4368,7 +4363,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { - Expr *PointerRef = createPointerParamReferenceExpr(ParamTy, false); + Expr *PointerRef = createPointerParamReferenceExpr(ParamTy); ArgExprs.push_back(PointerRef); return true; } @@ -4388,7 +4383,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType) final { - Expr *TempCopy = createReferenceToLocalStructCopy(PD); + Expr *TempCopy = createStructTemporary(PD); ArgExprs.push_back(TempCopy); return true; } @@ -4675,7 +4670,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { - // TODO addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); return true; } From 6d8a28f60a82d3ba129f3801c844a7b9ac38abb8 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 04:20:13 -0700 Subject: [PATCH 06/16] Diagnose bad struct kernel parameters --- clang/lib/Sema/SemaSYCL.cpp | 14 ++++++++- ...ee_function_kernel_params_restrictions.cpp | 31 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100755 clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e29d1a3bb17fa..6d11fc97cfa31 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1967,12 +1967,24 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { bool handleStructType(ParmVarDecl *PD, QualType ParamTy) final { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + // For free functions all struct/class kernel arguments are forward declared + // in integration header, that adds additional restrictions for kernel + // arguments. + // Lambdas are not forward declarable. So, diagnose them properly. if (RD->isLambda()) { Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; IsInvalid = true; + return isValid(); + } + + // Check that the type is defined at namespace scope. + const DeclContext *DeclCtx = RD->getDeclContext(); + if (!DeclCtx->isTranslationUnit() && !isa(DeclCtx)) { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) + << ParamTy; + IsInvalid = true; } - // TODO check that the type is defined at namespace scope. return isValid(); } diff --git a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp new file mode 100755 index 0000000000000..7ef2733d5eb4b --- /dev/null +++ b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -verify %s +// This test checks that compiler correctly diagnoses violations of restrictions +// applied to free function kernel parameters defined by the spec. + +#include "sycl.hpp" + +class Outer { +public: + class DefinedWithinAClass { + int f; + }; +}; + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_4(Outer::DefinedWithinAClass S1) { // expected-error {{'Outer::DefinedWithinAClass' cannot be used as the type of a kernel parameter}} +} + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] + void ff_6(T1 S1) { // expected-error 2{{cannot be used as the type of a kernel parameter}} +} + +void bar() { + ff_6([=](){}); +} + +auto Glob = [](int P){ return P + 1;}; + +template void ff_6(typeof(Glob) S1); From 7b17d82ec495a1db043ef34e9aa0697c9073360d Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 05:10:50 -0700 Subject: [PATCH 07/16] Fix format --- clang/lib/Sema/SemaSYCL.cpp | 2 +- sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 6d11fc97cfa31..d2de07fc9541f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1264,7 +1264,7 @@ class KernelObjVisitor { return result; } template - bool handleField(ParmVarDecl *PD, QualType PDTy, Tn &&... tn) { + bool handleField(ParmVarDecl *PD, QualType PDTy, Tn &&...tn) { bool result = true; std::initializer_list{(result = result && tn(PD, PDTy), 0)...}; return result; diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 76e7964fa02e6..c260a281f596c 100644 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -298,8 +298,8 @@ bool test_4(queue Queue) { #ifndef __SYCL_DEVICE_ONLY__ kernel_bundle Bundle = get_kernel_bundle(Queue.get_context()); - kernel_id Kernel_id = ext::oneapi::experimental::get_kernel_id<( - void (*)(KArg))ff_4>(); + kernel_id Kernel_id = + ext::oneapi::experimental::get_kernel_id<(void (*)(KArg))ff_4>(); kernel Kernel = Bundle.get_kernel(Kernel_id); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { @@ -354,8 +354,8 @@ bool test_5(queue Queue) { #ifndef __SYCL_DEVICE_ONLY__ kernel_bundle Bundle = get_kernel_bundle(Queue.get_context()); - kernel_id Kernel_id = ext::oneapi::experimental::get_kernel_id<( - void (*)(KArg))ff_5>(); + kernel_id Kernel_id = + ext::oneapi::experimental::get_kernel_id<(void (*)(KArg))ff_5>(); kernel Kernel = Bundle.get_kernel(Kernel_id); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { From efcfc47ed96c18eaff3a334f81e83d2b6d0935ae Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 05:18:12 -0700 Subject: [PATCH 08/16] Remove obsolete TODO --- clang/lib/Sema/SemaSYCL.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d2de07fc9541f..0e9975a870c29 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -3253,7 +3253,6 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { - // TODO addParam(ParamTy); return true; } From 4e293dae0f1fd712e7569b60456088e0f5a0999e Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Tue, 10 Sep 2024 05:18:32 -0700 Subject: [PATCH 09/16] Add codegen test to see address spaces --- .../free_function_kernel_params.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 clang/test/CodeGenSYCL/free_function_kernel_params.cpp diff --git a/clang/test/CodeGenSYCL/free_function_kernel_params.cpp b/clang/test/CodeGenSYCL/free_function_kernel_params.cpp new file mode 100755 index 0000000000000..97a8d29b95bc2 --- /dev/null +++ b/clang/test/CodeGenSYCL/free_function_kernel_params.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -triple spir64 \ +// RUN: -emit-llvm %s -o - | FileCheck %s +// This test checks parameter IR generation for free functions with parameters +// of non-decomposed struct type. + +#include "sycl.hpp" + +struct NoPointers { + int f; +}; + +struct Pointers { + int * a; + float * b; +}; + +struct Agg { + NoPointers F1; + int F2; + int *F3; + Pointers F4; +}; + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_4(NoPointers S1, Pointers S2, Agg S3) { +} + +// CHECK: %struct.NoPointers = type { i32 } +// CHECK: %struct.Pointers = type { ptr addrspace(4), ptr addrspace(4) } +// CHECK: %struct.Agg = type { %struct.NoPointers, i32, ptr addrspace(4), %struct.Pointers } +// CHECK: %struct.__generated_Pointers = type { ptr addrspace(1), ptr addrspace(1) } +// CHECK: %struct.__generated_Agg = type { %struct.NoPointers, i32, ptr addrspace(1), %struct.__generated_Pointers.0 } +// CHECK: %struct.__generated_Pointers.0 = type { ptr addrspace(1), ptr addrspace(1) } +// CHECK: define dso_local spir_kernel void @{{.*}}__sycl_kernel{{.*}}(ptr noundef byval(%struct.NoPointers) align 4 %__arg_S1, ptr noundef byval(%struct.__generated_Pointers) align 8 %__arg_S2, ptr noundef byval(%struct.__generated_Agg) align 8 %__arg_S3) From 34524f43f1bc3686e68ab6bb803feddf06dbcdb3 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Wed, 11 Sep 2024 02:54:52 -0700 Subject: [PATCH 10/16] Incorportate review feedback --- clang/lib/Sema/SemaSYCL.cpp | 18 +++++++++++------- ...ree_function_kernel_params_restrictions.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 0e9975a870c29..b97f59f56266b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1452,7 +1452,7 @@ class KernelObjVisitor { else if (ParamTy->isStructureOrClassType()) { if (KF_FOR_EACH(handleStructType, Param, ParamTy)) { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); - visitRecord(RD, Param, RD, ParamTy, Handlers...); + visitRecord(nullptr, Param, RD, ParamTy, Handlers...); } } else if (ParamTy->isUnionType()) KP_FOR_EACH(handleOtherType, Param, ParamTy); @@ -1980,7 +1980,11 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { // Check that the type is defined at namespace scope. const DeclContext *DeclCtx = RD->getDeclContext(); - if (!DeclCtx->isTranslationUnit() && !isa(DeclCtx)) { + while (!DeclCtx->isTranslationUnit() && + (isa(DeclCtx) || isa(DeclCtx))) + DeclCtx = DeclCtx->getParent(); + + if (!DeclCtx->isTranslationUnit()) { Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; IsInvalid = true; @@ -3017,13 +3021,13 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) final { - // This is a field which should not be decomposed. - CXXRecordDecl *FieldRecordDecl = ParamTy->getAsCXXRecordDecl(); - assert(FieldRecordDecl && "Type must be a C++ record type"); + // This is a struct parameter which should not be decomposed. + CXXRecordDecl *ParamRecordDecl = ParamTy->getAsCXXRecordDecl(); + assert(ParamRecordDecl && "Type must be a C++ record type"); // Check if we need to generate a new type for this record, // i.e. this record contains pointers. - if (FieldRecordDecl->hasAttr()) - addParam(PD, GenerateNewRecordType(FieldRecordDecl)); + if (ParamRecordDecl->hasAttr()) + addParam(PD, GenerateNewRecordType(ParamRecordDecl)); else addParam(PD, ParamTy); return true; diff --git a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp index 7ef2733d5eb4b..a224fa782ee6d 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp @@ -29,3 +29,14 @@ void bar() { auto Glob = [](int P){ return P + 1;}; template void ff_6(typeof(Glob) S1); + +extern "C" { + struct A { + int a; + }; +} + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_5(A S1) { +} From dd52ed5deeb77913793e692062c7daa66ea0432a Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Thu, 12 Sep 2024 07:20:20 -0700 Subject: [PATCH 11/16] Cleanup --- clang/lib/Sema/SemaSYCL.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b97f59f56266b..919d847dd638a 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1263,12 +1263,6 @@ class KernelObjVisitor { std::initializer_list{(result = result && tn(BD, BDTy), 0)...}; return result; } - template - bool handleField(ParmVarDecl *PD, QualType PDTy, Tn &&...tn) { - bool result = true; - std::initializer_list{(result = result && tn(PD, PDTy), 0)...}; - return result; - } // This definition using std::bind is necessary because of a gcc 7.x bug. #define KF_FOR_EACH(FUNC, Item, Qt) \ @@ -1450,7 +1444,7 @@ class KernelObjVisitor { if (isSyclSpecialType(ParamTy, SemaSYCLRef)) KP_FOR_EACH(handleOtherType, Param, ParamTy); else if (ParamTy->isStructureOrClassType()) { - if (KF_FOR_EACH(handleStructType, Param, ParamTy)) { + if (KP_FOR_EACH(handleStructType, Param, ParamTy)) { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); visitRecord(nullptr, Param, RD, ParamTy, Handlers...); } From ef3ca91c24f96932ee7411e6da7becd92da4b824 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Thu, 19 Sep 2024 08:36:02 -0700 Subject: [PATCH 12/16] Diagnose special types in structs since they are not yet supported. --- clang/lib/Sema/SemaSYCL.cpp | 47 +++++++++++-------- ...ee_function_kernel_params_restrictions.cpp | 16 +++++++ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 919d847dd638a..0cdb841de7506 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2067,11 +2067,21 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType ParamTy) final { // TODO manipulate struct depth once special types are supported for free // function kernels. // --StructFieldDepth; - return true; + // TODO We don't yet support special types and therefore structs that + // require decomposition and leaving/entering. Diagnose for better user + // experience. + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + if (RD->hasAttr()) { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) + << ParamTy; + IsInvalid = true; + } + return isValid(); } bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &BS, @@ -2177,8 +2187,9 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + // TODO We don't support special types in free function kernel parameters, + // but track them to diagnose the case properly. + CollectionStack.back() = true; return true; } @@ -2219,9 +2230,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO handle decomposition once special type arguments are supported - // for free function kernels. - // CollectionStack.push_back(false); + CollectionStack.push_back(false); PointerStack.push_back(false); return true; } @@ -2252,15 +2261,13 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { QualType ParamTy) final { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); assert(RD && "should not be null."); - // TODO handle decomposition once special type arguments are supported - // for free function kernels. - // if (CollectionStack.pop_back_val()) { - // if (!RD->hasAttr()) - // RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( - // SemaSYCLRef.getASTContext())); - // CollectionStack.back() = true; - // PointerStack.pop_back(); - if (PointerStack.pop_back_val()) { + if (CollectionStack.pop_back_val()) { + if (!RD->hasAttr()) + RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( + SemaSYCLRef.getASTContext())); + CollectionStack.back() = true; + PointerStack.pop_back(); + } else if (PointerStack.pop_back_val()) { PointerStack.back() = true; if (!RD->hasAttr()) RD->addAttr(SYCLGenerateNewTypeAttr::CreateImplicit( @@ -2864,7 +2871,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO - unsupportedFreeFunctionParamType(); + // ++StructDepth; return true; } @@ -2875,7 +2882,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO - unsupportedFreeFunctionParamType(); + // --StructDepth; return true; } @@ -5534,8 +5541,8 @@ void SemaSYCL::ProcessFreeFunction(FunctionDecl *FD) { DiagnosingSYCLKernel = true; // Check parameters of free function. - Visitor.VisitFunctionParameters(FD, FieldChecker, UnionChecker, - DecompMarker); + Visitor.VisitFunctionParameters(FD, DecompMarker, FieldChecker, + UnionChecker); DiagnosingSYCLKernel = false; diff --git a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp index a224fa782ee6d..adfa1761fa607 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp @@ -40,3 +40,19 @@ __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void ff_5(A S1) { } + + + +struct StructWithAccessor { + sycl::accessor acc; + int *ptr; +}; + +struct Wrapper { + StructWithAccessor SWA; + +}; + +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_6(Wrapper S1) { // expected-error {{cannot be used as the type of a kernel parameter}} +} From 431a40572e9382aedcc79542072da9656bd1c954 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Thu, 19 Sep 2024 09:19:41 -0700 Subject: [PATCH 13/16] Rename createStructTemporary -> createCopyInitExpr --- clang/lib/Sema/SemaSYCL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 0cdb841de7506..e2f57c46a0d00 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4289,7 +4289,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SourceLocation(), SourceLocation(), SourceRange()); } - Expr *createStructTemporary(ParmVarDecl *OrigFunctionParameter) { + Expr *createCopyInitExpr(ParmVarDecl *OrigFunctionParameter) { Expr *DRE = createParamReferenceExpr(); assert(OrigFunctionParameter && "no parameter?"); @@ -4399,7 +4399,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType) final { - Expr *TempCopy = createStructTemporary(PD); + Expr *TempCopy = createCopyInitExpr(PD); ArgExprs.push_back(TempCopy); return true; } From 0b88367f2f67916a4aec0f73986fc080b8c2a984 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Fri, 20 Sep 2024 01:50:04 -0700 Subject: [PATCH 14/16] Improve diagnotic messages --- .../include/clang/Basic/DiagnosticSemaKinds.td | 8 ++++++++ clang/lib/Sema/SemaSYCL.cpp | 18 +++++++++++++++--- ...ree_function_kernel_params_restrictions.cpp | 9 ++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 856a8f676fa45..3e143c6ed9f76 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12414,6 +12414,14 @@ def err_sycl_kernel_incorrectly_named : Error< "'-fsycl-unnamed-lambda' to enable unnamed kernel lambdas" "}0">; +// SYCL free function kernels extension. +def err_bad_free_function_kernel_param_type : Error< + "%0 cannot be used as the type of a free function kernel parameter">; +def note_free_function_kernel_param_type_not_fwd_declarable : Note< + "%0 is not forward declarable">; +def note_free_function_kernel_param_type_not_supported : Note< + "%0 is not yet supported as free function kernel parameter">; + def err_sycl_kernel_not_function_object : Error<"kernel parameter must be a lambda or function object">; def err_sycl_restrict : Error< diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e2f57c46a0d00..e7ae688ef406b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1966,7 +1966,11 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { // arguments. // Lambdas are not forward declarable. So, diagnose them properly. if (RD->isLambda()) { - Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) + Diag.Report(PD->getLocation(), + diag::err_bad_free_function_kernel_param_type) + << ParamTy; + Diag.Report(PD->getLocation(), + diag::note_free_function_kernel_param_type_not_fwd_declarable) << ParamTy; IsInvalid = true; return isValid(); @@ -1979,7 +1983,11 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { DeclCtx = DeclCtx->getParent(); if (!DeclCtx->isTranslationUnit()) { - Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) + Diag.Report(PD->getLocation(), + diag::err_bad_free_function_kernel_param_type) + << ParamTy; + Diag.Report(PD->getLocation(), + diag::note_free_function_kernel_param_type_not_fwd_declarable) << ParamTy; IsInvalid = true; } @@ -2077,7 +2085,11 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { // experience. CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); if (RD->hasAttr()) { - Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) + Diag.Report(PD->getLocation(), + diag::err_bad_free_function_kernel_param_type) + << ParamTy; + Diag.Report(PD->getLocation(), + diag::note_free_function_kernel_param_type_not_supported) << ParamTy; IsInvalid = true; } diff --git a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp index adfa1761fa607..86ba7ddf612ca 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp @@ -13,13 +13,15 @@ class Outer { __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void ff_4(Outer::DefinedWithinAClass S1) { // expected-error {{'Outer::DefinedWithinAClass' cannot be used as the type of a kernel parameter}} +void ff_4(Outer::DefinedWithinAClass S1) { // expected-error {{'Outer::DefinedWithinAClass' cannot be used as the type of a free function kernel parameter}} + // expected-note@-1 {{'Outer::DefinedWithinAClass' is not forward declarable}} } template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] - void ff_6(T1 S1) { // expected-error 2{{cannot be used as the type of a kernel parameter}} + void ff_6(T1 S1) { // expected-error 2{{cannot be used as the type of a free function kernel parameter}} + // expected-note@-1 2{{is not forward declarable}} } void bar() { @@ -54,5 +56,6 @@ struct Wrapper { }; [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void ff_6(Wrapper S1) { // expected-error {{cannot be used as the type of a kernel parameter}} +void ff_6(Wrapper S1) { // expected-error {{cannot be used as the type of a free function kernel parameter}} + // expected-note@-1 {{'Wrapper' is not yet supported as free function kernel parameter}} } From ce98062f0eb6cc755b1535c1d80f8a130fda8cd9 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Mon, 23 Sep 2024 03:19:44 -0700 Subject: [PATCH 15/16] Create isForwardDeclarable --- clang/lib/Sema/SemaSYCL.cpp | 206 +++++++++++++----------- clang/test/SemaSYCL/kernelname-enum.cpp | 2 +- 2 files changed, 109 insertions(+), 99 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e7ae688ef406b..3a4f518f3e3fb 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -489,6 +489,84 @@ void SemaSYCL::checkSYCLDeviceVarDecl(VarDecl *Var) { checkSYCLType(*this, Ty, Loc, Visited); } +enum NotForwardDeclarableReason { + UnscopedEnum, + StdNamespace, + UnnamedTag, + NotAtNamespaceScope, + None +}; + +// This is a helper function which is used to check if a class declaration is: +// * declared within namespace 'std' (at any level) +// e.g., namespace std { namespace literals { class Whatever; } } +// h.single_task([]() {}); +// * declared within a function +// e.g., void foo() { struct S { int i; }; +// h.single_task([]() {}); } +// * declared within another tag +// e.g., struct S { struct T { int i } t; }; +// h.single_task([]() {}); +// User for kernel name types and class/struct types used in free function +// kernel arguments. +static NotForwardDeclarableReason +isForwardDeclarable(const NamedDecl *DeclToCheck, SemaSYCL &S, + bool DiagForFreeFunction = false) { + if (const auto *ED = dyn_cast(DeclToCheck); + ED && !ED->isScoped() && !ED->isFixed()) + return NotForwardDeclarableReason::UnscopedEnum; + + const DeclContext *DeclCtx = DeclToCheck->getDeclContext(); + if (DeclCtx) { + while (!DeclCtx->isTranslationUnit() && + (isa(DeclCtx) || isa(DeclCtx))) { + const auto *NSDecl = dyn_cast(DeclCtx); + // We don't report free function kernel parameter case because the + // restriction for the type used there to be forward declarable comes from + // the need to forward declare it in the integration header. We're safe + // to do so because the integration header is an implemention detail and + // is generated by the compiler. + // We do diagnose case with kernel name type since the spec requires us to + // do so. + if (!DiagForFreeFunction && NSDecl && NSDecl->isStdNamespace()) + return NotForwardDeclarableReason::StdNamespace; + DeclCtx = DeclCtx->getParent(); + } + } + + // Check if the we've met a Tag declaration local to a non-namespace scope + // (i.e. Inside a function or within another Tag etc). + if (const auto *Tag = dyn_cast(DeclToCheck)) { + if (Tag->getIdentifier() == nullptr) + return NotForwardDeclarableReason::UnnamedTag; + if (!DeclCtx->isTranslationUnit()) { + // Diagnose used types without complete definition i.e. + // int main() { + // class KernelName1; + // parallel_for(..); + // } + // For kernel name type This case can only be diagnosed during host + // compilation because the integration header is required to distinguish + // between the invalid code (above) and the following valid code: + // int main() { + // parallel_for(..); + // } + // The device compiler forward declares both KernelName1 and + // KernelName2 in the integration header as ::KernelName1 and + // ::KernelName2. The problem with the former case is the additional + // declaration 'class KernelName1' in non-global scope. Lookup in this + // case will resolve to ::main::KernelName1 (instead of + // ::KernelName1). Since this is not visible to runtime code that + // submits kernels, this is invalid. + if (Tag->isCompleteDefinition() || + S.getLangOpts().SYCLEnableIntHeaderDiags || DiagForFreeFunction) + return NotForwardDeclarableReason::NotAtNamespaceScope; + } + } + + return NotForwardDeclarableReason::None; +} + // Tests whether given function is a lambda function or '()' operator used as // SYCL kernel body function (e.g. in parallel_for). // NOTE: This is incomplete implemenation. See TODO in the FE TODO list for the @@ -1964,25 +2042,9 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { // For free functions all struct/class kernel arguments are forward declared // in integration header, that adds additional restrictions for kernel // arguments. - // Lambdas are not forward declarable. So, diagnose them properly. - if (RD->isLambda()) { - Diag.Report(PD->getLocation(), - diag::err_bad_free_function_kernel_param_type) - << ParamTy; - Diag.Report(PD->getLocation(), - diag::note_free_function_kernel_param_type_not_fwd_declarable) - << ParamTy; - IsInvalid = true; - return isValid(); - } - - // Check that the type is defined at namespace scope. - const DeclContext *DeclCtx = RD->getDeclContext(); - while (!DeclCtx->isTranslationUnit() && - (isa(DeclCtx) || isa(DeclCtx))) - DeclCtx = DeclCtx->getParent(); - - if (!DeclCtx->isTranslationUnit()) { + NotForwardDeclarableReason NFDR = + isForwardDeclarable(RD, SemaSYCLRef, /*DiagForFreeFunction=*/true); + if (NFDR != NotForwardDeclarableReason::None) { Diag.Report(PD->getLocation(), diag::err_bad_free_function_kernel_param_type) << ParamTy; @@ -4875,89 +4937,37 @@ class SYCLKernelNameTypeVisitor } void DiagnoseKernelNameType(const NamedDecl *DeclNamed) { - /* - This is a helper function which throws an error if the kernel name - declaration is: - * declared within namespace 'std' (at any level) - e.g., namespace std { namespace literals { class Whatever; } } - h.single_task([]() {}); - * declared within a function - e.g., void foo() { struct S { int i; }; - h.single_task([]() {}); } - * declared within another tag - e.g., struct S { struct T { int i } t; }; - h.single_task([]() {}); - */ - - if (const auto *ED = dyn_cast(DeclNamed)) { - if (!ED->isScoped() && !ED->isFixed()) { + if (!IsUnnamedKernel) { + NotForwardDeclarableReason NFDR = isForwardDeclarable(DeclNamed, S); + switch (NFDR) { + case NotForwardDeclarableReason::UnscopedEnum: S.Diag(KernelInvocationFuncLoc, diag::err_sycl_kernel_incorrectly_named) << /* unscoped enum requires fixed underlying type */ 1 << DeclNamed; IsInvalid = true; - } - } - - const DeclContext *DeclCtx = DeclNamed->getDeclContext(); - if (DeclCtx && !IsUnnamedKernel) { - - // Check if the kernel name declaration is declared within namespace - // "std" (at any level). - while (!DeclCtx->isTranslationUnit() && isa(DeclCtx)) { - const auto *NSDecl = cast(DeclCtx); - if (NSDecl->isStdNamespace()) { - S.Diag(KernelInvocationFuncLoc, - diag::err_invalid_std_type_in_sycl_kernel) - << KernelNameType << DeclNamed; - IsInvalid = true; - return; - } - DeclCtx = DeclCtx->getParent(); - } - - // Check if the kernel name is a Tag declaration - // local to a non-namespace scope (i.e. Inside a function or within - // another Tag etc). - if (!DeclCtx->isTranslationUnit() && !isa(DeclCtx)) { - if (const auto *Tag = dyn_cast(DeclNamed)) { - bool UnnamedLambdaUsed = Tag->getIdentifier() == nullptr; - - if (UnnamedLambdaUsed) { - S.Diag(KernelInvocationFuncLoc, - diag::err_sycl_kernel_incorrectly_named) - << /* unnamed type is invalid */ 2 << KernelNameType; - IsInvalid = true; - return; - } - - // Diagnose used types without complete definition i.e. - // int main() { - // class KernelName1; - // parallel_for(..); - // } - // This case can only be diagnosed during host compilation because the - // integration header is required to distinguish between the invalid - // code (above) and the following valid code: - // int main() { - // parallel_for(..); - // } - // The device compiler forward declares both KernelName1 and - // KernelName2 in the integration header as ::KernelName1 and - // ::KernelName2. The problem with the former case is the additional - // declaration 'class KernelName1' in non-global scope. Lookup in this - // case will resolve to ::main::KernelName1 (instead of - // ::KernelName1). Since this is not visible to runtime code that - // submits kernels, this is invalid. - if (Tag->isCompleteDefinition() || - S.getLangOpts().SYCLEnableIntHeaderDiags) { - S.Diag(KernelInvocationFuncLoc, - diag::err_sycl_kernel_incorrectly_named) - << /* kernel name should be forward declarable at namespace - scope */ - 0 << KernelNameType; - IsInvalid = true; - } - } + return; + case NotForwardDeclarableReason::StdNamespace: + S.Diag(KernelInvocationFuncLoc, + diag::err_invalid_std_type_in_sycl_kernel) + << KernelNameType << DeclNamed; + IsInvalid = true; + return; + case NotForwardDeclarableReason::UnnamedTag: + S.Diag(KernelInvocationFuncLoc, diag::err_sycl_kernel_incorrectly_named) + << /* unnamed type is invalid */ 2 << KernelNameType; + IsInvalid = true; + return; + case NotForwardDeclarableReason::NotAtNamespaceScope: + S.Diag(KernelInvocationFuncLoc, diag::err_sycl_kernel_incorrectly_named) + << /* kernel name should be forward declarable at namespace + scope */ + 0 << KernelNameType; + IsInvalid = true; + return; + case NotForwardDeclarableReason::None: + default: + // Do nothing, we're fine. + break; } } } diff --git a/clang/test/SemaSYCL/kernelname-enum.cpp b/clang/test/SemaSYCL/kernelname-enum.cpp index 34c201cd7f1c2..726d339c84e16 100644 --- a/clang/test/SemaSYCL/kernelname-enum.cpp +++ b/clang/test/SemaSYCL/kernelname-enum.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -fsyntax-only -sycl-std=2020 -verify %s +// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -fsyntax-only -sycl-std=2020 -fno-sycl-unnamed-lambda -verify %s // This test verifies that kernel names containing unscoped enums are diagnosed correctly. From 2eb3d6156234da17f7d6e6806794ef52a99e9fe5 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" Date: Wed, 25 Sep 2024 02:34:21 -0700 Subject: [PATCH 16/16] Resolve diagnostic concerns --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 +--- clang/lib/Sema/SemaSYCL.cpp | 4 ++-- .../SemaSYCL/free_function_kernel_params_restrictions.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 41d9e072f3aa7..02f688aa9774f 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12434,12 +12434,10 @@ def err_sycl_kernel_incorrectly_named : Error< "}0">; // SYCL free function kernels extension. -def err_bad_free_function_kernel_param_type : Error< - "%0 cannot be used as the type of a free function kernel parameter">; def note_free_function_kernel_param_type_not_fwd_declarable : Note< "%0 is not forward declarable">; def note_free_function_kernel_param_type_not_supported : Note< - "%0 is not yet supported as free function kernel parameter">; + "%0 is not yet supported as a free function kernel parameter">; def err_sycl_kernel_not_function_object : Error<"kernel parameter must be a lambda or function object">; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 44a5934e67b9b..99d9cbe1f4f60 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2049,7 +2049,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { isForwardDeclarable(RD, SemaSYCLRef, /*DiagForFreeFunction=*/true); if (NFDR != NotForwardDeclarableReason::None) { Diag.Report(PD->getLocation(), - diag::err_bad_free_function_kernel_param_type) + diag::err_bad_kernel_param_type) << ParamTy; Diag.Report(PD->getLocation(), diag::note_free_function_kernel_param_type_not_fwd_declarable) @@ -2151,7 +2151,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); if (RD->hasAttr()) { Diag.Report(PD->getLocation(), - diag::err_bad_free_function_kernel_param_type) + diag::err_bad_kernel_param_type) << ParamTy; Diag.Report(PD->getLocation(), diag::note_free_function_kernel_param_type_not_supported) diff --git a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp index 86ba7ddf612ca..d1bdc0e3da475 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp @@ -13,14 +13,14 @@ class Outer { __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void ff_4(Outer::DefinedWithinAClass S1) { // expected-error {{'Outer::DefinedWithinAClass' cannot be used as the type of a free function kernel parameter}} +void ff_4(Outer::DefinedWithinAClass S1) { // expected-error {{'Outer::DefinedWithinAClass' cannot be used as the type of a kernel parameter}} // expected-note@-1 {{'Outer::DefinedWithinAClass' is not forward declarable}} } template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] - void ff_6(T1 S1) { // expected-error 2{{cannot be used as the type of a free function kernel parameter}} + void ff_6(T1 S1) { // expected-error 2{{cannot be used as the type of a kernel parameter}} // expected-note@-1 2{{is not forward declarable}} } @@ -56,6 +56,6 @@ struct Wrapper { }; [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void ff_6(Wrapper S1) { // expected-error {{cannot be used as the type of a free function kernel parameter}} - // expected-note@-1 {{'Wrapper' is not yet supported as free function kernel parameter}} +void ff_6(Wrapper S1) { // expected-error {{cannot be used as the type of a kernel parameter}} + // expected-note@-1 {{'Wrapper' is not yet supported as a free function kernel parameter}} }