From b8835d17fcba294a862fe2b2332bc6314e61a702 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Fri, 1 Mar 2024 11:35:15 -0800 Subject: [PATCH 01/52] Prototype for free functions. --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/CodeGen/CGExpr.cpp | 9 + clang/lib/Sema/Sema.cpp | 4 +- clang/lib/Sema/SemaSYCL.cpp | 1379 ++++++++++++++++- .../oneapi/kernel_properties/properties.hpp | 116 ++ .../sycl/ext/oneapi/properties/property.hpp | 5 +- 6 files changed, 1456 insertions(+), 59 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 78804036383d0..74bb0a7613d51 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14810,7 +14810,7 @@ class Sema final { void copySYCLKernelAttrs(CXXMethodDecl *CallOperator); void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC); void SetSYCLKernelNames(); - void MarkDevices(); + void ProcessDeviceFunctions(); /// Get the number of fields or captures within the parsed type. ExprResult ActOnSYCLBuiltinNumFieldsExpr(ParsedType PT); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 6c09920c3c990..b722afbe3c821 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -48,6 +48,7 @@ #include #include +#include using namespace clang; using namespace CodeGen; @@ -2836,6 +2837,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } if (const auto *VD = dyn_cast(ND)) { +#if 0 + std::cerr << "VD=" << (void*)VD << std::endl; +#endif // Check if this is a global variable. if (VD->hasLinkage() || VD->isStaticDataMember()) return EmitGlobalVarDeclLValue(*this, E, VD); @@ -2865,7 +2869,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // No other cases for now. } else { +#if 0 + for (auto LDMEntry : LocalDeclMap) { + LDMEntry.first->dump(); + } llvm_unreachable("DeclRefExpr for Decl not entered in LocalDeclMap?"); +#endif } // Handle threadlocal function locals. diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9ad274fc8f185..80cccf0790153 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1117,6 +1117,9 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { } if (getLangOpts().SYCLIsDevice) { + // Generate device code for free function kernels and propagate "device" + // attributes + ProcessDeviceFunctions(); // Set the names of the kernels, now that the names have settled down. This // needs to happen before we generate the integration headers. SetSYCLKernelNames(); @@ -1128,7 +1131,6 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { // Emit SYCL integration header for current translation unit if needed if (SyclIntHeader != nullptr) SyclIntHeader->emit(getLangOpts().SYCLIntHeader); - MarkDevices(); } emitDeferredDiags(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e2a8d10ded1ab..62e885bdab2b1 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -35,6 +35,7 @@ #include #include #include +#include using namespace clang; using namespace std::placeholders; @@ -383,8 +384,7 @@ bool Sema::isDeclAllowedInSYCLDeviceCode(const Decl *D) { return true; } const DeclContext *DC = FD->getDeclContext(); - if (II && II->isStr("__spirv_ocl_printf") && - !FD->isDefined() && + if (II && II->isStr("__spirv_ocl_printf") && !FD->isDefined() && FD->getLanguageLinkage() == CXXLanguageLinkage && DC->getEnclosingNamespaceContext()->isTranslationUnit()) return true; @@ -655,9 +655,7 @@ class DiagDeviceFunction : public RecursiveASTVisitor { // Make sure we skip the condition of the case, since that is a constant // expression. - bool TraverseCaseStmt(CaseStmt *S) { - return TraverseStmt(S->getSubStmt()); - } + bool TraverseCaseStmt(CaseStmt *S) { return TraverseStmt(S->getSubStmt()); } // Skip checking the size expr, since a constant array type loc's size expr is // a constant expression. @@ -854,7 +852,8 @@ class SingleDeviceFunctionTracker { !KernelBody->hasAttr() && !KernelBody->hasAttr()) { KernelBody->addAttr(AlwaysInlineAttr::CreateImplicit( - KernelBody->getASTContext(), {}, AlwaysInlineAttr::Keyword_forceinline)); + KernelBody->getASTContext(), {}, + AlwaysInlineAttr::Keyword_forceinline)); } } @@ -889,9 +888,13 @@ class KernelBodyTransform : public TreeTransform { bool AlwaysRebuild() { return true; } ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) { + // std::cerr << "TransformDeclRefExpr(" << (void*)DRE << ")\n"; auto Ref = dyn_cast(DRE->getDecl()); + // std::cerr << "Ref = " << (void*)Ref << "\n"; if (Ref && Ref == MappingPair.first) { + // std::cerr << "Ref matches " << (void*)(MappingPair.first) << "\n"; auto NewDecl = MappingPair.second; + // std::cerr << "Replacing with " << (void*)(NewDecl) << "\n"; return DeclRefExpr::Create( SemaRef.getASTContext(), DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(), NewDecl, false, DRE->getNameInfo(), @@ -900,6 +903,42 @@ class KernelBodyTransform : public TreeTransform { return DRE; } + Decl *TransformDecl(SourceLocation Loc, Decl *D) { + std::cerr << "TransformDecl(D=" << (void *)D << ")\n"; + VarDecl *VD = dyn_cast(D); + if (VD) { + std::cerr << "TransformDecl(VD=" << (void *)VD << ")\n"; + VD->dump(); + Expr *InitExpr = VD->getInit(); + if (InitExpr) { + std::cerr << "VD has init\n"; + ExprResult NewInit = TransformExpr(InitExpr); + VD->setInit(SemaRef.MaybeCreateExprWithCleanups(NewInit.get())); + VD->setIsUsed(); + std::cerr << "Transformed VD=\n"; + VD->dump(); + return VD; + } + } + return D; + } +#if 1 + Decl *TransformDecl(SourceLocation Loc, ParmVarDecl *PD) { + std::cerr << "TransformDecl(PD=" << (void *)PD << ")\n"; + PD->dump(); + Expr *InitExpr = PD->getInit(); + if (InitExpr) { + std::cerr << "PD has init\n"; + ExprResult NewInit = TransformExpr(InitExpr); + PD->setInit(SemaRef.MaybeCreateExprWithCleanups(NewInit.get())); + PD->setIsUsed(); + std::cerr << "Transformed PD=\n"; + PD->dump(); + return PD; + } + } +#endif + private: std::pair MappingPair; Sema &SemaRef; @@ -1005,6 +1044,12 @@ static ParamDesc makeParamDesc(const FieldDecl *Src, QualType Ty) { return std::make_tuple(Ty, &Ctx.Idents.get(Name), Ctx.getTrivialTypeSourceInfo(Ty)); } +static ParamDesc makeParamDesc(const ParmVarDecl *Src, QualType Ty) { + ASTContext &Ctx = Src->getASTContext(); + std::string Name = (Twine("_arg_") + Src->getName()).str(); + return std::make_tuple(Ty, &Ctx.Idents.get(Name), + Ctx.getTrivialTypeSourceInfo(Ty)); +} static ParamDesc makeParamDesc(ASTContext &Ctx, StringRef Name, QualType Ty) { return std::make_tuple(Ty, &Ctx.Idents.get(Name), @@ -1021,21 +1066,71 @@ static target getAccessTarget(QualType FieldTy, AccTy->getTemplateArgs()[3].getAsIntegral().getExtValue()); } +static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { + if (FD->hasAttr()) { + const auto *A = FD->getAttr(); + SmallVector, 4> NameValuePairs = + A->getFilteredAttributeNameValuePairs(SemaRef.Context); + for (const auto &NameValuePair : NameValuePairs) { + std::cerr << "\t" << NameValuePair.first << ":" << NameValuePair.second + << std::endl; + if (NameValuePair.first == "sycl-range-kernel" || + NameValuePair.first == "sycl-nd-range-kernel" || + NameValuePair.first == "sycl-single-task-kernel") + return true; + } + } + return false; +} + +static std::string constructFreeFunctionKernelName(ASTContext &Ctx, + const FunctionDecl *FD) { + IdentifierInfo *Id = FD->getIdentifier(); + std::string NewIdent = (Twine("__free_function_") + Id->getName()).str(); + return NewIdent; +} + +// Free functions are always void type. +static QualType calculateFreeFunctionNameType(const FunctionDecl *FF) { + return FF->getType(); +} + // The first template argument to the kernel caller function is used to identify // the kernel itself. static QualType calculateKernelNameType(ASTContext &Ctx, const FunctionDecl *KernelCallerFunc) { +#if 1 const TemplateArgumentList *TAL = KernelCallerFunc->getTemplateSpecializationArgs(); assert(TAL && "No template argument info"); return TAL->get(0).getAsType().getCanonicalType(); +#else + const TemplateArgumentList *TAL = + KernelCallerFunc->getTemplateSpecializationArgs(); + if (TAL) { + // assert(TAL && "No template argument info"); + return TAL->get(0).getAsType().getCanonicalType(); + } else { + return KernelCallerFunc->parameters()[0]->getType(); + } +#endif } -// Gets a name for the OpenCL kernel function, calculated from the first +// Gets a name for the kernel function, calculated from the first // template argument of the kernel caller function. +// Free functions may not be templated. Use original function name with a +// prefix. static std::pair constructKernelName(Sema &S, const FunctionDecl *KernelCallerFunc, MangleContext &MC) { + if (IsFreeFunction(S, KernelCallerFunc)) { + std::string MangledName( + constructFreeFunctionKernelName(S.getASTContext(), KernelCallerFunc)); + std::string StableName = + (constructFreeFunctionKernelName(S.getASTContext(), KernelCallerFunc)); + return {MangledName, StableName}; + } + QualType KernelNameType = calculateKernelNameType(S.getASTContext(), KernelCallerFunc); @@ -1104,15 +1199,21 @@ static bool isReadOnlyAccessor(const TemplateArgument &AccessModeArg) { // anonymous namespace so these don't get linkage. namespace { -template struct bind_param { using type = T; }; +template struct bind_param { + using type = T; +}; template <> struct bind_param { using type = const CXXBaseSpecifier &; }; -template <> struct bind_param { using type = FieldDecl *; }; +template <> struct bind_param { + using type = FieldDecl *; +}; -template <> struct bind_param { using type = FieldDecl *; }; +template <> struct bind_param { + using type = FieldDecl *; +}; template using bind_param_t = typename bind_param::type; @@ -1121,7 +1222,7 @@ class KernelObjVisitor { template void VisitUnionImpl(const CXXRecordDecl *Owner, ParentTy &Parent, - const CXXRecordDecl *Wrapper, HandlerTys &... Handlers) { + const CXXRecordDecl *Wrapper, HandlerTys &...Handlers) { (void)std::initializer_list{ (Handlers.enterUnion(Owner, Parent), 0)...}; VisitRecordHelper(Wrapper, Wrapper->fields(), Handlers...); @@ -1131,13 +1232,13 @@ class KernelObjVisitor { // These enable handler execution only when previous Handlers succeed. template - bool handleField(FieldDecl *FD, QualType FDTy, Tn &&... tn) { + bool handleField(FieldDecl *FD, QualType FDTy, Tn &&...tn) { bool result = true; (void)std::initializer_list{(result = result && tn(FD, FDTy), 0)...}; return result; } template - bool handleField(const CXXBaseSpecifier &BD, QualType BDTy, Tn &&... tn) { + bool handleField(const CXXBaseSpecifier &BD, QualType BDTy, Tn &&...tn) { bool result = true; std::initializer_list{(result = result && tn(BD, BDTy), 0)...}; return result; @@ -1153,11 +1254,28 @@ class KernelObjVisitor { std::ref(Handlers), _1, _2)...) // The following simpler definition works with gcc 8.x and later. - //#define KF_FOR_EACH(FUNC) \ + // #define KF_FOR_EACH(FUNC) \ // handleField(Field, FieldTy, ([&](FieldDecl *FD, QualType FDTy) { \ // return Handlers.f(FD, FDTy); \ // })...) + // This enables handler execution only when previous Handlers succeed. + template + bool handleParam(ParmVarDecl *PD, QualType PDTy, Tn &&...tn) { + bool result = true; + (void)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 KP_FOR_EACH(FUNC, Item, Qt) \ + handleParam( \ + Item, Qt, \ + std::bind(static_cast::*)( \ + bind_param_t, QualType)>( \ + &std::decay_t::FUNC), \ + std::ref(Handlers), _1, _2)...) + // Parent contains the FieldDecl or CXXBaseSpecifier that was used to enter // the Wrapper structure that we're currently visiting. Owner is the parent // type (which doesn't exist in cases where it is a FieldDecl in the @@ -1165,7 +1283,10 @@ class KernelObjVisitor { template void visitComplexRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, - HandlerTys &... Handlers) { + HandlerTys &...Handlers) { + std::cerr << "visitComplexRecord(Owner=" << (void*)Owner + << ", Parent=, Wrapper=" << (void*)Wrapper + << ", RecordTy)\n"; (void)std::initializer_list{ (Handlers.enterStruct(Owner, Parent, RecordTy), 0)...}; VisitRecordHelper(Wrapper, Wrapper->bases(), Handlers...); @@ -1177,7 +1298,10 @@ class KernelObjVisitor { template void visitSimpleRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, - HandlerTys &... Handlers) { + HandlerTys &...Handlers) { + std::cerr << "visitSimpleRecord(Owner=" << (void*)Owner + << ", Parent=, Wrapper=" << (void*)Wrapper + << ", RecordTy)\n"; (void)std::initializer_list{ (Handlers.handleNonDecompStruct(Owner, Parent, RecordTy), 0)...}; } @@ -1185,65 +1309,92 @@ class KernelObjVisitor { template void visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, - HandlerTys &... Handlers); + HandlerTys &...Handlers); template void VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent, - const CXXRecordDecl *Wrapper, HandlerTys &... Handlers); + const CXXRecordDecl *Wrapper, HandlerTys &...Handlers); template void VisitRecordHelper(const CXXRecordDecl *Owner, clang::CXXRecordDecl::base_class_const_range Range, - HandlerTys &... Handlers) { + HandlerTys &...Handlers) { + std::cerr << "VisitRecordHelper1(Owner=" << (void *)Owner << ")\n"; for (const auto &Base : Range) { QualType BaseTy = Base.getType(); // Handle accessor class as base - if (isSyclSpecialType(BaseTy, SemaRef)) + if (isSyclSpecialType(BaseTy, SemaRef)) { + std::cerr << "VisitRecordHelper1 calling handleSyclSpecialType\n"; (void)std::initializer_list{ (Handlers.handleSyclSpecialType(Owner, Base, BaseTy), 0)...}; - else + } else { // For all other bases, visit the record + std::cerr << "VisitRecordHelper1 calling visitRecord\n"; visitRecord(Owner, Base, BaseTy->getAsCXXRecordDecl(), BaseTy, Handlers...); + } } } template void VisitRecordHelper(const CXXRecordDecl *Owner, RecordDecl::field_range Range, - HandlerTys &... Handlers) { + HandlerTys &...Handlers) { + std::cerr << "VisitRecordHelper2(Owner=" << (void*)Owner << ")\n"; VisitRecordFields(Owner, Handlers...); } template void visitArrayElementImpl(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &... Handlers) { + HandlerTys &...Handlers) { (void)std::initializer_list{ (Handlers.nextElement(ElementTy, Index), 0)...}; visitField(Owner, ArrayField, ElementTy, Handlers...); } + template + void visitArrayElementImpl(ParmVarDecl *ArrayField, QualType ElementTy, + uint64_t Index, HandlerTys &...Handlers) { + (void)std::initializer_list{ + (Handlers.nextElement(ElementTy, Index), 0)...}; + visitParam(ArrayField, ElementTy, Handlers...); + } template void visitFirstArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, - QualType ElementTy, HandlerTys &... Handlers) { + QualType ElementTy, HandlerTys &...Handlers) { visitArrayElementImpl(Owner, ArrayField, ElementTy, 0, Handlers...); } template void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &... Handlers); + HandlerTys &...Handlers); + + template + void visitFirstArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, + HandlerTys &...Handlers) { + visitArrayElementImpl(ArrayField, ElementTy, 0, Handlers...); + } + template + void visitNthArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, + uint64_t Index, HandlerTys &...Handlers); template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &... Handlers) { + QualType ArrayTy, HandlerTys &...Handlers) { (void)std::initializer_list{ (Handlers.handleSimpleArrayType(Field, ArrayTy), 0)...}; } + template + void visitSimpleArray(ParmVarDecl *Param, QualType ArrayTy, + HandlerTys &...Handlers) { + (void)std::initializer_list{ + (Handlers.handleSimpleArrayType(Param, ArrayTy), 0)...}; + } template void visitComplexArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &... Handlers) { + QualType ArrayTy, HandlerTys &...Handlers) { // Array workflow is: // handleArrayType // enterArray @@ -1272,10 +1423,41 @@ class KernelObjVisitor { (void)std::initializer_list{ (Handlers.leaveArray(Field, ArrayTy, ET), 0)...}; } + template + void visitComplexArray(ParmVarDecl *Param, QualType ArrayTy, + HandlerTys &...Handlers) { + // Array workflow is: + // handleArrayType + // enterArray + // nextElement + // VisitField (same as before, note that The FieldDecl is the of array + // itself, not the element) + // ... repeat per element, opt-out for duplicates. + // leaveArray + + if (!KP_FOR_EACH(handleArrayType, Param, ArrayTy)) + return; + + const ConstantArrayType *CAT = + SemaRef.getASTContext().getAsConstantArrayType(ArrayTy); + assert(CAT && "Should only be called on constant-size array."); + QualType ET = CAT->getElementType(); + uint64_t ElemCount = CAT->getSize().getZExtValue(); + + (void)std::initializer_list{ + (Handlers.enterArray(Param, ArrayTy, ET), 0)...}; + + visitFirstArrayElement(Param, ET, Handlers...); + for (uint64_t Index = 1; Index < ElemCount; ++Index) + visitNthArrayElement(Param, ET, Index, Handlers...); + + (void)std::initializer_list{ + (Handlers.leaveArray(Param, ArrayTy, ET), 0)...}; + } template void visitField(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType FieldTy, HandlerTys &... Handlers) { + QualType FieldTy, HandlerTys &...Handlers) { if (isSyclSpecialType(FieldTy, SemaRef)) KF_FOR_EACH(handleSyclSpecialType, Field, FieldTy); else if (FieldTy->isStructureOrClassType()) { @@ -1300,26 +1482,68 @@ class KernelObjVisitor { KF_FOR_EACH(handleOtherType, Field, FieldTy); } + template + void visitParam(ParmVarDecl *Param, QualType ParamTy, + HandlerTys &...Handlers) { + if (isSyclSpecialType(ParamTy, SemaRef)) + KP_FOR_EACH(handleSyclSpecialType, Param, ParamTy); + else if (ParamTy->isStructureOrClassType()) { + if (KP_FOR_EACH(handleStructType, Param, ParamTy)) { + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + visitRecord(nullptr, Param, RD, ParamTy, Handlers...); + } + } else if (ParamTy->isUnionType()) { + if (KP_FOR_EACH(handleUnionType, Param, ParamTy)) { + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); + VisitUnion(nullptr, Param, RD, Handlers...); + } + } else if (ParamTy->isReferenceType()) + KP_FOR_EACH(handleReferenceType, Param, ParamTy); + else if (ParamTy->isPointerType()) + KP_FOR_EACH(handlePointerType, Param, ParamTy); + else if (ParamTy->isArrayType()) + visitArray(Param, ParamTy, Handlers...); + else if (ParamTy->isScalarType() || ParamTy->isVectorType()) + KP_FOR_EACH(handleScalarType, Param, ParamTy); + else + KP_FOR_EACH(handleOtherType, Param, ParamTy); + } + public: KernelObjVisitor(Sema &S) : SemaRef(S) {} template void VisitRecordBases(const CXXRecordDecl *KernelFunctor, - HandlerTys &... Handlers) { + HandlerTys &...Handlers) { VisitRecordHelper(KernelFunctor, KernelFunctor->bases(), Handlers...); } // A visitor function that dispatches to functions as defined in // SyclKernelFieldHandler for the purposes of kernel generation. template - void VisitRecordFields(const CXXRecordDecl *Owner, HandlerTys &... Handlers) { - for (const auto Field : Owner->fields()) + void VisitRecordFields(const CXXRecordDecl *Owner, HandlerTys &...Handlers) { + std::cerr << "VisitRecordFields(Owner=" << (void*)Owner << ")\n"; + for (const auto Field : Owner->fields()) { + std::cerr << "Visiting a Field\n"; visitField(Owner, Field, Field->getType(), Handlers...); + } } template void visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, QualType ArrayTy, HandlerTys &...Handlers); + template + void visitArray(ParmVarDecl *Param, QualType ArrayTy, + HandlerTys &...Handlers); + + // A visitor function that dispatches to functions as defined in + // SyclKernelFieldHandler by iterating over a free function parameter list. + template + void VisitFunctionParameters(FunctionDecl *FreeFunc, + HandlerTys &...Handlers) { + for (ParmVarDecl *Param : FreeFunc->parameters()) + visitParam(Param, Param->getType(), Handlers...); + } #undef KF_FOR_EACH }; @@ -1345,15 +1569,23 @@ class SyclKernelFieldHandlerBase { return true; } virtual bool handleSyclSpecialType(FieldDecl *, QualType) { return true; } + virtual bool handleSyclSpecialType(ParmVarDecl *, QualType) { return true; } virtual bool handleStructType(FieldDecl *, QualType) { return true; } + virtual bool handleStructType(ParmVarDecl *, QualType) { return true; } virtual bool handleUnionType(FieldDecl *, QualType) { return true; } + virtual bool handleUnionType(ParmVarDecl *, QualType) { return true; } virtual bool handleReferenceType(FieldDecl *, QualType) { return true; } + virtual bool handleReferenceType(ParmVarDecl *, QualType) { return true; } virtual bool handlePointerType(FieldDecl *, QualType) { return true; } + virtual bool handlePointerType(ParmVarDecl *, QualType) { return true; } virtual bool handleArrayType(FieldDecl *, QualType) { return true; } + virtual bool handleArrayType(ParmVarDecl *, QualType) { return true; } virtual bool handleScalarType(FieldDecl *, QualType) { return true; } + virtual bool handleScalarType(ParmVarDecl *, QualType) { return true; } // Most handlers shouldn't be handling this, just the field checker. virtual bool handleOtherType(FieldDecl *, QualType) { return true; } + virtual bool handleOtherType(ParmVarDecl *, QualType) { return true; } // Handle a simple struct that doesn't need to be decomposed, only called on // handlers with VisitInsideSimpleContainers as false. Replaces @@ -1362,6 +1594,10 @@ class SyclKernelFieldHandlerBase { QualType) { return true; } + virtual bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, + QualType) { + return true; + } virtual bool handleNonDecompStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) { return true; @@ -1371,6 +1607,7 @@ class SyclKernelFieldHandlerBase { // descending down the elements), this function gets called in the event of an // array containing simple elements (even in the case of an MD array). virtual bool handleSimpleArrayType(FieldDecl *, QualType) { return true; } + virtual bool handleSimpleArrayType(ParmVarDecl *, QualType) { return true; } // The following are only used for keeping track of where we are in the base // class/field graph. Int Headers use this to calculate offset, most others @@ -1382,6 +1619,12 @@ class SyclKernelFieldHandlerBase { virtual bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType) { return true; } + virtual bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) { + return true; + } + virtual bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) { + return true; + } virtual bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) { return true; @@ -1392,6 +1635,8 @@ class SyclKernelFieldHandlerBase { } virtual bool enterUnion(const CXXRecordDecl *, FieldDecl *) { return true; } virtual bool leaveUnion(const CXXRecordDecl *, FieldDecl *) { return true; } + virtual bool enterUnion(const CXXRecordDecl *, ParmVarDecl *) { return true; } + virtual bool leaveUnion(const CXXRecordDecl *, ParmVarDecl *) { return true; } // The following are used for stepping through array elements. virtual bool enterArray(FieldDecl *, QualType ArrayTy, QualType ElementTy) { @@ -1400,6 +1645,12 @@ class SyclKernelFieldHandlerBase { virtual bool leaveArray(FieldDecl *, QualType ArrayTy, QualType ElementTy) { return true; } + virtual bool enterArray(ParmVarDecl *, QualType ArrayTy, QualType ElementTy) { + return true; + } + virtual bool leaveArray(ParmVarDecl *, QualType ArrayTy, QualType ElementTy) { + return true; + } virtual bool nextElement(QualType, uint64_t) { return true; } @@ -1421,6 +1672,9 @@ class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { bool isArrayElement(const FieldDecl *FD, QualType Ty) const { return !SemaRef.getASTContext().hasSameType(FD->getType(), Ty); } + bool isArrayElement(const ParmVarDecl *PD, QualType Ty) const { + return !SemaRef.getASTContext().hasSameType(PD->getType(), Ty); + } }; // A class to represent the 'do nothing' case for filtering purposes. @@ -1439,7 +1693,9 @@ template struct HandlerFilter { template struct AnyTrue; -template struct AnyTrue { static constexpr bool Value = B; }; +template struct AnyTrue { + static constexpr bool Value = B; +}; template struct AnyTrue { static constexpr bool Value = B || AnyTrue::Value; @@ -1447,7 +1703,9 @@ template struct AnyTrue { template struct AllTrue; -template struct AllTrue { static constexpr bool Value = B; }; +template struct AllTrue { + static constexpr bool Value = B; +}; template struct AllTrue { static constexpr bool Value = B && AllTrue::Value; @@ -1456,7 +1714,7 @@ template struct AllTrue { template void KernelObjVisitor::VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, - Handlers &... handlers) { + Handlers &...handlers) { // Don't continue descending if none of the handlers 'care'. This could be 'if // constexpr' starting in C++17. Until then, we have to count on the // optimizer to realize "if (false)" is a dead branch. @@ -1470,7 +1728,7 @@ template void KernelObjVisitor::visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - Handlers &... handlers) { + Handlers &...handlers) { // Don't continue descending if none of the handlers 'care'. This could be 'if // constexpr' starting in C++17. Until then, we have to count on the // optimizer to realize "if (false)" is a dead branch. @@ -1480,12 +1738,27 @@ void KernelObjVisitor::visitNthArrayElement(const CXXRecordDecl *Owner, HandlerFilter(handlers) .Handler...); } +template +void KernelObjVisitor::visitNthArrayElement(ParmVarDecl *ArrayField, + QualType ElementTy, uint64_t Index, + Handlers &...handlers) { + // Don't continue descending if none of the handlers 'care'. This could be 'if + // constexpr' starting in C++17. Until then, we have to count on the + // optimizer to realize "if (false)" is a dead branch. + if (AnyTrue::Value) + visitArrayElementImpl( + ArrayField, ElementTy, Index, + HandlerFilter(handlers) + .Handler...); +} template void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, - QualType RecordTy, - HandlerTys &... Handlers) { + QualType RecordTy, HandlerTys &...Handlers) { + std::cerr << "KernelObjVisitor::visitRecord(Owner=" << (void *)Owner + << ", Parent=, Wrapper=" << (void *)Wrapper + << ", RecordTy)\n"; RecordDecl *RD = RecordTy->getAsRecordDecl(); assert(RD && "should not be null."); if (RD->hasAttr()) { @@ -1495,6 +1768,7 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, visitComplexRecord(Owner, Parent, Wrapper, RecordTy, Handlers...); } else if (AnyTrue:: Value) { + std::cerr << "KernelObjVisitor:: We are currently in PointerHandler visitor\n"; // We are currently in PointerHandler visitor. if (RD->hasAttr()) { // This is a record containing pointers. @@ -1504,6 +1778,7 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, visitSimpleRecord(Owner, Parent, Wrapper, RecordTy, Handlers...); } } else { + std::cerr << "KernelObjVisitor:: VisitInsideSimpleContainers check\n"; // "Simple" Containers are those that do NOT need to be decomposed, // "Complex" containers are those that DO. In the case where the container // does NOT need to be decomposed, we can call VisitSimpleRecord on the @@ -1530,7 +1805,7 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, template void KernelObjVisitor::visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &... Handlers) { + QualType ArrayTy, HandlerTys &...Handlers) { if (Field->hasAttr()) { visitComplexArray(Owner, Field, ArrayTy, Handlers...); @@ -1562,6 +1837,40 @@ void KernelObjVisitor::visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, } } +template +void KernelObjVisitor::visitArray(ParmVarDecl *Param, QualType ArrayTy, + HandlerTys &...Handlers) { + + if (Param->hasAttr()) { + visitComplexArray(Param, ArrayTy, Handlers...); + } else if (AnyTrue:: + Value) { + // We are currently in PointerHandler visitor. + if (Param->hasAttr()) { + // This is an array of pointers, or an array of a type containing + // pointers. + visitComplexArray(Param, ArrayTy, Handlers...); + } else { + // This is an array which does not contain pointers. + visitSimpleArray(Param, ArrayTy, Handlers...); + } + } else { + if (!AllTrue::Value) + visitSimpleArray( + Param, ArrayTy, + HandlerFilter( + Handlers) + .Handler...); + + if (AnyTrue::Value) + visitComplexArray( + Param, ArrayTy, + HandlerFilter( + Handlers) + .Handler...); + } +} + // A type to check the validity of all of the argument types. class SyclKernelFieldChecker : public SyclKernelFieldHandler { bool IsInvalid = false; @@ -1590,6 +1899,20 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return false; } + bool checkNotCopyableToKernel(const ParmVarDecl *PD, QualType FieldTy) { + if (FieldTy->isArrayType()) { + if (const auto *CAT = + SemaRef.getASTContext().getAsConstantArrayType(FieldTy)) { + QualType ET = CAT->getElementType(); + return checkNotCopyableToKernel(PD, ET); + } + return Diag.Report(PD->getLocation(), + diag::err_sycl_non_constant_array_type) + << FieldTy; + } + + return false; + } bool checkPropertyListType(TemplateArgument PropList, SourceLocation Loc) { if (PropList.getKind() != TemplateArgument::ArgKind::Type) @@ -1663,7 +1986,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { // directly by the SYCL kernel. if ((isSyclType(Ty, SYCLTypeAttr::annotated_ptr) || isSyclType(Ty, SYCLTypeAttr::annotated_arg)) && - (StructFieldDepth > 0 || StructBaseDepth > 0)) + (StructFieldDepth > 0 || StructBaseDepth > 0)) return SemaRef.Diag(Loc.getBegin(), diag::err_bad_kernel_param_data_members) << Ty << /*Struct*/ 1; @@ -1697,6 +2020,11 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { IsInvalid = true; return isValid(); } + bool handleReferenceType(ParmVarDecl *PD, QualType FieldTy) final { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << FieldTy; + IsInvalid = true; + return isValid(); + } bool handleStructType(FieldDecl *FD, QualType FieldTy) final { IsInvalid |= checkNotCopyableToKernel(FD, FieldTy); @@ -1711,6 +2039,19 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } return isValid(); } + bool handleStructType(ParmVarDecl *PD, QualType FieldTy) final { + IsInvalid |= checkNotCopyableToKernel(PD, FieldTy); + CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl(); + assert(RD && "Not a RecordDecl inside the handler for struct type"); + if (RD->isLambda()) { + for (const LambdaCapture &LC : RD->captures()) + if (LC.capturesThis() && LC.isImplicit()) { + SemaRef.Diag(LC.getLocation(), diag::err_implicit_this_capture); + IsInvalid = true; + } + } + return isValid(); + } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { @@ -1722,11 +2063,19 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { IsInvalid |= checkSyclSpecialType(FieldTy, FD->getLocation()); return isValid(); } + bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + IsInvalid |= checkSyclSpecialType(FieldTy, PD->getLocation()); + return isValid(); + } bool handleArrayType(FieldDecl *FD, QualType FieldTy) final { IsInvalid |= checkNotCopyableToKernel(FD, FieldTy); return isValid(); } + bool handleArrayType(ParmVarDecl *PD, QualType FieldTy) final { + IsInvalid |= checkNotCopyableToKernel(PD, FieldTy); + return isValid(); + } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { while (FieldTy->isAnyPointerType()) { @@ -1739,12 +2088,28 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } return isValid(); } + bool handlePointerType(ParmVarDecl *FD, QualType FieldTy) final { + while (FieldTy->isAnyPointerType()) { + FieldTy = QualType{FieldTy->getPointeeOrArrayElementType(), 0}; + if (FieldTy->isVariableArrayType()) { + Diag.Report(FD->getLocation(), diag::err_vla_unsupported) << 0; + IsInvalid = true; + break; + } + } + return isValid(); + } bool handleOtherType(FieldDecl *FD, QualType FieldTy) final { Diag.Report(FD->getLocation(), diag::err_bad_kernel_param_type) << FieldTy; IsInvalid = true; return isValid(); } + bool handleOtherType(ParmVarDecl *PD, QualType FieldTy) final { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << FieldTy; + IsInvalid = true; + return isValid(); + } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { ++StructFieldDepth; @@ -1756,6 +2121,16 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return true; } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + ++StructFieldDepth; + return true; + } + + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + --StructFieldDepth; + return true; + } + bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { ++StructBaseDepth; @@ -1797,14 +2172,27 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler { return true; } + bool enterUnion(const CXXRecordDecl *, ParmVarDecl *) override { + ++UnionCount; + return true; + } + bool leaveUnion(const CXXRecordDecl *RD, FieldDecl *FD) override { --UnionCount; return true; } + bool leaveUnion(const CXXRecordDecl *, ParmVarDecl *) override { + --UnionCount; + return true; + } + bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { return checkType(FD->getLocation(), FieldTy); } + bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + return checkType(PD->getLocation(), FieldTy); + } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { @@ -1833,6 +2221,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) final { + std::cerr << "SyclKernelDecompMarker::handleSyclSpecialType(RD)\n"; CollectionStack.back() = true; return true; } @@ -1840,11 +2229,21 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { CollectionStack.back() = true; return true; } + bool handleSyclSpecialType(ParmVarDecl *, QualType) final { + std::cerr << "SyclKernelDecompMarker::handleSyclSpecialType(PD)\n"; + CollectionStack.back() = true; + return true; + } bool handlePointerType(FieldDecl *, QualType) final { PointerStack.back() = true; return true; } + bool handlePointerType(ParmVarDecl *, QualType) final { + std::cerr << "SyclKernelDecompMarker::handlePointerType\n"; + PointerStack.back() = true; + return true; + } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { CollectionStack.push_back(false); @@ -1852,7 +2251,15 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { return true; } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + std::cerr << "SyclKernelDecompMarker::enterStruct\n"; + CollectionStack.push_back(false); + PointerStack.push_back(false); + return true; + } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType Ty) final { + std::cerr << "SyclKernelDecompMarker::leaveStruct\n"; // If a record needs to be decomposed, it is marked with // SYCLRequiresDecompositionAttr. Else if a record contains // a pointer, it is marked with SYCLGenerateNewTypeAttr. A record @@ -1860,9 +2267,34 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); assert(RD && "should not be null."); if (CollectionStack.pop_back_val()) { - if (!RD->hasAttr()) + if (!RD->hasAttr()) { RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( SemaRef.getASTContext())); + std::cerr << "SyclKernelDecompMarker(RD=" << (void *)RD + << ") added SYCLRequiresDecompositionAttr\n"; + } + CollectionStack.back() = true; + PointerStack.pop_back(); + } else if (PointerStack.pop_back_val()) { + PointerStack.back() = true; + if (!RD->hasAttr()) + RD->addAttr( + SYCLGenerateNewTypeAttr::CreateImplicit(SemaRef.getASTContext())); + } + return true; + } + + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType Ty) final { + std::cerr << "SyclKernelDecompMarker::leaveStruct\n"; + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + assert(RD && "should not be null."); + if (CollectionStack.pop_back_val()) { + if (!RD->hasAttr()) { + RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( + SemaRef.getASTContext())); + std::cerr << "SyclKernelDecompMarker(RD=" << (void *)RD + << ") added SYCLRequiresDecompositionAttr\n"; + } CollectionStack.back() = true; PointerStack.pop_back(); } else if (PointerStack.pop_back_val()) { @@ -1909,6 +2341,12 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { PointerStack.push_back(false); return true; } + bool enterArray(ParmVarDecl *, QualType ArrayTy, QualType ElementTy) final { + std::cerr << "SyclKernelDecompMarker::enterArray\n"; + CollectionStack.push_back(false); + PointerStack.push_back(false); + return true; + } bool leaveArray(FieldDecl *FD, QualType ArrayTy, QualType ElementTy) final { // If an array needs to be decomposed, it is marked with @@ -1932,6 +2370,29 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } return true; } + bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ElementTy) final { + std::cerr << "SyclKernelDecompMarker::leaveArray\n"; + // If an array needs to be decomposed, it is marked with + // SYCLRequiresDecompositionAttr. Else if the array is an array of pointers + // or an array of structs containing pointers, it is marked with + // SYCLGenerateNewTypeAttr. An array will never be marked with both + // attributes. + if (CollectionStack.pop_back_val()) { + // Cannot assert, since in MD arrays we'll end up marking them multiple + // times. + if (!PD->hasAttr()) + PD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( + SemaRef.getASTContext())); + CollectionStack.back() = true; + PointerStack.pop_back(); + } else if (PointerStack.pop_back_val()) { + if (!PD->hasAttr()) + PD->addAttr( + SYCLGenerateNewTypeAttr::CreateImplicit(SemaRef.getASTContext())); + PointerStack.back() = true; + } + return true; + } }; static QualType ModifyAddressSpace(Sema &SemaRef, QualType Ty) { @@ -1997,6 +2458,22 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { // Add generated field to generated record. ModifiedRecords.back()->addDecl(Field); } + // Create and add FieldDecl for FieldTy to generated record. + void addField(const ParmVarDecl *PD, QualType FieldTy) { + assert(!ModifiedRecords.empty() && + "ModifiedRecords should have at least 1 record"); + ASTContext &Ctx = SemaRef.getASTContext(); + auto *Field = FieldDecl::Create( + Ctx, ModifiedRecords.back(), SourceLocation(), SourceLocation(), + getModifiedName(PD->getIdentifier()), FieldTy, + Ctx.getTrivialTypeSourceInfo(FieldTy, SourceLocation()), /*BW=*/nullptr, + /*Mutable=*/false, ICIS_NoInit); + Field->setAccess(PD->getAccess()); + if (PD->hasAttrs()) + Field->setAttrs(PD->getAttrs()); + // Add generated field to generated record. + ModifiedRecords.back()->addDecl(Field); + } void createBaseSpecifier(const CXXRecordDecl *Parent, const CXXRecordDecl *RD, const CXXBaseSpecifier &BS) { @@ -2041,6 +2518,10 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { createNewType(Ty->getAsCXXRecordDecl()); return true; } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType Ty) final { + createNewType(Ty->getAsCXXRecordDecl()); + return true; + } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { CXXRecordDecl *ModifiedRD = getGeneratedNewRecord(Ty->getAsCXXRecordDecl()); @@ -2055,6 +2536,19 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + CXXRecordDecl *ModifiedRD = getGeneratedNewRecord(Ty->getAsCXXRecordDecl()); + + // Add this record as a field of it's parent record if it is not an + // array element. + if (!isArrayElement(PD, Ty)) + addField(PD, QualType(ModifiedRD->getTypeForDecl(), 0)); + else + ModifiedArrayElementsOrArray.push_back( + QualType(ModifiedRD->getTypeForDecl(), 0)); + + return true; + } bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType Ty) final { @@ -2095,6 +2589,30 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } + bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ET) final { + QualType ModifiedArrayElement = ModifiedArrayElementsOrArray.pop_back_val(); + + const ConstantArrayType *CAT = + SemaRef.getASTContext().getAsConstantArrayType(ArrayTy); + assert(CAT && "Should only be called on constant-size array."); + QualType ModifiedArray = SemaRef.getASTContext().getConstantArrayType( + ModifiedArrayElement, CAT->getSize(), + const_cast(CAT->getSizeExpr()), CAT->getSizeModifier(), + CAT->getIndexTypeCVRQualifiers()); + + if (ModifiedRecords.empty()) { + // This is a top-level kernel argument. + ModifiedArrayElementsOrArray.push_back(ModifiedArray); + } else if (!isArrayElement(PD, ArrayTy)) { + // Add this array field as a field of it's parent record. + addField(PD, ModifiedArray); + } else { + // Multi-dimensional array element. + ModifiedArrayElementsOrArray.push_back(ModifiedArray); + } + + return true; + } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { QualType ModifiedPointerType = ModifyAddressSpace(SemaRef, FieldTy); @@ -2106,21 +2624,43 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { // non-decomposed struct. return true; } + bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { + QualType ModifiedPointerType = ModifyAddressSpace(SemaRef, FieldTy); + if (!isArrayElement(PD, FieldTy)) + addField(PD, ModifiedPointerType); + else + ModifiedArrayElementsOrArray.push_back(ModifiedPointerType); + // We do not need to wrap pointers since this is a pointer inside + // non-decomposed struct. + return true; + } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { addField(FD, FieldTy); return true; } + bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { + addField(PD, FieldTy); + return true; + } bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return handleScalarType(FD, FieldTy); } + bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { + return handleScalarType(PD, FieldTy); + } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { addField(FD, Ty); return true; } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType Ty) final { + addField(PD, Ty); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *Parent, const CXXBaseSpecifier &BS, QualType Ty) final { @@ -2132,6 +2672,10 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { addField(FD, Ty); return true; } + bool handleSimpleArrayType(ParmVarDecl *PD, QualType Ty) final { + addField(PD, Ty); + return true; + } public: QualType getNewRecordType() { @@ -2158,11 +2702,20 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { size_t LastParamIndex = 0; // Keeps track of whether we are currently handling fields inside a struct. int StructDepth = 0; +#if 0 + // Map between original params and params generated for kernel. This is used + // for free functions. + llvm::SmallVector OrigParams; +#endif void addParam(const FieldDecl *FD, QualType FieldTy) { ParamDesc newParamDesc = makeParamDesc(FD, FieldTy); addParam(newParamDesc, FieldTy); } + void addParam(const ParmVarDecl *PD, QualType FieldTy) { + ParamDesc newParamDesc = makeParamDesc(PD, FieldTy); + addParam(newParamDesc, FieldTy); + } void addParam(const CXXBaseSpecifier &BS, QualType FieldTy) { // TODO: There is no name for the base available, but duplicate names are @@ -2306,6 +2859,40 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { LastParamIndex = ParamIndex; return true; } + bool handleSpecialType(ParmVarDecl *PD, QualType FieldTy) { + const auto *RecordDecl = FieldTy->getAsCXXRecordDecl(); + assert(RecordDecl && "The type must be a RecordDecl"); + llvm::StringLiteral MethodName = + KernelDecl->hasAttr() && isSyclAccessorType(FieldTy) + ? InitESIMDMethodName + : InitMethodName; + CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, MethodName); + assert(InitMethod && "The type must have the __init method"); + + // Don't do -1 here because we count on this to be the first parameter added + // (if any). + size_t ParamIndex = Params.size(); + for (const ParmVarDecl *Param : InitMethod->parameters()) { + QualType ParamTy = Param->getType(); + addParam(PD, ParamTy.getCanonicalType()); + + // Propagate add_ir_attributes_kernel_parameter attribute. + if (const auto *AddIRAttr = + Param->getAttr()) + Params.back()->addAttr(AddIRAttr->clone(SemaRef.getASTContext())); + + // FIXME: This code is temporary, and will be removed once __init_esimd + // is removed and property list refactored. + // The function handleAccessorType includes a call to + // handleAccessorPropertyList. If new classes with property list are + // added, this code needs to be refactored to call + // handleAccessorPropertyList for each class which requires it. + if (ParamTy.getTypePtr()->isPointerType() && isSyclAccessorType(FieldTy)) + handleAccessorType(FieldTy, RecordDecl, PD->getBeginLoc()); + } + LastParamIndex = ParamIndex; + return true; + } static void setKernelImplicitAttrs(ASTContext &Context, FunctionDecl *FD, bool IsSIMDKernel) { @@ -2334,6 +2921,26 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return FD; } + static FunctionDecl *createFreeFunctionDecl(ASTContext &Ctx, FunctionDecl *FD, + SourceLocation Loc, + bool IsInline) { + // Create this with no prototype, and we can fix this up after we've seen + // all the params. + FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); + QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); + const IdentifierInfo *NewIdent = + &Ctx.Idents.get(constructFreeFunctionKernelName(Ctx, FD)); + FD = FunctionDecl::Create( + Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), + FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); + FD->setImplicitlyInline(IsInline); + setKernelImplicitAttrs(Ctx, FD, false); + + // Add kernel to translation unit to see it in AST-dump. + Ctx.getTranslationUnitDecl()->addDecl(FD); + return FD; + } + // If the record has been marked with SYCLGenerateNewTypeAttr, // it implies that it contains a pointer within. This function // defines a PointerHandler visitor which visits this record @@ -2360,6 +2967,12 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { Visitor.visitArray(Owner, FD, FieldTy, PointerHandler); return PointerHandler.getNewArrayType(); } + QualType GenerateNewArrayType(ParmVarDecl *PD, QualType ParamTy) { + SyclKernelPointerHandler PointerHandler(SemaRef); + KernelObjVisitor Visitor{SemaRef}; + Visitor.visitArray(PD, ParamTy, PointerHandler); + return PointerHandler.getNewArrayType(); + } public: static constexpr const bool VisitInsideSimpleContainers = false; @@ -2375,6 +2988,28 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernel->getAttr()) KernelDecl->addAttr(AddIRAttrFunc->clone(SemaRef.getASTContext())); } + SyclKernelDeclCreator(Sema &S, SourceLocation Loc, bool IsInline, + FunctionDecl *SYCLKernel) + : SyclKernelFieldHandler(S), + KernelDecl(createFreeFunctionDecl(S.getASTContext(), SYCLKernel, Loc, + IsInline)), + FuncContext(SemaRef, KernelDecl) { +#if 1 + std::cerr << "Old free function declarator:\n"; + KernelDecl->dump(); + { + const IdentifierInfo *II = SYCLKernel->getIdentifier(); + if (II) + std::cerr << "Old free function name: " << II->getName().data() + << std::endl; + } +#endif + S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); + + if (const auto *AddIRAttrFunc = + SYCLKernel->getAttr()) + KernelDecl->addAttr(AddIRAttrFunc->clone(SemaRef.getASTContext())); + } ~SyclKernelDeclCreator() { ASTContext &Ctx = SemaRef.getASTContext(); @@ -2397,6 +3032,16 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernelAttr::CreateImplicit(SemaRef.getASTContext())); SemaRef.addSyclDeviceDecl(KernelDecl); +#if 1 + std::cerr << "Generated device function:\n"; + KernelDecl->dump(); + { + const IdentifierInfo *II = KernelDecl->getIdentifier(); + if (II) + std::cerr << "Generated device function name: " << II->getName().data() + << std::endl; + } +#endif } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { @@ -2404,11 +3049,23 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + //if (StructDepth == 0) + // addParam(PD, Ty); + ++StructDepth; + return true; + } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { --StructDepth; return true; } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + --StructDepth; + return true; + } + bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { ++StructDepth; @@ -2454,12 +3111,15 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { return handleSpecialType(FD, FieldTy); } + bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + return handleSpecialType(PD, FieldTy); + } - RecordDecl *wrapField(FieldDecl *Field, QualType FieldTy) { + RecordDecl *wrapParam(QualType FieldTy) { RecordDecl *WrapperClass = SemaRef.getASTContext().buildImplicitRecord("__wrapper_class"); WrapperClass->startDefinition(); - Field = FieldDecl::Create( + FieldDecl *Field = FieldDecl::Create( SemaRef.getASTContext(), WrapperClass, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy, SemaRef.getASTContext().getTrivialTypeSourceInfo(FieldTy, @@ -2480,24 +3140,52 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // passed directly. To work around this issue, all pointers inside the // struct are wrapped in a generated '__wrapper_class'. if (StructDepth) { - RecordDecl *WrappedPointer = wrapField(FD, ModTy); + RecordDecl *WrappedPointer = wrapParam(ModTy); ModTy = SemaRef.getASTContext().getRecordType(WrappedPointer); } addParam(FD, ModTy); return true; } + bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { + QualType ModTy = ModifyAddressSpace(SemaRef, FieldTy); + // When the kernel is generated, struct type kernel arguments are + // decomposed; i.e. the parameters of the kernel are the fields of the + // struct, and not the struct itself. This causes an error in the backend + // when the struct field is a pointer, since non-USM pointers cannot be + // passed directly. To work around this issue, all pointers inside the + // struct are wrapped in a generated '__wrapper_class'. + if (StructDepth) { + RecordDecl *WrappedPointer = wrapParam(ModTy); + ModTy = SemaRef.getASTContext().getRecordType(WrappedPointer); + } + + addParam(PD, ModTy); + return true; + } bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { QualType ArrayTy = FieldTy; // This is an array of pointers or an array of a type with pointer. - if (FD->hasAttr()) - ArrayTy = GenerateNewArrayType(FD, FieldTy); + if (FD->hasAttr()) + ArrayTy = GenerateNewArrayType(FD, FieldTy); + + // Arrays are wrapped in a struct since they cannot be passed directly. + RecordDecl *WrappedArray = wrapParam(ArrayTy); + addParam(FD, SemaRef.getASTContext().getRecordType(WrappedArray)); + return true; + } + bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { + QualType ArrayTy = FieldTy; + + // This is an array of pointers or an array of a type with pointer. + if (PD->hasAttr()) + ArrayTy = GenerateNewArrayType(PD, FieldTy); // Arrays are wrapped in a struct since they cannot be passed directly. - RecordDecl *WrappedArray = wrapField(FD, ArrayTy); - addParam(FD, SemaRef.getASTContext().getRecordType(WrappedArray)); + RecordDecl *WrappedArray = wrapParam(ArrayTy); + addParam(PD, SemaRef.getASTContext().getRecordType(WrappedArray)); return true; } @@ -2505,6 +3193,10 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { addParam(FD, FieldTy); return true; } + bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { + addParam(PD, FieldTy); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { @@ -2519,6 +3211,19 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { addParam(FD, Ty); return true; } + bool handleNonDecompStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + QualType Ty) final { + // This is a field which should not be decomposed. + CXXRecordDecl *FieldRecordDecl = Ty->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, Ty); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *Base, const CXXBaseSpecifier &BS, QualType Ty) final { @@ -2537,6 +3242,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return handleScalarType(FD, FieldTy); } + bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { + return handleScalarType(PD, FieldTy); + } // Generate kernel argument to initialize specialization constants. void handleSyclKernelHandlerType() { @@ -2550,6 +3258,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionDecl *getKernelDecl() { return KernelDecl; } + ParmVarDecl *getParamDecl(size_t Index) { return Params[Index]; } + llvm::ArrayRef getParamVarDeclsForCurrentField() { return ArrayRef(std::begin(Params) + LastParamIndex, std::end(Params)); @@ -2681,11 +3391,17 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { if (SizeOfParams > MaxKernelArgsSize) SemaRef.Diag(KernelLoc, diag::warn_sycl_kernel_too_big_args) << SizeOfParams << MaxKernelArgsSize; + std::cerr << "SyclKernelArgsSizeChecker::SizeOfParams = " << SizeOfParams + << std::endl; } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { return handleSpecialType(FieldTy); } + bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelArgsSizeChecker::handleSyclSpecialType\n"; + return handleSpecialType(FieldTy); + } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { @@ -2696,25 +3412,47 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { addParam(FieldTy); return true; } + bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelArgsSizeChecker::handlePointerType\n"; + addParam(FieldTy); + return true; + } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { addParam(FieldTy); return true; } + bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelArgsSizeChecker::handleScalarType\n"; + addParam(FieldTy); + return true; + } bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { addParam(FieldTy); return true; } + bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelArgsSizeChecker::handleSimpleArrayType\n"; + addParam(FieldTy); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { addParam(Ty); return true; } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType Ty) final { + std::cerr << "SyclKernelArgsSizeChecker::handleNonDecompStruct\n"; + addParam(Ty); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *Base, const CXXBaseSpecifier &BS, QualType Ty) final { + std::cerr << "SyclKernelArgsSizeChecker::handleUnionType\n"; addParam(Ty); return true; } @@ -2722,6 +3460,10 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return handleScalarType(FD, FieldTy); } + bool handleUnionType(ParmVarDecl *PD, QualType ParmTy) final { + std::cerr << "SyclKernelArgsSizeChecker::handleUnionType\n"; + return handleScalarType(PD, ParmTy); + } }; std::string getKernelArgDesc(StringRef KernelArgDescription) { @@ -2900,6 +3642,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { llvm::SmallVector MemberExprBases; llvm::SmallVector ArrayParamBases; FunctionDecl *KernelCallerFunc; + FunctionDecl *FreeFunc; SourceLocation KernelCallerSrcLoc; // KernelCallerFunc source location. // Contains a count of how many containers we're in. This is used by the // pointer-struct-wrapping code to ensure that we don't try to wrap @@ -2908,6 +3651,11 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { VarDecl *KernelHandlerClone = nullptr; bool IsESIMD = false; CXXMethodDecl *CallOperator = nullptr; + // For free functions we create local copies of the parameters and replace + // uses within the body to use the local copies. For parameters requiring + // breakdown into components multiple items will be placed on these lists. + llvm::SmallVector OriginalParams; + llvm::SmallVector NewParams; Stmt *replaceWithLocalClone(ParmVarDecl *OriginalParam, VarDecl *LocalClone, Stmt *FunctionBody) { @@ -2956,6 +3704,34 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { FPOptionsOverride(), {}, {}); } + // Using the statements/init expressions that we've created, this generates + // the kernel body compound stmt. CompoundStmt needs to know its number of + // statements in advance to allocate it, so we cannot do this as we go along. + CompoundStmt *createFreeFunctionKernelBody() { + // Push the Kernel function scope to ensure the scope isn't empty + SemaRef.PushFunctionScope(); + + BodyStmts.push_back(FreeFunc->getBody()); + + BodyStmts.insert(BodyStmts.end(), FinalizeStmts.begin(), + FinalizeStmts.end()); + + Stmt *NewBody = CompoundStmt::Create(SemaRef.getASTContext(), BodyStmts, + FPOptionsOverride(), {}, {}); + + // Replace references to the parameters in kernel body, to use the + // parameters of the newly created body function, or the compiler generated + // local clones for the parameters that are expanded. + int index = 0; + for (auto Param : OriginalParams) { + NewParams[index]->setIsUsed(); + NewBody = replaceWithLocalClone(Param, NewParams[index], NewBody); + ++index; + } + + return static_cast(NewBody); + } + void annotateHierarchicalParallelismAPICalls() { // Is this a hierarchical parallelism kernel invocation? if (getKernelInvocationKind(KernelCallerFunc) != InvokeParallelForWorkGroup) @@ -3078,6 +3854,37 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { Init.get()); } + // Creates an initialized entity for a function local. + InitializedEntity getVarEntity(VarDecl *VD, QualType Ty) { + return InitializedEntity::InitializeVariable(VD); + } + + void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef) { + InitializationKind InitKind = + InitializationKind::CreateCopy(KernelCallerSrcLoc, KernelCallerSrcLoc); + addVarInit(VD, Ty, ParamRef, InitKind); + } + + void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, + InitializationKind InitKind) { + addVarInit(VD, Ty, ParamRef, InitKind, getVarEntity(VD, Ty)); + } + + void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, + InitializationKind InitKind, InitializedEntity Entity) { + InitializationSequence InitSeq(SemaRef, Entity, InitKind, ParamRef); + ExprResult Init = InitSeq.Perform(SemaRef, Entity, InitKind, ParamRef); + InitListExpr *ILE = createInitListExpr(Ty, 1); + CollectionInitExprs.push_back(ILE); + VD->setInit(ILE); + Stmt *DS = new (SemaRef.Context) + DeclStmt(DeclGroupRef(VD), KernelCallerSrcLoc, KernelCallerSrcLoc); + BodyStmts.push_back(DS); + DeclRefExpr *VDRef = DeclRefExpr::Create( + SemaRef.Context, NestedNameSpecifierLoc(), KernelCallerSrcLoc, VD, + false, DeclarationNameInfo(), Ty, VK_LValue); + } + void addBaseInit(const CXXBaseSpecifier &BS, QualType Ty, InitializationKind InitKind) { InitializedEntity Entity = InitializedEntity::InitializeBase( @@ -3123,6 +3930,10 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { Expr *ParamRef = createParamReferenceExpr(); addFieldInit(FD, Ty, ParamRef); } + void addSimpleLocalInit(VarDecl *VD, QualType Ty) { + Expr *ParamRef = createParamReferenceExpr(); + addVarInit(VD, Ty, ParamRef); + } Expr *createGetAddressOf(Expr *E) { return UnaryOperator::Create(SemaRef.Context, E, UO_AddrOf, @@ -3157,6 +3968,21 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { Expr *Initializer = createDerefOp(RCE); addFieldInit(FD, Ty, Initializer); } + void handleGeneratedType(ParmVarDecl *PD, QualType Ty) { + std::cerr << "SyclKernelBodyCreator::handleGeneratedType(PD)\n"; + Expr *RCE = createReinterpretCastExpr( + createGetAddressOf(createParamReferenceExpr()), + SemaRef.Context.getPointerType(Ty)); + Expr *Initializer = createDerefOp(RCE); + addVarInit(PD, Ty, Initializer); + } + void handleGeneratedType(VarDecl *VD, QualType Ty) { + Expr *RCE = createReinterpretCastExpr( + createGetAddressOf(createParamReferenceExpr()), + SemaRef.Context.getPointerType(Ty)); + Expr *Initializer = createDerefOp(RCE); + addVarInit(VD, Ty, Initializer); + } void handleGeneratedType(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) { @@ -3194,6 +4020,19 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { MemberExprBases.pop_back(); } + Expr *buildParamCloneExpr(VarDecl *LocalClone, QualType Ty) { + DeclRefExpr *ParamCloneRef = DeclRefExpr::Create( + SemaRef.Context, NestedNameSpecifierLoc(), KernelCallerSrcLoc, + LocalClone, false, DeclarationNameInfo(), Ty, VK_LValue); + return ParamCloneRef; + } + + void addParamCloneExpr(VarDecl *VD, QualType Ty) { + MemberExprBases.push_back(buildParamCloneExpr(VD, Ty)); + } + + void removeParamCloneExpr() { MemberExprBases.pop_back(); } + void createSpecialMethodCall(const CXXRecordDecl *RD, StringRef MethodName, SmallVectorImpl &AddTo) { CXXMethodDecl *Method = getMethodByName(RD, MethodName); @@ -3276,6 +4115,18 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { QualType(KernelObj->getTypeForDecl(), 0), TSInfo, SC_None); return VD; } + static VarDecl *createParamClone(ASTContext &Ctx, DeclContext *DC, + const ParmVarDecl *Param) { + IdentifierInfo *Ident = Param->getIdentifier(); + if (!Ident) + Ident = &Ctx.Idents.get("__SYCLParam"); + + VarDecl *VD = + VarDecl::Create(Ctx, DC, Param->getLocation(), Param->getLocation(), + Ident, QualType(Param->getType()), nullptr, SC_None); + VD->setIsUsed(); + return VD; + } const llvm::StringLiteral getInitMethodName() const { return IsESIMD ? InitESIMDMethodName : InitMethodName; @@ -3283,6 +4134,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { // Default inits the type, then calls the init-method in the body. bool handleSpecialType(FieldDecl *FD, QualType Ty) { + std::cerr << "SyclKernelBodyCreator::handleSpecialType(FD)\n"; addFieldInit(FD, Ty, std::nullopt, InitializationKind::CreateDefault(KernelCallerSrcLoc)); @@ -3300,8 +4152,39 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } + // Default inits the type. + bool handleSpecialType(ParmVarDecl *PD, QualType Ty) { + std::cerr << "SyclKernelBodyCreator::handleSpecialType(PD)\n"; + VarDecl *VD = createParamClone(SemaRef.getASTContext(), + DeclCreator.getKernelDecl(), PD); + // Create local clone of the special parameter + handleGeneratedType(VD, Ty); + // Default initialize local clone + InitializedEntity VarEntity = InitializedEntity::InitializeVariable(VD); + InitializationKind InitKind = + InitializationKind::CreateDefault(KernelCallerSrcLoc); + InitializationSequence InitSeq(SemaRef, VarEntity, InitKind, std::nullopt); + ExprResult Init = + InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); + VD->setInit(SemaRef.MaybeCreateExprWithCleanups(Init.get())); + + addParamCloneExpr(VD, Ty); + + const auto *RecordDecl = Ty->getAsCXXRecordDecl(); + createSpecialMethodCall(RecordDecl, getInitMethodName(), BodyStmts); + CXXMethodDecl *FinalizeMethod = + getMethodByName(RecordDecl, FinalizeMethodName); + // A finalize-method is expected for special type such as stream. + if (FinalizeMethod) + createSpecialMethodCall(RecordDecl, FinalizeMethodName, FinalizeStmts); + + removeParamCloneExpr(); + + return true; + } bool handleSpecialType(const CXXBaseSpecifier &BS, QualType Ty) { + std::cerr << "SyclKernelBodyCreator::handleSpecialType(BS)\n"; const auto *RecordDecl = Ty->getAsCXXRecordDecl(); addBaseInit(BS, Ty, InitializationKind::CreateDefault(KernelCallerSrcLoc)); createSpecialMethodCall(RecordDecl, getInitMethodName(), BodyStmts); @@ -3335,7 +4218,8 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { InitializationKind InitKind = InitializationKind::CreateDefault(KernelCallerSrcLoc); InitializationSequence InitSeq(SemaRef, VarEntity, InitKind, std::nullopt); - ExprResult Init = InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); + ExprResult Init = + InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); KernelHandlerClone->setInit( SemaRef.MaybeCreateExprWithCleanups(Init.get())); KernelHandlerClone->setInitStyle(VarDecl::CallInit); @@ -3428,7 +4312,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { KernelObjClone(createKernelObjClone(S.getASTContext(), DC.getKernelDecl(), KernelObj)), VarEntity(InitializedEntity::InitializeVariable(KernelObjClone)), - KernelCallerFunc(KernelCallerFunc), + KernelCallerFunc(KernelCallerFunc), FreeFunc(nullptr), KernelCallerSrcLoc(KernelCallerFunc->getLocation()), IsESIMD(IsSIMDKernel), CallOperator(CallOperator) { CollectionInitExprs.push_back(createInitListExpr(KernelObj)); @@ -3443,38 +4327,99 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { VK_LValue); MemberExprBases.push_back(KernelObjCloneRef); } + SyclKernelBodyCreator(Sema &S, SyclKernelDeclCreator &DC, FunctionDecl *FF, + CXXRecordDecl *Dummy) + : SyclKernelFieldHandler(S), DeclCreator(DC), + KernelObjClone( + createKernelObjClone(S.getASTContext(), DC.getKernelDecl(), Dummy)), + VarEntity(InitializedEntity::InitializeVariable(KernelObjClone)), + KernelCallerFunc(nullptr), FreeFunc(FF), + KernelCallerSrcLoc(FreeFunc->getLocation()), IsESIMD(false) {} ~SyclKernelBodyCreator() { - CompoundStmt *KernelBody = createKernelBody(); + CompoundStmt *KernelBody; + if (KernelCallerFunc) + KernelBody = createKernelBody(); + else + KernelBody = createFreeFunctionKernelBody(); + DeclCreator.setBody(KernelBody); } +#if 0 + bool handleStructType(FieldDecl* FD, QualType FieldTy) final { + return true; + } + bool handleStructType(ParmVarDecl* PD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handleStructType(FD)\n"; + VarDecl* VD = createParamClone(SemaRef.getASTContext(), + DeclCreator.getKernelDecl(), PD); + addParamCloneExpr(VD, FieldTy); + handleGeneratedType(VD, FieldTy); + return true; + } +#endif + bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::handleSyclSpecialType(FD)\n"; return handleSpecialType(FD, Ty); } + bool handleSyclSpecialType(ParmVarDecl *PD, QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::handleSyclSpecialType(PD)\n"; + bool Result = handleSpecialType(PD, Ty); + OriginalParams.push_back(PD); + NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + return Result; + } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::handleSyclSpecialType(RD)\n"; return handleSpecialType(BS, Ty); } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handlePointerType(FD)\n"; Expr *PointerRef = createPointerParamReferenceExpr(FieldTy, StructDepth != 0); addFieldInit(FD, FieldTy, PointerRef); return true; } + bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handlePointerType(PD)\n"; + std::cerr << "CurrParamIndex = " + << DeclCreator.getParamVarDeclsForCurrentField()[0] + << " OriginalParams = " << (void *)PD << " NewParams = " + << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) + << std::endl; + OriginalParams.push_back(PD); + NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + return true; + } bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handleSimpleArrayType(FD)\n"; if (FD->hasAttr()) handleGeneratedArrayType(FD, FieldTy); else addSimpleArrayInit(FD, FieldTy); return true; } + bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handleSimpleArrayType(PD)\n"; + std::cerr << "CurrParamIndex = " + << DeclCreator.getParamVarDeclsForCurrentField()[0] + << " OriginalParams = " << (void *)PD << " NewParams = " + << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) + << std::endl; + OriginalParams.push_back(PD); + NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::handleNonDecompStruct()\n"; CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); assert(RD && "Type must be a C++ record type"); if (RD->hasAttr()) @@ -3483,9 +4428,27 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addSimpleFieldInit(FD, Ty); return true; } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::handleNonDecompStruct(PD)\n"; + std::cerr << "CurrParamIndex = " + << DeclCreator.getParamVarDeclsForCurrentField()[0] + << " OriginalParams = " << (void *)PD << " NewParams = " + << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) + << std::endl; + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + assert(RD && "Type must be a C++ record type"); + if (RD->hasAttr()) + handleGeneratedType(PD, Ty); + + OriginalParams.push_back(PD); + NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::handleNonDecompStruct(RD)\n"; CXXRecordDecl *BaseDecl = Ty->getAsCXXRecordDecl(); assert(BaseDecl && "Type must be a C++ record type"); if (BaseDecl->hasAttr()) @@ -3496,14 +4459,45 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handleScalarType(FD)\n"; addSimpleFieldInit(FD, FieldTy); return true; } + bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { +#if 0 + // Create local variable initialized with parameter. + VarDecl *VD = createParamClone(SemaRef.getASTContext(), + DeclCreator.getKernelDecl(), PD); + addSimpleLocalInit(VD, FieldTy); + OriginalParams.push_back(PD); + NewParams.push_back(VD); +#endif + std::cerr << "SyclKernelBodyCreator::handleScalarType(PD)\n"; + std::cerr << "CurrParamIndex = " + << DeclCreator.getParamVarDeclsForCurrentField()[0] + << " OriginalParams = " << (void *)PD << " NewParams = " + << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) + << std::endl; + OriginalParams.push_back(PD); + NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + return true; + } bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { addSimpleFieldInit(FD, FieldTy); return true; } + bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelBodyCreator::handleUnionType(PD)\n"; + std::cerr << "CurrParamIndex = " + << DeclCreator.getParamVarDeclsForCurrentField()[0] + << " OriginalParams = " << (void *)PD << " NewParams = " + << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) + << std::endl; + OriginalParams.push_back(PD); + NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + return true; + } // Default inits the type, then calls the init-method in the body void handleSyclKernelHandlerType(ParmVarDecl *KernelHandlerArg) { @@ -3535,6 +4529,37 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } + bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::enterStruct(PD)\n"; + if (StructDepth == 0) { + std::cerr << "SyclKernelBodyCreator::enterStruct \n"; + + // Get type of PD, which should be a Record + RD = PD->getType()->getAsCXXRecordDecl(); + assert(RD && "Free function parameter expected as Record type"); + // Create local clone of the Record parameter. + VarDecl *ParamClone = createKernelObjClone( + SemaRef.getASTContext(), DeclCreator.getKernelDecl(), RD); + // Default init it. + InitializedEntity::InitializeVariable(ParamClone); + CollectionInitExprs.push_back(createInitListExpr(RD)); + + Stmt *DS = new (SemaRef.Context) DeclStmt( + DeclGroupRef(ParamClone), KernelCallerSrcLoc, KernelCallerSrcLoc); + BodyStmts.push_back(DS); + DeclRefExpr *ParamCloneRef = DeclRefExpr::Create( + SemaRef.Context, NestedNameSpecifierLoc(), KernelCallerSrcLoc, + ParamClone, false, DeclarationNameInfo(), + QualType(RD->getTypeForDecl(), 0), VK_LValue); + MemberExprBases.push_back(ParamCloneRef); + OriginalParams.push_back(PD); + NewParams.push_back(ParamClone); + } + ++StructDepth; + return true; + } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { --StructDepth; CollectionInitExprs.pop_back(); @@ -3543,6 +4568,15 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + std::cerr << "SyclKernelBodyCreator::leaveStruct(PD)\n"; + if (StructDepth == 0) { + std::cerr << "SyclKernelBodyCreator::leaveStruct \n"; + } + --StructDepth; + return true; + } + bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { ++StructDepth; @@ -3583,6 +4617,22 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addFieldMemberExpr(FD, ArrayType); return true; } + bool enterArray(ParmVarDecl *PD, QualType ArrayType, + QualType ElementType) final { +#if 0 + const ConstantArrayType* CAT = + SemaRef.getASTContext().getAsConstantArrayType(ArrayType); + assert(CAT && "Should only be called on constant-size array."); + uint64_t ArraySize = CAT->getSize().getZExtValue(); + addCollectionInitListExpr(ArrayType, ArraySize); + ArrayInfos.emplace_back(getFieldEntity(FD, ArrayType), 0); + + // If this is the top-level array, we need to make a MemberExpr in addition + // to an array subscript. + addFieldMemberExpr(FD, ArrayType); +#endif + return true; + } bool nextElement(QualType, uint64_t Index) final { ArrayInfos.back().second = Index; @@ -3611,14 +4661,37 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { removeFieldMemberExpr(FD, ArrayType); return true; } + + bool leaveArray(ParmVarDecl *PD, QualType ArrayType, + QualType ElementType) final { +#if 0 + CollectionInitExprs.pop_back(); + ArrayInfos.pop_back(); + + // Remove the IndexExpr. + if (!FD->hasAttr()) + MemberExprBases.pop_back(); + else + ArrayParamBases.pop_back(); + + // Remove the field access expr as well. + removeFieldMemberExpr(FD, ArrayType); +#endif + return true; + } }; // Kernels are only the unnamed-lambda feature if the feature is enabled, AND // the first template argument has been corrected by the library to match the // functor type. static bool IsSYCLUnnamedKernel(Sema &SemaRef, const FunctionDecl *FD) { + // If free function then remaining checks are not applicable. + if (IsFreeFunction(SemaRef, FD)) + return false; + if (!SemaRef.getLangOpts().SYCLUnnamedLambda) return false; + QualType FunctorTy = GetSYCLKernelObjectType(FD); QualType TmplArgTy = calculateKernelNameType(SemaRef.Context, FD); return SemaRef.Context.hasSameType(FunctorTy, TmplArgTy); @@ -3636,6 +4709,10 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ? 0 : SemaRef.getASTContext().getFieldOffset(FD) / 8; } + // For free functions each parameter is stand-alone, so offsets within a + // lambda/function object are not relevant. Therefore offsetOf will always be + // 0. + int64_t offsetOf(const ParmVarDecl *, QualType) const { return 0; } int64_t offsetOf(const CXXRecordDecl *RD, const CXXRecordDecl *Base) const { const ASTRecordLayout &Layout = @@ -3647,6 +4724,16 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { SYCLIntegrationHeader::kernel_param_kind_t Kind) { addParam(ArgTy, Kind, offsetOf(FD, ArgTy)); } + + // For free function we increment the current offset as each parameter is + // added. + void addParam(const ParmVarDecl *PD, QualType ArgTy, + SYCLIntegrationHeader::kernel_param_kind_t Kind) { + addParam(ArgTy, Kind, offsetOf(PD, ArgTy)); + CurOffset += + SemaRef.getASTContext().getTypeSizeInChars(ArgTy).getQuantity(); + } + void addParam(QualType ArgTy, SYCLIntegrationHeader::kernel_param_kind_t Kind, uint64_t OffsetAdj) { uint64_t Size; @@ -3669,6 +4756,13 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { Header.startKernel(KernelFunc, NameType, KernelObj->getLocation(), IsESIMD, IsSYCLUnnamedKernel(S, KernelFunc), ObjSize); } + SyclKernelIntHeaderCreator(Sema &S, SYCLIntegrationHeader &H, int64_t ObjSize, + QualType NameType, FunctionDecl *FreeFunc) + : SyclKernelFieldHandler(S), Header(H) { + Header.startKernel(FreeFunc, NameType, FreeFunc->getLocation(), + false /*IsESIMD*/, true /*IsSYCLUnnamedKernel*/, + ObjSize); + } bool handleSyclSpecialType(const CXXRecordDecl *RD, const CXXBaseSpecifier &BC, @@ -3722,6 +4816,45 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } return true; } + bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelIntHeaderCreator::handleSyclSpecialType\n"; + const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); + assert(ClassTy && "Type must be a C++ record type"); + if (isSyclAccessorType(FieldTy)) { + const auto *AccTy = + cast(FieldTy->getAsRecordDecl()); + assert(AccTy->getTemplateArgs().size() >= 2 && + "Incorrect template args for Accessor Type"); + int Dims = static_cast( + AccTy->getTemplateArgs()[1].getAsIntegral().getExtValue()); + int Info = getAccessTarget(FieldTy, AccTy) | (Dims << 11); + + Header.addParamDesc(SYCLIntegrationHeader::kind_accessor, Info, + CurOffset + offsetOf(PD, FieldTy)); + CurOffset += + SemaRef.getASTContext().getTypeSizeInChars(FieldTy).getQuantity(); + } else if (isSyclType(FieldTy, SYCLTypeAttr::stream)) { + addParam(PD, FieldTy, SYCLIntegrationHeader::kind_stream); + } else if (isSyclType(FieldTy, SYCLTypeAttr::sampler) || + isSyclType(FieldTy, SYCLTypeAttr::annotated_ptr) || + isSyclType(FieldTy, SYCLTypeAttr::annotated_arg)) { + CXXMethodDecl *InitMethod = getMethodByName(ClassTy, InitMethodName); + assert(InitMethod && "type must have __init method"); + const ParmVarDecl *InitArg = InitMethod->getParamDecl(0); + assert(InitArg && "Init method must have arguments"); + QualType T = InitArg->getType(); + SYCLIntegrationHeader::kernel_param_kind_t ParamKind = + isSyclType(FieldTy, SYCLTypeAttr::sampler) + ? SYCLIntegrationHeader::kind_sampler + : (T->isPointerType() ? SYCLIntegrationHeader::kind_pointer + : SYCLIntegrationHeader::kind_std_layout); + addParam(T, ParamKind, offsetOf(PD, FieldTy)); + } else { + llvm_unreachable( + "Unexpected SYCL special class when generating integration header"); + } + return true; + } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { addParam(FD, FieldTy, @@ -3729,11 +4862,23 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { : SYCLIntegrationHeader::kind_pointer)); return true; } + bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelIntHeaderCreator::handlePointerType\n"; + addParam(PD, FieldTy, + ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout + : SYCLIntegrationHeader::kind_pointer)); + return true; + } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); return true; } + bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelIntHeaderCreator::handleScalarType\n"; + addParam(PD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { // Arrays are always wrapped inside of structs, so just treat it as a simple @@ -3741,12 +4886,24 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); return true; } + bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelIntHeaderCreator::handleSimpleArrayType\n"; + // Arrays are always wrapped inside of structs, so just treat it as a simple + // struct. + addParam(PD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { addParam(FD, Ty, SYCLIntegrationHeader::kind_std_layout); return true; } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType Ty) final { + addParam(PD, Ty, SYCLIntegrationHeader::kind_std_layout); + return true; + } bool handleNonDecompStruct(const CXXRecordDecl *Base, const CXXBaseSpecifier &, QualType Ty) final { @@ -3758,6 +4915,10 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return handleScalarType(FD, FieldTy); } + bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { + std::cerr << "SyclKernelIntHeaderCreator::handleUnionType\n"; + return handleScalarType(PD, FieldTy); + } void handleSyclKernelHandlerType(QualType Ty) { // The compiler generated kernel argument used to initialize SYCL 2020 @@ -3775,12 +4936,24 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { CurOffset += offsetOf(FD, Ty); return true; } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + std::cerr << "SyclKernelIntHeaderCreator::enterStruct\n"; + ++StructDepth; + CurOffset += offsetOf(PD, Ty); + return true; + } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { --StructDepth; CurOffset -= offsetOf(FD, Ty); return true; } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + std::cerr << "SyclKernelIntHeaderCreator::leaveStruct\n"; + --StructDepth; + CurOffset -= offsetOf(PD, Ty); + return true; + } bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { @@ -3798,6 +4971,11 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ArrayBaseOffsets.push_back(CurOffset + offsetOf(FD, ArrayTy)); return true; } + bool enterArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { + std::cerr << "SyclKernelIntHeaderCreator::enterArray\n"; + ArrayBaseOffsets.push_back(CurOffset + offsetOf(PD, ArrayTy)); + return true; + } bool nextElement(QualType ET, uint64_t Index) final { int64_t Size = SemaRef.getASTContext().getTypeSizeInChars(ET).getQuantity(); @@ -3810,6 +4988,12 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { CurOffset -= offsetOf(FD, ArrayTy); return true; } + bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { + std::cerr << "SyclKernelIntHeaderCreator::leaveArray\n"; + CurOffset = ArrayBaseOffsets.pop_back_val(); + CurOffset -= offsetOf(PD, ArrayTy); + return true; + } using SyclKernelFieldHandler::enterStruct; using SyclKernelFieldHandler::leaveStruct; @@ -4256,6 +5440,63 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, } } +void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { +#if 1 + { + const IdentifierInfo *II = FD->getIdentifier(); + if (II) + std::cerr << "ConstructFreeFunctionKernel: " << II->getName().data() + << std::endl; + FD->dump(); + } +#endif + + SyclKernelArgsSizeChecker argsSizeChecker(SemaRef, FD->getLocation(), + false /*IsSIMDKernel*/); + SyclKernelDeclCreator kernel_decl(SemaRef, FD->getLocation(), FD->isInlined(), + FD); + +#if 1 + RecordDecl *DummyClass = + SemaRef.getASTContext().buildImplicitRecord("__dummy_class"); + DummyClass->startDefinition(); + DummyClass->completeDefinition(); + + CXXRecordDecl *DummyClass1 = static_cast(DummyClass); + SyclKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD, DummyClass1); +#endif + + // Kernel object size is irrelevant, so set to 0. + SyclKernelIntHeaderCreator int_header(SemaRef, + SemaRef.getSyclIntegrationHeader(), 0, + calculateFreeFunctionNameType(FD), FD); + + SyclKernelIntFooterCreator int_footer(SemaRef, + SemaRef.getSyclIntegrationFooter()); + KernelObjVisitor Visitor{SemaRef}; + + // Visit handlers to generate information for optimization record only if + // optimization record is saved. + if (!SemaRef.getLangOpts().OptRecordFile.empty()) { + Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, + kernel_body, int_header, + int_footer /*,opt_report*/); + } else { + Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, + kernel_body, int_header, int_footer); + } +#if 1 + { + FunctionDecl *FF_FD = kernel_decl.getKernelDecl(); + const IdentifierInfo *II = FF_FD->getIdentifier(); + if (II) + std::cerr << "Generated FreeFunction: " << II->getName().data() + << std::endl; + FF_FD->dump(); + } +#endif +}; + // Figure out the sub-group for the this function. First we check the // attributes, then the global settings. static std::pair @@ -4515,7 +5756,9 @@ static void PropagateAndDiagnoseDeviceAttr( } } -void Sema::MarkDevices() { +void Sema::ProcessDeviceFunctions() { + std::cerr << "***** ProcessDeviceFunctions\n"; + SmallVector FreeFunctions; // This Tracker object ensures that the SyclDeviceDecls collection includes // the SYCL_EXTERNAL functions, and manages the diagnostics for all of the // functions in the kernel. @@ -4535,6 +5778,32 @@ void Sema::MarkDevices() { PropagateAndDiagnoseDeviceAttr(*this, T, A, T.GetSYCLKernel(), T.GetKernelBody()); CheckSYCLAddIRAttributesFunctionAttrConflicts(T.GetSYCLKernel()); + + if (IsFreeFunction(*this, SYCLKernel)) { + FreeFunctions.push_back(SYCLKernel); + } + } + + for (FunctionDecl* FF : FreeFunctions) { + SyclKernelDecompMarker DecompMarker(*this); + SyclKernelFieldChecker FieldChecker(*this); + SyclKernelUnionChecker UnionChecker(*this); + + KernelObjVisitor Visitor{ *this }; + + DiagnosingSYCLKernel = true; + + // Check parameters of free function. + Visitor.VisitFunctionParameters(FF, DecompMarker, FieldChecker, + UnionChecker); + + DiagnosingSYCLKernel = false; + + // Ignore the free function if any of the checkers fail validation. + if (!FieldChecker.isValid() || !UnionChecker.isValid()) + return; + + ConstructFreeFunctionKernel(*this, FF); } } @@ -5224,7 +6493,6 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "\n"; } - O << "// names of all kernels defined in the corresponding source\n"; O << "static constexpr\n"; O << "const char* const kernel_names[] = {\n"; @@ -5610,10 +6878,10 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) { for (const VarDecl *VD : GlobalVars) { VD = VD->getCanonicalDecl(); - // Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This + // Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This // can happen if it was a deduced type. if (!isSyclType(VD->getType(), SYCLTypeAttr::specialization_id) && - !isSyclType(VD->getType(), SYCLTypeAttr::host_pipe) && + !isSyclType(VD->getType(), SYCLTypeAttr::host_pipe) && !S.isTypeDecoratedWithDeclAttribute( VD->getType())) continue; @@ -5655,8 +6923,7 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) { VD->getNameForDiagnostic(HostPipesOS, Policy, true); } HostPipesOS << ", \""; - HostPipesOS << SYCLUniqueStableIdExpr::ComputeName(S.getASTContext(), - VD); + HostPipesOS << SYCLUniqueStableIdExpr::ComputeName(S.getASTContext(), VD); HostPipesOS << "\");\n"; } else { EmittedFirstSpecConstant = true; diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index dc53678d2618c..86b1172a8cae5 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -58,6 +58,23 @@ struct device_has_key { std::integral_constant...>; }; +struct range_kernel_key { + template + using value_t = + property_value>; +}; + +struct nd_range_kernel_key { + template + using value_t = + property_value>; +}; + +struct single_task_kernel_key { + using value_t = property_value; +}; + + template struct property_value, std::integral_constant...> { @@ -110,6 +127,32 @@ struct property_value value{Aspects...}; }; +template +struct property_value> { + static_assert(Dims >= 1 && Dims <= 3, + "range_kernel_key property must use dimension of 1, 2 or 3."); + + using key_t = range_kernel_key; + using value_t = int; + static constexpr int value = Dims; +}; + +template +struct property_value> { + static_assert( + Dims >= 1 && Dims <= 3, + "nd_range_kernel_key property must use dimension of 1, 2 or 3."); + + using key_t = nd_range_kernel_key; + using value_t = int; + static constexpr int value = Dims; +}; + +template <> +struct property_value { + using key_t = single_task_kernel_key; +}; + template inline constexpr work_group_size_key::value_t work_group_size; @@ -123,11 +166,35 @@ inline constexpr sub_group_size_key::value_t sub_group_size; template inline constexpr device_has_key::value_t device_has; +template +inline constexpr range_kernel_key::value_t range_kernel; + +template +inline constexpr nd_range_kernel_key::value_t nd_range_kernel; + +inline constexpr single_task_kernel_key::value_t single_task_kernel; + template <> struct is_property_key : std::true_type {}; template <> struct is_property_key : std::true_type {}; template <> struct is_property_key : std::true_type {}; template <> struct is_property_key : std::true_type {}; +template <> struct is_property_key : std::true_type {}; +template <> struct is_property_key : std::true_type {}; +template <> struct is_property_key : std::true_type {}; + +template struct is_range_kernel; +template struct is_nd_range_kernel; +template struct is_single_task_kernel; + +template +inline constexpr bool is_range_kernel_v = is_range_kernel::value; +template +inline constexpr bool is_nd_range_kernel_v = + is_nd_range_kernel::value; +template +inline constexpr bool is_single_task_kernel_v = + is_single_task_kernel::value; namespace detail { template <> struct PropertyToKind { @@ -142,6 +209,15 @@ template <> struct PropertyToKind { template <> struct PropertyToKind { static constexpr PropKind Kind = PropKind::DeviceHas; }; +template <> struct PropertyToKind { + static constexpr PropKind Kind = PropKind::RangeKernel; +}; +template <> struct PropertyToKind { + static constexpr PropKind Kind = PropKind::NDRangeKernel; +}; +template <> struct PropertyToKind { + static constexpr PropKind Kind = PropKind::SingleTaskKernel; +}; template <> struct IsCompileTimeProperty : std::true_type {}; @@ -172,6 +248,20 @@ struct PropertyMetaInfo> { static constexpr const char *value = SizeListToStr(Aspects)...>::value; }; +template +struct PropertyMetaInfo> { + static constexpr const char* name = "sycl-range-kernel"; + static constexpr int value = Dims; +}; +template +struct PropertyMetaInfo> { + static constexpr const char* name = "sycl-nd-range-kernel"; + static constexpr int value = Dims; +}; +template <> +struct PropertyMetaInfo { + static constexpr const char* name = "sycl-single-task-kernel"; +}; template struct HasKernelPropertiesGetMethod : std::false_type {}; @@ -198,6 +288,32 @@ struct HasKernelPropertiesGetMethod>>::name, \ sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ std::remove_cv_t>>::value)]] + +#define SYCL_EXT_ONEAPI_RANGE_KERNEL_PROPERTY(PROP) \ + [[__sycl_detail__::add_ir_attributes_function( \ + {"sycl-range-kernel"}, \ + sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ + std::remove_cv_t>>::name, \ + sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ + std::remove_cv_t>>::value)]] + +#define SYCL_EXT_ONEAPI_ND_RANGE_KERNEL_PROPERTY(PROP) \ + [[__sycl_detail__::add_ir_attributes_function( \ + {"sycl-nd-range-kernel"}, \ + sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ + std::remove_cv_t>>::name, \ + sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ + std::remove_cv_t>>::value)]] + +#define SYCL_EXT_ONEAPI_SINGLE_TASK_KERNEL_PROPERTY(PROP) \ + [[__sycl_detail__::add_ir_attributes_function( \ + {"sycl-single-task-kernel"}, \ + sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ + std::remove_cv_t>>::name, \ + 0)]] #else #define SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(PROP) +#define SYCL_EXT_ONEAPI_RANGE_KERNEL_PROPERTY(PROP) +#define SYCL_EXT_ONEAPI_ND_RANGE_KERNEL_PROPERTY(PROP) +#define SYCL_EXT_ONEAPI_SINGLE_TASK_KERNEL_PROPERTY(PROP) #endif diff --git a/sycl/include/sycl/ext/oneapi/properties/property.hpp b/sycl/include/sycl/ext/oneapi/properties/property.hpp index 72cd83b7c435a..458253770aba7 100644 --- a/sycl/include/sycl/ext/oneapi/properties/property.hpp +++ b/sycl/include/sycl/ext/oneapi/properties/property.hpp @@ -221,8 +221,11 @@ enum PropKind : uint32_t { BuildOptions = 51, BuildLog = 52, FloatingPointControls = 53, + RangeKernel = 54, + NDRangeKernel = 55, + SingleTaskKernel = 56, // PropKindSize must always be the last value. - PropKindSize = 54, + PropKindSize = 57, }; // This trait must be specialized for all properties and must have a unique From 776caa411df69a76d22f2ec3ed011db69b40d8e6 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 7 Mar 2024 15:25:45 -0800 Subject: [PATCH 02/52] Reenabled an assert. --- clang/lib/CodeGen/CGExpr.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f19ee93e647fc..a001502ce3445 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3077,9 +3077,6 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } if (const auto *VD = dyn_cast(ND)) { -#if 0 - std::cerr << "VD=" << (void*)VD << std::endl; -#endif // Check if this is a global variable. if (VD->hasLinkage() || VD->isStaticDataMember()) return EmitGlobalVarDeclLValue(*this, E, VD); @@ -3109,12 +3106,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // No other cases for now. } else { -#if 0 - for (auto LDMEntry : LocalDeclMap) { - LDMEntry.first->dump(); - } llvm_unreachable("DeclRefExpr for Decl not entered in LocalDeclMap?"); -#endif } // Handle threadlocal function locals. From 1bcbc380a1efc4f2171d75cfca522adbb237af55 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 26 Mar 2024 15:53:22 -0700 Subject: [PATCH 03/52] Various enhancements. --- clang/lib/Sema/SemaSYCL.cpp | 629 +++++++++--------- .../oneapi/kernel_properties/properties.hpp | 35 +- sycl/source/detail/scheduler/commands.cpp | 7 +- 3 files changed, 343 insertions(+), 328 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 199f3370b3a4c..b9eacba40bb9f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -37,6 +37,13 @@ #include #include +static const int FFDebug = [] { + const char *FFDebugStr = std::getenv("FFDEBUG"); + if (!FFDebugStr) + return 0; + return std::stoi(FFDebugStr); +}(); + using namespace clang; using namespace std::placeholders; @@ -888,13 +895,9 @@ class KernelBodyTransform : public TreeTransform { bool AlwaysRebuild() { return true; } ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) { - // std::cerr << "TransformDeclRefExpr(" << (void*)DRE << ")\n"; auto Ref = dyn_cast(DRE->getDecl()); - // std::cerr << "Ref = " << (void*)Ref << "\n"; if (Ref && Ref == MappingPair.first) { - // std::cerr << "Ref matches " << (void*)(MappingPair.first) << "\n"; auto NewDecl = MappingPair.second; - // std::cerr << "Replacing with " << (void*)(NewDecl) << "\n"; return DeclRefExpr::Create( SemaRef.getASTContext(), DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(), NewDecl, false, DRE->getNameInfo(), @@ -904,43 +907,148 @@ class KernelBodyTransform : public TreeTransform { } Decl *TransformDecl(SourceLocation Loc, Decl *D) { - std::cerr << "TransformDecl(D=" << (void *)D << ")\n"; VarDecl *VD = dyn_cast(D); if (VD) { - std::cerr << "TransformDecl(VD=" << (void *)VD << ")\n"; - VD->dump(); Expr *InitExpr = VD->getInit(); if (InitExpr) { - std::cerr << "VD has init\n"; ExprResult NewInit = TransformExpr(InitExpr); VD->setInit(SemaRef.MaybeCreateExprWithCleanups(NewInit.get())); VD->setIsUsed(); - std::cerr << "Transformed VD=\n"; - VD->dump(); return VD; } } return D; } -#if 1 - Decl *TransformDecl(SourceLocation Loc, ParmVarDecl *PD) { - std::cerr << "TransformDecl(PD=" << (void *)PD << ")\n"; - PD->dump(); - Expr *InitExpr = PD->getInit(); - if (InitExpr) { - std::cerr << "PD has init\n"; - ExprResult NewInit = TransformExpr(InitExpr); - PD->setInit(SemaRef.MaybeCreateExprWithCleanups(NewInit.get())); - PD->setIsUsed(); - std::cerr << "Transformed PD=\n"; - PD->dump(); - return PD; + +private: + std::pair MappingPair; + Sema &SemaRef; +}; + +/// Creates a kernel parameter descriptor +/// \param Src field declaration to construct name from +/// \param Ty the desired parameter type +/// \return the constructed descriptor +static ParamDesc makeParamDesc(const FieldDecl* Src, QualType Ty) { + ASTContext& Ctx = Src->getASTContext(); + std::string Name = (Twine("_arg_") + Src->getName()).str(); + return std::make_tuple(Ty, &Ctx.Idents.get(Name), + Ctx.getTrivialTypeSourceInfo(Ty)); +} +static ParamDesc makeParamDesc(const ParmVarDecl* Src, QualType Ty) { + ASTContext& Ctx = Src->getASTContext(); + std::string Name = (Twine("_arg_") + Src->getName()).str(); + return std::make_tuple(Ty, &Ctx.Idents.get(Name), + Ctx.getTrivialTypeSourceInfo(Ty)); +} + +static ParamDesc makeParamDesc(ASTContext& Ctx, StringRef Name, QualType Ty) { + return std::make_tuple(Ty, &Ctx.Idents.get(Name), + Ctx.getTrivialTypeSourceInfo(Ty)); +} + +// Map used to replace original fields with new fields for free functions that +// contain structs with pointers. +struct FieldMap { + ParmVarDecl *OriginalParm; + ParmVarDecl *NewParm; + FieldDecl *NewField; +}; + +class KernelBodyTransformFF : public TreeTransform { +public: + KernelBodyTransformFF( + std::unordered_map &ParamMapP, + std::unordered_map &FieldMapP, Sema &S) + : TreeTransform(S), ParamMap(ParamMapP), + FieldMap(FieldMapP), SemaRef(S) {} + bool AlwaysRebuild() { return true; } + + ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) { + auto Ref = dyn_cast(DRE->getDecl()); + auto OldParm = dyn_cast(Ref); + //std::cerr << "TransformDeclRefExpr(OldParm): " << (void *)OldParm + // << std::endl; + if (OldParm) { + if (auto NewParam = ParamMap.find(OldParm); NewParam != ParamMap.end()) { + //std::cerr << "Matched!\n"; + //std::cerr << "TransformDeclRefExpr incoming DRE:\n"; + //DRE->dump(); + auto NewDecl = NewParam->second; + NewDecl->setIsUsed(); + auto NewDRE = DeclRefExpr::Create( + SemaRef.getASTContext(), DRE->getQualifierLoc(), + DRE->getTemplateKeywordLoc(), NewDecl, false, DRE->getNameInfo(), + NewDecl->getType(), DRE->getValueKind()); + //std::cerr << "TransformDeclRefExpr outgoing DRE after replace:\n"; + //NewDRE->dump(); + return NewDRE; + } } + //std::cerr << "TransformDeclRefExpr outgoing DRE:\n"; + //DRE->dump(); + return DRE; + } + + Decl *TransformDecl(SourceLocation Loc, Decl *D) { + //std::cerr << "TransformDecl:" << (void *)D << std::endl; + //std::cerr << "TransformDecl incoming D:\n"; + //D->dump(); + VarDecl *VD = dyn_cast(D); + if (VD) { + Expr *InitExpr = VD->getInit(); + if (InitExpr) { + ExprResult NewInit = TransformExpr(InitExpr); + VD->setInit(SemaRef.MaybeCreateExprWithCleanups(NewInit.get())); + VD->setIsUsed(); + return VD; + } + } + //std::cerr << "TransformDecl outgoing D:\n"; + //D->dump(); + return D; + } + + ExprResult TransformMemberExpr(MemberExpr* ME) { + //MemberExpr* ME = dyn_cast(E); + auto VD = ME->getMemberDecl(); + FieldDecl* OldFD = dyn_cast(VD); + // TODO: handle static member + //std::cerr << "TransformMemberExpr: " << (void*)OldFD << std::endl; + if (OldFD) { + if (auto Replacement = FieldMap.find(OldFD); + Replacement != FieldMap.end()) { + //std::cerr << "Matched!\n"; + //std::cerr << "TransformMemberExpr incoming E:\n"; + //ME->dump(); + FieldDecl* NewFD = dyn_cast(Replacement->second.NewField); + auto NewFDParent = dyn_cast(NewFD->getParent()); + ParmVarDecl* NewPD = Replacement->second.NewParm; + auto Base = DeclRefExpr::Create( + SemaRef.getASTContext(), NestedNameSpecifierLoc(), ME->getExprLoc(), + NewPD, false, DeclarationNameInfo(), + QualType(NewFDParent->getTypeForDecl(), 0), ME->getValueKind()); + DeclAccessPair MemberDAP = DeclAccessPair::make(NewFD, AS_none); + MemberExpr* NewME = SemaRef.BuildMemberExpr( + Base, /*IsArrow */ false, ME->getExprLoc(), NestedNameSpecifierLoc(), + ME->getExprLoc(), NewFD, MemberDAP, + /*HadMultipleCandidates*/ false, + DeclarationNameInfo(NewFD->getDeclName(), ME->getExprLoc()), + NewFD->getType(), VK_LValue, OK_Ordinary); + + //std::cerr << "TransformDeclRefExpr outgoing ME after replace:\n"; + //NewME->dump(); + return NewME; + } + } + // works for iotar3, fails for others + //std::cerr << "TransformMemberExpr falls back to base\n"; + return TreeTransform::TransformMemberExpr(ME); } -#endif private: - std::pair MappingPair; + std::unordered_map &ParamMap; + std::unordered_map &FieldMap; Sema &SemaRef; }; @@ -1034,28 +1142,6 @@ static QualType GetSYCLKernelObjectType(const FunctionDecl *KernelCaller) { return KernelParamTy.getUnqualifiedType(); } -/// Creates a kernel parameter descriptor -/// \param Src field declaration to construct name from -/// \param Ty the desired parameter type -/// \return the constructed descriptor -static ParamDesc makeParamDesc(const FieldDecl *Src, QualType Ty) { - ASTContext &Ctx = Src->getASTContext(); - std::string Name = (Twine("_arg_") + Src->getName()).str(); - return std::make_tuple(Ty, &Ctx.Idents.get(Name), - Ctx.getTrivialTypeSourceInfo(Ty)); -} -static ParamDesc makeParamDesc(const ParmVarDecl *Src, QualType Ty) { - ASTContext &Ctx = Src->getASTContext(); - std::string Name = (Twine("_arg_") + Src->getName()).str(); - return std::make_tuple(Ty, &Ctx.Idents.get(Name), - Ctx.getTrivialTypeSourceInfo(Ty)); -} - -static ParamDesc makeParamDesc(ASTContext &Ctx, StringRef Name, QualType Ty) { - return std::make_tuple(Ty, &Ctx.Idents.get(Name), - Ctx.getTrivialTypeSourceInfo(Ty)); -} - /// \return the target of given SYCL accessor type static target getAccessTarget(QualType FieldTy, const ClassTemplateSpecializationDecl *AccTy) { @@ -1066,14 +1152,79 @@ static target getAccessTarget(QualType FieldTy, AccTy->getTemplateArgs()[3].getAsIntegral().getExtValue()); } +static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { + //std::cerr << "IsFreeFunction?\n"; + //FD->dump(); + + if (FD->hasAttr()) { + const auto &Attrs = FD->getAttrs(); + //std::cerr << "Got all Attrs\n"; + //std::cout << "Number of Attrs=" << Attrs.size() << std::endl; +#if 0 + for (unsigned i = 0, e = Attrs.size(); i < e; i++) { + std::cout << "i=" << i << std::endl; + const SYCLAddIRAttributesFunctionAttr *AnAttr = + dyn_cast(Attrs[i]); + if (AnAttr) { + std::cerr << "Got a SYCLAddIRAttributesFunctionAttr\n"; + { + SmallVector, 4> NameValuePairs = + AnAttr->getAttributeNameValuePairs(SemaRef.Context); + std::cerr << "\nUnfiltered Name:Value pairs follow:\n"; + for (const auto &NameValuePair : NameValuePairs) { + std::cerr << "Name=" << NameValuePair.first + << " : Value=" << NameValuePair.second << std::endl; + } + std::cerr << "----------------------\n"; + } + { + SmallVector, 4> NameValuePairs = + AnAttr->getFilteredAttributeNameValuePairs(SemaRef.Context); + std::cerr << "\nFiltered Name:Value pairs follow\n"; + for (const auto &NameValuePair : NameValuePairs) { + std::cerr << "Name=" << NameValuePair.first + << " : Value=" << NameValuePair.second << std::endl; + if (NameValuePair.first == "sycl-range-kernel" || + NameValuePair.first == "sycl-nd-range-kernel" || + NameValuePair.first == "sycl-single-task-kernel") + std::cerr << "Would return true\n"; + } + std::cerr << "----------------------\n"; + } + } else + std::cerr << "Got some other\n"; + } +#endif + +#if 1 + for (unsigned i = 0, e = Attrs.size(); i < e; i++) { + const SYCLAddIRAttributesFunctionAttr* AnAttr = + dyn_cast(Attrs[i]); + if (AnAttr) { + SmallVector, 4> NameValuePairs = + AnAttr->getFilteredAttributeNameValuePairs(SemaRef.Context); + for (const auto& NameValuePair : NameValuePairs) { + if (NameValuePair.first == "sycl-range-kernel" || + NameValuePair.first == "sycl-nd-range-kernel" || + NameValuePair.first == "sycl-single-task-kernel") + return true; + } + } + } +#endif + } + //std::cerr << "Done with Attrs\n"; + + return false; +} + +#if 0 static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { if (FD->hasAttr()) { const auto *A = FD->getAttr(); SmallVector, 4> NameValuePairs = A->getFilteredAttributeNameValuePairs(SemaRef.Context); for (const auto &NameValuePair : NameValuePairs) { - std::cerr << "\t" << NameValuePair.first << ":" << NameValuePair.second - << std::endl; if (NameValuePair.first == "sycl-range-kernel" || NameValuePair.first == "sycl-nd-range-kernel" || NameValuePair.first == "sycl-single-task-kernel") @@ -1082,6 +1233,7 @@ static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { } return false; } +#endif static std::string constructFreeFunctionKernelName(ASTContext &Ctx, const FunctionDecl *FD) { @@ -1099,21 +1251,10 @@ static QualType calculateFreeFunctionNameType(const FunctionDecl *FF) { // the kernel itself. static QualType calculateKernelNameType(ASTContext &Ctx, const FunctionDecl *KernelCallerFunc) { -#if 1 const TemplateArgumentList *TAL = KernelCallerFunc->getTemplateSpecializationArgs(); assert(TAL && "No template argument info"); return TAL->get(0).getAsType().getCanonicalType(); -#else - const TemplateArgumentList *TAL = - KernelCallerFunc->getTemplateSpecializationArgs(); - if (TAL) { - // assert(TAL && "No template argument info"); - return TAL->get(0).getAsType().getCanonicalType(); - } else { - return KernelCallerFunc->parameters()[0]->getType(); - } -#endif } // Gets a name for the kernel function, calculated from the first @@ -1123,17 +1264,22 @@ static QualType calculateKernelNameType(ASTContext &Ctx, static std::pair constructKernelName(Sema &S, const FunctionDecl *KernelCallerFunc, MangleContext &MC) { + QualType KernelNameType; if (IsFreeFunction(S, KernelCallerFunc)) { - std::string MangledName( - constructFreeFunctionKernelName(S.getASTContext(), KernelCallerFunc)); - std::string StableName = - (constructFreeFunctionKernelName(S.getASTContext(), KernelCallerFunc)); - return {MangledName, StableName}; + if (KernelCallerFunc->getTemplateSpecializationArgs()) { + KernelNameType = KernelCallerFunc->getType(); + } else { + std::string MangledName( + constructFreeFunctionKernelName(S.getASTContext(), KernelCallerFunc)); + std::string StableName = (constructFreeFunctionKernelName( + S.getASTContext(), KernelCallerFunc)); + return {MangledName, StableName}; + } + } else { + KernelNameType = + calculateKernelNameType(S.getASTContext(), KernelCallerFunc); } - QualType KernelNameType = - calculateKernelNameType(S.getASTContext(), KernelCallerFunc); - SmallString<256> Result; llvm::raw_svector_ostream Out(Result); @@ -1284,9 +1430,6 @@ class KernelObjVisitor { void visitComplexRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, HandlerTys &...Handlers) { - std::cerr << "visitComplexRecord(Owner=" << (void*)Owner - << ", Parent=, Wrapper=" << (void*)Wrapper - << ", RecordTy)\n"; (void)std::initializer_list{ (Handlers.enterStruct(Owner, Parent, RecordTy), 0)...}; VisitRecordHelper(Wrapper, Wrapper->bases(), Handlers...); @@ -1299,9 +1442,6 @@ class KernelObjVisitor { void visitSimpleRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, HandlerTys &...Handlers) { - std::cerr << "visitSimpleRecord(Owner=" << (void*)Owner - << ", Parent=, Wrapper=" << (void*)Wrapper - << ", RecordTy)\n"; (void)std::initializer_list{ (Handlers.handleNonDecompStruct(Owner, Parent, RecordTy), 0)...}; } @@ -1319,20 +1459,16 @@ class KernelObjVisitor { void VisitRecordHelper(const CXXRecordDecl *Owner, clang::CXXRecordDecl::base_class_const_range Range, HandlerTys &...Handlers) { - std::cerr << "VisitRecordHelper1(Owner=" << (void *)Owner << ")\n"; for (const auto &Base : Range) { QualType BaseTy = Base.getType(); // Handle accessor class as base - if (isSyclSpecialType(BaseTy, SemaRef)) { - std::cerr << "VisitRecordHelper1 calling handleSyclSpecialType\n"; + if (isSyclSpecialType(BaseTy, SemaRef)) (void)std::initializer_list{ (Handlers.handleSyclSpecialType(Owner, Base, BaseTy), 0)...}; - } else { + else // For all other bases, visit the record - std::cerr << "VisitRecordHelper1 calling visitRecord\n"; visitRecord(Owner, Base, BaseTy->getAsCXXRecordDecl(), BaseTy, Handlers...); - } } } @@ -1340,7 +1476,6 @@ class KernelObjVisitor { void VisitRecordHelper(const CXXRecordDecl *Owner, RecordDecl::field_range Range, HandlerTys &...Handlers) { - std::cerr << "VisitRecordHelper2(Owner=" << (void*)Owner << ")\n"; VisitRecordFields(Owner, Handlers...); } @@ -1522,11 +1657,8 @@ class KernelObjVisitor { // SyclKernelFieldHandler for the purposes of kernel generation. template void VisitRecordFields(const CXXRecordDecl *Owner, HandlerTys &...Handlers) { - std::cerr << "VisitRecordFields(Owner=" << (void*)Owner << ")\n"; - for (const auto Field : Owner->fields()) { - std::cerr << "Visiting a Field\n"; + for (const auto Field : Owner->fields()) visitField(Owner, Field, Field->getType(), Handlers...); - } } template @@ -1756,9 +1888,6 @@ template void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, HandlerTys &...Handlers) { - std::cerr << "KernelObjVisitor::visitRecord(Owner=" << (void *)Owner - << ", Parent=, Wrapper=" << (void *)Wrapper - << ", RecordTy)\n"; RecordDecl *RD = RecordTy->getAsRecordDecl(); assert(RD && "should not be null."); if (RD->hasAttr()) { @@ -1768,7 +1897,6 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, visitComplexRecord(Owner, Parent, Wrapper, RecordTy, Handlers...); } else if (AnyTrue:: Value) { - std::cerr << "KernelObjVisitor:: We are currently in PointerHandler visitor\n"; // We are currently in PointerHandler visitor. if (RD->hasAttr()) { // This is a record containing pointers. @@ -1778,7 +1906,6 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, visitSimpleRecord(Owner, Parent, Wrapper, RecordTy, Handlers...); } } else { - std::cerr << "KernelObjVisitor:: VisitInsideSimpleContainers check\n"; // "Simple" Containers are those that do NOT need to be decomposed, // "Complex" containers are those that DO. In the case where the container // does NOT need to be decomposed, we can call VisitSimpleRecord on the @@ -2221,7 +2348,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) final { - std::cerr << "SyclKernelDecompMarker::handleSyclSpecialType(RD)\n"; CollectionStack.back() = true; return true; } @@ -2230,7 +2356,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { return true; } bool handleSyclSpecialType(ParmVarDecl *, QualType) final { - std::cerr << "SyclKernelDecompMarker::handleSyclSpecialType(PD)\n"; CollectionStack.back() = true; return true; } @@ -2240,7 +2365,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { return true; } bool handlePointerType(ParmVarDecl *, QualType) final { - std::cerr << "SyclKernelDecompMarker::handlePointerType\n"; PointerStack.back() = true; return true; } @@ -2252,14 +2376,12 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - std::cerr << "SyclKernelDecompMarker::enterStruct\n"; CollectionStack.push_back(false); PointerStack.push_back(false); return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType Ty) final { - std::cerr << "SyclKernelDecompMarker::leaveStruct\n"; // If a record needs to be decomposed, it is marked with // SYCLRequiresDecompositionAttr. Else if a record contains // a pointer, it is marked with SYCLGenerateNewTypeAttr. A record @@ -2267,12 +2389,9 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); assert(RD && "should not be null."); if (CollectionStack.pop_back_val()) { - if (!RD->hasAttr()) { + if (!RD->hasAttr()) RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( SemaRef.getASTContext())); - std::cerr << "SyclKernelDecompMarker(RD=" << (void *)RD - << ") added SYCLRequiresDecompositionAttr\n"; - } CollectionStack.back() = true; PointerStack.pop_back(); } else if (PointerStack.pop_back_val()) { @@ -2285,16 +2404,12 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType Ty) final { - std::cerr << "SyclKernelDecompMarker::leaveStruct\n"; CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); assert(RD && "should not be null."); if (CollectionStack.pop_back_val()) { - if (!RD->hasAttr()) { + if (!RD->hasAttr()) RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( SemaRef.getASTContext())); - std::cerr << "SyclKernelDecompMarker(RD=" << (void *)RD - << ") added SYCLRequiresDecompositionAttr\n"; - } CollectionStack.back() = true; PointerStack.pop_back(); } else if (PointerStack.pop_back_val()) { @@ -2342,7 +2457,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { return true; } bool enterArray(ParmVarDecl *, QualType ArrayTy, QualType ElementTy) final { - std::cerr << "SyclKernelDecompMarker::enterArray\n"; CollectionStack.push_back(false); PointerStack.push_back(false); return true; @@ -2371,7 +2485,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { return true; } bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ElementTy) final { - std::cerr << "SyclKernelDecompMarker::leaveArray\n"; // If an array needs to be decomposed, it is marked with // SYCLRequiresDecompositionAttr. Else if the array is an array of pointers // or an array of structs containing pointers, it is marked with @@ -2539,13 +2652,17 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { CXXRecordDecl *ModifiedRD = getGeneratedNewRecord(Ty->getAsCXXRecordDecl()); - // Add this record as a field of it's parent record if it is not an - // array element. - if (!isArrayElement(PD, Ty)) - addField(PD, QualType(ModifiedRD->getTypeForDecl(), 0)); - else - ModifiedArrayElementsOrArray.push_back( + // If there is only one entry, then we are done with the the free function + // parameter. + if (ModifiedRecords.size() > 1) { + // Add this record as a field of it's parent record if it is not an + // array element. + if (!isArrayElement(PD, Ty)) + addField(PD, QualType(ModifiedRD->getTypeForDecl(), 0)); + else + ModifiedArrayElementsOrArray.push_back( QualType(ModifiedRD->getTypeForDecl(), 0)); + } return true; } @@ -2702,11 +2819,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { size_t LastParamIndex = 0; // Keeps track of whether we are currently handling fields inside a struct. int StructDepth = 0; -#if 0 - // Map between original params and params generated for kernel. This is used - // for free functions. - llvm::SmallVector OrigParams; -#endif void addParam(const FieldDecl *FD, QualType FieldTy) { ParamDesc newParamDesc = makeParamDesc(FD, FieldTy); @@ -2949,11 +3061,17 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // pointers in 'right' address space. PointerHandler.getNewRecordType() // returns this generated type. QualType GenerateNewRecordType(const CXXRecordDecl *RD) { + //std::cerr << "GenerateNewRecordType, Original:\n"; + //RD->dump(); SyclKernelPointerHandler PointerHandler(SemaRef, RD); KernelObjVisitor Visitor{SemaRef}; Visitor.VisitRecordBases(RD, PointerHandler); Visitor.VisitRecordFields(RD, PointerHandler); + //auto New_RD = PointerHandler.getNewRecordType(); + //std::cerr << "GenerateNewRecordType, Modified:\n"; + //New_RD->dump(); return PointerHandler.getNewRecordType(); + //return New_RD; } // If the array has been marked with SYCLGenerateNewTypeAttr, @@ -2988,22 +3106,13 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernel->getAttr()) KernelDecl->addAttr(AddIRAttrFunc->clone(SemaRef.getASTContext())); } + SyclKernelDeclCreator(Sema &S, SourceLocation Loc, bool IsInline, FunctionDecl *SYCLKernel) : SyclKernelFieldHandler(S), KernelDecl(createFreeFunctionDecl(S.getASTContext(), SYCLKernel, Loc, IsInline)), FuncContext(SemaRef, KernelDecl) { -#if 1 - std::cerr << "Old free function declarator:\n"; - KernelDecl->dump(); - { - const IdentifierInfo *II = SYCLKernel->getIdentifier(); - if (II) - std::cerr << "Old free function name: " << II->getName().data() - << std::endl; - } -#endif S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); if (const auto *AddIRAttrFunc = @@ -3032,14 +3141,12 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernelAttr::CreateImplicit(SemaRef.getASTContext())); SemaRef.addSyclDeviceDecl(KernelDecl); -#if 1 - std::cerr << "Generated device function:\n"; - KernelDecl->dump(); - { +#if 0 + if (FFDebug > 0) { const IdentifierInfo *II = KernelDecl->getIdentifier(); - if (II) - std::cerr << "Generated device function name: " << II->getName().data() - << std::endl; + std::cerr << "Generated Function: " + << (II ? II->getName().data() : "Unnamed") << std::endl; + KernelDecl->dump(); } #endif } @@ -3050,8 +3157,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - //if (StructDepth == 0) - // addParam(PD, Ty); + // if (StructDepth == 0) + // addParam(PD, Ty); ++StructDepth; return true; } @@ -3349,6 +3456,8 @@ class ESIMDKernelDiagnostics : public SyclKernelFieldHandler { ESIMDKernelDiagnostics(Sema &S, SourceLocation Loc, bool IsESIMD) : SyclKernelFieldHandler(S), KernelLoc(Loc), IsESIMD(IsESIMD) {} + using SyclKernelFieldHandler::handleSyclSpecialType; + bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { return handleSpecialType(FieldTy); } @@ -3391,15 +3500,12 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { if (SizeOfParams > MaxKernelArgsSize) SemaRef.Diag(KernelLoc, diag::warn_sycl_kernel_too_big_args) << SizeOfParams << MaxKernelArgsSize; - std::cerr << "SyclKernelArgsSizeChecker::SizeOfParams = " << SizeOfParams - << std::endl; } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { return handleSpecialType(FieldTy); } bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelArgsSizeChecker::handleSyclSpecialType\n"; return handleSpecialType(FieldTy); } @@ -3413,7 +3519,6 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelArgsSizeChecker::handlePointerType\n"; addParam(FieldTy); return true; } @@ -3423,7 +3528,6 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelArgsSizeChecker::handleScalarType\n"; addParam(FieldTy); return true; } @@ -3433,7 +3537,6 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelArgsSizeChecker::handleSimpleArrayType\n"; addParam(FieldTy); return true; } @@ -3445,14 +3548,12 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { } bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelArgsSizeChecker::handleNonDecompStruct\n"; addParam(Ty); return true; } bool handleNonDecompStruct(const CXXRecordDecl *Base, const CXXBaseSpecifier &BS, QualType Ty) final { - std::cerr << "SyclKernelArgsSizeChecker::handleUnionType\n"; addParam(Ty); return true; } @@ -3461,7 +3562,6 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return handleScalarType(FD, FieldTy); } bool handleUnionType(ParmVarDecl *PD, QualType ParmTy) final { - std::cerr << "SyclKernelArgsSizeChecker::handleUnionType\n"; return handleScalarType(PD, ParmTy); } }; @@ -3537,6 +3637,7 @@ class SyclOptReportCreator : public SyclKernelFieldHandler { SyclOptReportCreator(Sema &S, SyclKernelDeclCreator &DC, SourceLocation Loc) : SyclKernelFieldHandler(S), DC(DC), KernelInvocationLoc(Loc) {} + using SyclKernelFieldHandler::handleSyclSpecialType; bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { for (const auto *Param : DC.getParamVarDeclsForCurrentField()) addParam(FD, Param->getType(), FieldTy.getAsString()); @@ -3559,6 +3660,7 @@ class SyclOptReportCreator : public SyclKernelFieldHandler { return true; } + using SyclKernelFieldHandler::handlePointerType; bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { std::string KernelArgDescription = ""; bool IsCompilerGeneratedType = false; @@ -3577,11 +3679,13 @@ class SyclOptReportCreator : public SyclKernelFieldHandler { return true; } + using SyclKernelFieldHandler::handleScalarType; bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { addParam(FD, FieldTy); return true; } + using SyclKernelFieldHandler::handleSimpleArrayType; bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { // Simple arrays are always wrapped. for (const auto *Param : DC.getParamVarDeclsForCurrentField()) @@ -3589,6 +3693,7 @@ class SyclOptReportCreator : public SyclKernelFieldHandler { return true; } + using SyclKernelFieldHandler::handleNonDecompStruct; bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); @@ -3612,6 +3717,7 @@ class SyclOptReportCreator : public SyclKernelFieldHandler { return true; } + using SyclKernelFieldHandler::handleUnionType; bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return handleScalarType(FD, FieldTy); } @@ -3654,8 +3760,10 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { // For free functions we create local copies of the parameters and replace // uses within the body to use the local copies. For parameters requiring // breakdown into components multiple items will be placed on these lists. - llvm::SmallVector OriginalParams; - llvm::SmallVector NewParams; + std::unordered_map ParamMap; + // For free functions that need replacement structs (because they contain + // pointers), also collect fields to replace. + std::unordered_map FieldMap; Stmt *replaceWithLocalClone(ParmVarDecl *OriginalParam, VarDecl *LocalClone, Stmt *FunctionBody) { @@ -3668,6 +3776,14 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return KBT.TransformStmt(FunctionBody).get(); } + Stmt *replaceParamsAndFields( + Stmt *FunctionBody, + std::unordered_map &ParamMap, + std::unordered_map &FieldMap) { + KernelBodyTransformFF KBT(ParamMap, FieldMap, SemaRef); + return KBT.TransformStmt(FunctionBody).get(); + } + // Using the statements/init expressions that we've created, this generates // the kernel body compound stmt. CompoundStmt needs to know its number of // statements in advance to allocate it, so we cannot do this as we go along. @@ -3711,8 +3827,14 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { // Push the Kernel function scope to ensure the scope isn't empty SemaRef.PushFunctionScope(); + // Use the function body for the free function kernel BodyStmts.push_back(FreeFunc->getBody()); + // Replace the original body with an empty body + Stmt *EmptyBody = CompoundStmt::Create(SemaRef.getASTContext(), {}, + FPOptionsOverride(), {}, {}); + FreeFunc->setBody(EmptyBody); + BodyStmts.insert(BodyStmts.end(), FinalizeStmts.begin(), FinalizeStmts.end()); @@ -3722,12 +3844,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { // Replace references to the parameters in kernel body, to use the // parameters of the newly created body function, or the compiler generated // local clones for the parameters that are expanded. - int index = 0; - for (auto Param : OriginalParams) { - NewParams[index]->setIsUsed(); - NewBody = replaceWithLocalClone(Param, NewParams[index], NewBody); - ++index; - } + NewBody = replaceParamsAndFields(NewBody, ParamMap, FieldMap); return static_cast(NewBody); } @@ -3873,16 +3990,16 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, InitializationKind InitKind, InitializedEntity Entity) { InitializationSequence InitSeq(SemaRef, Entity, InitKind, ParamRef); - ExprResult Init = InitSeq.Perform(SemaRef, Entity, InitKind, ParamRef); + InitSeq.Perform(SemaRef, Entity, InitKind, ParamRef); InitListExpr *ILE = createInitListExpr(Ty, 1); CollectionInitExprs.push_back(ILE); VD->setInit(ILE); Stmt *DS = new (SemaRef.Context) DeclStmt(DeclGroupRef(VD), KernelCallerSrcLoc, KernelCallerSrcLoc); BodyStmts.push_back(DS); - DeclRefExpr *VDRef = DeclRefExpr::Create( - SemaRef.Context, NestedNameSpecifierLoc(), KernelCallerSrcLoc, VD, - false, DeclarationNameInfo(), Ty, VK_LValue); + DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), + KernelCallerSrcLoc, VD, false, DeclarationNameInfo(), + Ty, VK_LValue); } void addBaseInit(const CXXBaseSpecifier &BS, QualType Ty, @@ -3968,14 +4085,15 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { Expr *Initializer = createDerefOp(RCE); addFieldInit(FD, Ty, Initializer); } + void handleGeneratedType(ParmVarDecl *PD, QualType Ty) { - std::cerr << "SyclKernelBodyCreator::handleGeneratedType(PD)\n"; Expr *RCE = createReinterpretCastExpr( createGetAddressOf(createParamReferenceExpr()), SemaRef.Context.getPointerType(Ty)); Expr *Initializer = createDerefOp(RCE); addVarInit(PD, Ty, Initializer); } + void handleGeneratedType(VarDecl *VD, QualType Ty) { Expr *RCE = createReinterpretCastExpr( createGetAddressOf(createParamReferenceExpr()), @@ -4134,7 +4252,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { // Default inits the type, then calls the init-method in the body. bool handleSpecialType(FieldDecl *FD, QualType Ty) { - std::cerr << "SyclKernelBodyCreator::handleSpecialType(FD)\n"; addFieldInit(FD, Ty, std::nullopt, InitializationKind::CreateDefault(KernelCallerSrcLoc)); @@ -4154,7 +4271,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } // Default inits the type. bool handleSpecialType(ParmVarDecl *PD, QualType Ty) { - std::cerr << "SyclKernelBodyCreator::handleSpecialType(PD)\n"; VarDecl *VD = createParamClone(SemaRef.getASTContext(), DeclCreator.getKernelDecl(), PD); // Create local clone of the special parameter @@ -4184,7 +4300,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handleSpecialType(const CXXBaseSpecifier &BS, QualType Ty) { - std::cerr << "SyclKernelBodyCreator::handleSpecialType(BS)\n"; const auto *RecordDecl = Ty->getAsCXXRecordDecl(); addBaseInit(BS, Ty, InitializationKind::CreateDefault(KernelCallerSrcLoc)); createSpecialMethodCall(RecordDecl, getInitMethodName(), BodyStmts); @@ -4346,59 +4461,32 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { DeclCreator.setBody(KernelBody); } -#if 0 - bool handleStructType(FieldDecl* FD, QualType FieldTy) final { - return true; - } - bool handleStructType(ParmVarDecl* PD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handleStructType(FD)\n"; - VarDecl* VD = createParamClone(SemaRef.getASTContext(), - DeclCreator.getKernelDecl(), PD); - addParamCloneExpr(VD, FieldTy); - handleGeneratedType(VD, FieldTy); - return true; - } -#endif - bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::handleSyclSpecialType(FD)\n"; return handleSpecialType(FD, Ty); } bool handleSyclSpecialType(ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::handleSyclSpecialType(PD)\n"; bool Result = handleSpecialType(PD, Ty); - OriginalParams.push_back(PD); - NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return Result; } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::handleSyclSpecialType(RD)\n"; return handleSpecialType(BS, Ty); } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handlePointerType(FD)\n"; Expr *PointerRef = createPointerParamReferenceExpr(FieldTy, StructDepth != 0); addFieldInit(FD, FieldTy, PointerRef); return true; } bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handlePointerType(PD)\n"; - std::cerr << "CurrParamIndex = " - << DeclCreator.getParamVarDeclsForCurrentField()[0] - << " OriginalParams = " << (void *)PD << " NewParams = " - << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) - << std::endl; - OriginalParams.push_back(PD); - NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handleSimpleArrayType(FD)\n"; if (FD->hasAttr()) handleGeneratedArrayType(FD, FieldTy); else @@ -4406,20 +4494,12 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handleSimpleArrayType(PD)\n"; - std::cerr << "CurrParamIndex = " - << DeclCreator.getParamVarDeclsForCurrentField()[0] - << " OriginalParams = " << (void *)PD << " NewParams = " - << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) - << std::endl; - OriginalParams.push_back(PD); - NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::handleNonDecompStruct()\n"; CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); assert(RD && "Type must be a C++ record type"); if (RD->hasAttr()) @@ -4428,27 +4508,44 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addSimpleFieldInit(FD, Ty); return true; } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::handleNonDecompStruct(PD)\n"; - std::cerr << "CurrParamIndex = " - << DeclCreator.getParamVarDeclsForCurrentField()[0] - << " OriginalParams = " << (void *)PD << " NewParams = " - << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) - << std::endl; + //std::cerr << "SyclKernelBodyCreator:handleNonDecompStruct\n"; CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); assert(RD && "Type must be a C++ record type"); - if (RD->hasAttr()) - handleGeneratedType(PD, Ty); + //std::cerr << "PD Type:\n"; + //PD->dump(); + + //std::cerr << "OriginalParams:" << (void *)PD << "\n"; + //PD->dump(); + ParmVarDecl* NewPD = DeclCreator.getParamVarDeclsForCurrentField()[0]; + //std::cerr << "NewParams:" << (void*)(NewPD) << "\n"; + + // If the struct has been rewritten with new pointers, change all the field + // references. Otherwise handle the struct as a single object. + if (RD->hasAttr()) { + const auto *OrigRecord = Ty->getAsRecordDecl(); + const auto *NewRecord = NewPD->getType()->getAsRecordDecl(); + if (OrigRecord && NewRecord) { + auto OldField = OrigRecord->fields().begin(); + auto NewField = NewRecord->fields().begin(); + for (; OldField != OrigRecord->fields().end(); OldField++, NewField++) { + //std::cerr << "OldField:" << (void *)*OldField << "\n"; + //(*OldField)->dump(); + //std::cerr << "NewField:" << (void *)*NewField << "\n"; + //(*NewField)->dump(); + FieldMap[*OldField] = {PD, NewPD, *NewField}; + } + } + } else + ParamMap[PD] = NewPD; - OriginalParams.push_back(PD); - NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); return true; } bool handleNonDecompStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::handleNonDecompStruct(RD)\n"; CXXRecordDecl *BaseDecl = Ty->getAsCXXRecordDecl(); assert(BaseDecl && "Type must be a C++ record type"); if (BaseDecl->hasAttr()) @@ -4459,27 +4556,11 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handleScalarType(FD)\n"; addSimpleFieldInit(FD, FieldTy); return true; } bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { -#if 0 - // Create local variable initialized with parameter. - VarDecl *VD = createParamClone(SemaRef.getASTContext(), - DeclCreator.getKernelDecl(), PD); - addSimpleLocalInit(VD, FieldTy); - OriginalParams.push_back(PD); - NewParams.push_back(VD); -#endif - std::cerr << "SyclKernelBodyCreator::handleScalarType(PD)\n"; - std::cerr << "CurrParamIndex = " - << DeclCreator.getParamVarDeclsForCurrentField()[0] - << " OriginalParams = " << (void *)PD << " NewParams = " - << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) - << std::endl; - OriginalParams.push_back(PD); - NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } @@ -4488,14 +4569,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelBodyCreator::handleUnionType(PD)\n"; - std::cerr << "CurrParamIndex = " - << DeclCreator.getParamVarDeclsForCurrentField()[0] - << " OriginalParams = " << (void *)PD << " NewParams = " - << (void *)(DeclCreator.getParamVarDeclsForCurrentField()[0]) - << std::endl; - OriginalParams.push_back(PD); - NewParams.push_back(DeclCreator.getParamVarDeclsForCurrentField()[0]); + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } @@ -4531,10 +4605,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::enterStruct(PD)\n"; if (StructDepth == 0) { - std::cerr << "SyclKernelBodyCreator::enterStruct \n"; - // Get type of PD, which should be a Record RD = PD->getType()->getAsCXXRecordDecl(); assert(RD && "Free function parameter expected as Record type"); @@ -4553,8 +4624,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { ParamClone, false, DeclarationNameInfo(), QualType(RD->getTypeForDecl(), 0), VK_LValue); MemberExprBases.push_back(ParamCloneRef); - OriginalParams.push_back(PD); - NewParams.push_back(ParamClone); + ParamMap[PD] = ParamClone; } ++StructDepth; return true; @@ -4569,10 +4639,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelBodyCreator::leaveStruct(PD)\n"; - if (StructDepth == 0) { - std::cerr << "SyclKernelBodyCreator::leaveStruct \n"; - } --StructDepth; return true; } @@ -4619,18 +4685,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool enterArray(ParmVarDecl *PD, QualType ArrayType, QualType ElementType) final { -#if 0 - const ConstantArrayType* CAT = - SemaRef.getASTContext().getAsConstantArrayType(ArrayType); - assert(CAT && "Should only be called on constant-size array."); - uint64_t ArraySize = CAT->getSize().getZExtValue(); - addCollectionInitListExpr(ArrayType, ArraySize); - ArrayInfos.emplace_back(getFieldEntity(FD, ArrayType), 0); - - // If this is the top-level array, we need to make a MemberExpr in addition - // to an array subscript. - addFieldMemberExpr(FD, ArrayType); -#endif return true; } @@ -4664,19 +4718,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { bool leaveArray(ParmVarDecl *PD, QualType ArrayType, QualType ElementType) final { -#if 0 - CollectionInitExprs.pop_back(); - ArrayInfos.pop_back(); - - // Remove the IndexExpr. - if (!FD->hasAttr()) - MemberExprBases.pop_back(); - else - ArrayParamBases.pop_back(); - - // Remove the field access expr as well. - removeFieldMemberExpr(FD, ArrayType); -#endif return true; } }; @@ -4817,7 +4858,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelIntHeaderCreator::handleSyclSpecialType\n"; const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); assert(ClassTy && "Type must be a C++ record type"); if (isSyclAccessorType(FieldTy)) { @@ -4863,7 +4903,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelIntHeaderCreator::handlePointerType\n"; addParam(PD, FieldTy, ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout : SYCLIntegrationHeader::kind_pointer)); @@ -4875,7 +4914,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelIntHeaderCreator::handleScalarType\n"; addParam(PD, FieldTy, SYCLIntegrationHeader::kind_std_layout); return true; } @@ -4887,7 +4925,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelIntHeaderCreator::handleSimpleArrayType\n"; // Arrays are always wrapped inside of structs, so just treat it as a simple // struct. addParam(PD, FieldTy, SYCLIntegrationHeader::kind_std_layout); @@ -4916,7 +4953,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return handleScalarType(FD, FieldTy); } bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - std::cerr << "SyclKernelIntHeaderCreator::handleUnionType\n"; return handleScalarType(PD, FieldTy); } @@ -4937,7 +4973,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelIntHeaderCreator::enterStruct\n"; ++StructDepth; CurOffset += offsetOf(PD, Ty); return true; @@ -4949,7 +4984,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - std::cerr << "SyclKernelIntHeaderCreator::leaveStruct\n"; --StructDepth; CurOffset -= offsetOf(PD, Ty); return true; @@ -4972,7 +5006,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool enterArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { - std::cerr << "SyclKernelIntHeaderCreator::enterArray\n"; ArrayBaseOffsets.push_back(CurOffset + offsetOf(PD, ArrayTy)); return true; } @@ -4989,7 +5022,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { - std::cerr << "SyclKernelIntHeaderCreator::leaveArray\n"; CurOffset = ArrayBaseOffsets.pop_back_val(); CurOffset -= offsetOf(PD, ArrayTy); return true; @@ -5360,6 +5392,8 @@ void Sema::SetSYCLKernelNames() { // void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC) { + //std::cerr << "ConstructOpenCLKernel from:\n"; + //KernelCallerFunc->dump(); // The first argument to the KernelCallerFunc is the lambda object. const CXXRecordDecl *KernelObj = GetSYCLKernelObjectType(KernelCallerFunc)->getAsCXXRecordDecl(); @@ -5441,22 +5475,20 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, } void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { -#if 1 - { +#if 0 + if (FFDebug > 0) { const IdentifierInfo *II = FD->getIdentifier(); - if (II) - std::cerr << "ConstructFreeFunctionKernel: " << II->getName().data() - << std::endl; + std::cerr << "ConstructFreeFunctionKernel from: " << II->getName().data() + << std::endl; FD->dump(); } #endif - SyclKernelArgsSizeChecker argsSizeChecker(SemaRef, FD->getLocation(), false /*IsSIMDKernel*/); SyclKernelDeclCreator kernel_decl(SemaRef, FD->getLocation(), FD->isInlined(), FD); -#if 1 + // TODO: remove this dummy struct RecordDecl *DummyClass = SemaRef.getASTContext().buildImplicitRecord("__dummy_class"); DummyClass->startDefinition(); @@ -5464,7 +5496,6 @@ void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { CXXRecordDecl *DummyClass1 = static_cast(DummyClass); SyclKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD, DummyClass1); -#endif // Kernel object size is irrelevant, so set to 0. SyclKernelIntHeaderCreator int_header(SemaRef, @@ -5485,16 +5516,6 @@ void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, int_header, int_footer); } -#if 1 - { - FunctionDecl *FF_FD = kernel_decl.getKernelDecl(); - const IdentifierInfo *II = FF_FD->getIdentifier(); - if (II) - std::cerr << "Generated FreeFunction: " << II->getName().data() - << std::endl; - FF_FD->dump(); - } -#endif }; // Figure out the sub-group for the this function. First we check the @@ -5757,8 +5778,7 @@ static void PropagateAndDiagnoseDeviceAttr( } void Sema::ProcessDeviceFunctions() { - std::cerr << "***** ProcessDeviceFunctions\n"; - SmallVector FreeFunctions; + SmallVector FreeFunctions; // This Tracker object ensures that the SyclDeviceDecls collection includes // the SYCL_EXTERNAL functions, and manages the diagnostics for all of the // functions in the kernel. @@ -5766,6 +5786,15 @@ void Sema::ProcessDeviceFunctions() { for (Decl *D : syclDeviceDecls()) { auto *SYCLKernel = cast(D); +#if 0 + { + const IdentifierInfo* II = SYCLKernel->getIdentifier(); + if (II) + std::cerr << "Here's a device function: " << II->getName().data() + << std::endl; + //FD->dump(); + } +#endif // This type does the actual analysis on a per-kernel basis. It does this to // make sure that we're only ever dealing with the context of a single @@ -5784,12 +5813,12 @@ void Sema::ProcessDeviceFunctions() { } } - for (FunctionDecl* FF : FreeFunctions) { + for (FunctionDecl *FF : FreeFunctions) { SyclKernelDecompMarker DecompMarker(*this); SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); - KernelObjVisitor Visitor{ *this }; + KernelObjVisitor Visitor{*this}; DiagnosingSYCLKernel = true; diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index f397d65895d4d..b729181277420 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -253,17 +253,23 @@ struct PropertyMetaInfo> { }; template struct PropertyMetaInfo> { + //static constexpr const char* name = "sycl-range-kernel"; static constexpr const char* name = "sycl-range-kernel"; static constexpr int value = Dims; + //static constexpr const char *value = + // SizeListToStr(Dims)>::value; }; template struct PropertyMetaInfo> { + //static constexpr const char* name = "sycl-nd-range-kernel"; static constexpr const char* name = "sycl-nd-range-kernel"; static constexpr int value = Dims; }; template <> struct PropertyMetaInfo { + //static constexpr const char* name = "sycl-single-task-kernel"; static constexpr const char* name = "sycl-single-task-kernel"; + static constexpr int value = 0; }; template @@ -283,40 +289,15 @@ struct HasKernelPropertiesGetMethod>>::name, \ sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ std::remove_cv_t>>::value)]] - -#define SYCL_EXT_ONEAPI_RANGE_KERNEL_PROPERTY(PROP) \ - [[__sycl_detail__::add_ir_attributes_function( \ - {"sycl-range-kernel"}, \ - sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ - std::remove_cv_t>>::name, \ - sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ - std::remove_cv_t>>::value)]] - -#define SYCL_EXT_ONEAPI_ND_RANGE_KERNEL_PROPERTY(PROP) \ - [[__sycl_detail__::add_ir_attributes_function( \ - {"sycl-nd-range-kernel"}, \ - sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ - std::remove_cv_t>>::name, \ - sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ - std::remove_cv_t>>::value)]] - -#define SYCL_EXT_ONEAPI_SINGLE_TASK_KERNEL_PROPERTY(PROP) \ - [[__sycl_detail__::add_ir_attributes_function( \ - {"sycl-single-task-kernel"}, \ - sycl::ext::oneapi::experimental::detail::PropertyMetaInfo< \ - std::remove_cv_t>>::name, \ - 0)]] #else #define SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(PROP) -#define SYCL_EXT_ONEAPI_RANGE_KERNEL_PROPERTY(PROP) -#define SYCL_EXT_ONEAPI_ND_RANGE_KERNEL_PROPERTY(PROP) -#define SYCL_EXT_ONEAPI_SINGLE_TASK_KERNEL_PROPERTY(PROP) #endif diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index b113da757bd0c..dd623ac8b4b5c 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2575,7 +2575,12 @@ pi_int32 enqueueImpKernel( Queue->get_context()); Kernel = MSyclKernel->getHandleRef(); auto SyclProg = MSyclKernel->getProgramImpl(); - Program = SyclProg->getHandleRef(); + if (SyclProg != nullptr) { + Program = SyclProg->getHandleRef(); + } else { + DeviceImageImpl = MSyclKernel->getDeviceImage(); + Program = DeviceImageImpl->get_program_ref(); + } // Non-cacheable kernels use mutexes from kernel_impls. // TODO this can still result in a race condition if multiple SYCL // kernels are created with the same native handle. To address this, From ec6f4f4c7f611cfd7fe05d1bc2f2d2b9f4458817 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 28 Mar 2024 16:37:11 -0700 Subject: [PATCH 04/52] Fix for reordered attributes. --- clang/include/clang/Sema/Sema.h | 16 +- clang/lib/Sema/Sema.cpp | 6 +- clang/lib/Sema/SemaSYCL.cpp | 52 +++--- .../oneapi/kernel_properties/properties.hpp | 2 - .../free_function_kernels.cpp | 152 +++++++++++------- 5 files changed, 128 insertions(+), 100 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3e61c408ae6d4..327b41e1ac635 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3312,8 +3312,6 @@ class Sema final { TemplateIdAnnotation *TemplateId, bool IsMemberSpecialization); - bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key); - void DiagnoseFunctionSpecifiers(const DeclSpec &DS); NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R); @@ -5656,7 +5654,6 @@ class Sema final { enum ExpressionKind { EK_Decltype, EK_TemplateArgument, - EK_BoundsAttrArgument, EK_Other } ExprContext; @@ -5774,12 +5771,6 @@ class Sema final { return ExprEvalContexts.back(); }; - bool isBoundsAttrContext() const { - return ExprEvalContexts.back().ExprContext == - ExpressionEvaluationContextRecord::ExpressionKind:: - EK_BoundsAttrArgument; - } - /// Increment when we find a reference; decrement when we find an ignored /// assignment. Ultimately the value is 0 if every reference is an ignored /// assignment. @@ -9667,7 +9658,7 @@ class Sema final { bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); @@ -12197,8 +12188,6 @@ class Sema final { QualType BuildMatrixType(QualType T, Expr *NumRows, Expr *NumColumns, SourceLocation AttrLoc); - QualType BuildCountAttributedArrayType(QualType WrappedTy, Expr *CountExpr); - QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, SourceLocation AttrLoc); @@ -15299,7 +15288,8 @@ class Sema final { void copySYCLKernelAttrs(CXXMethodDecl *CallOperator); void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC); void SetSYCLKernelNames(); - void ProcessDeviceFunctions(); + void MarkDevices(); + void ProcessFreeFunctions(); /// Get the number of fields or captures within the parsed type. ExprResult ActOnSYCLBuiltinNumFieldsExpr(ParsedType PT); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9736572014675..52a30fe2187e8 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1117,9 +1117,8 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { } if (getLangOpts().SYCLIsDevice) { - // Generate device code for free function kernels and propagate "device" - // attributes - ProcessDeviceFunctions(); + // Generate device code for free function kernels. + ProcessFreeFunctions(); // Set the names of the kernels, now that the names have settled down. This // needs to happen before we generate the integration headers. SetSYCLKernelNames(); @@ -1131,6 +1130,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { // Emit SYCL integration header for current translation unit if needed if (SyclIntHeader != nullptr) SyclIntHeader->emit(getLangOpts().SYCLIntHeader); + MarkDevices(); } emitDeferredDiags(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c97f438cd2b6d..f9c412a5fa800 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1147,7 +1147,7 @@ static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { dyn_cast(Attrs[i]); if (AnAttr) { SmallVector, 4> NameValuePairs = - AnAttr->getFilteredAttributeNameValuePairs(SemaRef.Context); + AnAttr->getAttributeNameValuePairs(SemaRef.Context); for (const auto &NameValuePair : NameValuePairs) { if (NameValuePair.first == "sycl-range-kernel" || NameValuePair.first == "sycl-nd-range-kernel" || @@ -5643,13 +5643,12 @@ static void PropagateAndDiagnoseDeviceAttr( } } -void Sema::ProcessDeviceFunctions() { +void Sema::MarkDevices() { // This Tracker object ensures that the SyclDeviceDecls collection includes // the SYCL_EXTERNAL functions, and manages the diagnostics for all of the // functions in the kernel. DeviceFunctionTracker Tracker(*this); - SmallVector FreeFunctions; for (Decl *D : syclDeviceDecls()) { auto *SYCLKernel = cast(D); @@ -5664,31 +5663,44 @@ void Sema::ProcessDeviceFunctions() { PropagateAndDiagnoseDeviceAttr(*this, T, A, T.GetSYCLKernel(), T.GetKernelBody()); CheckSYCLAddIRAttributesFunctionAttrConflicts(T.GetSYCLKernel()); - - if (IsFreeFunction(*this, SYCLKernel)) - FreeFunctions.push_back(SYCLKernel); } +} - for (FunctionDecl *FF : FreeFunctions) { - SyclKernelDecompMarker DecompMarker(*this); - SyclKernelFieldChecker FieldChecker(*this); - SyclKernelUnionChecker UnionChecker(*this); +void Sema::ProcessFreeFunctions() { + // This Tracker object ensures that the SyclDeviceDecls collection includes + // the SYCL_EXTERNAL functions, and manages the diagnostics for all of the + // functions in the kernel. + DeviceFunctionTracker Tracker(*this); - KernelObjVisitor Visitor{*this}; + for (Decl *D : syclDeviceDecls()) { + auto *SYCLKernel = cast(D); - DiagnosingSYCLKernel = true; + // This type does the actual analysis on a per-kernel basis. It does this to + // make sure that we're only ever dealing with the context of a single + // kernel at a time. + SingleDeviceFunctionTracker T{Tracker, SYCLKernel}; - // Check parameters of free function. - Visitor.VisitFunctionParameters(FF, DecompMarker, FieldChecker, - UnionChecker); + if (IsFreeFunction(*this, SYCLKernel)) { + SyclKernelDecompMarker DecompMarker(*this); + SyclKernelFieldChecker FieldChecker(*this); + SyclKernelUnionChecker UnionChecker(*this); - DiagnosingSYCLKernel = false; + KernelObjVisitor Visitor{*this}; - // Ignore the free function if any of the checkers fail validation. - if (!FieldChecker.isValid() || !UnionChecker.isValid()) - return; + DiagnosingSYCLKernel = true; - ConstructFreeFunctionKernel(*this, FF); + // Check parameters of free function. + Visitor.VisitFunctionParameters(SYCLKernel, DecompMarker, FieldChecker, + UnionChecker); + + DiagnosingSYCLKernel = false; + + // Ignore the free function if any of the checkers fail validation. + if (!FieldChecker.isValid() || !UnionChecker.isValid()) + return; + + ConstructFreeFunctionKernel(*this, SYCLKernel); + } } } diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index b729181277420..eccedbc428d9a 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -289,8 +289,6 @@ struct HasKernelPropertiesGetMethod(size, Queue); - memset(usmPtr, 0, size * sizeof(int)); - return usmPtr; -} - void printUSM(int *usmPtr, int size) { std::cout << "usmPtr[] = {"; for (int i = 0; i < size; i++) { @@ -102,13 +96,25 @@ void ff_0(int *ptr, int start, int end) { int test_0(queue Queue, KernelFinder &KF) { constexpr int Range = 10; - int *usmPtr = initUSM(Queue, Range); + int *usmPtr = malloc_shared(Range, Queue); int start = 3; int end = 5; int Result[Range] = {0, 0, 0, 8, 8, 8, 0, 0, 0, 0}; - range<1> R1{Range}; + + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.single_task([=]() { + for (int i = start; i <= end; i++) + usmPtr[i] = start + end; + }); + }); + Queue.wait(); + bool Passa = checkUSM(usmPtr, Range, Result); + std::cout << "Test 0a: " << (Passa ? "PASS" : "FAIL") << std::endl; + kernel Kernel = KF.get_kernel("__free_function_ff_0"); + memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); Handler.set_arg(1, start); @@ -116,12 +122,11 @@ int test_0(queue Queue, KernelFinder &KF) { Handler.single_task(Kernel); }); Queue.wait(); + bool Passb = checkUSM(usmPtr, Range, Result); + std::cout << "Test 0b: " << (Passb ? "PASS" : "FAIL") << std::endl; - bool Pass = checkUSM(usmPtr, Range, Result); - std::cout << "Test 0: " << (Pass ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - - return 0; + return Passa && Passb; } SYCL_EXTERNAL @@ -133,15 +138,27 @@ void ff_1(int *ptr, int start, int end) { int test_1(queue Queue, KernelFinder &KF) { constexpr int Range = 10; - int *usmPtr = initUSM(Queue, Range); + int* usmPtr = malloc_shared(Range, Queue); int start = 3; struct Simple S { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 }; int Result[Range] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; - range<1> R1{Range}; + + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler& Handler) { + Handler.parallel_for(R1, [=](item<1> Item) { + id<1> Id = Item.get_id(); + usmPtr[Id.get(0)] = Id.get(0) + start + Range; + }); + }); + Queue.wait(); + bool Passa = checkUSM(usmPtr, Range, Result); + std::cout << "Test 1a: " << (Passa ? "PASS" : "FAIL") << std::endl; + kernel Kernel = KF.get_kernel("__free_function_ff_1"); + memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); Handler.set_arg(1, start); @@ -149,12 +166,11 @@ int test_1(queue Queue, KernelFinder &KF) { Handler.parallel_for(R1, Kernel); }); Queue.wait(); + bool Passb = checkUSM(usmPtr, Range, Result); + std::cout << "Test 1b: " << (Passb ? "PASS" : "FAIL") << std::endl; - bool Pass = checkUSM(usmPtr, Range, Result); - std::cout << "Test 1: " << (Pass ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - - return Pass; + return Passa && Passb; } SYCL_EXTERNAL @@ -171,39 +187,43 @@ void ff_2(int *ptr, int start, struct Simple S) { int test_2(queue Queue, KernelFinder &KF) { constexpr int Range = 16; - int *usmPtr = initUSM(Queue, Range); + int* usmPtr = malloc_shared(Range, Queue); int value = 55; struct Simple S { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 }; int Result[Range] = {130, 131, 130, 131, 131, 132, 131, 132, 130, 131, 130, 131, 131, 132, 131, 132}; - nd_range<2> R2{range<2>{4, 4}, range<2>{2, 2}}; - kernel Kernel = KF.get_kernel("__free_function_ff_2"); - Queue.submit([&](handler &Handler) { -#if 1 - Handler.set_arg(0, usmPtr); - Handler.set_arg(1, value); - Handler.set_arg(2, S); - Handler.parallel_for(R2, Kernel); -#else + + 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 + S.x + S.f + S.c[2]; + LId.get(0) + LId.get(1) + value + S.x + S.f + S.c[2]; + }); }); -#endif + Queue.wait(); + bool Passa = checkUSM(usmPtr, Range, Result); + std::cout << "Test 2a: " << (Passa ? "PASS" : "FAIL") << std::endl; + + kernel Kernel = KF.get_kernel("__free_function_ff_2"); + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.set_arg(0, usmPtr); + Handler.set_arg(1, value); + Handler.set_arg(2, S); + Handler.parallel_for(R2, Kernel); }); Queue.wait(); + bool Passb = checkUSM(usmPtr, Range, Result); + std::cout << "Test 2b: " << (Passb ? "PASS" : "FAIL") << std::endl; - bool Pass = checkUSM(usmPtr, Range, Result); - std::cout << "Test 2: " << (Pass ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - - return Pass; + return Passa && Passb; } // Templated free function definition @@ -224,23 +244,17 @@ template void ff_3(int *ptr, int start, struct Simple S); int test_3(queue Queue, KernelFinder &KF) { constexpr int Range = 16; - int *usmPtr = initUSM(Queue, Range); + int* usmPtr = malloc_shared(Range, Queue); int value = 55; struct Simple S { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 }; int Result[Range] = {130, 131, 130, 131, 131, 132, 131, 132, 130, 131, 130, 131, 131, 132, 131, 132}; - nd_range<2> R2{range<2>{4, 4}, range<2>{2, 2}}; - kernel Kernel = KF.get_kernel("_ZTSFvPii6SimpleE"); + + memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { -#if 1 - Handler.set_arg(0, usmPtr); - Handler.set_arg(1, value); - Handler.set_arg(2, S); - Handler.parallel_for(R2, Kernel); -#else Handler.parallel_for(R2, [=](nd_item<2> Item) { int(&ptr2D)[4][4] = *reinterpret_cast(usmPtr); id<2> GId = Item.get_global_id(); @@ -248,15 +262,25 @@ int test_3(queue Queue, KernelFinder &KF) { ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + value + S.x + S.f + S.c[2]; }); -#endif }); Queue.wait(); + bool Passa = checkUSM(usmPtr, Range, Result); + std::cout << "Test 3a: " << (Passa ? "PASS" : "FAIL") << std::endl; - bool Pass = checkUSM(usmPtr, Range, Result); - std::cout << "Test 3: " << (Pass ? "PASS" : "FAIL") << std::endl; - free(usmPtr, Queue); + kernel Kernel = KF.get_kernel("_ZTSFvPii6SimpleE"); + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.set_arg(0, usmPtr); + Handler.set_arg(1, value); + Handler.set_arg(2, S); + Handler.parallel_for(R2, Kernel); + }); + Queue.wait(); + bool Passb = checkUSM(usmPtr, Range, Result); + std::cout << "Test 3b: " << (Passb ? "PASS" : "FAIL") << std::endl; - return Pass; + free(usmPtr, Queue); + return Passa && Passb; } // Templated free function definition @@ -278,7 +302,7 @@ template void ff_4(int *ptr, int start, struct WithPointer S); int test_4(queue Queue, KernelFinder &KF) { constexpr int Range = 16; - int *usmPtr = initUSM(Queue, Range); + int* usmPtr = malloc_shared(Range, Queue); float *fp = malloc_shared(1, Queue); *fp = 8.2; int value = 55; @@ -287,16 +311,10 @@ int test_4(queue Queue, KernelFinder &KF) { }; int Result[Range] = {73, 74, 73, 74, 74, 75, 74, 75, 73, 74, 73, 74, 74, 75, 74, 75}; - nd_range<2> R2{range<2>{4, 4}, range<2>{2, 2}}; - kernel Kernel = KF.get_kernel("_ZTSFvPii11WithPointerE"); + + memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { -#if 1 - Handler.set_arg(0, usmPtr); - Handler.set_arg(1, value); - Handler.set_arg(2, S); - Handler.parallel_for(R2, Kernel); -#else Handler.parallel_for(R2, [=](nd_item<2> Item) { int(&ptr2D)[4][4] = *reinterpret_cast(usmPtr); id<2> GId = Item.get_global_id(); @@ -304,15 +322,25 @@ int test_4(queue Queue, KernelFinder &KF) { ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + value + S.x + S.f + *S.fp; }); -#endif }); Queue.wait(); + bool Passa = checkUSM(usmPtr, Range, Result); + std::cout << "Test 4a: " << (Passa ? "PASS" : "FAIL") << std::endl; - bool Pass = checkUSM(usmPtr, Range, Result); - std::cout << "Test 4: " << (Pass ? "PASS" : "FAIL") << std::endl; - free(usmPtr, Queue); + kernel Kernel = KF.get_kernel("_ZTSFvPii11WithPointerE"); + memset(usmPtr, 0, Range * sizeof(int)); + Queue.submit([&](handler &Handler) { + Handler.set_arg(0, usmPtr); + Handler.set_arg(1, value); + Handler.set_arg(2, S); + Handler.parallel_for(R2, Kernel); + }); + Queue.wait(); + bool Passb = checkUSM(usmPtr, Range, Result); + std::cout << "Test 4b: " << (Passb ? "PASS" : "FAIL") << std::endl; - return Pass; + free(usmPtr, Queue); + return Passa && Passb; } int main() { From 1c98d080030c479ae134954b1abf95673715354a Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 28 Mar 2024 16:58:52 -0700 Subject: [PATCH 05/52] Fixed merge error. --- clang/include/clang/Sema/Sema.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 327b41e1ac635..ad7730b263a5b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3312,6 +3312,8 @@ class Sema final { TemplateIdAnnotation *TemplateId, bool IsMemberSpecialization); + bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key); + void DiagnoseFunctionSpecifiers(const DeclSpec &DS); NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R); @@ -5654,6 +5656,7 @@ class Sema final { enum ExpressionKind { EK_Decltype, EK_TemplateArgument, + EK_BoundsAttrArgument, EK_Other } ExprContext; @@ -5771,6 +5774,12 @@ class Sema final { return ExprEvalContexts.back(); }; + bool isBoundsAttrContext() const { + return ExprEvalContexts.back().ExprContext == + ExpressionEvaluationContextRecord::ExpressionKind:: + EK_BoundsAttrArgument; + } + /// Increment when we find a reference; decrement when we find an ignored /// assignment. Ultimately the value is 0 if every reference is an ignored /// assignment. @@ -9658,7 +9667,7 @@ class Sema final { bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, + ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); @@ -12188,6 +12197,8 @@ class Sema final { QualType BuildMatrixType(QualType T, Expr *NumRows, Expr *NumColumns, SourceLocation AttrLoc); + QualType BuildCountAttributedArrayType(QualType WrappedTy, Expr *CountExpr); + QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, SourceLocation AttrLoc); From 96b7666e4dd5a9a877089cc08b9544009d60d5f7 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 28 Mar 2024 22:58:26 -0700 Subject: [PATCH 06/52] Test fiex. --- clang/lib/Sema/Sema.cpp | 3 ++- clang/lib/Sema/SemaSYCL.cpp | 11 ----------- .../SemaSYCL/check-direct-attribute-propagation.cpp | 6 +++--- .../check-notdirect-attribute-propagation.cpp | 2 +- clang/test/SemaSYCL/sycl-esimd-ast.cpp | 6 +++--- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 52a30fe2187e8..2721016766dcf 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1117,6 +1117,8 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { } if (getLangOpts().SYCLIsDevice) { + // Check and propagate device function attributes. + MarkDevices(); // Generate device code for free function kernels. ProcessFreeFunctions(); // Set the names of the kernels, now that the names have settled down. This @@ -1130,7 +1132,6 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { // Emit SYCL integration header for current translation unit if needed if (SyclIntHeader != nullptr) SyclIntHeader->emit(getLangOpts().SYCLIntHeader); - MarkDevices(); } emitDeferredDiags(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index f9c412a5fa800..1eee221988171 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5667,19 +5667,8 @@ void Sema::MarkDevices() { } void Sema::ProcessFreeFunctions() { - // This Tracker object ensures that the SyclDeviceDecls collection includes - // the SYCL_EXTERNAL functions, and manages the diagnostics for all of the - // functions in the kernel. - DeviceFunctionTracker Tracker(*this); - for (Decl *D : syclDeviceDecls()) { auto *SYCLKernel = cast(D); - - // This type does the actual analysis on a per-kernel basis. It does this to - // make sure that we're only ever dealing with the context of a single - // kernel at a time. - SingleDeviceFunctionTracker T{Tracker, SYCLKernel}; - if (IsFreeFunction(*this, SYCLKernel)) { SyclKernelDecompMarker DecompMarker(*this); SyclKernelFieldChecker FieldChecker(*this); diff --git a/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp b/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp index f40bf981ea606..73a3d8a486e3a 100644 --- a/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp +++ b/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp @@ -76,15 +76,15 @@ int main() { // CHECK: FunctionDecl {{.*}}test_kernel1 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( FuncObj()); // CHECK: FunctionDecl {{.*}}test_kernel2 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( []() [[intel::sycl_explicit_simd]]{}); @@ -92,9 +92,9 @@ int main() { // CHECK: FunctionDecl {{.*}}test_kernel3 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr // CHECK-NOT: SYCLSimdAttr + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( []() [[intel::sycl_explicit_simd]] { func(); }); diff --git a/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp b/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp index bdabd1f40d52d..c269fb2b01cc4 100644 --- a/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp +++ b/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp @@ -46,7 +46,7 @@ void invoke_foo2() { // CHECK-LABEL: FunctionDecl {{.*}} invoke_foo2 'void ()' // CHECK: `-FunctionDecl {{.*}}KernelName 'void ()' // CHECK: -IntelReqdSubGroupSizeAttr {{.*}} - // CHECK: `-SYCLIntelNoGlobalWorkOffsetAttr {{.*}} + // CHECK: -SYCLIntelNoGlobalWorkOffsetAttr {{.*}} parallel_for([]() {}); #else parallel_for([]() {}); // expected-error 3 {{conflicting attributes applied to a SYCL kernel or SYCL_EXTERNAL function}} diff --git a/clang/test/SemaSYCL/sycl-esimd-ast.cpp b/clang/test/SemaSYCL/sycl-esimd-ast.cpp index 54914f087c91c..a065b47c00783 100644 --- a/clang/test/SemaSYCL/sycl-esimd-ast.cpp +++ b/clang/test/SemaSYCL/sycl-esimd-ast.cpp @@ -17,16 +17,16 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel1 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr {{.*}} + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( FuncObj()); // CHECK-LABEL: FunctionDecl {{.*}}test_kernel2 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr {{.*}} + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( []() [[intel::sycl_explicit_simd]]{}); @@ -34,9 +34,9 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel3 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr {{.*}} // CHECK-NEXT: SYCLSimdAttr {{.*}} + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( []() [[intel::sycl_explicit_simd]] { func(); }); }); From 30e13a4924ca2569e78e7f9f8fa14efc4e96b33d Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Fri, 29 Mar 2024 08:00:57 -0700 Subject: [PATCH 07/52] Remove unused code. --- clang/lib/CodeGen/CGExpr.cpp | 1 - .../oneapi/kernel_properties/properties.hpp | 56 +------------------ 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 1c163aff2415e..2b3b8f1d805ad 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -50,7 +50,6 @@ #include #include -#include using namespace clang; using namespace CodeGen; diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index eccedbc428d9a..25f7b9a42855a 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -154,6 +154,8 @@ struct property_value> { template <> struct property_value { using key_t = single_task_kernel_key; + using value_t = int; + static constexpr int value = 0; }; template @@ -177,58 +179,7 @@ inline constexpr nd_range_kernel_key::value_t nd_range_kernel; inline constexpr single_task_kernel_key::value_t single_task_kernel; -template <> struct is_property_key : std::true_type {}; -template <> -struct is_property_key : std::true_type {}; -template <> struct is_property_key : std::true_type {}; -template <> struct is_property_key : std::true_type {}; -template <> struct is_property_key : std::true_type {}; -template <> struct is_property_key : std::true_type {}; -template <> struct is_property_key : std::true_type {}; - -template struct is_range_kernel; -template struct is_nd_range_kernel; -template struct is_single_task_kernel; - -template -inline constexpr bool is_range_kernel_v = is_range_kernel::value; -template -inline constexpr bool is_nd_range_kernel_v = - is_nd_range_kernel::value; -template -inline constexpr bool is_single_task_kernel_v = - is_single_task_kernel::value; - namespace detail { -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::WorkGroupSize; -}; -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::WorkGroupSizeHint; -}; -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::SubGroupSize; -}; -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::DeviceHas; -}; -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::RangeKernel; -}; -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::NDRangeKernel; -}; -template <> struct PropertyToKind { - static constexpr PropKind Kind = PropKind::SingleTaskKernel; -}; - -template <> -struct IsCompileTimeProperty : std::true_type {}; -template <> -struct IsCompileTimeProperty : std::true_type {}; -template <> -struct IsCompileTimeProperty : std::true_type {}; -template <> struct IsCompileTimeProperty : std::true_type {}; template struct PropertyMetaInfo> { @@ -253,7 +204,6 @@ struct PropertyMetaInfo> { }; template struct PropertyMetaInfo> { - //static constexpr const char* name = "sycl-range-kernel"; static constexpr const char* name = "sycl-range-kernel"; static constexpr int value = Dims; //static constexpr const char *value = @@ -261,13 +211,11 @@ struct PropertyMetaInfo> { }; template struct PropertyMetaInfo> { - //static constexpr const char* name = "sycl-nd-range-kernel"; static constexpr const char* name = "sycl-nd-range-kernel"; static constexpr int value = Dims; }; template <> struct PropertyMetaInfo { - //static constexpr const char* name = "sycl-single-task-kernel"; static constexpr const char* name = "sycl-single-task-kernel"; static constexpr int value = 0; }; From aebaec93835e8605c3b2180d316fcb9cd79a83da Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Fri, 29 Mar 2024 09:24:24 -0700 Subject: [PATCH 08/52] Formatting changes. --- clang/lib/Sema/SemaSYCL.cpp | 18 +++++------ .../oneapi/kernel_properties/properties.hpp | 17 ++++------- .../free_function_kernels.cpp | 30 +++++++++---------- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 1eee221988171..8e467dbdcf5c2 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -940,22 +940,22 @@ class KernelBodyTransform : public TreeTransform { /// \param Src field declaration to construct name from /// \param Ty the desired parameter type /// \return the constructed descriptor -static ParamDesc makeParamDesc(const FieldDecl* Src, QualType Ty) { - ASTContext& Ctx = Src->getASTContext(); +static ParamDesc makeParamDesc(const FieldDecl *Src, QualType Ty) { + ASTContext &Ctx = Src->getASTContext(); std::string Name = (Twine("_arg_") + Src->getName()).str(); return std::make_tuple(Ty, &Ctx.Idents.get(Name), - Ctx.getTrivialTypeSourceInfo(Ty)); + Ctx.getTrivialTypeSourceInfo(Ty)); } -static ParamDesc makeParamDesc(const ParmVarDecl* Src, QualType Ty) { - ASTContext& Ctx = Src->getASTContext(); +static ParamDesc makeParamDesc(const ParmVarDecl *Src, QualType Ty) { + ASTContext &Ctx = Src->getASTContext(); std::string Name = (Twine("_arg_") + Src->getName()).str(); return std::make_tuple(Ty, &Ctx.Idents.get(Name), - Ctx.getTrivialTypeSourceInfo(Ty)); + Ctx.getTrivialTypeSourceInfo(Ty)); } -static ParamDesc makeParamDesc(ASTContext& Ctx, StringRef Name, QualType Ty) { +static ParamDesc makeParamDesc(ASTContext &Ctx, StringRef Name, QualType Ty) { return std::make_tuple(Ty, &Ctx.Idents.get(Name), - Ctx.getTrivialTypeSourceInfo(Ty)); + Ctx.getTrivialTypeSourceInfo(Ty)); } // Map used to replace original fields with new fields for free functions that @@ -2621,7 +2621,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { addField(PD, QualType(ModifiedRD->getTypeForDecl(), 0)); else ModifiedArrayElementsOrArray.push_back( - QualType(ModifiedRD->getTypeForDecl(), 0)); + QualType(ModifiedRD->getTypeForDecl(), 0)); } return true; diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index 25f7b9a42855a..c5f32a7c8c522 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -151,8 +151,7 @@ struct property_value> { static constexpr int value = Dims; }; -template <> -struct property_value { +template <> struct property_value { using key_t = single_task_kernel_key; using value_t = int; static constexpr int value = 0; @@ -202,21 +201,17 @@ struct PropertyMetaInfo> { static constexpr const char *value = SizeListToStr(Aspects)...>::value; }; -template -struct PropertyMetaInfo> { - static constexpr const char* name = "sycl-range-kernel"; +template struct PropertyMetaInfo> { + static constexpr const char *name = "sycl-range-kernel"; static constexpr int value = Dims; - //static constexpr const char *value = - // SizeListToStr(Dims)>::value; }; template struct PropertyMetaInfo> { - static constexpr const char* name = "sycl-nd-range-kernel"; + static constexpr const char *name = "sycl-nd-range-kernel"; static constexpr int value = Dims; }; -template <> -struct PropertyMetaInfo { - static constexpr const char* name = "sycl-single-task-kernel"; +template <> struct PropertyMetaInfo { + static constexpr const char *name = "sycl-single-task-kernel"; static constexpr int value = 0; }; diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 947c7a38f2d19..0cf300ec1ee4d 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -3,8 +3,8 @@ // This test tests free function kernel code generation and execution. -#include #include +#include using namespace sycl; @@ -94,7 +94,7 @@ void ff_0(int *ptr, int start, int end) { ptr[i] = start + end; } -int test_0(queue Queue, KernelFinder &KF) { +bool test_0(queue Queue, KernelFinder &KF) { constexpr int Range = 10; int *usmPtr = malloc_shared(Range, Queue); int start = 3; @@ -136,9 +136,9 @@ void ff_1(int *ptr, int start, int end) { ptr[Id.get(0)] = Id.get(0) + start + end; } -int test_1(queue Queue, KernelFinder &KF) { +bool test_1(queue Queue, KernelFinder &KF) { constexpr int Range = 10; - int* usmPtr = malloc_shared(Range, Queue); + int *usmPtr = malloc_shared(Range, Queue); int start = 3; struct Simple S { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 @@ -147,12 +147,12 @@ int test_1(queue Queue, KernelFinder &KF) { range<1> R1{Range}; memset(usmPtr, 0, Range * sizeof(int)); - Queue.submit([&](handler& Handler) { + Queue.submit([&](handler &Handler) { Handler.parallel_for(R1, [=](item<1> Item) { id<1> Id = Item.get_id(); usmPtr[Id.get(0)] = Id.get(0) + start + Range; - }); }); + }); Queue.wait(); bool Passa = checkUSM(usmPtr, Range, Result); std::cout << "Test 1a: " << (Passa ? "PASS" : "FAIL") << std::endl; @@ -185,9 +185,9 @@ void ff_2(int *ptr, int start, struct Simple S) { LId.get(0) + LId.get(1) + start + S.x + S.f + S.c[2]; } -int test_2(queue Queue, KernelFinder &KF) { +bool test_2(queue Queue, KernelFinder &KF) { constexpr int Range = 16; - int* usmPtr = malloc_shared(Range, Queue); + int *usmPtr = malloc_shared(Range, Queue); int value = 55; struct Simple S { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 @@ -197,15 +197,15 @@ int test_2(queue Queue, KernelFinder &KF) { nd_range<2> R2{range<2>{4, 4}, range<2>{2, 2}}; memset(usmPtr, 0, Range * sizeof(int)); - Queue.submit([&](handler& Handler) { + 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 + S.x + S.f + S.c[2]; - }); + LId.get(0) + LId.get(1) + value + S.x + S.f + S.c[2]; }); + }); Queue.wait(); bool Passa = checkUSM(usmPtr, Range, Result); std::cout << "Test 2a: " << (Passa ? "PASS" : "FAIL") << std::endl; @@ -242,9 +242,9 @@ SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( // Explicit instantiation with �int*� template void ff_3(int *ptr, int start, struct Simple S); -int test_3(queue Queue, KernelFinder &KF) { +bool test_3(queue Queue, KernelFinder &KF) { constexpr int Range = 16; - int* usmPtr = malloc_shared(Range, Queue); + int *usmPtr = malloc_shared(Range, Queue); int value = 55; struct Simple S { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 @@ -300,9 +300,9 @@ SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( // Explicit instantiation with �int*� template void ff_4(int *ptr, int start, struct WithPointer S); -int test_4(queue Queue, KernelFinder &KF) { +bool test_4(queue Queue, KernelFinder &KF) { constexpr int Range = 16; - int* usmPtr = malloc_shared(Range, Queue); + int *usmPtr = malloc_shared(Range, Queue); float *fp = malloc_shared(1, Queue); *fp = 8.2; int value = 55; From 7f9a8250336a99ea13cd26527822a3029f2ef7f2 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Fri, 29 Mar 2024 09:44:11 -0700 Subject: [PATCH 09/52] Formatting change. --- sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index c5f32a7c8c522..84525b038fe75 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -77,7 +77,6 @@ struct single_task_kernel_key { using value_t = property_value; }; - template struct property_value, std::integral_constant...> { From fff52dc06b9a8e43eea1d72695b98cebf22adb42 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 1 Apr 2024 14:18:55 -0700 Subject: [PATCH 10/52] Updated formatting, removed unneeded range_kernel property and updated a test. --- clang/lib/Sema/SemaSYCL.cpp | 94 +++++++++---------- .../oneapi/kernel_properties/properties.hpp | 27 +----- .../free_function_kernels.cpp | 17 ++-- 3 files changed, 53 insertions(+), 85 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 8e467dbdcf5c2..c652076e0bb4e 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -383,7 +383,8 @@ bool Sema::isDeclAllowedInSYCLDeviceCode(const Decl *D) { return true; } const DeclContext *DC = FD->getDeclContext(); - if (II && II->isStr("__spirv_ocl_printf") && !FD->isDefined() && + if (II && II->isStr("__spirv_ocl_printf") && + !FD->isDefined() && FD->getLanguageLinkage() == CXXLanguageLinkage && DC->getEnclosingNamespaceContext()->isTranslationUnit()) return true; @@ -654,7 +655,9 @@ class DiagDeviceFunction : public RecursiveASTVisitor { // Make sure we skip the condition of the case, since that is a constant // expression. - bool TraverseCaseStmt(CaseStmt *S) { return TraverseStmt(S->getSubStmt()); } + bool TraverseCaseStmt(CaseStmt *S) { + return TraverseStmt(S->getSubStmt()); + } // Skip checking the size expr, since a constant array type loc's size expr is // a constant expression. @@ -884,8 +887,7 @@ class SingleDeviceFunctionTracker { !KernelBody->hasAttr() && !KernelBody->hasAttr()) { KernelBody->addAttr(AlwaysInlineAttr::CreateImplicit( - KernelBody->getASTContext(), {}, - AlwaysInlineAttr::Keyword_forceinline)); + KernelBody->getASTContext(), {}, AlwaysInlineAttr::Keyword_forceinline)); } } @@ -1270,21 +1272,15 @@ static bool isReadOnlyAccessor(const TemplateArgument &AccessModeArg) { // anonymous namespace so these don't get linkage. namespace { -template struct bind_param { - using type = T; -}; +template struct bind_param { using type = T; }; template <> struct bind_param { using type = const CXXBaseSpecifier &; }; -template <> struct bind_param { - using type = FieldDecl *; -}; +template <> struct bind_param { using type = FieldDecl *; }; -template <> struct bind_param { - using type = FieldDecl *; -}; +template <> struct bind_param { using type = FieldDecl *; }; template using bind_param_t = typename bind_param::type; @@ -1293,7 +1289,7 @@ class KernelObjVisitor { template void VisitUnionImpl(const CXXRecordDecl *Owner, ParentTy &Parent, - const CXXRecordDecl *Wrapper, HandlerTys &...Handlers) { + const CXXRecordDecl *Wrapper, HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.enterUnion(Owner, Parent), 0)...}; VisitRecordHelper(Wrapper, Wrapper->fields(), Handlers...); @@ -1303,13 +1299,13 @@ class KernelObjVisitor { // These enable handler execution only when previous Handlers succeed. template - bool handleField(FieldDecl *FD, QualType FDTy, Tn &&...tn) { + bool handleField(FieldDecl *FD, QualType FDTy, Tn &&... tn) { bool result = true; (void)std::initializer_list{(result = result && tn(FD, FDTy), 0)...}; return result; } template - bool handleField(const CXXBaseSpecifier &BD, QualType BDTy, Tn &&...tn) { + bool handleField(const CXXBaseSpecifier &BD, QualType BDTy, Tn &&... tn) { bool result = true; std::initializer_list{(result = result && tn(BD, BDTy), 0)...}; return result; @@ -1325,10 +1321,10 @@ class KernelObjVisitor { std::ref(Handlers), _1, _2)...) // The following simpler definition works with gcc 8.x and later. - // #define KF_FOR_EACH(FUNC) \ - // handleField(Field, FieldTy, ([&](FieldDecl *FD, QualType FDTy) { \ - // return Handlers.f(FD, FDTy); \ - // })...) + //#define KF_FOR_EACH(FUNC) \ +// handleField(Field, FieldTy, ([&](FieldDecl *FD, QualType FDTy) { \ +// return Handlers.f(FD, FDTy); \ +// })...) // This enables handler execution only when previous Handlers succeed. template @@ -1354,7 +1350,7 @@ class KernelObjVisitor { template void visitComplexRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, - HandlerTys &...Handlers) { + HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.enterStruct(Owner, Parent, RecordTy), 0)...}; VisitRecordHelper(Wrapper, Wrapper->bases(), Handlers...); @@ -1366,7 +1362,7 @@ class KernelObjVisitor { template void visitSimpleRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, - HandlerTys &...Handlers) { + HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.handleNonDecompStruct(Owner, Parent, RecordTy), 0)...}; } @@ -1374,16 +1370,16 @@ class KernelObjVisitor { template void visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, QualType RecordTy, - HandlerTys &...Handlers); + HandlerTys &... Handlers); template void VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent, - const CXXRecordDecl *Wrapper, HandlerTys &...Handlers); + const CXXRecordDecl *Wrapper, HandlerTys &... Handlers); template void VisitRecordHelper(const CXXRecordDecl *Owner, clang::CXXRecordDecl::base_class_const_range Range, - HandlerTys &...Handlers) { + HandlerTys &... Handlers) { for (const auto &Base : Range) { QualType BaseTy = Base.getType(); // Handle accessor class as base @@ -1400,14 +1396,14 @@ class KernelObjVisitor { template void VisitRecordHelper(const CXXRecordDecl *Owner, RecordDecl::field_range Range, - HandlerTys &...Handlers) { + HandlerTys &... Handlers) { VisitRecordFields(Owner, Handlers...); } template void visitArrayElementImpl(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &...Handlers) { + HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.nextElement(ElementTy, Index), 0)...}; visitField(Owner, ArrayField, ElementTy, Handlers...); @@ -1422,13 +1418,13 @@ class KernelObjVisitor { template void visitFirstArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, - QualType ElementTy, HandlerTys &...Handlers) { + QualType ElementTy, HandlerTys &... Handlers) { visitArrayElementImpl(Owner, ArrayField, ElementTy, 0, Handlers...); } template void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &...Handlers); + HandlerTys &... Handlers); template void visitFirstArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, @@ -1441,7 +1437,7 @@ class KernelObjVisitor { template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &...Handlers) { + QualType ArrayTy, HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.handleSimpleArrayType(Field, ArrayTy), 0)...}; } @@ -1454,7 +1450,7 @@ class KernelObjVisitor { template void visitComplexArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &...Handlers) { + QualType ArrayTy, HandlerTys &... Handlers) { // Array workflow is: // handleArrayType // enterArray @@ -1517,7 +1513,7 @@ class KernelObjVisitor { template void visitField(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType FieldTy, HandlerTys &...Handlers) { + QualType FieldTy, HandlerTys &... Handlers) { if (isSyclSpecialType(FieldTy, SemaRef)) KF_FOR_EACH(handleSyclSpecialType, Field, FieldTy); else if (FieldTy->isStructureOrClassType()) { @@ -1574,14 +1570,14 @@ class KernelObjVisitor { template void VisitRecordBases(const CXXRecordDecl *KernelFunctor, - HandlerTys &...Handlers) { + HandlerTys &... Handlers) { VisitRecordHelper(KernelFunctor, KernelFunctor->bases(), Handlers...); } // A visitor function that dispatches to functions as defined in // SyclKernelFieldHandler for the purposes of kernel generation. template - void VisitRecordFields(const CXXRecordDecl *Owner, HandlerTys &...Handlers) { + void VisitRecordFields(const CXXRecordDecl *Owner, HandlerTys &... Handlers) { for (const auto Field : Owner->fields()) visitField(Owner, Field, Field->getType(), Handlers...); } @@ -1751,9 +1747,7 @@ template struct HandlerFilter { template struct AnyTrue; -template struct AnyTrue { - static constexpr bool Value = B; -}; +template struct AnyTrue { static constexpr bool Value = B; }; template struct AnyTrue { static constexpr bool Value = B || AnyTrue::Value; @@ -1761,9 +1755,7 @@ template struct AnyTrue { template struct AllTrue; -template struct AllTrue { - static constexpr bool Value = B; -}; +template struct AllTrue { static constexpr bool Value = B; }; template struct AllTrue { static constexpr bool Value = B && AllTrue::Value; @@ -1772,7 +1764,7 @@ template struct AllTrue { template void KernelObjVisitor::VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, - Handlers &...handlers) { + Handlers &... handlers) { // Don't continue descending if none of the handlers 'care'. This could be 'if // constexpr' starting in C++17. Until then, we have to count on the // optimizer to realize "if (false)" is a dead branch. @@ -1786,7 +1778,7 @@ template void KernelObjVisitor::visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - Handlers &...handlers) { + Handlers &... handlers) { // Don't continue descending if none of the handlers 'care'. This could be 'if // constexpr' starting in C++17. Until then, we have to count on the // optimizer to realize "if (false)" is a dead branch. @@ -1800,7 +1792,7 @@ void KernelObjVisitor::visitNthArrayElement(const CXXRecordDecl *Owner, template void KernelObjVisitor::visitNthArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, uint64_t Index, - Handlers &...handlers) { + Handlers &... handlers) { // Don't continue descending if none of the handlers 'care'. This could be 'if // constexpr' starting in C++17. Until then, we have to count on the // optimizer to realize "if (false)" is a dead branch. @@ -1814,7 +1806,8 @@ void KernelObjVisitor::visitNthArrayElement(ParmVarDecl *ArrayField, template void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, - QualType RecordTy, HandlerTys &...Handlers) { + QualType RecordTy, + HandlerTys &... Handlers) { RecordDecl *RD = RecordTy->getAsRecordDecl(); assert(RD && "should not be null."); if (RD->hasAttr()) { @@ -1859,7 +1852,7 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, template void KernelObjVisitor::visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &...Handlers) { + QualType ArrayTy, HandlerTys &... Handlers) { if (Field->hasAttr()) { visitComplexArray(Owner, Field, ArrayTy, Handlers...); @@ -2308,7 +2301,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { CollectionStack.back() = true; return true; } - bool handleSyclSpecialType(FieldDecl *, QualType) final { CollectionStack.back() = true; return true; @@ -2764,7 +2756,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { makeParamDesc(SemaRef.getASTContext(), Name, FieldTy); addParam(newParamDesc, FieldTy); } - // Add a parameter with specified name and type void addParam(StringRef Name, QualType ParamTy) { ParamDesc newParamDesc = @@ -4229,8 +4220,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { InitializationKind InitKind = InitializationKind::CreateDefault(KernelCallerSrcLoc); InitializationSequence InitSeq(SemaRef, VarEntity, InitKind, std::nullopt); - ExprResult Init = - InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); + ExprResult Init = InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); KernelHandlerClone->setInit( SemaRef.MaybeCreateExprWithCleanups(Init.get())); KernelHandlerClone->setInitStyle(VarDecl::CallInit); @@ -6388,6 +6378,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "\n"; } + O << "// names of all kernels defined in the corresponding source\n"; O << "static constexpr\n"; O << "const char* const kernel_names[] = {\n"; @@ -6773,7 +6764,7 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) { for (const VarDecl *VD : GlobalVars) { VD = VD->getCanonicalDecl(); - // Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This + // Skip if this isn't a SpecIdType, DeviceGlobal, or HostPipe. This // can happen if it was a deduced type. if (!Sema::isSyclType(VD->getType(), SYCLTypeAttr::specialization_id) && !Sema::isSyclType(VD->getType(), SYCLTypeAttr::host_pipe) && @@ -6818,7 +6809,8 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) { VD->getNameForDiagnostic(HostPipesOS, Policy, true); } HostPipesOS << ", \""; - HostPipesOS << SYCLUniqueStableIdExpr::ComputeName(S.getASTContext(), VD); + HostPipesOS << SYCLUniqueStableIdExpr::ComputeName(S.getASTContext(), + VD); HostPipesOS << "\");\n"; } else { EmittedFirstSpecConstant = true; diff --git a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp index 84525b038fe75..3d2d09dc3a5c1 100644 --- a/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp +++ b/sycl/include/sycl/ext/oneapi/kernel_properties/properties.hpp @@ -61,12 +61,6 @@ struct device_has_key : detail::compile_time_property_key...>; }; -struct range_kernel_key { - template - using value_t = - property_value>; -}; - struct nd_range_kernel_key { template using value_t = @@ -129,16 +123,6 @@ struct property_value value{Aspects...}; }; -template -struct property_value> { - static_assert(Dims >= 1 && Dims <= 3, - "range_kernel_key property must use dimension of 1, 2 or 3."); - - using key_t = range_kernel_key; - using value_t = int; - static constexpr int value = Dims; -}; - template struct property_value> { static_assert( @@ -147,13 +131,11 @@ struct property_value> { using key_t = nd_range_kernel_key; using value_t = int; - static constexpr int value = Dims; + static constexpr int dimensions = Dims; }; template <> struct property_value { using key_t = single_task_kernel_key; - using value_t = int; - static constexpr int value = 0; }; template @@ -169,9 +151,6 @@ inline constexpr sub_group_size_key::value_t sub_group_size; template inline constexpr device_has_key::value_t device_has; -template -inline constexpr range_kernel_key::value_t range_kernel; - template inline constexpr nd_range_kernel_key::value_t nd_range_kernel; @@ -200,10 +179,6 @@ struct PropertyMetaInfo> { static constexpr const char *value = SizeListToStr(Aspects)...>::value; }; -template struct PropertyMetaInfo> { - static constexpr const char *name = "sycl-range-kernel"; - static constexpr int value = Dims; -}; template struct PropertyMetaInfo> { static constexpr const char *name = "sycl-nd-range-kernel"; diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 0cf300ec1ee4d..08fe79dab89fd 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -130,10 +130,11 @@ bool test_0(queue Queue, KernelFinder &KF) { } SYCL_EXTERNAL -SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((ext::oneapi::experimental::range_kernel<1>)) +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((ext::oneapi::experimental::nd_range_kernel<1>)) void ff_1(int *ptr, int start, int end) { - id<1> Id = ext::oneapi::experimental::this_id<1>(); - ptr[Id.get(0)] = Id.get(0) + start + end; + nd_item<1> Item = ext::oneapi::experimental::this_nd_item<1>(); + id<1> GId = Item.get_global_id(); + ptr[GId.get(0)] = GId.get(0) + start + end; } bool test_1(queue Queue, KernelFinder &KF) { @@ -144,13 +145,13 @@ bool test_1(queue Queue, KernelFinder &KF) { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 }; int Result[Range] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; - range<1> R1{Range}; + nd_range<1> R1{ {Range},{1} }; memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { - Handler.parallel_for(R1, [=](item<1> Item) { - id<1> Id = Item.get_id(); - usmPtr[Id.get(0)] = Id.get(0) + start + Range; + Handler.parallel_for(R1, [=](nd_item<1> Item) { + id<1> GId = Item.get_global_id(); + usmPtr[GId.get(0)] = GId.get(0) + start + Range; }); }); Queue.wait(); @@ -354,5 +355,5 @@ int main() { Pass &= test_3(Queue, KF); Pass &= test_4(Queue, KF); - return Pass; + return Pass ? 0 : 1; } From 28ce5fb0dac999cc3b8663bf34e36a65c640a9ca Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 1 Apr 2024 14:30:04 -0700 Subject: [PATCH 11/52] Formatting change. --- clang/lib/Sema/SemaSYCL.cpp | 2 +- sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c652076e0bb4e..0e5920ce96994 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1792,7 +1792,7 @@ void KernelObjVisitor::visitNthArrayElement(const CXXRecordDecl *Owner, template void KernelObjVisitor::visitNthArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, uint64_t Index, - Handlers &... handlers) { + Handlers &...handlers) { // Don't continue descending if none of the handlers 'care'. This could be 'if // constexpr' starting in C++17. Until then, we have to count on the // optimizer to realize "if (false)" is a dead branch. diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 08fe79dab89fd..2d76d227a0a0d 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -130,7 +130,8 @@ bool test_0(queue Queue, KernelFinder &KF) { } SYCL_EXTERNAL -SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((ext::oneapi::experimental::nd_range_kernel<1>)) +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( + (ext::oneapi::experimental::nd_range_kernel<1>)) void ff_1(int *ptr, int start, int end) { nd_item<1> Item = ext::oneapi::experimental::this_nd_item<1>(); id<1> GId = Item.get_global_id(); @@ -145,7 +146,7 @@ bool test_1(queue Queue, KernelFinder &KF) { 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 }; int Result[Range] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; - nd_range<1> R1{ {Range},{1} }; + nd_range<1> R1{{Range}, {1}}; memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { From 8c8cd019d402e79aba0d63183eb1036529c39d36 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 1 Apr 2024 20:34:01 -0700 Subject: [PATCH 12/52] Corrected test and added feature test macro. --- sycl/include/sycl/ext/oneapi/properties/property.hpp | 7 +++---- sycl/source/feature_test.hpp.in | 1 + sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sycl/include/sycl/ext/oneapi/properties/property.hpp b/sycl/include/sycl/ext/oneapi/properties/property.hpp index d3e84895dbc1b..84f39e65c8935 100644 --- a/sycl/include/sycl/ext/oneapi/properties/property.hpp +++ b/sycl/include/sycl/ext/oneapi/properties/property.hpp @@ -196,11 +196,10 @@ enum PropKind : uint32_t { Balanced = 55, InvocationCapacity = 56, ResponseCapacity = 57, - RangeKernel = 58, - NDRangeKernel = 59, - SingleTaskKernel = 60, + NDRangeKernel = 58, + SingleTaskKernel = 59, // PropKindSize must always be the last value. - PropKindSize = 61, + PropKindSize = 60, }; struct property_key_base_tag {}; diff --git a/sycl/source/feature_test.hpp.in b/sycl/source/feature_test.hpp.in index 818430a374c8f..1797cfe12d9f2 100644 --- a/sycl/source/feature_test.hpp.in +++ b/sycl/source/feature_test.hpp.in @@ -104,6 +104,7 @@ inline namespace _V1 { #define SYCL_EXT_INTEL_MATRIX 1 #define SYCL_EXT_INTEL_FPGA_TASK_SEQUENCE 1 #define SYCL_EXT_ONEAPI_PRIVATE_ALLOCA 1 +#define SYCL_EXT_ONEAPI_FREE_FUNCTION_KERNELS 1 #ifndef __has_include #define __has_include(x) 0 diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 2d76d227a0a0d..4cd56baafccf7 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -1,5 +1,6 @@ // RUN: %{build} -o %t.out // RUN: %{run} %t.out +// UNSUPPORTED: hip // This test tests free function kernel code generation and execution. From 8e6906b2a39050f6c45b1dec3d17bd19c7e068b3 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Wed, 3 Apr 2024 21:02:44 -0700 Subject: [PATCH 13/52] Added a frontend test, updated end-to-end test. --- clang/include/clang/Sema/Sema.h | 9 ++- clang/lib/Sema/SemaSYCL.cpp | 78 ++++++++++--------- .../free_function_kernel_params.cpp | 41 ++++++++++ .../free_function_kernels.cpp | 65 ++++++++-------- 4 files changed, 121 insertions(+), 72 deletions(-) create mode 100755 clang/test/CodeGenSYCL/free_function_kernel_params.cpp diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ad7730b263a5b..718dfb0b0289e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -341,7 +341,7 @@ class SYCLIntegrationHeader { /// the kernel with given name. Starts new kernel invocation descriptor. void startKernel(const FunctionDecl *SyclKernel, QualType KernelNameType, SourceLocation Loc, bool IsESIMD, bool IsUnnamedKernel, - int64_t ObjSize); + bool IsFreeFunctionKernel, int64_t ObjSize); /// Adds a kernel parameter descriptor to current kernel invocation /// descriptor. @@ -422,15 +422,18 @@ class SYCLIntegrationHeader { // hasn't provided an explicit name for. bool IsUnnamedKernel; + // Whether this is a free function kernel. + bool IsFreeFunctionKernel; + /// Size of the kernel object. int64_t ObjSize = 0; KernelDesc(const FunctionDecl *SyclKernel, QualType NameType, SourceLocation KernelLoc, bool IsESIMD, bool IsUnnamedKernel, - int64_t ObjSize) + bool IsFreeFunctionKernel, int64_t ObjSize) : SyclKernel(SyclKernel), NameType(NameType), KernelLocation(KernelLoc), IsESIMDKernel(IsESIMD), IsUnnamedKernel(IsUnnamedKernel), - ObjSize(ObjSize) {} + IsFreeFunctionKernel(IsFreeFunctionKernel), ObjSize(ObjSize) {} void updateKernelNames(StringRef Name, StringRef StableName) { this->Name = Name.str(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 0e5920ce96994..1836f9c5c7aea 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1162,16 +1162,31 @@ static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { return false; } -static std::string constructFreeFunctionKernelName(ASTContext &Ctx, - const FunctionDecl *FD) { +static std::string constructFFKernelName(ASTContext &Ctx, + const FunctionDecl *FD) { IdentifierInfo *Id = FD->getIdentifier(); std::string NewIdent = (Twine("__free_function_") + Id->getName()).str(); return NewIdent; } -// Free functions are always void type. -static QualType calculateFreeFunctionNameType(const FunctionDecl *FF) { - return FF->getType(); +// Gets a name for the free function kernel function. The suffix allows a normal +// device function to coexist with the kernel function. +static std::pair +constructFreeFunctionKernelName(Sema &S, const FunctionDecl *KernelCallerFunc, + MangleContext &MC) { + SmallString<256> Result; + llvm::raw_svector_ostream Out(Result); + std::string MangledName; + std::string StableName; + + if (KernelCallerFunc->getTemplateSpecializationArgs()) { + MC.mangleName(KernelCallerFunc, Out); + MangledName = (Twine("__free_function") + Out.str()).str(); + } else { + MangledName = constructFFKernelName(S.getASTContext(), KernelCallerFunc); + } + StableName = MangledName; + return {MangledName, StableName}; } // The first template argument to the kernel caller function is used to identify @@ -1184,28 +1199,13 @@ static QualType calculateKernelNameType(ASTContext &Ctx, return TAL->get(0).getAsType().getCanonicalType(); } -// Gets a name for the kernel function, calculated from the first +// Gets a name for the OpenCL kernel function, calculated from the first // template argument of the kernel caller function. -// Free functions may not be templated. Use original function name with a -// prefix. static std::pair constructKernelName(Sema &S, const FunctionDecl *KernelCallerFunc, MangleContext &MC) { - QualType KernelNameType; - if (IsFreeFunction(S, KernelCallerFunc)) { - if (KernelCallerFunc->getTemplateSpecializationArgs()) { - KernelNameType = KernelCallerFunc->getType(); - } else { - std::string MangledName( - constructFreeFunctionKernelName(S.getASTContext(), KernelCallerFunc)); - std::string StableName = (constructFreeFunctionKernelName( - S.getASTContext(), KernelCallerFunc)); - return {MangledName, StableName}; - } - } else { - KernelNameType = - calculateKernelNameType(S.getASTContext(), KernelCallerFunc); - } + QualType KernelNameType = + calculateKernelNameType(S.getASTContext(), KernelCallerFunc); SmallString<256> Result; llvm::raw_svector_ostream Out(Result); @@ -2926,7 +2926,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); const IdentifierInfo *NewIdent = - &Ctx.Idents.get(constructFreeFunctionKernelName(Ctx, FD)); + &Ctx.Idents.get(constructFFKernelName(Ctx, FD)); FD = FunctionDecl::Create( Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); @@ -4712,7 +4712,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { .getTypeSizeInChars(KernelObj->getTypeForDecl()) .getQuantity(); Header.startKernel(KernelFunc, NameType, KernelObj->getLocation(), IsESIMD, - IsSYCLUnnamedKernel(S, KernelFunc), ObjSize); + IsSYCLUnnamedKernel(S, KernelFunc), + false /*IsFreeFunctionKernel*/, ObjSize); } SyclKernelIntHeaderCreator(Sema &S, SYCLIntegrationHeader &H, int64_t ObjSize, @@ -4720,7 +4721,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { : SyclKernelFieldHandler(S), Header(H) { Header.startKernel(FreeFunc, NameType, FreeFunc->getLocation(), false /*IsESIMD*/, true /*IsSYCLUnnamedKernel*/, - ObjSize); + true /*IsFreeFunctionKernel*/, ObjSize); } bool handleSyclSpecialType(const CXXRecordDecl *RD, @@ -5219,8 +5220,12 @@ void Sema::SetSYCLKernelNames() { for (const std::pair &Pair : SyclKernelsToOpenCLKernels) { std::string CalculatedName, StableName; - std::tie(CalculatedName, StableName) = - constructKernelName(*this, Pair.first, *MangleCtx); + if (IsFreeFunction(*this, Pair.first)) + std::tie(CalculatedName, StableName) = + constructFreeFunctionKernelName(*this, Pair.first, *MangleCtx); + else + std::tie(CalculatedName, StableName) = + constructKernelName(*this, Pair.first, *MangleCtx); StringRef KernelName( IsSYCLUnnamedKernel(*this, Pair.first) ? StableName : CalculatedName); @@ -5354,9 +5359,8 @@ void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { SyclKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD, DummyClass1); // Kernel object size is irrelevant, so set to 0. - SyclKernelIntHeaderCreator int_header(SemaRef, - SemaRef.getSyclIntegrationHeader(), 0, - calculateFreeFunctionNameType(FD), FD); + SyclKernelIntHeaderCreator int_header( + SemaRef, SemaRef.getSyclIntegrationHeader(), 0, FD->getType(), FD); SyclKernelIntFooterCreator int_footer(SemaRef, SemaRef.getSyclIntegrationFooter()); @@ -6524,13 +6528,13 @@ bool SYCLIntegrationHeader::emit(StringRef IntHeaderName) { return true; } -void SYCLIntegrationHeader::startKernel(const FunctionDecl *SyclKernel, - QualType KernelNameType, - SourceLocation KernelLocation, - bool IsESIMDKernel, - bool IsUnnamedKernel, int64_t ObjSize) { +void SYCLIntegrationHeader::startKernel( + const FunctionDecl *SyclKernel, QualType KernelNameType, + SourceLocation KernelLocation, bool IsESIMDKernel, bool IsUnnamedKernel, + bool IsFreeFunctionKernel, int64_t ObjSize) { KernelDescs.emplace_back(SyclKernel, KernelNameType, KernelLocation, - IsESIMDKernel, IsUnnamedKernel, ObjSize); + IsESIMDKernel, IsUnnamedKernel, IsFreeFunctionKernel, + ObjSize); } void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info, 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..a0e26a25e2801 --- /dev/null +++ b/clang/test/CodeGenSYCL/free_function_kernel_params.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -internal-isystem %S/Inputs -disable-llvm-passes \ +// RUN: -triple spir64-unknown-unknown -fsycl-is-device -S \ +// RUN: -emit-llvm %s -o - | FileCheck %s +// +// This test checks device code generation for free functions with scalar, +// pointer, simple struct and struct with pointer parameters. + +#include "mock_properties.hpp" +#include "sycl.hpp" + +struct Simple { + int x; + char c[100]; + float f; +}; +struct WithPointer { + int x; + float* fp; + float f; +}; + +// CHECK: %struct.Simple = type { i32, [100 x i8], float } +// CHECK: %struct.WithPointer = type { i32, ptr addrspace(4), float } +// CHECK: %struct.__generated_WithPointer = type { i32, ptr addrspace(1), float } +// CHECK: %struct.__generated_WithPointer.0 = type { i32, ptr addrspace(1), float } + + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] +void ff_2(int *ptr, int start, int end, struct Simple S, struct WithPointer P) { + for (int i = start; i <= end; i++) + ptr[i] = start + S.x + S.f + S.c[2]+ P.x + 66; +} +// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S, ptr noundef byval(%struct.__generated_WithPointer) align 8 %_arg_P) + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 1)]] +void iotar3(int* usmPtr, struct WithPointer P) { + usmPtr[55] = P.x + 66; +} +// CHECK: spir_kernel void @__free_function_iotar3(ptr addrspace(1) {{.*}} %_arg_usmPtr, {{.*}}(%struct.__generated_WithPointer.0) {{.*}} %_arg_P) diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 4cd56baafccf7..a9097b42fde76 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -12,7 +12,7 @@ using namespace sycl; // Kernel finder class KernelFinder { queue &Queue; - std::vector AllKernelIDs; + std::vector AllKernelIDs; public: KernelFinder(queue &Q) : Queue(Q) { @@ -20,7 +20,7 @@ class KernelFinder { kernel_bundle Bundle = get_kernel_bundle(Queue.get_context()); std::cout << "Bundle obtained\n"; - AllKernelIDs = sycl::get_kernel_ids(); + AllKernelIDs = get_kernel_ids(); std::cout << "Number of kernels = " << AllKernelIDs.size() << std::endl; for (auto K : AllKernelIDs) { std::cout << "Kernel obtained: " << K.get_name() << std::endl; @@ -111,8 +111,8 @@ bool test_0(queue Queue, KernelFinder &KF) { }); }); Queue.wait(); - bool Passa = checkUSM(usmPtr, Range, Result); - std::cout << "Test 0a: " << (Passa ? "PASS" : "FAIL") << std::endl; + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 0a: " << (PassA ? "PASS" : "FAIL") << std::endl; kernel Kernel = KF.get_kernel("__free_function_ff_0"); memset(usmPtr, 0, Range * sizeof(int)); @@ -123,11 +123,11 @@ bool test_0(queue Queue, KernelFinder &KF) { Handler.single_task(Kernel); }); Queue.wait(); - bool Passb = checkUSM(usmPtr, Range, Result); - std::cout << "Test 0b: " << (Passb ? "PASS" : "FAIL") << std::endl; + bool PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 0b: " << (PassB ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - return Passa && Passb; + return PassA && PassB; } SYCL_EXTERNAL @@ -157,8 +157,8 @@ bool test_1(queue Queue, KernelFinder &KF) { }); }); Queue.wait(); - bool Passa = checkUSM(usmPtr, Range, Result); - std::cout << "Test 1a: " << (Passa ? "PASS" : "FAIL") << std::endl; + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 1a: " << (PassA ? "PASS" : "FAIL") << std::endl; kernel Kernel = KF.get_kernel("__free_function_ff_1"); memset(usmPtr, 0, Range * sizeof(int)); @@ -169,11 +169,11 @@ bool test_1(queue Queue, KernelFinder &KF) { Handler.parallel_for(R1, Kernel); }); Queue.wait(); - bool Passb = checkUSM(usmPtr, Range, Result); - std::cout << "Test 1b: " << (Passb ? "PASS" : "FAIL") << std::endl; + bool PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 1b: " << (PassB ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - return Passa && Passb; + return PassA && PassB; } SYCL_EXTERNAL @@ -210,8 +210,8 @@ bool test_2(queue Queue, KernelFinder &KF) { }); }); Queue.wait(); - bool Passa = checkUSM(usmPtr, Range, Result); - std::cout << "Test 2a: " << (Passa ? "PASS" : "FAIL") << std::endl; + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 2a: " << (PassA ? "PASS" : "FAIL") << std::endl; kernel Kernel = KF.get_kernel("__free_function_ff_2"); memset(usmPtr, 0, Range * sizeof(int)); @@ -222,14 +222,14 @@ bool test_2(queue Queue, KernelFinder &KF) { Handler.parallel_for(R2, Kernel); }); Queue.wait(); - bool Passb = checkUSM(usmPtr, Range, Result); - std::cout << "Test 2b: " << (Passb ? "PASS" : "FAIL") << std::endl; + bool PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 2b: " << (PassB ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - return Passa && Passb; + return PassA && PassB; } -// Templated free function definition +// Templated free function definition. template SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( ext::oneapi::experimental::nd_range_kernel<2>)) void ff_3(T *ptr, T start, @@ -267,10 +267,10 @@ bool test_3(queue Queue, KernelFinder &KF) { }); }); Queue.wait(); - bool Passa = checkUSM(usmPtr, Range, Result); - std::cout << "Test 3a: " << (Passa ? "PASS" : "FAIL") << std::endl; + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 3a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_ZTSFvPii6SimpleE"); + kernel Kernel = KF.get_kernel("__free_function_Z4ff_3IiEvPT_S0_6Simple"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -279,14 +279,14 @@ bool test_3(queue Queue, KernelFinder &KF) { Handler.parallel_for(R2, Kernel); }); Queue.wait(); - bool Passb = checkUSM(usmPtr, Range, Result); - std::cout << "Test 3b: " << (Passb ? "PASS" : "FAIL") << std::endl; + bool PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 3b: " << (PassB ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - return Passa && Passb; + return PassA && PassB; } -// Templated free function definition +// Templated free function definition. template SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( ext::oneapi::experimental::nd_range_kernel<2>)) void ff_4(T *ptr, T start, @@ -300,7 +300,7 @@ SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( LId.get(0) + LId.get(1) + start + S.x + S.f + *S.fp; } -// Explicit instantiation with �int*� +// Explicit instantiation with �int*�. template void ff_4(int *ptr, int start, struct WithPointer S); bool test_4(queue Queue, KernelFinder &KF) { @@ -327,10 +327,11 @@ bool test_4(queue Queue, KernelFinder &KF) { }); }); Queue.wait(); - bool Passa = checkUSM(usmPtr, Range, Result); - std::cout << "Test 4a: " << (Passa ? "PASS" : "FAIL") << std::endl; + bool PassA = checkUSM(usmPtr, Range, Result); + std::cout << "Test 4a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_ZTSFvPii11WithPointerE"); + kernel Kernel = + KF.get_kernel("__free_function_Z4ff_4IiEvPT_S0_11WithPointer"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -339,11 +340,11 @@ bool test_4(queue Queue, KernelFinder &KF) { Handler.parallel_for(R2, Kernel); }); Queue.wait(); - bool Passb = checkUSM(usmPtr, Range, Result); - std::cout << "Test 4b: " << (Passb ? "PASS" : "FAIL") << std::endl; + bool PassB = checkUSM(usmPtr, Range, Result); + std::cout << "Test 4b: " << (PassB ? "PASS" : "FAIL") << std::endl; free(usmPtr, Queue); - return Passa && Passb; + return PassA && PassB; } int main() { From fd3bc83c7c79a31ce38518a0dd64cfd0db6e375c Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 4 Apr 2024 10:08:05 -0700 Subject: [PATCH 14/52] Replaced a CodeGen test with an AST test. --- .../free_function_kernel_params.cpp | 41 ------------------- .../SemaSYCL/free_function_kernel_params.cpp | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 41 deletions(-) delete mode 100755 clang/test/CodeGenSYCL/free_function_kernel_params.cpp create mode 100755 clang/test/SemaSYCL/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 deleted file mode 100755 index a0e26a25e2801..0000000000000 --- a/clang/test/CodeGenSYCL/free_function_kernel_params.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// RUN: %clang_cc1 -internal-isystem %S/Inputs -disable-llvm-passes \ -// RUN: -triple spir64-unknown-unknown -fsycl-is-device -S \ -// RUN: -emit-llvm %s -o - | FileCheck %s -// -// This test checks device code generation for free functions with scalar, -// pointer, simple struct and struct with pointer parameters. - -#include "mock_properties.hpp" -#include "sycl.hpp" - -struct Simple { - int x; - char c[100]; - float f; -}; -struct WithPointer { - int x; - float* fp; - float f; -}; - -// CHECK: %struct.Simple = type { i32, [100 x i8], float } -// CHECK: %struct.WithPointer = type { i32, ptr addrspace(4), float } -// CHECK: %struct.__generated_WithPointer = type { i32, ptr addrspace(1), float } -// CHECK: %struct.__generated_WithPointer.0 = type { i32, ptr addrspace(1), float } - - -__attribute__((sycl_device)) -[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int start, int end, struct Simple S, struct WithPointer P) { - for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2]+ P.x + 66; -} -// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S, ptr noundef byval(%struct.__generated_WithPointer) align 8 %_arg_P) - -__attribute__((sycl_device)) -[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 1)]] -void iotar3(int* usmPtr, struct WithPointer P) { - usmPtr[55] = P.x + 66; -} -// CHECK: spir_kernel void @__free_function_iotar3(ptr addrspace(1) {{.*}} %_arg_usmPtr, {{.*}}(%struct.__generated_WithPointer.0) {{.*}} %_arg_P) diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp new file mode 100755 index 0000000000000..ad622bdd757d1 --- /dev/null +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -0,0 +1,41 @@ +// 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, pointer, simple struct and struct with pointers. + +#include "sycl.hpp" + +struct Simple { + int x; + char c[100]; + float f; +}; +struct WithPointer { + int x; + float* fp; + float f; +}; + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] +void ff_2(int *ptr, int start, int end, struct Simple S, struct WithPointer P) { + for (int i = start; i <= end; i++) + ptr[i] = start + S.x + S.f + S.c[2]+ P.x + 66; +} +// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int, struct Simple, __generated_WithPointer)' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_P '__generated_WithPointer' + + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 1)]] +void iotar3(int* usmPtr, struct WithPointer P) { + usmPtr[55] = P.x + 66; +} +// CHECK: FunctionDecl {{.*}} __free_function_iotar3 'void (__global int *, __generated_WithPointer)' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_usmPtr '__global int *' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_P '__generated_WithPointer' \ No newline at end of file From 3e61a19e25f183fcaa8ec33f9b55ab5e8a360311 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 4 Apr 2024 13:53:27 -0700 Subject: [PATCH 15/52] Added CodeGen test. --- .../CodeGenSYCL/free_function_param_refs.cpp | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 clang/test/CodeGenSYCL/free_function_param_refs.cpp diff --git a/clang/test/CodeGenSYCL/free_function_param_refs.cpp b/clang/test/CodeGenSYCL/free_function_param_refs.cpp new file mode 100755 index 0000000000000..ea72655421628 --- /dev/null +++ b/clang/test/CodeGenSYCL/free_function_param_refs.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -internal-isystem %S/Inputs -disable-llvm-passes \ +// RUN: -triple spir64-unknown-unknown -fsycl-is-device -S \ +// RUN: -emit-llvm %s -o - | FileCheck %s +// +// This test checks device code generation for free functions with scalar, +// pointer, simple struct and struct with pointer parameters. + +#include "mock_properties.hpp" +#include "sycl.hpp" + +struct Simple { + int x; + char c[100]; + float f; +}; +struct WithPointer { + int x; + float* fp; + float f; +}; + +// CHECK: %struct.Simple = type { i32, [100 x i8], float } +// CHECK: %struct.WithPointer = type { i32, ptr addrspace(4), float } +// CHECK: %struct.__generated_WithPointer = type { i32, ptr addrspace(1), float } + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] +void ff_2(int *ptr, int start, int end, struct Simple S, struct WithPointer P) { + for (int i = start; i <= end; i++) + ptr[i] = start + S.x + S.f + S.c[2]+ P.x + 66; +} +// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S, ptr noundef byval(%struct.__generated_WithPointer) align 8 %_arg_P) +// CHECK: store ptr addrspace(1) %_arg_ptr, ptr addrspace(4) %_arg_ptr.{{.*}} +// CHECK: store i32 %_arg_start, ptr addrspace(4) %_arg_start.{{.*}} +// CHECK: store i32 %_arg_end, ptr addrspace(4) %_arg_end.{{.*}} +// CHECK: %x = getelementptr inbounds %struct.Simple +// CHECK: %f = getelementptr inbounds %struct.Simple +// CHECK: %c = getelementptr inbounds %struct.Simple +// CHECK: %__generated_x = getelementptr inbounds %struct.__generated_WithPointer, ptr addrspace(4) %_arg_P.{{.*}} From f97a99de77af5a2bc788b925316676fbfaf83476 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 8 Apr 2024 22:42:36 -0700 Subject: [PATCH 16/52] Separated free function kernel BodyCreator from SYCL kernel BodyCreator, and process free functions one at a time. --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Sema/Sema.cpp | 5 +- clang/lib/Sema/SemaDecl.cpp | 5 + clang/lib/Sema/SemaSYCL.cpp | 848 +++++++++--------- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 + .../CodeGenSYCL/free_function_param_refs.cpp | 14 +- .../check-direct-attribute-propagation.cpp | 6 +- .../check-notdirect-attribute-propagation.cpp | 2 +- .../SemaSYCL/free_function_kernel_params.cpp | 25 +- clang/test/SemaSYCL/sycl-esimd-ast.cpp | 6 +- .../free_function_kernels.cpp | 68 -- 11 files changed, 426 insertions(+), 559 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5f3260ec6a2e3..29ef4c1cdc1ac 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -15304,7 +15304,7 @@ class Sema final { void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC); void SetSYCLKernelNames(); void MarkDevices(); - void ProcessFreeFunctions(); + void ProcessFreeFunction(FunctionDecl *FD); /// Get the number of fields or captures within the parsed type. ExprResult ActOnSYCLBuiltinNumFieldsExpr(ParsedType PT); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 0caff34bb90ad..42b177be90922 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1118,10 +1118,6 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { } if (getLangOpts().SYCLIsDevice) { - // Check and propagate device function attributes. - MarkDevices(); - // Generate device code for free function kernels. - ProcessFreeFunctions(); // Set the names of the kernels, now that the names have settled down. This // needs to happen before we generate the integration headers. SetSYCLKernelNames(); @@ -1133,6 +1129,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { // Emit SYCL integration header for current translation unit if needed if (SyclIntHeader != nullptr) SyclIntHeader->emit(getLangOpts().SYCLIntHeader); + MarkDevices(); } emitDeferredDiags(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7619381bc0a3e..daa9dbef9f852 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16671,6 +16671,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD && !FD->isDeleted()) checkTypeSupport(FD->getType(), FD->getLocation(), FD); + // Handle non-templated free function. + if (LangOpts.SYCLIsDevice && FD->hasAttr() && Body && + !FD->isTemplated()) + ProcessFreeFunction(FD); + return dcl; } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 5cb92d3303301..112b5a9f04229 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -976,11 +976,11 @@ class FreeFunctionBodyTransform std::unordered_map &FieldMapP, Sema &S) : TreeTransform(S), ParamMap(ParamMapP), FieldMap(FieldMapP), SemaRef(S) {} - bool AlwaysRebuild() { return true; } + //bool AlwaysRebuild() { return true; } ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) { - auto Ref = dyn_cast(DRE->getDecl()); - auto OldParm = dyn_cast(Ref); + auto Ref = dyn_cast_if_present (DRE->getDecl()); + auto OldParm = dyn_cast_if_present (Ref); if (OldParm) { if (auto NewParam = ParamMap.find(OldParm); NewParam != ParamMap.end()) { auto NewDecl = NewParam->second; @@ -2115,8 +2115,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - IsInvalid |= checkSyclSpecialType(FieldTy, PD->getLocation()); - return isValid(); + // TODO + return true; } bool handleArrayType(FieldDecl *FD, QualType FieldTy) final { @@ -2176,12 +2176,12 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ++StructFieldDepth; + // TODO return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - --StructFieldDepth; + // TODO return true; } @@ -2246,7 +2246,8 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - return checkType(PD->getLocation(), FieldTy); + // TODO + return true; } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, @@ -2263,28 +2264,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { llvm::SmallVector CollectionStack; llvm::SmallVector PointerStack; - // The second parameter allows handling both FieldDecl and ParmVarDecl - void leaveStructFP(const CXXRecordDecl *, void *, QualType Ty) { - // If a record needs to be decomposed, it is marked with - // SYCLRequiresDecompositionAttr. Else if a record contains - // a pointer, it is marked with SYCLGenerateNewTypeAttr. A record - // will never be marked with both attributes. - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - assert(RD && "should not be null."); - if (CollectionStack.pop_back_val()) { - if (!RD->hasAttr()) - RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( - SemaRef.getASTContext())); - CollectionStack.back() = true; - PointerStack.pop_back(); - } else if (PointerStack.pop_back_val()) { - PointerStack.back() = true; - if (!RD->hasAttr()) - RD->addAttr( - SYCLGenerateNewTypeAttr::CreateImplicit(SemaRef.getASTContext())); - } - } - public: static constexpr const bool VisitUnionBody = false; static constexpr const bool VisitNthArrayElement = false; @@ -2307,7 +2286,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *, QualType) final { - CollectionStack.back() = true; + // TODO return true; } @@ -2328,19 +2307,35 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - CollectionStack.push_back(false); - PointerStack.push_back(false); + // TODO return true; } - bool leaveStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { - leaveStructFP(RD, FD, Ty); + bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType Ty) final { + // If a record needs to be decomposed, it is marked with + // SYCLRequiresDecompositionAttr. Else if a record contains + // a pointer, it is marked with SYCLGenerateNewTypeAttr. A record + // will never be marked with both attributes. + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + assert(RD && "should not be null."); + if (CollectionStack.pop_back_val()) { + if (!RD->hasAttr()) + RD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( + SemaRef.getASTContext())); + CollectionStack.back() = true; + PointerStack.pop_back(); + } else if (PointerStack.pop_back_val()) { + PointerStack.back() = true; + if (!RD->hasAttr()) + RD->addAttr( + SYCLGenerateNewTypeAttr::CreateImplicit(SemaRef.getASTContext())); + } return true; } bool leaveStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType Ty) final { - leaveStructFP(RD, PD, Ty); + // TODO return true; } @@ -2381,8 +2376,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool enterArray(ParmVarDecl *, QualType ArrayTy, QualType ElementTy) final { - CollectionStack.push_back(false); - PointerStack.push_back(false); + // TODO return true; } @@ -2410,25 +2404,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ElementTy) final { - // If an array needs to be decomposed, it is marked with - // SYCLRequiresDecompositionAttr. Else if the array is an array of pointers - // or an array of structs containing pointers, it is marked with - // SYCLGenerateNewTypeAttr. An array will never be marked with both - // attributes. - if (CollectionStack.pop_back_val()) { - // Cannot assert, since in MD arrays we'll end up marking them multiple - // times. - if (!PD->hasAttr()) - PD->addAttr(SYCLRequiresDecompositionAttr::CreateImplicit( - SemaRef.getASTContext())); - CollectionStack.back() = true; - PointerStack.pop_back(); - } else if (PointerStack.pop_back_val()) { - if (!PD->hasAttr()) - PD->addAttr( - SYCLGenerateNewTypeAttr::CreateImplicit(SemaRef.getASTContext())); - PointerStack.back() = true; - } + // TODO return true; } }; @@ -2543,30 +2519,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return ModifiedRD; } - template - void leaveArrayFP(FieldOrParm *D, QualType ArrayTy, QualType ET) { - QualType ModifiedArrayElement = ModifiedArrayElementsOrArray.pop_back_val(); - - const ConstantArrayType *CAT = - SemaRef.getASTContext().getAsConstantArrayType(ArrayTy); - assert(CAT && "Should only be called on constant-size array."); - QualType ModifiedArray = SemaRef.getASTContext().getConstantArrayType( - ModifiedArrayElement, CAT->getSize(), - const_cast(CAT->getSizeExpr()), CAT->getSizeModifier(), - CAT->getIndexTypeCVRQualifiers()); - - if (ModifiedRecords.empty()) { - // This is a top-level kernel argument. - ModifiedArrayElementsOrArray.push_back(ModifiedArray); - } else if (!isArrayElement(D, ArrayTy)) { - // Add this array field as a field of it's parent record. - addField(D, ModifiedArray); - } else { - // Multi-dimensional array element. - ModifiedArrayElementsOrArray.push_back(ModifiedArray); - } - } - public: static constexpr const bool VisitInsideSimpleContainersWithPointer = true; static constexpr const bool VisitNthArrayElement = false; @@ -2583,7 +2535,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType Ty) final { - createNewType(Ty->getAsCXXRecordDecl()); + // TODO return true; } @@ -2602,20 +2554,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - CXXRecordDecl *ModifiedRD = getGeneratedNewRecord(Ty->getAsCXXRecordDecl()); - - // If there is only one entry, then we are done with the the free function - // parameter. - if (ModifiedRecords.size() > 1) { - // Add this record as a field of it's parent record if it is not an - // array element. - if (!isArrayElement(PD, Ty)) - addField(PD, QualType(ModifiedRD->getTypeForDecl(), 0)); - else - ModifiedArrayElementsOrArray.push_back( - QualType(ModifiedRD->getTypeForDecl(), 0)); - } - + // TODO return true; } @@ -2635,12 +2574,32 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { } bool leaveArray(FieldDecl *FD, QualType ArrayTy, QualType ET) final { - leaveArrayFP(FD, ArrayTy, ET); + QualType ModifiedArrayElement = ModifiedArrayElementsOrArray.pop_back_val(); + + const ConstantArrayType *CAT = + SemaRef.getASTContext().getAsConstantArrayType(ArrayTy); + assert(CAT && "Should only be called on constant-size array."); + QualType ModifiedArray = SemaRef.getASTContext().getConstantArrayType( + ModifiedArrayElement, CAT->getSize(), + const_cast(CAT->getSizeExpr()), CAT->getSizeModifier(), + CAT->getIndexTypeCVRQualifiers()); + + if (ModifiedRecords.empty()) { + // This is a top-level kernel argument. + ModifiedArrayElementsOrArray.push_back(ModifiedArray); + } else if (!isArrayElement(FD, ArrayTy)) { + // Add this array field as a field of it's parent record. + addField(FD, ModifiedArray); + } else { + // Multi-dimensional array element. + ModifiedArrayElementsOrArray.push_back(ModifiedArray); + } + return true; } bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ET) final { - leaveArrayFP(PD, ArrayTy, ET); + // TODO return true; } @@ -2728,6 +2687,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { // A type to Create and own the FunctionDecl for the kernel. class SyclKernelDeclCreator : public SyclKernelFieldHandler { + SYCLIntegrationHeader &Header; + bool IsFreeFunction; FunctionDecl *KernelDecl; llvm::SmallVector Params; Sema::ContextRAII FuncContext; @@ -2855,8 +2816,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // kernel parameters from __init method parameters. We will use __init method // and kernel parameters which we build here to initialize special objects in // the kernel body. - template - bool handleSpecialType(FieldOrParm *D, QualType FieldTy) { + bool handleSpecialType(FieldDecl *FD, QualType FieldTy) { const auto *RecordDecl = FieldTy->getAsCXXRecordDecl(); assert(RecordDecl && "The type must be a RecordDecl"); llvm::StringLiteral MethodName = @@ -2871,7 +2831,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { size_t ParamIndex = Params.size(); for (const ParmVarDecl *Param : InitMethod->parameters()) { QualType ParamTy = Param->getType(); - addParam(D, ParamTy.getCanonicalType()); + addParam(FD, ParamTy.getCanonicalType()); // Propagate add_ir_attributes_kernel_parameter attribute. if (const auto *AddIRAttr = @@ -2885,7 +2845,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // added, this code needs to be refactored to call // handleAccessorPropertyList for each class which requires it. if (ParamTy.getTypePtr()->isPointerType() && isSyclAccessorType(FieldTy)) - handleAccessorType(FieldTy, RecordDecl, D->getBeginLoc()); + handleAccessorType(FieldTy, RecordDecl, FD->getBeginLoc()); } LastParamIndex = ParamIndex; return true; @@ -2965,36 +2925,19 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return PointerHandler.getNewArrayType(); } - QualType GenerateNewArrayType(ParmVarDecl *PD, QualType ParamTy) { - SyclKernelPointerHandler PointerHandler(SemaRef); - KernelObjVisitor Visitor{SemaRef}; - Visitor.visitArray(PD, ParamTy, PointerHandler); - return PointerHandler.getNewArrayType(); - } - public: static constexpr const bool VisitInsideSimpleContainers = false; SyclKernelDeclCreator(Sema &S, SourceLocation Loc, bool IsInline, - bool IsSIMDKernel, FunctionDecl *SYCLKernel) - : SyclKernelFieldHandler(S), - KernelDecl( - createKernelDecl(S.getASTContext(), Loc, IsInline, IsSIMDKernel)), - FuncContext(SemaRef, KernelDecl) { - S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); - - if (const auto *AddIRAttrFunc = - SYCLKernel->getAttr()) - KernelDecl->addAttr(AddIRAttrFunc->clone(SemaRef.getASTContext())); - } - - SyclKernelDeclCreator(Sema &S, SourceLocation Loc, bool IsInline, - FunctionDecl *SYCLKernel) - : SyclKernelFieldHandler(S), - KernelDecl(createFreeFunctionDecl(S.getASTContext(), SYCLKernel, Loc, - IsInline)), + bool IsSIMDKernel, bool IsFreeFunction, + FunctionDecl *SYCLKernel, SYCLIntegrationHeader &H) + : SyclKernelFieldHandler(S), Header(H), IsFreeFunction(IsFreeFunction), + KernelDecl(IsFreeFunction + ? createFreeFunctionDecl(S.getASTContext(), SYCLKernel, + Loc, IsInline) + : createKernelDecl(S.getASTContext(), Loc, IsInline, + IsSIMDKernel)), FuncContext(SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); - if (const auto *AddIRAttrFunc = SYCLKernel->getAttr()) KernelDecl->addAttr(AddIRAttrFunc->clone(SemaRef.getASTContext())); @@ -3029,19 +2972,16 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - // if (StructDepth == 0) - // addParam(PD, Ty); - ++StructDepth; + // TODO return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { - --StructDepth; return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - --StructDepth; + // TODO return true; } @@ -3092,7 +3032,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - return handleSpecialType(PD, FieldTy); + // TODO + return true; } RecordDecl *wrapParam(QualType FieldTy) { @@ -3130,17 +3071,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { QualType ModTy = ModifyAddressSpace(SemaRef, FieldTy); - // When the kernel is generated, struct type kernel arguments are - // decomposed; i.e. the parameters of the kernel are the fields of the - // struct, and not the struct itself. This causes an error in the backend - // when the struct field is a pointer, since non-USM pointers cannot be - // passed directly. To work around this issue, all pointers inside the - // struct are wrapped in a generated '__wrapper_class'. - if (StructDepth) { - RecordDecl *WrappedPointer = wrapParam(ModTy); - ModTy = SemaRef.getASTContext().getRecordType(WrappedPointer); - } - addParam(PD, ModTy); return true; } @@ -3160,11 +3090,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { QualType ArrayTy = FieldTy; - - // This is an array of pointers or an array of a type with pointer. - if (PD->hasAttr()) - ArrayTy = GenerateNewArrayType(PD, FieldTy); - // Arrays are wrapped in a struct since they cannot be passed directly. RecordDecl *WrappedArray = wrapParam(ArrayTy); addParam(PD, SemaRef.getASTContext().getRecordType(WrappedArray)); @@ -3200,12 +3125,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // This is a field which should not be decomposed. CXXRecordDecl *FieldRecordDecl = Ty->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, Ty); + addParam(PD, Ty); return true; } @@ -3632,7 +3552,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { llvm::SmallVector MemberExprBases; llvm::SmallVector ArrayParamBases; FunctionDecl *KernelCallerFunc; - FunctionDecl *FreeFunc; SourceLocation KernelCallerSrcLoc; // KernelCallerFunc source location. // Contains a count of how many containers we're in. This is used by the // pointer-struct-wrapping code to ensure that we don't try to wrap @@ -3641,13 +3560,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { VarDecl *KernelHandlerClone = nullptr; bool IsESIMD = false; CXXMethodDecl *CallOperator = nullptr; - // For free functions we create local copies of the parameters and replace - // uses within the body to use the local copies. For parameters requiring - // breakdown into components multiple items will be placed on these lists. - std::unordered_map ParamMap; - // For free functions that need replacement structs (because they contain - // pointers), also collect fields to replace. - std::unordered_map FieldMap; Stmt *replaceWithLocalClone(ParmVarDecl *OriginalParam, VarDecl *LocalClone, Stmt *FunctionBody) { @@ -3660,14 +3572,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return KBT.TransformStmt(FunctionBody).get(); } - Stmt *replaceParamsAndFields( - Stmt *FunctionBody, - std::unordered_map &ParamMap, - std::unordered_map &FieldMap) { - FreeFunctionBodyTransform FFBT(ParamMap, FieldMap, SemaRef); - return FFBT.TransformStmt(FunctionBody).get(); - } - // Using the statements/init expressions that we've created, this generates // the kernel body compound stmt. CompoundStmt needs to know its number of // statements in advance to allocate it, so we cannot do this as we go along. @@ -3704,35 +3608,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { FPOptionsOverride(), {}, {}); } - // Using the statements/init expressions that we've created, this generates - // the kernel body compound stmt. CompoundStmt needs to know its number of - // statements in advance to allocate it, so we cannot do this as we go along. - CompoundStmt *createFreeFunctionKernelBody() { - // Push the Kernel function scope to ensure the scope isn't empty - SemaRef.PushFunctionScope(); - - // Use the function body for the free function kernel - BodyStmts.push_back(FreeFunc->getBody()); - - // Replace the original body with an empty body - Stmt *EmptyBody = CompoundStmt::Create(SemaRef.getASTContext(), {}, - FPOptionsOverride(), {}, {}); - FreeFunc->setBody(EmptyBody); - - BodyStmts.insert(BodyStmts.end(), FinalizeStmts.begin(), - FinalizeStmts.end()); - - Stmt *NewBody = CompoundStmt::Create(SemaRef.getASTContext(), BodyStmts, - FPOptionsOverride(), {}, {}); - - // Replace references to the parameters in kernel body, to use the - // parameters of the newly created body function, or the compiler generated - // local clones for the parameters that are expanded. - NewBody = replaceParamsAndFields(NewBody, ParamMap, FieldMap); - - return static_cast(NewBody); - } - void annotateHierarchicalParallelismAPICalls() { // Is this a hierarchical parallelism kernel invocation? if (getKernelInvocationKind(KernelCallerFunc) != InvokeParallelForWorkGroup) @@ -3855,37 +3730,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { Init.get()); } - // Creates an initialized entity for a function local. - InitializedEntity getVarEntity(VarDecl *VD, QualType Ty) { - return InitializedEntity::InitializeVariable(VD); - } - - void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef) { - InitializationKind InitKind = - InitializationKind::CreateCopy(KernelCallerSrcLoc, KernelCallerSrcLoc); - addVarInit(VD, Ty, ParamRef, InitKind); - } - - void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, - InitializationKind InitKind) { - addVarInit(VD, Ty, ParamRef, InitKind, getVarEntity(VD, Ty)); - } - - void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, - InitializationKind InitKind, InitializedEntity Entity) { - InitializationSequence InitSeq(SemaRef, Entity, InitKind, ParamRef); - InitSeq.Perform(SemaRef, Entity, InitKind, ParamRef); - InitListExpr *ILE = createInitListExpr(Ty, 1); - CollectionInitExprs.push_back(ILE); - VD->setInit(ILE); - Stmt *DS = new (SemaRef.Context) - DeclStmt(DeclGroupRef(VD), KernelCallerSrcLoc, KernelCallerSrcLoc); - BodyStmts.push_back(DS); - DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), - KernelCallerSrcLoc, VD, false, DeclarationNameInfo(), - Ty, VK_LValue); - } - void addBaseInit(const CXXBaseSpecifier &BS, QualType Ty, InitializationKind InitKind) { InitializedEntity Entity = InitializedEntity::InitializeBase( @@ -3932,11 +3776,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addFieldInit(FD, Ty, ParamRef); } - void addSimpleLocalInit(VarDecl *VD, QualType Ty) { - Expr *ParamRef = createParamReferenceExpr(); - addVarInit(VD, Ty, ParamRef); - } - Expr *createGetAddressOf(Expr *E) { return UnaryOperator::Create(SemaRef.Context, E, UO_AddrOf, SemaRef.Context.getPointerType(E->getType()), @@ -3971,22 +3810,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addFieldInit(FD, Ty, Initializer); } - void handleGeneratedType(ParmVarDecl *PD, QualType Ty) { - Expr *RCE = createReinterpretCastExpr( - createGetAddressOf(createParamReferenceExpr()), - SemaRef.Context.getPointerType(Ty)); - Expr *Initializer = createDerefOp(RCE); - addVarInit(PD, Ty, Initializer); - } - - void handleGeneratedType(VarDecl *VD, QualType Ty) { - Expr *RCE = createReinterpretCastExpr( - createGetAddressOf(createParamReferenceExpr()), - SemaRef.Context.getPointerType(Ty)); - Expr *Initializer = createDerefOp(RCE); - addVarInit(VD, Ty, Initializer); - } - void handleGeneratedType(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) { // Equivalent of the following code is generated here: @@ -4023,19 +3846,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { MemberExprBases.pop_back(); } - Expr *buildParamCloneExpr(VarDecl *LocalClone, QualType Ty) { - DeclRefExpr *ParamCloneRef = DeclRefExpr::Create( - SemaRef.Context, NestedNameSpecifierLoc(), KernelCallerSrcLoc, - LocalClone, false, DeclarationNameInfo(), Ty, VK_LValue); - return ParamCloneRef; - } - - void addParamCloneExpr(VarDecl *VD, QualType Ty) { - MemberExprBases.push_back(buildParamCloneExpr(VD, Ty)); - } - - void removeParamCloneExpr() { MemberExprBases.pop_back(); } - void createSpecialMethodCall(const CXXRecordDecl *RD, StringRef MethodName, SmallVectorImpl &AddTo) { CXXMethodDecl *Method = getMethodByName(RD, MethodName); @@ -4119,22 +3929,9 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return VD; } - static VarDecl *createParamClone(ASTContext &Ctx, DeclContext *DC, - const ParmVarDecl *Param) { - IdentifierInfo *Ident = Param->getIdentifier(); - if (!Ident) - Ident = &Ctx.Idents.get("__SYCLParam"); - - VarDecl *VD = - VarDecl::Create(Ctx, DC, Param->getLocation(), Param->getLocation(), - Ident, QualType(Param->getType()), nullptr, SC_None); - VD->setIsUsed(); - return VD; - } - - const llvm::StringLiteral getInitMethodName() const { - return IsESIMD ? InitESIMDMethodName : InitMethodName; - } + const llvm::StringLiteral getInitMethodName() const { + return IsESIMD ? InitESIMDMethodName : InitMethodName; + } // Default inits the type, then calls the init-method in the body. bool handleSpecialType(FieldDecl *FD, QualType Ty) { @@ -4156,36 +3953,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - // Default inits the type. - bool handleSpecialType(ParmVarDecl *PD, QualType Ty) { - VarDecl *VD = createParamClone(SemaRef.getASTContext(), - DeclCreator.getKernelDecl(), PD); - // Create local clone of the special parameter - handleGeneratedType(VD, Ty); - // Default initialize local clone - InitializedEntity VarEntity = InitializedEntity::InitializeVariable(VD); - InitializationKind InitKind = - InitializationKind::CreateDefault(KernelCallerSrcLoc); - InitializationSequence InitSeq(SemaRef, VarEntity, InitKind, std::nullopt); - ExprResult Init = - InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); - VD->setInit(SemaRef.MaybeCreateExprWithCleanups(Init.get())); - - addParamCloneExpr(VD, Ty); - - const auto *RecordDecl = Ty->getAsCXXRecordDecl(); - createSpecialMethodCall(RecordDecl, getInitMethodName(), BodyStmts); - CXXMethodDecl *FinalizeMethod = - getMethodByName(RecordDecl, FinalizeMethodName); - // A finalize-method is expected for special type such as stream. - if (FinalizeMethod) - createSpecialMethodCall(RecordDecl, FinalizeMethodName, FinalizeStmts); - - removeParamCloneExpr(); - - return true; - } - bool handleSpecialType(const CXXBaseSpecifier &BS, QualType Ty) { const auto *RecordDecl = Ty->getAsCXXRecordDecl(); addBaseInit(BS, Ty, InitializationKind::CreateDefault(KernelCallerSrcLoc)); @@ -4220,7 +3987,8 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { InitializationKind InitKind = InitializationKind::CreateDefault(KernelCallerSrcLoc); InitializationSequence InitSeq(SemaRef, VarEntity, InitKind, std::nullopt); - ExprResult Init = InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); + ExprResult Init = + InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); KernelHandlerClone->setInit( SemaRef.MaybeCreateExprWithCleanups(Init.get())); KernelHandlerClone->setInitStyle(VarDecl::CallInit); @@ -4313,7 +4081,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { KernelObjClone(createKernelObjClone(S.getASTContext(), DC.getKernelDecl(), KernelObj)), VarEntity(InitializedEntity::InitializeVariable(KernelObjClone)), - KernelCallerFunc(KernelCallerFunc), FreeFunc(nullptr), + KernelCallerFunc(KernelCallerFunc), KernelCallerSrcLoc(KernelCallerFunc->getLocation()), IsESIMD(IsSIMDKernel), CallOperator(CallOperator) { CollectionInitExprs.push_back(createInitListExpr(KernelObj)); @@ -4329,22 +4097,8 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { MemberExprBases.push_back(KernelObjCloneRef); } - SyclKernelBodyCreator(Sema &S, SyclKernelDeclCreator &DC, FunctionDecl *FF, - CXXRecordDecl *Dummy) - : SyclKernelFieldHandler(S), DeclCreator(DC), - KernelObjClone( - createKernelObjClone(S.getASTContext(), DC.getKernelDecl(), Dummy)), - VarEntity(InitializedEntity::InitializeVariable(KernelObjClone)), - KernelCallerFunc(nullptr), FreeFunc(FF), - KernelCallerSrcLoc(FreeFunc->getLocation()), IsESIMD(false) {} - ~SyclKernelBodyCreator() { - CompoundStmt *KernelBody; - if (KernelCallerFunc) - KernelBody = createKernelBody(); - else - KernelBody = createFreeFunctionKernelBody(); - + CompoundStmt *KernelBody = createKernelBody(); DeclCreator.setBody(KernelBody); } @@ -4353,9 +4107,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *PD, QualType Ty) final { - bool Result = handleSpecialType(PD, Ty); - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; - return Result; + return true; } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, @@ -4371,7 +4123,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } @@ -4384,7 +4135,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } @@ -4401,23 +4151,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - assert(RD && "Type must be a C++ record type"); - ParmVarDecl *NewPD = DeclCreator.getParamVarDeclsForCurrentField()[0]; - // If the struct has been rewritten with new pointers, change all the field - // references. Otherwise handle the struct as a single object. - if (RD->hasAttr()) { - const auto *OrigRecord = Ty->getAsRecordDecl(); - const auto *NewRecord = NewPD->getType()->getAsRecordDecl(); - if (OrigRecord && NewRecord) { - auto OldField = OrigRecord->fields().begin(); - auto NewField = NewRecord->fields().begin(); - for (; OldField != OrigRecord->fields().end(); OldField++, NewField++) { - FieldMap[*OldField] = {PD, NewPD, *NewField}; - } - } - } else - ParamMap[PD] = NewPD; return true; } @@ -4438,7 +4171,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; return true; } @@ -4447,10 +4179,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; - return true; - } + bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { return true; } // Default inits the type, then calls the init-method in the body void handleSyclKernelHandlerType(ParmVarDecl *KernelHandlerArg) { @@ -4484,28 +4213,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType Ty) final { - if (StructDepth == 0) { - // Get type of PD, which should be a Record - RD = PD->getType()->getAsCXXRecordDecl(); - assert(RD && "Free function parameter expected as Record type"); - // Create local clone of the Record parameter. - VarDecl *ParamClone = createKernelObjClone( - SemaRef.getASTContext(), DeclCreator.getKernelDecl(), RD); - // Default init it. - InitializedEntity::InitializeVariable(ParamClone); - CollectionInitExprs.push_back(createInitListExpr(RD)); - - Stmt *DS = new (SemaRef.Context) DeclStmt( - DeclGroupRef(ParamClone), KernelCallerSrcLoc, KernelCallerSrcLoc); - BodyStmts.push_back(DS); - DeclRefExpr *ParamCloneRef = DeclRefExpr::Create( - SemaRef.Context, NestedNameSpecifierLoc(), KernelCallerSrcLoc, - ParamClone, false, DeclarationNameInfo(), - QualType(RD->getTypeForDecl(), 0), VK_LValue); - MemberExprBases.push_back(ParamCloneRef); - ParamMap[PD] = ParamClone; - } - ++StructDepth; return true; } @@ -4518,7 +4225,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - --StructDepth; return true; } @@ -4602,6 +4308,264 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { } }; +class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { + SyclKernelDeclCreator &DeclCreator; + llvm::SmallVector BodyStmts; + llvm::SmallVector CollectionInitExprs; + llvm::SmallVector FinalizeStmts; + // This collection contains the information required to add/remove information + // about arrays as we enter them. The InitializedEntity component is + // necessary for initializing child members. uin64_t is the index of the + // current element being worked on, which is updated every time we visit + // nextElement. + llvm::SmallVector, 8> ArrayInfos; + llvm::SmallVector MemberExprBases; + llvm::SmallVector ArrayParamBases; + FunctionDecl *FreeFunc; + SourceLocation KernelCallerSrcLoc; // KernelCallerFunc source location. + // Contains a count of how many containers we're in. This is used by the + // pointer-struct-wrapping code to ensure that we don't try to wrap + // top-level pointers. + uint64_t StructDepth = 0; + // For free functions we create local copies of the parameters and replace + // uses within the body to use the local copies. For parameters requiring + // breakdown into components multiple items will be placed on these lists. + std::unordered_map ParamMap; + // For free functions that need replacement structs (because they contain + // pointers), also collect fields to replace. + std::unordered_map FieldMap; + + Stmt *replaceParamsAndFields( + Stmt *FunctionBody, + std::unordered_map &ParamMap, + std::unordered_map &FieldMap) { + FreeFunctionBodyTransform FFBT(ParamMap, FieldMap, SemaRef); + return FFBT.TransformStmt(FunctionBody).get(); + } + + // Using the statements/init expressions that we've created, this generates + // the kernel body compound stmt. CompoundStmt needs to know its number of + // statements in advance to allocate it, so we cannot do this as we go along. + CompoundStmt *createFreeFunctionKernelBody() { + // Push the Kernel function scope to ensure the scope isn't empty + SemaRef.PushFunctionScope(); + + // Use the function body for the free function kernel + BodyStmts.push_back(FreeFunc->getBody()); + + // Replace the original body with an empty body + Stmt *EmptyBody = CompoundStmt::Create(SemaRef.getASTContext(), {}, + FPOptionsOverride(), {}, {}); + FreeFunc->setBody(EmptyBody); + + BodyStmts.insert(BodyStmts.end(), FinalizeStmts.begin(), + FinalizeStmts.end()); + + Stmt *NewBody = CompoundStmt::Create(SemaRef.getASTContext(), BodyStmts, + FPOptionsOverride(), {}, {}); + + // Replace references to the parameters in kernel body, to use the + // parameters of the newly created body function, or the compiler generated + // local clones for the parameters that are expanded. + NewBody = replaceParamsAndFields(NewBody, ParamMap, FieldMap); + + return static_cast(NewBody); + } + + // Creates a DeclRefExpr to the ParmVar that represents the current field. + Expr *createParamReferenceExpr() { + ParmVarDecl *KernelParameter = + DeclCreator.getParamVarDeclsForCurrentField()[0]; + + QualType ParamType = KernelParameter->getOriginalType(); + Expr *DRE = SemaRef.BuildDeclRefExpr(KernelParameter, ParamType, VK_LValue, + KernelCallerSrcLoc); + return DRE; + } + + // Creates an initialized entity for a function local. + InitializedEntity getVarEntity(VarDecl *VD, QualType Ty) { + return InitializedEntity::InitializeVariable(VD); + } + + void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef) { + InitializationKind InitKind = + InitializationKind::CreateCopy(KernelCallerSrcLoc, KernelCallerSrcLoc); + addVarInit(VD, Ty, ParamRef, InitKind); + } + + void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, + InitializationKind InitKind) { + addVarInit(VD, Ty, ParamRef, InitKind, getVarEntity(VD, Ty)); + } + + void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, + InitializationKind InitKind, InitializedEntity Entity) { + InitializationSequence InitSeq(SemaRef, Entity, InitKind, ParamRef); + InitSeq.Perform(SemaRef, Entity, InitKind, ParamRef); + InitListExpr *ILE = createInitListExpr(Ty, 1); + CollectionInitExprs.push_back(ILE); + VD->setInit(ILE); + Stmt *DS = new (SemaRef.Context) + DeclStmt(DeclGroupRef(VD), KernelCallerSrcLoc, KernelCallerSrcLoc); + BodyStmts.push_back(DS); + DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), + KernelCallerSrcLoc, VD, false, DeclarationNameInfo(), + Ty, VK_LValue); + } + + void addSimpleLocalInit(VarDecl *VD, QualType Ty) { + Expr *ParamRef = createParamReferenceExpr(); + addVarInit(VD, Ty, ParamRef); + } + + InitListExpr *createInitListExpr(QualType InitTy, uint64_t NumChildInits) { + InitListExpr *ILE = new (SemaRef.getASTContext()) InitListExpr( + SemaRef.getASTContext(), KernelCallerSrcLoc, {}, KernelCallerSrcLoc); + ILE->reserveInits(SemaRef.getASTContext(), NumChildInits); + ILE->setType(InitTy); + + return ILE; + } + + static VarDecl *createParamClone(ASTContext &Ctx, DeclContext *DC, + const ParmVarDecl *Param) { + IdentifierInfo *Ident = Param->getIdentifier(); + if (!Ident) + Ident = &Ctx.Idents.get("__SYCLParam"); + + VarDecl *VD = + VarDecl::Create(Ctx, DC, Param->getLocation(), Param->getLocation(), + Ident, QualType(Param->getType()), nullptr, SC_None); + VD->setIsUsed(); + return VD; + } + + bool handleSpecialType(ParmVarDecl *PD, QualType Ty) { return true; } + +public: + static constexpr const bool VisitInsideSimpleContainers = false; + + FreeFunctionKernelBodyCreator(Sema &S, SyclKernelDeclCreator &DC, + FunctionDecl *FF) + : SyclKernelFieldHandler(S), DeclCreator(DC), FreeFunc(FF), + KernelCallerSrcLoc(FreeFunc->getLocation()) {} + + ~FreeFunctionKernelBodyCreator() { + CompoundStmt *KernelBody = createFreeFunctionKernelBody(); + DeclCreator.setBody(KernelBody); + } + + bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { return true; } + + bool handleSyclSpecialType(ParmVarDecl *PD, QualType Ty) final { + return true; + } + + bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, + QualType Ty) final { + return true; + } + + bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { return true; } + + bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + return true; + } + + bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { + return true; + } + + bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + return true; + } + + bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, + QualType Ty) final { + return true; + } + + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType Ty) final { + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + assert(RD && "Type must be a C++ record type"); + ParmVarDecl *NewPD = DeclCreator.getParamVarDeclsForCurrentField()[0]; + ParamMap[PD] = NewPD; + return true; + } + + bool handleNonDecompStruct(const CXXRecordDecl *RD, + const CXXBaseSpecifier &BS, QualType Ty) final { + return true; + } + + bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { return true; } + + bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + return true; + } + + bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return true; } + + bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { + ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + return true; + } + + bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { + return true; + } + + bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + QualType Ty) final { + ++StructDepth; + return true; + } + + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + return true; + } + + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + --StructDepth; + return true; + } + + bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, + QualType) final { + return true; + } + + bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, + QualType) final { + return true; + } + + bool enterArray(FieldDecl *FD, QualType ArrayType, + QualType ElementType) final { + return true; + } + + bool enterArray(ParmVarDecl *PD, QualType ArrayType, + QualType ElementType) final { + return true; + } + + bool leaveArray(FieldDecl *FD, QualType ArrayType, + QualType ElementType) final { + return true; + } + + bool leaveArray(ParmVarDecl *PD, QualType ArrayType, + QualType ElementType) final { + return true; + } +}; + // Kernels are only the unnamed-lambda feature if the feature is enabled, AND // the first template argument has been corrected by the library to match the // functor type. @@ -4663,43 +4627,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { static_cast(CurOffset + OffsetAdj)); } - template - void processSyclSpecialType(FieldOrParm *D, QualType FieldTy) { - const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); - assert(ClassTy && "Type must be a C++ record type"); - if (isSyclAccessorType(FieldTy)) { - const auto *AccTy = - cast(FieldTy->getAsRecordDecl()); - assert(AccTy->getTemplateArgs().size() >= 2 && - "Incorrect template args for Accessor Type"); - int Dims = static_cast( - AccTy->getTemplateArgs()[1].getAsIntegral().getExtValue()); - int Info = getAccessTarget(FieldTy, AccTy) | (Dims << 11); - - Header.addParamDesc(SYCLIntegrationHeader::kind_accessor, Info, - CurOffset + offsetOf(D, FieldTy)); - } else if (Sema::isSyclType(FieldTy, SYCLTypeAttr::stream)) { - addParam(D, FieldTy, SYCLIntegrationHeader::kind_stream); - } else if (Sema::isSyclType(FieldTy, SYCLTypeAttr::sampler) || - Sema::isSyclType(FieldTy, SYCLTypeAttr::annotated_ptr) || - Sema::isSyclType(FieldTy, SYCLTypeAttr::annotated_arg)) { - CXXMethodDecl *InitMethod = getMethodByName(ClassTy, InitMethodName); - assert(InitMethod && "type must have __init method"); - const ParmVarDecl *InitArg = InitMethod->getParamDecl(0); - assert(InitArg && "Init method must have arguments"); - QualType T = InitArg->getType(); - SYCLIntegrationHeader::kernel_param_kind_t ParamKind = - Sema::isSyclType(FieldTy, SYCLTypeAttr::sampler) - ? SYCLIntegrationHeader::kind_sampler - : (T->isPointerType() ? SYCLIntegrationHeader::kind_pointer - : SYCLIntegrationHeader::kind_std_layout); - addParam(T, ParamKind, offsetOf(D, FieldTy)); - } else { - llvm_unreachable( - "Unexpected SYCL special class when generating integration header"); - } - } - public: static constexpr const bool VisitInsideSimpleContainers = false; SyclKernelIntHeaderCreator(bool IsESIMD, Sema &S, SYCLIntegrationHeader &H, @@ -4741,16 +4668,44 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { - processSyclSpecialType(FD, FieldTy); + const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); + assert(ClassTy && "Type must be a C++ record type"); + if (isSyclAccessorType(FieldTy)) { + const auto *AccTy = + cast(FieldTy->getAsRecordDecl()); + assert(AccTy->getTemplateArgs().size() >= 2 && + "Incorrect template args for Accessor Type"); + int Dims = static_cast( + AccTy->getTemplateArgs()[1].getAsIntegral().getExtValue()); + int Info = getAccessTarget(FieldTy, AccTy) | (Dims << 11); + + Header.addParamDesc(SYCLIntegrationHeader::kind_accessor, Info, + CurOffset + offsetOf(FD, FieldTy)); + } else if (Sema::isSyclType(FieldTy, SYCLTypeAttr::stream)) { + addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); + } else if (Sema::isSyclType(FieldTy, SYCLTypeAttr::sampler) || + Sema::isSyclType(FieldTy, SYCLTypeAttr::annotated_ptr) || + Sema::isSyclType(FieldTy, SYCLTypeAttr::annotated_arg)) { + CXXMethodDecl *InitMethod = getMethodByName(ClassTy, InitMethodName); + assert(InitMethod && "type must have __init method"); + const ParmVarDecl *InitArg = InitMethod->getParamDecl(0); + assert(InitArg && "Init method must have arguments"); + QualType T = InitArg->getType(); + SYCLIntegrationHeader::kernel_param_kind_t ParamKind = + Sema::isSyclType(FieldTy, SYCLTypeAttr::sampler) + ? SYCLIntegrationHeader::kind_sampler + : (T->isPointerType() ? SYCLIntegrationHeader::kind_pointer + : SYCLIntegrationHeader::kind_std_layout); + addParam(T, ParamKind, offsetOf(FD, FieldTy)); + } else { + llvm_unreachable( + "Unexpected SYCL special class when generating integration header"); + } return true; } bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - processSyclSpecialType(PD, FieldTy); - if (isSyclAccessorType(FieldTy)) { - CurOffset += - SemaRef.getASTContext().getTypeSizeInChars(FieldTy).getQuantity(); - } + // TODO return true; } @@ -4872,7 +4827,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool enterArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { - ArrayBaseOffsets.push_back(CurOffset + offsetOf(PD, ArrayTy)); + // TODO return true; } @@ -4889,8 +4844,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { - CurOffset = ArrayBaseOffsets.pop_back_val(); - CurOffset -= offsetOf(PD, ArrayTy); + // TODO return true; } @@ -5300,10 +5254,10 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, IsSIMDKernel); ESIMDKernelDiagnostics esimdKernel(*this, KernelObj->getLocation(), IsSIMDKernel); - SyclKernelDeclCreator kernel_decl(*this, KernelObj->getLocation(), KernelCallerFunc->isInlined(), IsSIMDKernel, - KernelCallerFunc); + false /*IsFreeFunction*/, KernelCallerFunc, + getSyclIntegrationHeader()); SyclKernelBodyCreator kernel_body(*this, kernel_decl, KernelObj, KernelCallerFunc, IsSIMDKernel, CallOperator); @@ -5346,17 +5300,19 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { SyclKernelArgsSizeChecker argsSizeChecker(SemaRef, FD->getLocation(), false /*IsSIMDKernel*/); - SyclKernelDeclCreator kernel_decl(SemaRef, FD->getLocation(), FD->isInlined(), - FD); + SyclKernelDeclCreator kernel_decl( + SemaRef, FD->getLocation(), FD->isInlined(), false /*IsSIMDKernel */, + true /*IsFreeFunction*/, FD, SemaRef.getSyclIntegrationHeader()); +#if 0 // TODO: remove this dummy struct RecordDecl *DummyClass = SemaRef.getASTContext().buildImplicitRecord("__dummy_class"); DummyClass->startDefinition(); DummyClass->completeDefinition(); - CXXRecordDecl *DummyClass1 = static_cast(DummyClass); - SyclKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD, DummyClass1); +#endif + FreeFunctionKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD); // Kernel object size is irrelevant, so set to 0. SyclKernelIntHeaderCreator int_header( @@ -5660,30 +5616,26 @@ void Sema::MarkDevices() { } } -void Sema::ProcessFreeFunctions() { - for (Decl *D : syclDeviceDecls()) { - auto *SYCLKernel = cast(D); - if (IsFreeFunction(*this, SYCLKernel)) { - SyclKernelDecompMarker DecompMarker(*this); - SyclKernelFieldChecker FieldChecker(*this); - SyclKernelUnionChecker UnionChecker(*this); +void Sema::ProcessFreeFunction(FunctionDecl *FD) { + if (IsFreeFunction(*this, FD)) { + SyclKernelDecompMarker DecompMarker(*this); + SyclKernelFieldChecker FieldChecker(*this); + SyclKernelUnionChecker UnionChecker(*this); - KernelObjVisitor Visitor{*this}; + KernelObjVisitor Visitor{ *this }; - DiagnosingSYCLKernel = true; + DiagnosingSYCLKernel = true; - // Check parameters of free function. - Visitor.VisitFunctionParameters(SYCLKernel, DecompMarker, FieldChecker, - UnionChecker); + // Check parameters of free function. + Visitor.VisitFunctionParameters(FD, DecompMarker, FieldChecker, UnionChecker); - DiagnosingSYCLKernel = false; + DiagnosingSYCLKernel = false; - // Ignore the free function if any of the checkers fail validation. - if (!FieldChecker.isValid() || !UnionChecker.isValid()) - return; + // Ignore the free function if any of the checkers fail validation. + if (!FieldChecker.isValid() || !UnionChecker.isValid()) + return; - ConstructFreeFunctionKernel(*this, SYCLKernel); - } + ConstructFreeFunctionKernel(*this, FD); } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index b0e8f836d2b5d..a40982afecf09 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -7034,6 +7034,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TUKind == TU_Prefix && Function->instantiationIsPending()) delayedPCHInstantiations.push_back(Inst); continue; + + // Handle SYCL free function. + if (LangOpts.SYCLIsDevice && Function->hasAttr()) + ProcessFreeFunction(Function); } // Instantiate variable definitions diff --git a/clang/test/CodeGenSYCL/free_function_param_refs.cpp b/clang/test/CodeGenSYCL/free_function_param_refs.cpp index ea72655421628..89a60bf9c1e69 100755 --- a/clang/test/CodeGenSYCL/free_function_param_refs.cpp +++ b/clang/test/CodeGenSYCL/free_function_param_refs.cpp @@ -13,27 +13,19 @@ struct Simple { char c[100]; float f; }; -struct WithPointer { - int x; - float* fp; - float f; -}; // CHECK: %struct.Simple = type { i32, [100 x i8], float } -// CHECK: %struct.WithPointer = type { i32, ptr addrspace(4), float } -// CHECK: %struct.__generated_WithPointer = type { i32, ptr addrspace(1), float } __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int start, int end, struct Simple S, struct WithPointer P) { +void ff_2(int *ptr, int arr[], int start, int end, struct Simple S) { for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2]+ P.x + 66; + ptr[i] = start + S.x + S.f + S.c[2] + 66; } -// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S, ptr noundef byval(%struct.__generated_WithPointer) align 8 %_arg_P) +// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, ptr addrspace(1) {{.*}} %_arg_arr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S) // CHECK: store ptr addrspace(1) %_arg_ptr, ptr addrspace(4) %_arg_ptr.{{.*}} // CHECK: store i32 %_arg_start, ptr addrspace(4) %_arg_start.{{.*}} // CHECK: store i32 %_arg_end, ptr addrspace(4) %_arg_end.{{.*}} // CHECK: %x = getelementptr inbounds %struct.Simple // CHECK: %f = getelementptr inbounds %struct.Simple // CHECK: %c = getelementptr inbounds %struct.Simple -// CHECK: %__generated_x = getelementptr inbounds %struct.__generated_WithPointer, ptr addrspace(4) %_arg_P.{{.*}} diff --git a/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp b/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp index 73a3d8a486e3a..f40bf981ea606 100644 --- a/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp +++ b/clang/test/SemaSYCL/check-direct-attribute-propagation.cpp @@ -76,15 +76,15 @@ int main() { // CHECK: FunctionDecl {{.*}}test_kernel1 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: SYCLSimdAttr // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit + // CHECK-NEXT: SYCLSimdAttr h.single_task( FuncObj()); // CHECK: FunctionDecl {{.*}}test_kernel2 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: SYCLSimdAttr // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit + // CHECK-NEXT: SYCLSimdAttr h.single_task( []() [[intel::sycl_explicit_simd]]{}); @@ -92,9 +92,9 @@ int main() { // CHECK: FunctionDecl {{.*}}test_kernel3 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr // CHECK-NOT: SYCLSimdAttr - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( []() [[intel::sycl_explicit_simd]] { func(); }); diff --git a/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp b/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp index c269fb2b01cc4..bdabd1f40d52d 100644 --- a/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp +++ b/clang/test/SemaSYCL/check-notdirect-attribute-propagation.cpp @@ -46,7 +46,7 @@ void invoke_foo2() { // CHECK-LABEL: FunctionDecl {{.*}} invoke_foo2 'void ()' // CHECK: `-FunctionDecl {{.*}}KernelName 'void ()' // CHECK: -IntelReqdSubGroupSizeAttr {{.*}} - // CHECK: -SYCLIntelNoGlobalWorkOffsetAttr {{.*}} + // CHECK: `-SYCLIntelNoGlobalWorkOffsetAttr {{.*}} parallel_for([]() {}); #else parallel_for([]() {}); // expected-error 3 {{conflicting attributes applied to a SYCL kernel or SYCL_EXTERNAL function}} diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index ad622bdd757d1..e5087e4d3f87a 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -11,31 +11,16 @@ struct Simple { char c[100]; float f; }; -struct WithPointer { - int x; - float* fp; - float f; -}; __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int start, int end, struct Simple S, struct WithPointer P) { +void ff_2(int *ptr, int arr[], int start, int end, struct Simple S) { for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2]+ P.x + 66; + ptr[i] = start + S.x + S.f + S.c[2] + arr[66]; } -// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int, struct Simple, __generated_WithPointer)' +// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, __global int *, int, int, struct Simple)' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_arr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_P '__generated_WithPointer' - - -__attribute__((sycl_device)) -[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 1)]] -void iotar3(int* usmPtr, struct WithPointer P) { - usmPtr[55] = P.x + 66; -} -// CHECK: FunctionDecl {{.*}} __free_function_iotar3 'void (__global int *, __generated_WithPointer)' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_usmPtr '__global int *' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_P '__generated_WithPointer' \ No newline at end of file +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' \ No newline at end of file diff --git a/clang/test/SemaSYCL/sycl-esimd-ast.cpp b/clang/test/SemaSYCL/sycl-esimd-ast.cpp index a065b47c00783..54914f087c91c 100644 --- a/clang/test/SemaSYCL/sycl-esimd-ast.cpp +++ b/clang/test/SemaSYCL/sycl-esimd-ast.cpp @@ -17,16 +17,16 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel1 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: SYCLSimdAttr {{.*}} // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit + // CHECK-NEXT: SYCLSimdAttr {{.*}} h.single_task( FuncObj()); // CHECK-LABEL: FunctionDecl {{.*}}test_kernel2 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit - // CHECK-NEXT: SYCLSimdAttr {{.*}} // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit + // CHECK-NEXT: SYCLSimdAttr {{.*}} h.single_task( []() [[intel::sycl_explicit_simd]]{}); @@ -34,9 +34,9 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel3 // CHECK: SYCLSimdAttr {{.*}} Implicit // CHECK-NEXT: SYCLKernelAttr {{.*}} Implicit + // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit // CHECK-NEXT: SYCLSimdAttr {{.*}} // CHECK-NEXT: SYCLSimdAttr {{.*}} - // CHECK-NEXT: AsmLabelAttr {{.*}} Implicit h.single_task( []() [[intel::sycl_explicit_simd]] { func(); }); }); diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index a9097b42fde76..014902ea7c141 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -49,12 +49,6 @@ struct Simple { float f; }; -struct WithPointer { - int x; - float *fp; - float f; -}; - void printUSM(int *usmPtr, int size) { std::cout << "usmPtr[] = {"; for (int i = 0; i < size; i++) { @@ -286,67 +280,6 @@ bool test_3(queue Queue, KernelFinder &KF) { return PassA && PassB; } -// Templated free function definition. -template -SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( - ext::oneapi::experimental::nd_range_kernel<2>)) void ff_4(T *ptr, T start, - struct WithPointer - S) { - int(&ptr2D)[4][4] = *reinterpret_cast(ptr); - nd_item<2> Item = ext::oneapi::experimental::this_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) + start + S.x + S.f + *S.fp; -} - -// Explicit instantiation with �int*�. -template void ff_4(int *ptr, int start, struct WithPointer S); - -bool test_4(queue Queue, KernelFinder &KF) { - constexpr int Range = 16; - int *usmPtr = malloc_shared(Range, Queue); - float *fp = malloc_shared(1, Queue); - *fp = 8.2; - int value = 55; - struct WithPointer S { - 3, fp, 7.1 - }; - int Result[Range] = {73, 74, 73, 74, 74, 75, 74, 75, - 73, 74, 73, 74, 74, 75, 74, 75}; - 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 + S.x + S.f + *S.fp; - }); - }); - Queue.wait(); - bool PassA = checkUSM(usmPtr, Range, Result); - std::cout << "Test 4a: " << (PassA ? "PASS" : "FAIL") << std::endl; - - kernel Kernel = - KF.get_kernel("__free_function_Z4ff_4IiEvPT_S0_11WithPointer"); - memset(usmPtr, 0, Range * sizeof(int)); - Queue.submit([&](handler &Handler) { - Handler.set_arg(0, usmPtr); - Handler.set_arg(1, value); - Handler.set_arg(2, S); - Handler.parallel_for(R2, Kernel); - }); - Queue.wait(); - bool PassB = checkUSM(usmPtr, Range, Result); - std::cout << "Test 4b: " << (PassB ? "PASS" : "FAIL") << std::endl; - - free(usmPtr, Queue); - return PassA && PassB; -} - int main() { queue Queue; KernelFinder KF(Queue); @@ -356,7 +289,6 @@ int main() { Pass &= test_1(Queue, KF); Pass &= test_2(Queue, KF); Pass &= test_3(Queue, KF); - Pass &= test_4(Queue, KF); return Pass ? 0 : 1; } From 369ea3a1abbede4a51337d3135241ab9b02b71fc Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 8 Apr 2024 23:54:55 -0700 Subject: [PATCH 17/52] Updated test and removed unused code. --- clang/lib/Sema/SemaSYCL.cpp | 8 -------- sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 112b5a9f04229..aa7f0eb4a2a43 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5304,14 +5304,6 @@ void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { SemaRef, FD->getLocation(), FD->isInlined(), false /*IsSIMDKernel */, true /*IsFreeFunction*/, FD, SemaRef.getSyclIntegrationHeader()); -#if 0 - // TODO: remove this dummy struct - RecordDecl *DummyClass = - SemaRef.getASTContext().buildImplicitRecord("__dummy_class"); - DummyClass->startDefinition(); - DummyClass->completeDefinition(); - CXXRecordDecl *DummyClass1 = static_cast(DummyClass); -#endif FreeFunctionKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD); // Kernel object size is irrelevant, so set to 0. diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 014902ea7c141..566c6e5d3b34d 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -128,7 +128,7 @@ SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<1>)) void ff_1(int *ptr, int start, int end) { - nd_item<1> Item = ext::oneapi::experimental::this_nd_item<1>(); + nd_item<1> Item = ext::oneapi::this_work_item::get_nd_item<1>(); id<1> GId = Item.get_global_id(); ptr[GId.get(0)] = GId.get(0) + start + end; } @@ -175,7 +175,7 @@ SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<2>)) void ff_2(int *ptr, int start, struct Simple S) { int(&ptr2D)[4][4] = *reinterpret_cast(ptr); - nd_item<2> Item = ext::oneapi::experimental::this_nd_item<2>(); + 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)] = @@ -229,7 +229,7 @@ SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( ext::oneapi::experimental::nd_range_kernel<2>)) void ff_3(T *ptr, T start, struct Simple S) { int(&ptr2D)[4][4] = *reinterpret_cast(ptr); - nd_item<2> Item = ext::oneapi::experimental::this_nd_item<2>(); + 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)] = From 4188d645b5a34eac2aed78102353374b70f3c6cf Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 9 Apr 2024 00:17:55 -0700 Subject: [PATCH 18/52] Formatting change. --- clang/lib/Sema/SemaSYCL.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index aa7f0eb4a2a43..13660f88c0391 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -976,11 +976,10 @@ class FreeFunctionBodyTransform std::unordered_map &FieldMapP, Sema &S) : TreeTransform(S), ParamMap(ParamMapP), FieldMap(FieldMapP), SemaRef(S) {} - //bool AlwaysRebuild() { return true; } ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) { - auto Ref = dyn_cast_if_present (DRE->getDecl()); - auto OldParm = dyn_cast_if_present (Ref); + auto Ref = dyn_cast_if_present(DRE->getDecl()); + auto OldParm = dyn_cast_if_present(Ref); if (OldParm) { if (auto NewParam = ParamMap.find(OldParm); NewParam != ParamMap.end()) { auto NewDecl = NewParam->second; @@ -5614,12 +5613,13 @@ void Sema::ProcessFreeFunction(FunctionDecl *FD) { SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); - KernelObjVisitor Visitor{ *this }; + KernelObjVisitor Visitor{*this}; DiagnosingSYCLKernel = true; // Check parameters of free function. - Visitor.VisitFunctionParameters(FD, DecompMarker, FieldChecker, UnionChecker); + Visitor.VisitFunctionParameters(FD, DecompMarker, FieldChecker, + UnionChecker); DiagnosingSYCLKernel = false; From b7834160f4e3936ee86baf51b050ff08e5fdc044 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 9 Apr 2024 18:13:05 -0700 Subject: [PATCH 19/52] Added some checking for unsupported types. --- clang/lib/Sema/SemaSYCL.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 13660f88c0391..d230e221bea47 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1541,7 +1541,7 @@ class KernelObjVisitor { void visitParam(ParmVarDecl *Param, QualType ParamTy, HandlerTys &...Handlers) { if (isSyclSpecialType(ParamTy, SemaRef)) - KP_FOR_EACH(handleSyclSpecialType, Param, ParamTy); + KP_FOR_EACH(handleOtherType, Param, ParamTy); else if (ParamTy->isStructureOrClassType()) { if (KP_FOR_EACH(handleStructType, Param, ParamTy)) { CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); @@ -1553,12 +1553,12 @@ class KernelObjVisitor { VisitUnion(nullptr, Param, RD, Handlers...); } } else if (ParamTy->isReferenceType()) - KP_FOR_EACH(handleReferenceType, Param, ParamTy); + KP_FOR_EACH(handleOtherType, Param, ParamTy); else if (ParamTy->isPointerType()) KP_FOR_EACH(handlePointerType, Param, ParamTy); else if (ParamTy->isArrayType()) - visitArray(Param, ParamTy, Handlers...); - else if (ParamTy->isScalarType() || ParamTy->isVectorType()) + KP_FOR_EACH(handleOtherType, Param, ParamTy); + else if (ParamTy->isScalarType()) KP_FOR_EACH(handleScalarType, Param, ParamTy); else KP_FOR_EACH(handleOtherType, Param, ParamTy); @@ -2976,6 +2976,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { + --StructDepth; return true; } From 7ce6411bd9d3e048787fe6fe73365a74b87b92d9 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 9 Apr 2024 20:54:55 -0700 Subject: [PATCH 20/52] Removed some code realted to arrays. --- clang/lib/Sema/SemaSYCL.cpp | 146 +----------------- .../CodeGenSYCL/free_function_param_refs.cpp | 4 +- .../SemaSYCL/free_function_kernel_params.cpp | 7 +- 3 files changed, 10 insertions(+), 147 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d230e221bea47..2022428e19136 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1407,13 +1407,6 @@ class KernelObjVisitor { (Handlers.nextElement(ElementTy, Index), 0)...}; visitField(Owner, ArrayField, ElementTy, Handlers...); } - template - void visitArrayElementImpl(ParmVarDecl *ArrayField, QualType ElementTy, - uint64_t Index, HandlerTys &...Handlers) { - (void)std::initializer_list{ - (Handlers.nextElement(ElementTy, Index), 0)...}; - visitParam(ArrayField, ElementTy, Handlers...); - } template void visitFirstArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, @@ -1424,28 +1417,12 @@ class KernelObjVisitor { void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, HandlerTys &... Handlers); - - template - void visitFirstArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, - HandlerTys &...Handlers) { - visitArrayElementImpl(ArrayField, ElementTy, 0, Handlers...); - } - template - void visitNthArrayElement(ParmVarDecl *ArrayField, QualType ElementTy, - uint64_t Index, HandlerTys &...Handlers); - template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, QualType ArrayTy, HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.handleSimpleArrayType(Field, ArrayTy), 0)...}; } - template - void visitSimpleArray(ParmVarDecl *Param, QualType ArrayTy, - HandlerTys &...Handlers) { - (void)std::initializer_list{ - (Handlers.handleSimpleArrayType(Param, ArrayTy), 0)...}; - } template void visitComplexArray(const CXXRecordDecl *Owner, FieldDecl *Field, @@ -1478,37 +1455,6 @@ class KernelObjVisitor { (void)std::initializer_list{ (Handlers.leaveArray(Field, ArrayTy, ET), 0)...}; } - template - void visitComplexArray(ParmVarDecl *Param, QualType ArrayTy, - HandlerTys &...Handlers) { - // Array workflow is: - // handleArrayType - // enterArray - // nextElement - // VisitField (same as before, note that The FieldDecl is the of array - // itself, not the element) - // ... repeat per element, opt-out for duplicates. - // leaveArray - - if (!KP_FOR_EACH(handleArrayType, Param, ArrayTy)) - return; - - const ConstantArrayType *CAT = - SemaRef.getASTContext().getAsConstantArrayType(ArrayTy); - assert(CAT && "Should only be called on constant-size array."); - QualType ET = CAT->getElementType(); - uint64_t ElemCount = CAT->getSize().getZExtValue(); - - (void)std::initializer_list{ - (Handlers.enterArray(Param, ArrayTy, ET), 0)...}; - - visitFirstArrayElement(Param, ET, Handlers...); - for (uint64_t Index = 1; Index < ElemCount; ++Index) - visitNthArrayElement(Param, ET, Index, Handlers...); - - (void)std::initializer_list{ - (Handlers.leaveArray(Param, ArrayTy, ET), 0)...}; - } template void visitField(const CXXRecordDecl *Owner, FieldDecl *Field, @@ -1584,6 +1530,7 @@ class KernelObjVisitor { template void visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, QualType ArrayTy, HandlerTys &...Handlers); + template void visitArray(ParmVarDecl *Param, QualType ArrayTy, HandlerTys &...Handlers); @@ -1646,10 +1593,12 @@ class SyclKernelFieldHandlerBase { QualType) { return true; } + virtual bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) { return true; } + virtual bool handleNonDecompStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) { return true; @@ -1659,7 +1608,6 @@ class SyclKernelFieldHandlerBase { // descending down the elements), this function gets called in the event of an // array containing simple elements (even in the case of an MD array). virtual bool handleSimpleArrayType(FieldDecl *, QualType) { return true; } - virtual bool handleSimpleArrayType(ParmVarDecl *, QualType) { return true; } // The following are only used for keeping track of where we are in the base // class/field graph. Int Headers use this to calculate offset, most others @@ -1724,10 +1672,6 @@ class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { bool isArrayElement(const FieldDecl *FD, QualType Ty) const { return !SemaRef.getASTContext().hasSameType(FD->getType(), Ty); } - - bool isArrayElement(const ParmVarDecl *PD, QualType Ty) const { - return !SemaRef.getASTContext().hasSameType(PD->getType(), Ty); - } }; // A class to represent the 'do nothing' case for filtering purposes. @@ -1788,20 +1732,6 @@ void KernelObjVisitor::visitNthArrayElement(const CXXRecordDecl *Owner, .Handler...); } -template -void KernelObjVisitor::visitNthArrayElement(ParmVarDecl *ArrayField, - QualType ElementTy, uint64_t Index, - Handlers &...handlers) { - // Don't continue descending if none of the handlers 'care'. This could be 'if - // constexpr' starting in C++17. Until then, we have to count on the - // optimizer to realize "if (false)" is a dead branch. - if (AnyTrue::Value) - visitArrayElementImpl( - ArrayField, ElementTy, Index, - HandlerFilter(handlers) - .Handler...); -} - template void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, const CXXRecordDecl *Wrapper, @@ -1886,35 +1816,7 @@ void KernelObjVisitor::visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, template void KernelObjVisitor::visitArray(ParmVarDecl *Param, QualType ArrayTy, HandlerTys &...Handlers) { - - if (Param->hasAttr()) { - visitComplexArray(Param, ArrayTy, Handlers...); - } else if (AnyTrue:: - Value) { - // We are currently in PointerHandler visitor. - if (Param->hasAttr()) { - // This is an array of pointers, or an array of a type containing - // pointers. - visitComplexArray(Param, ArrayTy, Handlers...); - } else { - // This is an array which does not contain pointers. - visitSimpleArray(Param, ArrayTy, Handlers...); - } - } else { - if (!AllTrue::Value) - visitSimpleArray( - Param, ArrayTy, - HandlerFilter( - Handlers) - .Handler...); - - if (AnyTrue::Value) - visitComplexArray( - Param, ArrayTy, - HandlerFilter( - Handlers) - .Handler...); - } + // TODO } // A type to check the validity of all of the argument types. @@ -2615,12 +2517,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { QualType ModifiedPointerType = ModifyAddressSpace(SemaRef, FieldTy); - if (!isArrayElement(PD, FieldTy)) - addField(PD, ModifiedPointerType); - else - ModifiedArrayElementsOrArray.push_back(ModifiedPointerType); - // We do not need to wrap pointers since this is a pointer inside - // non-decomposed struct. + ModifiedArrayElementsOrArray.push_back(ModifiedPointerType); return true; } @@ -2664,10 +2561,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { addField(FD, Ty); return true; } - bool handleSimpleArrayType(ParmVarDecl *PD, QualType Ty) final { - addField(PD, Ty); - return true; - } public: QualType getNewRecordType() { @@ -3088,14 +2981,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } - bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - QualType ArrayTy = FieldTy; - // Arrays are wrapped in a struct since they cannot be passed directly. - RecordDecl *WrappedArray = wrapParam(ArrayTy); - addParam(PD, SemaRef.getASTContext().getRecordType(WrappedArray)); - return true; - } - bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { addParam(FD, FieldTy); return true; @@ -3338,11 +3223,6 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } - bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - addParam(FieldTy); - return true; - } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { addParam(Ty); @@ -4134,10 +4014,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - return true; - } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); @@ -4478,11 +4354,6 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; - return true; - } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { return true; @@ -4740,13 +4611,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool handleSimpleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - // Arrays are always wrapped inside of structs, so just treat it as a simple - // struct. - addParam(PD, FieldTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { addParam(FD, Ty, SYCLIntegrationHeader::kind_std_layout); diff --git a/clang/test/CodeGenSYCL/free_function_param_refs.cpp b/clang/test/CodeGenSYCL/free_function_param_refs.cpp index 89a60bf9c1e69..6acbfc47305ae 100755 --- a/clang/test/CodeGenSYCL/free_function_param_refs.cpp +++ b/clang/test/CodeGenSYCL/free_function_param_refs.cpp @@ -18,11 +18,11 @@ struct Simple { __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int arr[], int start, int end, struct Simple S) { +void ff_2(int *ptr, int start, int end, struct Simple S) { for (int i = start; i <= end; i++) ptr[i] = start + S.x + S.f + S.c[2] + 66; } -// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, ptr addrspace(1) {{.*}} %_arg_arr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S) +// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S) // CHECK: store ptr addrspace(1) %_arg_ptr, ptr addrspace(4) %_arg_ptr.{{.*}} // CHECK: store i32 %_arg_start, ptr addrspace(4) %_arg_start.{{.*}} // CHECK: store i32 %_arg_end, ptr addrspace(4) %_arg_end.{{.*}} diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index e5087e4d3f87a..eb1313080cfd4 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -14,13 +14,12 @@ struct Simple { __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int arr[], int start, int end, struct Simple S) { +void ff_2(int *ptr, int start, int end, struct Simple S) { for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2] + arr[66]; + ptr[i] = start + S.x + S.f + S.c[2]; } -// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, __global int *, int, int, struct Simple)' +// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int, struct Simple)' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_arr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' \ No newline at end of file From 721ca8e703c629f1609bf58852311c561e84048f Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 9 Apr 2024 21:05:30 -0700 Subject: [PATCH 21/52] Formatting change. --- clang/lib/Sema/SemaSYCL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 2022428e19136..b3f15487e3f74 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1410,16 +1410,16 @@ class KernelObjVisitor { template void visitFirstArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, - QualType ElementTy, HandlerTys &... Handlers) { + QualType ElementTy, HandlerTys &...Handlers) { visitArrayElementImpl(Owner, ArrayField, ElementTy, 0, Handlers...); } template void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &... Handlers); + HandlerTys &...Handlers); template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &... Handlers) { + QualType ArrayTy, HandlerTys &...Handlers) { (void)std::initializer_list{ (Handlers.handleSimpleArrayType(Field, ArrayTy), 0)...}; } From d058180b71906e4d943dad07aab4a8fe4bc7f3e1 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Wed, 10 Apr 2024 15:26:56 -0700 Subject: [PATCH 22/52] Fixed a problem dealing with casts in the tree transformer. --- clang/lib/Sema/SemaSYCL.cpp | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b3f15487e3f74..ef70a1a5e1ad4 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -35,6 +35,7 @@ #include #include #include +#include using namespace clang; using namespace std::placeholders; @@ -1008,31 +1009,11 @@ class FreeFunctionBodyTransform return D; } - ExprResult TransformMemberExpr(MemberExpr *ME) { - auto VD = ME->getMemberDecl(); - FieldDecl *OldFD = dyn_cast(VD); - // TODO: handle static member - if (OldFD) { - if (auto Replacement = FieldMap.find(OldFD); - Replacement != FieldMap.end()) { - FieldDecl *NewFD = dyn_cast(Replacement->second.NewField); - auto NewFDParent = dyn_cast(NewFD->getParent()); - ParmVarDecl *NewPD = Replacement->second.NewParm; - auto Base = DeclRefExpr::Create( - SemaRef.getASTContext(), NestedNameSpecifierLoc(), ME->getExprLoc(), - NewPD, false, DeclarationNameInfo(), - QualType(NewFDParent->getTypeForDecl(), 0), ME->getValueKind()); - DeclAccessPair MemberDAP = DeclAccessPair::make(NewFD, AS_none); - MemberExpr *NewME = SemaRef.BuildMemberExpr( - Base, /*IsArrow */ false, ME->getExprLoc(), - NestedNameSpecifierLoc(), ME->getExprLoc(), NewFD, MemberDAP, - /*HadMultipleCandidates*/ false, - DeclarationNameInfo(NewFD->getDeclName(), ME->getExprLoc()), - NewFD->getType(), VK_LValue, OK_Ordinary); - return NewME; - } - } - return TreeTransform::TransformMemberExpr(ME); + ExprResult TransformImplicitCastExpr(ImplicitCastExpr *E) { + // Normally, implicit casts are eliminated during transformation, since they + // will be recomputed by semantic analysis after transformation. Here we + // retain them. + return TreeTransform::TransformExpr(E->getSubExpr()); } private: From 4a119ddb5b2d8d506d09e2e0911cff1b5aa3771b Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 15 Apr 2024 16:16:26 -0700 Subject: [PATCH 23/52] Changes based on reviewer comments. --- clang/lib/Sema/SemaDecl.cpp | 6 +++-- clang/lib/Sema/SemaSYCL.cpp | 16 ++++++------- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 ---- .../SemaSYCL/free_function_kernel_params.cpp | 23 +++++++++++++++++-- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a3db5b518bed6..193d31a348e1f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16683,9 +16683,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD && !FD->isDeleted()) checkTypeSupport(FD->getType(), FD->getLocation(), FD); - // Handle non-templated free function. + // Handle free functions. if (LangOpts.SYCLIsDevice && FD->hasAttr() && Body && - !FD->isTemplated()) + (FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate || + FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization)) ProcessFreeFunction(FD); return dcl; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ef70a1a5e1ad4..7c98b227bb97a 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1131,8 +1131,7 @@ static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { SmallVector, 4> NameValuePairs = AnAttr->getAttributeNameValuePairs(SemaRef.Context); for (const auto &NameValuePair : NameValuePairs) { - if (NameValuePair.first == "sycl-range-kernel" || - NameValuePair.first == "sycl-nd-range-kernel" || + if (NameValuePair.first == "sycl-nd-range-kernel" || NameValuePair.first == "sycl-single-task-kernel") return true; } @@ -1142,8 +1141,7 @@ static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { return false; } -static std::string constructFFKernelName(ASTContext &Ctx, - const FunctionDecl *FD) { +static std::string constructFFKernelName(const FunctionDecl *FD) { IdentifierInfo *Id = FD->getIdentifier(); std::string NewIdent = (Twine("__free_function_") + Id->getName()).str(); return NewIdent; @@ -1152,18 +1150,18 @@ static std::string constructFFKernelName(ASTContext &Ctx, // Gets a name for the free function kernel function. The suffix allows a normal // device function to coexist with the kernel function. static std::pair -constructFreeFunctionKernelName(Sema &S, const FunctionDecl *KernelCallerFunc, +constructFreeFunctionKernelName(Sema &S, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; llvm::raw_svector_ostream Out(Result); std::string MangledName; std::string StableName; - if (KernelCallerFunc->getTemplateSpecializationArgs()) { - MC.mangleName(KernelCallerFunc, Out); + if (FreeFunc->getTemplateSpecializationArgs()) { + MC.mangleName(FreeFunc, Out); MangledName = (Twine("__free_function") + Out.str()).str(); } else { - MangledName = constructFFKernelName(S.getASTContext(), KernelCallerFunc); + MangledName = constructFFKernelName(FreeFunc); } StableName = MangledName; return {MangledName, StableName}; @@ -2759,7 +2757,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); const IdentifierInfo *NewIdent = - &Ctx.Idents.get(constructFFKernelName(Ctx, FD)); + &Ctx.Idents.get(constructFFKernelName(FD)); FD = FunctionDecl::Create( Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a40982afecf09..b0e8f836d2b5d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -7034,10 +7034,6 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TUKind == TU_Prefix && Function->instantiationIsPending()) delayedPCHInstantiations.push_back(Inst); continue; - - // Handle SYCL free function. - if (LangOpts.SYCLIsDevice && Function->hasAttr()) - ProcessFreeFunction(Function); } // Instantiate variable definitions diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index eb1313080cfd4..51ca11479ec29 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -13,7 +13,7 @@ struct Simple { }; __attribute__((sycl_device)) -[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void ff_2(int *ptr, int start, int end, struct Simple S) { for (int i = start; i <= end; i++) ptr[i] = start + S.x + S.f + S.c[2]; @@ -22,4 +22,23 @@ void ff_2(int *ptr, int start, int end, struct Simple S) { // CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' \ No newline at end of file +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' + + +// Templated free function definition. +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] + void ff_3(T* ptr, T start, int end, struct Simple S) { + for (int i = start; i <= end; i++) + ptr[i] = start + S.x + S.f + S.c[2]; +} + +// Explicit instantiation with �int*� +template void ff_3(int* ptr, int start, int end, struct Simple S); + +// CHECK: FunctionDecl {{.*}} __free_function_Z4ff_3IiEvPT_S0_i6Simple 'void (__global int *, int, int, struct Simple)' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' From d0fe5a30f2227677d92fef9927ae17ad21821cdc Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 15 Apr 2024 16:24:55 -0700 Subject: [PATCH 24/52] Formatting change. --- clang/lib/Sema/SemaSYCL.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 7c98b227bb97a..68c57f4d667e6 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2756,8 +2756,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // all the params. FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); - const IdentifierInfo *NewIdent = - &Ctx.Idents.get(constructFFKernelName(FD)); + const IdentifierInfo *NewIdent = &Ctx.Idents.get(constructFFKernelName(FD)); FD = FunctionDecl::Create( Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); From 046d28ad8358f7aca6d159fff77c9056aa08bdbd Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 15 Apr 2024 17:40:42 -0700 Subject: [PATCH 25/52] Update test to temporarily test only on Linux. --- clang/test/SemaSYCL/free_function_kernel_params.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 51ca11479ec29..1ef3c9c37332e 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -1,8 +1,9 @@ // RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -ast-dump \ // RUN: %s -o - | FileCheck %s - +// UNSUPPORTED: system-windows // This test checks parameter rewriting for free functions with parameters // of type scalar, pointer, simple struct and struct with pointers. +// Windows support will be added later. #include "sycl.hpp" From 440871c204d4816a748a5a972687d04ce7f84dcc Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 22 Apr 2024 14:20:21 -0700 Subject: [PATCH 26/52] Modified device code generation. --- clang/include/clang/Sema/Sema.h | 9 +- clang/lib/Sema/SemaSYCL.cpp | 606 +++++++----------- .../CodeGenSYCL/free_function_int_header.cpp | 35 + .../CodeGenSYCL/free_function_param_refs.cpp | 31 - .../SemaSYCL/free_function_kernel_params.cpp | 20 + 5 files changed, 279 insertions(+), 422 deletions(-) create mode 100755 clang/test/CodeGenSYCL/free_function_int_header.cpp delete mode 100755 clang/test/CodeGenSYCL/free_function_param_refs.cpp diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c875c34083ff8..6bea053e348a6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -340,7 +340,7 @@ class SYCLIntegrationHeader { /// the kernel with given name. Starts new kernel invocation descriptor. void startKernel(const FunctionDecl *SyclKernel, QualType KernelNameType, SourceLocation Loc, bool IsESIMD, bool IsUnnamedKernel, - bool IsFreeFunctionKernel, int64_t ObjSize); + int64_t ObjSize); /// Adds a kernel parameter descriptor to current kernel invocation /// descriptor. @@ -421,18 +421,15 @@ class SYCLIntegrationHeader { // hasn't provided an explicit name for. bool IsUnnamedKernel; - // Whether this is a free function kernel. - bool IsFreeFunctionKernel; - /// Size of the kernel object. int64_t ObjSize = 0; KernelDesc(const FunctionDecl *SyclKernel, QualType NameType, SourceLocation KernelLoc, bool IsESIMD, bool IsUnnamedKernel, - bool IsFreeFunctionKernel, int64_t ObjSize) + int64_t ObjSize) : SyclKernel(SyclKernel), NameType(NameType), KernelLocation(KernelLoc), IsESIMDKernel(IsESIMD), IsUnnamedKernel(IsUnnamedKernel), - IsFreeFunctionKernel(IsFreeFunctionKernel), ObjSize(ObjSize) {} + ObjSize(ObjSize) {} void updateKernelNames(StringRef Name, StringRef StableName) { this->Name = Name.str(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 68c57f4d667e6..adfa70b52e314 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -961,67 +961,6 @@ static ParamDesc makeParamDesc(ASTContext &Ctx, StringRef Name, QualType Ty) { Ctx.getTrivialTypeSourceInfo(Ty)); } -// Map used to replace original fields with new fields for free functions that -// contain structs with pointers. -struct FieldMap { - ParmVarDecl *OriginalParm; - ParmVarDecl *NewParm; - FieldDecl *NewField; -}; - -class FreeFunctionBodyTransform - : public TreeTransform { -public: - FreeFunctionBodyTransform( - std::unordered_map &ParamMapP, - std::unordered_map &FieldMapP, Sema &S) - : TreeTransform(S), ParamMap(ParamMapP), - FieldMap(FieldMapP), SemaRef(S) {} - - ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) { - auto Ref = dyn_cast_if_present(DRE->getDecl()); - auto OldParm = dyn_cast_if_present(Ref); - if (OldParm) { - if (auto NewParam = ParamMap.find(OldParm); NewParam != ParamMap.end()) { - auto NewDecl = NewParam->second; - NewDecl->setIsUsed(); - auto NewDRE = DeclRefExpr::Create( - SemaRef.getASTContext(), DRE->getQualifierLoc(), - DRE->getTemplateKeywordLoc(), NewDecl, false, DRE->getNameInfo(), - NewDecl->getType(), DRE->getValueKind()); - return NewDRE; - } - } - return DRE; - } - - Decl *TransformDecl(SourceLocation Loc, Decl *D) { - VarDecl *VD = dyn_cast(D); - if (VD) { - Expr *InitExpr = VD->getInit(); - if (InitExpr) { - ExprResult NewInit = TransformExpr(InitExpr); - VD->setInit(SemaRef.MaybeCreateExprWithCleanups(NewInit.get())); - VD->setIsUsed(); - return VD; - } - } - return D; - } - - ExprResult TransformImplicitCastExpr(ImplicitCastExpr *E) { - // Normally, implicit casts are eliminated during transformation, since they - // will be recomputed by semantic analysis after transformation. Here we - // retain them. - return TreeTransform::TransformExpr(E->getSubExpr()); - } - -private: - std::unordered_map &ParamMap; - std::unordered_map &FieldMap; - Sema &SemaRef; -}; - class MarkWIScopeFnVisitor : public RecursiveASTVisitor { public: MarkWIScopeFnVisitor(ASTContext &Ctx) : Ctx(Ctx) {} @@ -1510,10 +1449,6 @@ class KernelObjVisitor { void visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, QualType ArrayTy, HandlerTys &...Handlers); - template - void visitArray(ParmVarDecl *Param, QualType ArrayTy, - HandlerTys &...Handlers); - // A visitor function that dispatches to functions as defined in // SyclKernelFieldHandler by iterating over a free function parameter list. template @@ -1524,6 +1459,7 @@ class KernelObjVisitor { } #undef KF_FOR_EACH +#undef KP_FOR_EACH }; // A base type that the SYCL OpenCL Kernel construction task uses to implement @@ -1792,12 +1728,6 @@ void KernelObjVisitor::visitArray(const CXXRecordDecl *Owner, FieldDecl *Field, } } -template -void KernelObjVisitor::visitArray(ParmVarDecl *Param, QualType ArrayTy, - HandlerTys &...Handlers) { - // TODO -} - // A type to check the validity of all of the argument types. class SyclKernelFieldChecker : public SyclKernelFieldHandler { bool IsInvalid = false; @@ -1827,16 +1757,16 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return false; } - bool checkNotCopyableToKernel(const ParmVarDecl *PD, QualType FieldTy) { - if (FieldTy->isArrayType()) { + bool checkNotCopyableToKernel(const ParmVarDecl *PD, QualType ParamTy) { + if (ParamTy->isArrayType()) { if (const auto *CAT = - SemaRef.getASTContext().getAsConstantArrayType(FieldTy)) { + SemaRef.getASTContext().getAsConstantArrayType(ParamTy)) { QualType ET = CAT->getElementType(); return checkNotCopyableToKernel(PD, ET); } return Diag.Report(PD->getLocation(), diag::err_sycl_non_constant_array_type) - << FieldTy; + << ParamTy; } return false; @@ -1949,8 +1879,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return isValid(); } - bool handleReferenceType(ParmVarDecl *PD, QualType FieldTy) final { - Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << FieldTy; + bool handleReferenceType(ParmVarDecl *PD, QualType ParamTy) final { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; IsInvalid = true; return isValid(); } @@ -1969,9 +1899,9 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return isValid(); } - bool handleStructType(ParmVarDecl *PD, QualType FieldTy) final { - IsInvalid |= checkNotCopyableToKernel(PD, FieldTy); - CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl(); + bool handleStructType(ParmVarDecl *PD, QualType ParamTy) final { + IsInvalid |= checkNotCopyableToKernel(PD, ParamTy); + CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); assert(RD && "Not a RecordDecl inside the handler for struct type"); if (RD->isLambda()) { for (const LambdaCapture &LC : RD->captures()) @@ -1994,7 +1924,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return isValid(); } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { // TODO return true; } @@ -2004,9 +1934,9 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return isValid(); } - bool handleArrayType(ParmVarDecl *PD, QualType FieldTy) final { - IsInvalid |= checkNotCopyableToKernel(PD, FieldTy); - return isValid(); + bool handleArrayType(ParmVarDecl *PD, QualType ParamTy) final { + // TODO + return true; } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { @@ -2021,10 +1951,10 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return isValid(); } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - while (FieldTy->isAnyPointerType()) { - FieldTy = QualType{FieldTy->getPointeeOrArrayElementType(), 0}; - if (FieldTy->isVariableArrayType()) { + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + while (ParamTy->isAnyPointerType()) { + ParamTy = QualType{ParamTy->getPointeeOrArrayElementType(), 0}; + if (ParamTy->isVariableArrayType()) { Diag.Report(PD->getLocation(), diag::err_vla_unsupported) << 0; IsInvalid = true; break; @@ -2039,8 +1969,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return isValid(); } - bool handleOtherType(ParmVarDecl *PD, QualType FieldTy) final { - Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << FieldTy; + bool handleOtherType(ParmVarDecl *PD, QualType ParamTy) final { + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; IsInvalid = true; return isValid(); } @@ -2125,7 +2055,7 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler { return checkType(FD->getLocation(), FieldTy); } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { // TODO return true; } @@ -2176,7 +2106,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool handlePointerType(ParmVarDecl *, QualType) final { - PointerStack.back() = true; + // TODO return true; } @@ -2214,7 +2144,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType Ty) final { + QualType ParamTy) final { // TODO return true; } @@ -2353,23 +2283,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { ModifiedRecords.back()->addDecl(Field); } - // Create and add FieldDecl for FieldTy to generated record. - void addField(const ParmVarDecl *PD, QualType FieldTy) { - assert(!ModifiedRecords.empty() && - "ModifiedRecords should have at least 1 record"); - ASTContext &Ctx = SemaRef.getASTContext(); - auto *Field = FieldDecl::Create( - Ctx, ModifiedRecords.back(), SourceLocation(), SourceLocation(), - getModifiedName(PD->getIdentifier()), FieldTy, - Ctx.getTrivialTypeSourceInfo(FieldTy, SourceLocation()), /*BW=*/nullptr, - /*Mutable=*/false, ICIS_NoInit); - Field->setAccess(PD->getAccess()); - if (PD->hasAttrs()) - Field->setAttrs(PD->getAttrs()); - // Add generated field to generated record. - ModifiedRecords.back()->addDecl(Field); - } - void createBaseSpecifier(const CXXRecordDecl *Parent, const CXXRecordDecl *RD, const CXXBaseSpecifier &BS) { TypeSourceInfo *TInfo = SemaRef.getASTContext().getTrivialTypeSourceInfo( @@ -2414,7 +2327,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType Ty) final { + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, + QualType ParamTy) final { // TODO return true; } @@ -2433,7 +2347,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType ParamTy) final { // TODO return true; } @@ -2494,9 +2409,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - QualType ModifiedPointerType = ModifyAddressSpace(SemaRef, FieldTy); - ModifiedArrayElementsOrArray.push_back(ModifiedPointerType); + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + // TODO return true; } @@ -2505,8 +2419,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } - bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - addField(PD, FieldTy); + bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { + // TODO return true; } @@ -2514,8 +2428,9 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return handleScalarType(FD, FieldTy); } - bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - return handleScalarType(PD, FieldTy); + bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { + // TODO + return true; } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, @@ -2525,8 +2440,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { } bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType Ty) final { - addField(PD, Ty); + QualType ParamTy) final { + // TODO return true; } @@ -2558,7 +2473,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { // A type to Create and own the FunctionDecl for the kernel. class SyclKernelDeclCreator : public SyclKernelFieldHandler { - SYCLIntegrationHeader &Header; bool IsFreeFunction; FunctionDecl *KernelDecl; llvm::SmallVector Params; @@ -2574,19 +2488,19 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { addParam(newParamDesc, FieldTy); } - void addParam(const ParmVarDecl *PD, QualType FieldTy) { - ParamDesc newParamDesc = makeParamDesc(PD, FieldTy); - addParam(newParamDesc, FieldTy); + void addParam(const ParmVarDecl *PD, QualType ParamTy) { + ParamDesc newParamDesc = makeParamDesc(PD, ParamTy); + addParam(newParamDesc, ParamTy); } - void addParam(const CXXBaseSpecifier &BS, QualType FieldTy) { + void addParam(const CXXBaseSpecifier &BS, QualType ParamTy) { // TODO: There is no name for the base available, but duplicate names are // seemingly already possible, so we'll give them all the same name for now. // This only happens with the accessor types. StringRef Name = "_arg__base"; ParamDesc newParamDesc = - makeParamDesc(SemaRef.getASTContext(), Name, FieldTy); - addParam(newParamDesc, FieldTy); + makeParamDesc(SemaRef.getASTContext(), Name, ParamTy); + addParam(newParamDesc, ParamTy); } // Add a parameter with specified name and type void addParam(StringRef Name, QualType ParamTy) { @@ -2799,8 +2713,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { static constexpr const bool VisitInsideSimpleContainers = false; SyclKernelDeclCreator(Sema &S, SourceLocation Loc, bool IsInline, bool IsSIMDKernel, bool IsFreeFunction, - FunctionDecl *SYCLKernel, SYCLIntegrationHeader &H) - : SyclKernelFieldHandler(S), Header(H), IsFreeFunction(IsFreeFunction), + FunctionDecl *SYCLKernel) + : SyclKernelFieldHandler(S), IsFreeFunction(IsFreeFunction), KernelDecl(IsFreeFunction ? createFreeFunctionDecl(S.getASTContext(), SYCLKernel, Loc, IsInline) @@ -2808,9 +2722,16 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { IsSIMDKernel)), FuncContext(SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); - if (const auto *AddIRAttrFunc = - SYCLKernel->getAttr()) - KernelDecl->addAttr(AddIRAttrFunc->clone(SemaRef.getASTContext())); + if (SYCLKernel->hasAttr()) { + const auto &Attrs = SYCLKernel->getAttrs(); + for (unsigned i = 0, e = Attrs.size(); i < e; i++) { + const SYCLAddIRAttributesFunctionAttr *AnAttr = + dyn_cast(Attrs[i]); + if (AnAttr) { + KernelDecl->addAttr(AnAttr->clone(SemaRef.getASTContext())); + } + } + } } ~SyclKernelDeclCreator() { @@ -2841,7 +2762,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO return true; } @@ -2902,16 +2823,16 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return handleSpecialType(FD, FieldTy); } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + bool handleSyclSpecialType(ParmVarDecl *, QualType) final { // TODO return true; } - RecordDecl *wrapParam(QualType FieldTy) { + RecordDecl *wrapField(FieldDecl *Field, QualType FieldTy) { RecordDecl *WrapperClass = SemaRef.getASTContext().buildImplicitRecord("__wrapper_class"); WrapperClass->startDefinition(); - FieldDecl *Field = FieldDecl::Create( + Field = FieldDecl::Create( SemaRef.getASTContext(), WrapperClass, SourceLocation(), SourceLocation(), /*Id=*/nullptr, FieldTy, SemaRef.getASTContext().getTrivialTypeSourceInfo(FieldTy, @@ -2932,7 +2853,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // passed directly. To work around this issue, all pointers inside the // struct are wrapped in a generated '__wrapper_class'. if (StructDepth) { - RecordDecl *WrappedPointer = wrapParam(ModTy); + RecordDecl *WrappedPointer = wrapField(FD, ModTy); ModTy = SemaRef.getASTContext().getRecordType(WrappedPointer); } @@ -2940,8 +2861,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - QualType ModTy = ModifyAddressSpace(SemaRef, FieldTy); + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + QualType ModTy = ModifyAddressSpace(SemaRef, ParamTy); addParam(PD, ModTy); return true; } @@ -2954,7 +2875,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { ArrayTy = GenerateNewArrayType(FD, FieldTy); // Arrays are wrapped in a struct since they cannot be passed directly. - RecordDecl *WrappedArray = wrapParam(ArrayTy); + RecordDecl *WrappedArray = wrapField(FD, ArrayTy); addParam(FD, SemaRef.getASTContext().getRecordType(WrappedArray)); return true; } @@ -2964,8 +2885,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } - bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - addParam(PD, FieldTy); + bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(PD, ParamTy); return true; } @@ -2984,11 +2905,11 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleNonDecompStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType Ty) final { + QualType ParamTy) final { // This is a field which should not be decomposed. - CXXRecordDecl *FieldRecordDecl = Ty->getAsCXXRecordDecl(); + CXXRecordDecl *FieldRecordDecl = ParamTy->getAsCXXRecordDecl(); assert(FieldRecordDecl && "Type must be a C++ record type"); - addParam(PD, Ty); + addParam(PD, ParamTy); return true; } @@ -3010,8 +2931,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return handleScalarType(FD, FieldTy); } - bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - return handleScalarType(PD, FieldTy); + bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { + return handleScalarType(PD, ParamTy); } // Generate kernel argument to initialize specialization constants. @@ -3026,8 +2947,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionDecl *getKernelDecl() { return KernelDecl; } - ParmVarDecl *getParamDecl(size_t Index) { return Params[Index]; } - llvm::ArrayRef getParamVarDeclsForCurrentField() { return ArrayRef(std::begin(Params) + LastParamIndex, std::end(Params)); @@ -3117,8 +3036,6 @@ class ESIMDKernelDiagnostics : public SyclKernelFieldHandler { ESIMDKernelDiagnostics(Sema &S, SourceLocation Loc, bool IsESIMD) : SyclKernelFieldHandler(S), KernelLoc(Loc), IsESIMD(IsESIMD) {} - using SyclKernelFieldHandler::handleSyclSpecialType; - bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { return handleSpecialType(FieldTy); } @@ -3127,6 +3044,8 @@ class ESIMDKernelDiagnostics : public SyclKernelFieldHandler { QualType FieldTy) final { return handleSpecialType(FieldTy); } + + using SyclKernelFieldHandler::handleSyclSpecialType; }; class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { @@ -3167,8 +3086,8 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return handleSpecialType(FieldTy); } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { - return handleSpecialType(FieldTy); + bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { + return handleSpecialType(ParamTy); } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, @@ -3181,8 +3100,8 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - addParam(FieldTy); + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(ParamTy); return true; } @@ -3191,8 +3110,8 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } - bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - addParam(FieldTy); + bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(ParamTy); return true; } @@ -3207,9 +3126,9 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return true; } - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType Ty) final { - addParam(Ty); + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, + QualType ParamTy) final { + addParam(ParamTy); return true; } @@ -3223,8 +3142,8 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { return handleScalarType(FD, FieldTy); } - bool handleUnionType(ParmVarDecl *PD, QualType ParmTy) final { - return handleScalarType(PD, ParmTy); + bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { + return handleScalarType(PD, ParamTy); } }; @@ -3845,8 +3764,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { InitializationKind InitKind = InitializationKind::CreateDefault(KernelCallerSrcLoc); InitializationSequence InitSeq(SemaRef, VarEntity, InitKind, std::nullopt); - ExprResult Init = - InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); + ExprResult Init = InitSeq.Perform(SemaRef, VarEntity, InitKind, std::nullopt); KernelHandlerClone->setInit( SemaRef.MaybeCreateExprWithCleanups(Init.get())); KernelHandlerClone->setInitStyle(VarDecl::CallInit); @@ -3964,10 +3882,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return handleSpecialType(FD, Ty); } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType Ty) final { - return true; - } - bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType Ty) final { return handleSpecialType(BS, Ty); @@ -3980,10 +3894,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - return true; - } - bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { if (FD->hasAttr()) handleGeneratedArrayType(FD, FieldTy); @@ -4003,11 +3913,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType Ty) final { - return true; - } - bool handleNonDecompStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) final { CXXRecordDecl *BaseDecl = Ty->getAsCXXRecordDecl(); @@ -4024,17 +3929,11 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - return true; - } - bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { addSimpleFieldInit(FD, FieldTy); return true; } - bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { return true; } - // Default inits the type, then calls the init-method in the body void handleSyclKernelHandlerType(ParmVarDecl *KernelHandlerArg) { @@ -4065,11 +3964,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType Ty) final { - return true; - } - bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { --StructDepth; CollectionInitExprs.pop_back(); @@ -4078,10 +3972,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - return true; - } - bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { ++StructDepth; @@ -4123,11 +4013,6 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool enterArray(ParmVarDecl *PD, QualType ArrayType, - QualType ElementType) final { - return true; - } - bool nextElement(QualType, uint64_t Index) final { ArrayInfos.back().second = Index; @@ -4155,76 +4040,23 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { removeFieldMemberExpr(FD, ArrayType); return true; } - - bool leaveArray(ParmVarDecl *PD, QualType ArrayType, - QualType ElementType) final { - return true; - } + using SyclKernelFieldHandler::handleSyclSpecialType; + using SyclKernelFieldHandler::handlePointerType; + using SyclKernelFieldHandler::handleNonDecompStruct; + using SyclKernelFieldHandler::handleScalarType; + using SyclKernelFieldHandler::handleUnionType; + using SyclKernelFieldHandler::enterStruct; + using SyclKernelFieldHandler::leaveStruct; + using SyclKernelFieldHandler::enterArray; + using SyclKernelFieldHandler::leaveArray; }; class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SyclKernelDeclCreator &DeclCreator; llvm::SmallVector BodyStmts; - llvm::SmallVector CollectionInitExprs; - llvm::SmallVector FinalizeStmts; - // This collection contains the information required to add/remove information - // about arrays as we enter them. The InitializedEntity component is - // necessary for initializing child members. uin64_t is the index of the - // current element being worked on, which is updated every time we visit - // nextElement. - llvm::SmallVector, 8> ArrayInfos; - llvm::SmallVector MemberExprBases; - llvm::SmallVector ArrayParamBases; FunctionDecl *FreeFunc; SourceLocation KernelCallerSrcLoc; // KernelCallerFunc source location. - // Contains a count of how many containers we're in. This is used by the - // pointer-struct-wrapping code to ensure that we don't try to wrap - // top-level pointers. - uint64_t StructDepth = 0; - // For free functions we create local copies of the parameters and replace - // uses within the body to use the local copies. For parameters requiring - // breakdown into components multiple items will be placed on these lists. - std::unordered_map ParamMap; - // For free functions that need replacement structs (because they contain - // pointers), also collect fields to replace. - std::unordered_map FieldMap; - - Stmt *replaceParamsAndFields( - Stmt *FunctionBody, - std::unordered_map &ParamMap, - std::unordered_map &FieldMap) { - FreeFunctionBodyTransform FFBT(ParamMap, FieldMap, SemaRef); - return FFBT.TransformStmt(FunctionBody).get(); - } - - // Using the statements/init expressions that we've created, this generates - // the kernel body compound stmt. CompoundStmt needs to know its number of - // statements in advance to allocate it, so we cannot do this as we go along. - CompoundStmt *createFreeFunctionKernelBody() { - // Push the Kernel function scope to ensure the scope isn't empty - SemaRef.PushFunctionScope(); - - // Use the function body for the free function kernel - BodyStmts.push_back(FreeFunc->getBody()); - - // Replace the original body with an empty body - Stmt *EmptyBody = CompoundStmt::Create(SemaRef.getASTContext(), {}, - FPOptionsOverride(), {}, {}); - FreeFunc->setBody(EmptyBody); - - BodyStmts.insert(BodyStmts.end(), FinalizeStmts.begin(), - FinalizeStmts.end()); - - Stmt *NewBody = CompoundStmt::Create(SemaRef.getASTContext(), BodyStmts, - FPOptionsOverride(), {}, {}); - - // Replace references to the parameters in kernel body, to use the - // parameters of the newly created body function, or the compiler generated - // local clones for the parameters that are expanded. - NewBody = replaceParamsAndFields(NewBody, ParamMap, FieldMap); - - return static_cast(NewBody); - } + llvm::SmallVector ArgExprs; // Creates a DeclRefExpr to the ParmVar that represents the current field. Expr *createParamReferenceExpr() { @@ -4232,185 +4064,202 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { DeclCreator.getParamVarDeclsForCurrentField()[0]; QualType ParamType = KernelParameter->getOriginalType(); - Expr *DRE = SemaRef.BuildDeclRefExpr(KernelParameter, ParamType, VK_LValue, + Expr *DRE = SemaRef.BuildDeclRefExpr(KernelParameter, ParamType, VK_PRValue, KernelCallerSrcLoc); return DRE; } - // Creates an initialized entity for a function local. - InitializedEntity getVarEntity(VarDecl *VD, QualType Ty) { - return InitializedEntity::InitializeVariable(VD); - } - - void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef) { - InitializationKind InitKind = - InitializationKind::CreateCopy(KernelCallerSrcLoc, KernelCallerSrcLoc); - addVarInit(VD, Ty, ParamRef, InitKind); - } - - void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, - InitializationKind InitKind) { - addVarInit(VD, Ty, ParamRef, InitKind, getVarEntity(VD, Ty)); - } - - void addVarInit(VarDecl *VD, QualType Ty, MultiExprArg ParamRef, - InitializationKind InitKind, InitializedEntity Entity) { - InitializationSequence InitSeq(SemaRef, Entity, InitKind, ParamRef); - InitSeq.Perform(SemaRef, Entity, InitKind, ParamRef); - InitListExpr *ILE = createInitListExpr(Ty, 1); - CollectionInitExprs.push_back(ILE); - VD->setInit(ILE); - Stmt *DS = new (SemaRef.Context) - DeclStmt(DeclGroupRef(VD), KernelCallerSrcLoc, KernelCallerSrcLoc); - BodyStmts.push_back(DS); - DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), - KernelCallerSrcLoc, VD, false, DeclarationNameInfo(), - Ty, VK_LValue); - } + // Creates a DeclRefExpr to the ParmVar that represents the current pointer + // field. + Expr *createPointerParamReferenceExpr(QualType PointerTy, bool Wrapped) { + ParmVarDecl *KernelParameter = + DeclCreator.getParamVarDeclsForCurrentField()[0]; - void addSimpleLocalInit(VarDecl *VD, QualType Ty) { - Expr *ParamRef = createParamReferenceExpr(); - addVarInit(VD, Ty, ParamRef); - } + QualType ParamType = KernelParameter->getOriginalType(); + Expr *DRE = SemaRef.BuildDeclRefExpr(KernelParameter, ParamType, VK_LValue, + KernelCallerSrcLoc); + DRE = ImplicitCastExpr::Create(SemaRef.Context, ParamType, + CK_LValueToRValue, DRE, /*BasePath=*/nullptr, + VK_PRValue, FPOptionsOverride()); - InitListExpr *createInitListExpr(QualType InitTy, uint64_t NumChildInits) { - InitListExpr *ILE = new (SemaRef.getASTContext()) InitListExpr( - SemaRef.getASTContext(), KernelCallerSrcLoc, {}, KernelCallerSrcLoc); - ILE->reserveInits(SemaRef.getASTContext(), NumChildInits); - ILE->setType(InitTy); + if (PointerTy->getPointeeType().getAddressSpace() != + ParamType->getPointeeType().getAddressSpace()) + DRE = ImplicitCastExpr::Create(SemaRef.Context, PointerTy, + CK_AddressSpaceConversion, DRE, nullptr, + VK_PRValue, FPOptionsOverride()); - return ILE; + return DRE; } - static VarDecl *createParamClone(ASTContext &Ctx, DeclContext *DC, - const ParmVarDecl *Param) { - IdentifierInfo *Ident = Param->getIdentifier(); - if (!Ident) - Ident = &Ctx.Idents.get("__SYCLParam"); - - VarDecl *VD = - VarDecl::Create(Ctx, DC, Param->getLocation(), Param->getLocation(), - Ident, QualType(Param->getType()), nullptr, SC_None); - VD->setIsUsed(); - return VD; + // For a free function such as: + // void f(int i, int* p, struct Simple S) { … } + // + // Keep the function as-is for the version callable from device code. + // void f(int i, int *p, struct Simple S) { … } + // + // For the host-callable kernel function generate this: + // void __free_function_f(int _arg_i, int* _arg_p, struct Simple _arg_S) + // { + // f(_arg_i, _arg_p, _arg_S); + // } + CompoundStmt *createFreeFunctionKernelBody() { + SemaRef.PushFunctionScope(); + Expr *Fn = SemaRef.BuildDeclRefExpr(FreeFunc, FreeFunc->getType(), + VK_PRValue, KernelCallerSrcLoc); + ASTContext &Context = SemaRef.getASTContext(); + QualType ResultTy = FreeFunc->getReturnType(); + ExprValueKind VK = Expr::getValueKindForType(ResultTy); + ResultTy = ResultTy.getNonLValueExprType(Context); + Fn = ImplicitCastExpr::Create(Context, + Context.getPointerType(FreeFunc->getType()), + CK_FunctionToPointerDecay, Fn, nullptr, + VK_PRValue, FPOptionsOverride()); + auto CallExpr = CallExpr::Create(Context, Fn, ArgExprs, ResultTy, VK, + KernelCallerSrcLoc, FPOptionsOverride()); + BodyStmts.push_back(CallExpr); + return CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, + {}); } - bool handleSpecialType(ParmVarDecl *PD, QualType Ty) { return true; } - public: static constexpr const bool VisitInsideSimpleContainers = false; FreeFunctionKernelBodyCreator(Sema &S, SyclKernelDeclCreator &DC, FunctionDecl *FF) : SyclKernelFieldHandler(S), DeclCreator(DC), FreeFunc(FF), - KernelCallerSrcLoc(FreeFunc->getLocation()) {} + KernelCallerSrcLoc(FF->getLocation()) {} ~FreeFunctionKernelBodyCreator() { CompoundStmt *KernelBody = createFreeFunctionKernelBody(); DeclCreator.setBody(KernelBody); } - bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { return true; } + bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { + // TODO + return true; + } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType Ty) final { + bool handleSyclSpecialType(ParmVarDecl *, QualType) final { + // TODO return true; } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType Ty) final { + // TODO return true; } - bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { return true; } + bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { + // TODO + return true; + } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + Expr *PointerRef = createPointerParamReferenceExpr(ParamTy, false); + ArgExprs.push_back(PointerRef); return true; } bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { + // TODO return true; } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + // TODO return true; } - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType Ty) final { - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - assert(RD && "Type must be a C++ record type"); - ParmVarDecl *NewPD = DeclCreator.getParamVarDeclsForCurrentField()[0]; - ParamMap[PD] = NewPD; + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, + QualType) final { + Expr *ParamRef = createParamReferenceExpr(); + ArgExprs.push_back(ParamRef); return true; } bool handleNonDecompStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) final { + // TODO return true; } - bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { return true; } + bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { + // TODO + return true; + } - bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + bool handleScalarType(ParmVarDecl *, QualType) final { + Expr *ParamRef = createParamReferenceExpr(); + ArgExprs.push_back(ParamRef); return true; } - bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return true; } + bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { + // TODO + return true; + } - bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - ParamMap[PD] = DeclCreator.getParamVarDeclsForCurrentField()[0]; + bool handleUnionType(ParmVarDecl *, QualType) final { + Expr *ParamRef = createParamReferenceExpr(); + ArgExprs.push_back(ParamRef); return true; } bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { + // TODO return true; } - bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType Ty) final { - ++StructDepth; + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + // TODO return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + // TODO return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - --StructDepth; + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + // TODO return true; } bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { + // TODO return true; } bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { + // TODO return true; } bool enterArray(FieldDecl *FD, QualType ArrayType, QualType ElementType) final { + // TODO return true; } bool enterArray(ParmVarDecl *PD, QualType ArrayType, QualType ElementType) final { + // TODO return true; } bool leaveArray(FieldDecl *FD, QualType ArrayType, QualType ElementType) final { + // TODO return true; } bool leaveArray(ParmVarDecl *PD, QualType ArrayType, QualType ElementType) final { + // TODO return true; } }; @@ -4461,17 +4310,18 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { // For free functions we increment the current offset as each parameter is // added. - void addParam(const ParmVarDecl *PD, QualType ArgTy, + void addParam(const ParmVarDecl *PD, QualType ParamTy, SYCLIntegrationHeader::kernel_param_kind_t Kind) { - addParam(ArgTy, Kind, offsetOf(PD, ArgTy)); + addParam(ParamTy, Kind, offsetOf(PD, ParamTy)); CurOffset += - SemaRef.getASTContext().getTypeSizeInChars(ArgTy).getQuantity(); + SemaRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); } - void addParam(QualType ArgTy, SYCLIntegrationHeader::kernel_param_kind_t Kind, + void addParam(QualType ParamTy, + SYCLIntegrationHeader::kernel_param_kind_t Kind, uint64_t OffsetAdj) { uint64_t Size; - Size = SemaRef.getASTContext().getTypeSizeInChars(ArgTy).getQuantity(); + Size = SemaRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); Header.addParamDesc(Kind, static_cast(Size), static_cast(CurOffset + OffsetAdj)); } @@ -4488,8 +4338,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { .getTypeSizeInChars(KernelObj->getTypeForDecl()) .getQuantity(); Header.startKernel(KernelFunc, NameType, KernelObj->getLocation(), IsESIMD, - IsSYCLUnnamedKernel(S, KernelFunc), - false /*IsFreeFunctionKernel*/, ObjSize); + IsSYCLUnnamedKernel(S, KernelFunc), ObjSize); } SyclKernelIntHeaderCreator(Sema &S, SYCLIntegrationHeader &H, int64_t ObjSize, @@ -4497,7 +4346,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { : SyclKernelFieldHandler(S), Header(H) { Header.startKernel(FreeFunc, NameType, FreeFunc->getLocation(), false /*IsESIMD*/, true /*IsSYCLUnnamedKernel*/, - true /*IsFreeFunctionKernel*/, ObjSize); + ObjSize); } bool handleSyclSpecialType(const CXXRecordDecl *RD, @@ -4553,7 +4402,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool handleSyclSpecialType(ParmVarDecl *PD, QualType FieldTy) final { + bool handleSyclSpecialType(ParmVarDecl *, QualType) final { // TODO return true; } @@ -4565,8 +4414,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool handlePointerType(ParmVarDecl *PD, QualType FieldTy) final { - addParam(PD, FieldTy, + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(PD, ParamTy, ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout : SYCLIntegrationHeader::kind_pointer)); return true; @@ -4577,8 +4426,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool handleScalarType(ParmVarDecl *PD, QualType FieldTy) final { - addParam(PD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); return true; } @@ -4596,8 +4445,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType Ty) final { - addParam(PD, Ty, SYCLIntegrationHeader::kind_std_layout); + QualType ParamTy) final { + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); return true; } @@ -4612,8 +4461,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return handleScalarType(FD, FieldTy); } - bool handleUnionType(ParmVarDecl *PD, QualType FieldTy) final { - return handleScalarType(PD, FieldTy); + bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { + return handleScalarType(PD, ParamTy); } void handleSyclKernelHandlerType(QualType Ty) { @@ -4633,9 +4482,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - ++StructDepth; - CurOffset += offsetOf(PD, Ty); + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + // TODO return true; } @@ -4645,9 +4493,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - --StructDepth; - CurOffset -= offsetOf(PD, Ty); + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + // TODO return true; } @@ -5098,8 +4945,7 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, IsSIMDKernel); SyclKernelDeclCreator kernel_decl(*this, KernelObj->getLocation(), KernelCallerFunc->isInlined(), IsSIMDKernel, - false /*IsFreeFunction*/, KernelCallerFunc, - getSyclIntegrationHeader()); + false /*IsFreeFunction*/, KernelCallerFunc); SyclKernelBodyCreator kernel_body(*this, kernel_decl, KernelObj, KernelCallerFunc, IsSIMDKernel, CallOperator); @@ -5142,9 +4988,9 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { SyclKernelArgsSizeChecker argsSizeChecker(SemaRef, FD->getLocation(), false /*IsSIMDKernel*/); - SyclKernelDeclCreator kernel_decl( - SemaRef, FD->getLocation(), FD->isInlined(), false /*IsSIMDKernel */, - true /*IsFreeFunction*/, FD, SemaRef.getSyclIntegrationHeader()); + SyclKernelDeclCreator kernel_decl(SemaRef, FD->getLocation(), FD->isInlined(), + false /*IsSIMDKernel */, + true /*IsFreeFunction*/, FD); FreeFunctionKernelBodyCreator kernel_body(SemaRef, kernel_decl, FD); @@ -5156,16 +5002,8 @@ void ConstructFreeFunctionKernel(Sema &SemaRef, FunctionDecl *FD) { SemaRef.getSyclIntegrationFooter()); KernelObjVisitor Visitor{SemaRef}; - // Visit handlers to generate information for optimization record only if - // optimization record is saved. - if (!SemaRef.getLangOpts().OptRecordFile.empty()) { - Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, - kernel_body, int_header, - int_footer /*,opt_report*/); - } else { - Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, - kernel_body, int_header, int_footer); - } + Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, + int_header, int_footer); }; // Figure out the sub-group for the this function. First we check the @@ -5452,7 +5290,6 @@ void Sema::MarkDevices() { void Sema::ProcessFreeFunction(FunctionDecl *FD) { if (IsFreeFunction(*this, FD)) { - SyclKernelDecompMarker DecompMarker(*this); SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); @@ -5461,8 +5298,7 @@ void Sema::ProcessFreeFunction(FunctionDecl *FD) { DiagnosingSYCLKernel = true; // Check parameters of free function. - Visitor.VisitFunctionParameters(FD, DecompMarker, FieldChecker, - UnionChecker); + Visitor.VisitFunctionParameters(FD, FieldChecker, UnionChecker); DiagnosingSYCLKernel = false; @@ -6321,13 +6157,13 @@ bool SYCLIntegrationHeader::emit(StringRef IntHeaderName) { return true; } -void SYCLIntegrationHeader::startKernel( - const FunctionDecl *SyclKernel, QualType KernelNameType, - SourceLocation KernelLocation, bool IsESIMDKernel, bool IsUnnamedKernel, - bool IsFreeFunctionKernel, int64_t ObjSize) { +void SYCLIntegrationHeader::startKernel(const FunctionDecl *SyclKernel, + QualType KernelNameType, + SourceLocation KernelLocation, + bool IsESIMDKernel, + bool IsUnnamedKernel, int64_t ObjSize) { KernelDescs.emplace_back(SyclKernel, KernelNameType, KernelLocation, - IsESIMDKernel, IsUnnamedKernel, IsFreeFunctionKernel, - ObjSize); + IsESIMDKernel, IsUnnamedKernel, ObjSize); } void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info, diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp new file mode 100755 index 0000000000000..54b14bb90651f --- /dev/null +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown -sycl-std=2020 -fsycl-int-header=%t.h %s -emit-llvm -o %t.ll +// RUN: FileCheck -input-file=%t.h %s +// +// This test checks integration header contents for free functions with scalar, +// pointer, simple struct parameters. + +#include "mock_properties.hpp" +#include "sycl.hpp" + +struct Simple { + int x; + char c[100]; + float f; +}; + +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] +void ff_2(int *ptr, int start, int end, struct Simple S) { + for (int i = start; i <= end; i++) + ptr[i] = start + S.x + S.f + S.c[2] + 66; +} +// CHECK: const char* const kernel_names[] = { +// CHECK-NEXT: "__free_function_ff_2" +// CHECK-NEXT: }; + + +// CHECK: const kernel_param_desc_t kernel_signatures[] = { +// CHECK-NEXT: //--- __free_function_ff_2 +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 108, 16 }, + +// CHECK: { kernel_param_kind_t::kind_invalid, -987654321, -987654321 }, +// CHECK-NEXT: }; diff --git a/clang/test/CodeGenSYCL/free_function_param_refs.cpp b/clang/test/CodeGenSYCL/free_function_param_refs.cpp deleted file mode 100755 index 6acbfc47305ae..0000000000000 --- a/clang/test/CodeGenSYCL/free_function_param_refs.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clang_cc1 -internal-isystem %S/Inputs -disable-llvm-passes \ -// RUN: -triple spir64-unknown-unknown -fsycl-is-device -S \ -// RUN: -emit-llvm %s -o - | FileCheck %s -// -// This test checks device code generation for free functions with scalar, -// pointer, simple struct and struct with pointer parameters. - -#include "mock_properties.hpp" -#include "sycl.hpp" - -struct Simple { - int x; - char c[100]; - float f; -}; - -// CHECK: %struct.Simple = type { i32, [100 x i8], float } - -__attribute__((sycl_device)) -[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int start, int end, struct Simple S) { - for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2] + 66; -} -// CHECK: spir_kernel void @__free_function_ff_2(ptr addrspace(1) {{.*}} %_arg_ptr, i32 noundef %_arg_start, i32 noundef %_arg_end, ptr noundef byval(%struct.Simple) align 4 %_arg_S) -// CHECK: store ptr addrspace(1) %_arg_ptr, ptr addrspace(4) %_arg_ptr.{{.*}} -// CHECK: store i32 %_arg_start, ptr addrspace(4) %_arg_start.{{.*}} -// CHECK: store i32 %_arg_end, ptr addrspace(4) %_arg_end.{{.*}} -// CHECK: %x = getelementptr inbounds %struct.Simple -// CHECK: %f = getelementptr inbounds %struct.Simple -// CHECK: %c = getelementptr inbounds %struct.Simple diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 1ef3c9c37332e..c5a80d1ad0fb4 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -24,6 +24,16 @@ void ff_2(int *ptr, int start, int end, struct Simple S) { // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int, struct Simple)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int, struct Simple)' Function {{.*}} 'ff_2' 'void (int *, int, int, struct Simple)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' +// CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '_arg_ptr' '__global int *' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_start' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_end' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'struct Simple':'Simple' ParmVar {{.*}} '_arg_S' 'struct Simple':'Simple' // Templated free function definition. @@ -43,3 +53,13 @@ template void ff_3(int* ptr, int start, int end, struct Simple S); // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CallExpr {{.*}} 'void' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int, struct Simple)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int, struct Simple)' Function {{.*}} 'ff_3' 'void (int *, int, int, struct Simple)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' +// CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '_arg_ptr' '__global int *' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_start' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_end' 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'struct Simple':'Simple' ParmVar {{.*}} '_arg_S' 'struct Simple':'Simple' From 8ec09f1133c9d2c706b063c14d750aa1ee3cabff Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 22 Apr 2024 16:50:32 -0700 Subject: [PATCH 27/52] Added error message for unsupported parameter types and minor cleanup. --- clang/lib/Sema/SemaSYCL.cpp | 98 +++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index adfa70b52e314..290b1c9bbde4d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -961,6 +961,12 @@ static ParamDesc makeParamDesc(ASTContext &Ctx, StringRef Name, QualType Ty) { Ctx.getTrivialTypeSourceInfo(Ty)); } +static void unsupportedFreeFunctionParamType() { + llvm::report_fatal_error( + "Only scalars, pointers and bit-wise copyable structs are permitted as " + "free function parameters"); +} + class MarkWIScopeFnVisitor : public RecursiveASTVisitor { public: MarkWIScopeFnVisitor(ASTContext &Ctx) : Ctx(Ctx) {} @@ -1061,20 +1067,13 @@ static target getAccessTarget(QualType FieldTy, } static bool IsFreeFunction(Sema &SemaRef, const FunctionDecl *FD) { - if (FD->hasAttr()) { - const auto &Attrs = FD->getAttrs(); - for (unsigned i = 0, e = Attrs.size(); i < e; i++) { - const SYCLAddIRAttributesFunctionAttr *AnAttr = - dyn_cast(Attrs[i]); - if (AnAttr) { - SmallVector, 4> NameValuePairs = - AnAttr->getAttributeNameValuePairs(SemaRef.Context); - for (const auto &NameValuePair : NameValuePairs) { - if (NameValuePair.first == "sycl-nd-range-kernel" || - NameValuePair.first == "sycl-single-task-kernel") - return true; - } - } + for (auto *IRAttr : FD->specific_attrs()) { + SmallVector, 4> NameValuePairs = + IRAttr->getAttributeNameValuePairs(SemaRef.Context); + for (const auto &NameValuePair : NameValuePairs) { + if (NameValuePair.first == "sycl-nd-range-kernel" || + NameValuePair.first == "sycl-single-task-kernel") + return true; } } return false; @@ -1926,6 +1925,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -1936,6 +1936,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { bool handleArrayType(ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -1987,11 +1988,13 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2057,6 +2060,7 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler { bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2097,6 +2101,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool handleSyclSpecialType(ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2107,6 +2112,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool handlePointerType(ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2118,6 +2124,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2146,6 +2153,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2187,6 +2195,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool enterArray(ParmVarDecl *, QualType ArrayTy, QualType ElementTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2215,6 +2224,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ElementTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } }; @@ -2330,6 +2340,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2350,6 +2361,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2395,6 +2407,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType ET) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2411,6 +2424,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2421,6 +2435,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2430,6 +2445,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2442,6 +2458,7 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2722,15 +2739,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { IsSIMDKernel)), FuncContext(SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); - if (SYCLKernel->hasAttr()) { - const auto &Attrs = SYCLKernel->getAttrs(); - for (unsigned i = 0, e = Attrs.size(); i < e; i++) { - const SYCLAddIRAttributesFunctionAttr *AnAttr = - dyn_cast(Attrs[i]); - if (AnAttr) { - KernelDecl->addAttr(AnAttr->clone(SemaRef.getASTContext())); - } - } + for (auto *IRAttr : + SYCLKernel->specific_attrs()) { + KernelDecl->addAttr(IRAttr->clone(SemaRef.getASTContext())); } } @@ -2764,6 +2775,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2774,6 +2786,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2825,6 +2838,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4040,15 +4054,15 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { removeFieldMemberExpr(FD, ArrayType); return true; } - using SyclKernelFieldHandler::handleSyclSpecialType; - using SyclKernelFieldHandler::handlePointerType; + using SyclKernelFieldHandler::enterArray; + using SyclKernelFieldHandler::enterStruct; using SyclKernelFieldHandler::handleNonDecompStruct; + using SyclKernelFieldHandler::handlePointerType; using SyclKernelFieldHandler::handleScalarType; + using SyclKernelFieldHandler::handleSyclSpecialType; using SyclKernelFieldHandler::handleUnionType; - using SyclKernelFieldHandler::enterStruct; - using SyclKernelFieldHandler::leaveStruct; - using SyclKernelFieldHandler::enterArray; using SyclKernelFieldHandler::leaveArray; + using SyclKernelFieldHandler::leaveStruct; }; class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { @@ -4056,7 +4070,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { llvm::SmallVector BodyStmts; FunctionDecl *FreeFunc; SourceLocation KernelCallerSrcLoc; // KernelCallerFunc source location. - llvm::SmallVector ArgExprs; + llvm::SmallVector ArgExprs; // Creates a DeclRefExpr to the ParmVar that represents the current field. Expr *createParamReferenceExpr() { @@ -4093,7 +4107,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // For a free function such as: // void f(int i, int* p, struct Simple S) { … } - // + // // Keep the function as-is for the version callable from device code. // void f(int i, int *p, struct Simple S) { … } // @@ -4136,22 +4150,26 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool handleSyclSpecialType(ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType Ty) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4163,12 +4181,14 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4182,11 +4202,13 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType Ty) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4198,6 +4220,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4209,57 +4232,67 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool enterArray(FieldDecl *FD, QualType ArrayType, QualType ElementType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool enterArray(ParmVarDecl *PD, QualType ArrayType, QualType ElementType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveArray(FieldDecl *FD, QualType ArrayType, QualType ElementType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveArray(ParmVarDecl *PD, QualType ArrayType, QualType ElementType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } }; @@ -4404,6 +4437,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4484,6 +4518,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4495,6 +4530,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4517,6 +4553,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool enterArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4534,6 +4571,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool leaveArray(ParmVarDecl *PD, QualType ArrayTy, QualType) final { // TODO + unsupportedFreeFunctionParamType(); return true; } From bca0d2508fde6880fde600d553ddc4c66efaa6a7 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 22 Apr 2024 17:17:47 -0700 Subject: [PATCH 28/52] Corrected diagnosing of unsupported parameter types. --- clang/lib/Sema/SemaSYCL.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 290b1c9bbde4d..01b575af29c77 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -35,7 +35,6 @@ #include #include #include -#include using namespace clang; using namespace std::placeholders; @@ -1987,14 +1986,14 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + // Define this function to prevent diagnostic about hidden overloaded + // virtual function. return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + // Define this function to prevent diagnostic about hidden overloaded + // virtual function. return true; } From 5b742943709bd0b112628e1f72058df8316084d4 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 23 Apr 2024 20:36:50 -0700 Subject: [PATCH 29/52] Removed support for simple structs because checking that a struct is simple is not fully implemented yet. --- clang/lib/Sema/SemaSYCL.cpp | 51 ++++++------------- .../CodeGenSYCL/free_function_int_header.cpp | 11 +--- .../SemaSYCL/free_function_kernel_params.cpp | 34 +++++-------- .../free_function_kernels.cpp | 46 +++++------------ 4 files changed, 41 insertions(+), 101 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 01b575af29c77..8722b781dfef5 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -961,9 +961,8 @@ static ParamDesc makeParamDesc(ASTContext &Ctx, StringRef Name, QualType Ty) { } static void unsupportedFreeFunctionParamType() { - llvm::report_fatal_error( - "Only scalars, pointers and bit-wise copyable structs are permitted as " - "free function parameters"); + llvm::report_fatal_error("Only scalars and pointers are permitted as " + "free function parameters"); } class MarkWIScopeFnVisitor : public RecursiveASTVisitor { @@ -1755,21 +1754,6 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { return false; } - bool checkNotCopyableToKernel(const ParmVarDecl *PD, QualType ParamTy) { - if (ParamTy->isArrayType()) { - if (const auto *CAT = - SemaRef.getASTContext().getAsConstantArrayType(ParamTy)) { - QualType ET = CAT->getElementType(); - return checkNotCopyableToKernel(PD, ET); - } - return Diag.Report(PD->getLocation(), - diag::err_sycl_non_constant_array_type) - << ParamTy; - } - - return false; - } - bool checkPropertyListType(TemplateArgument PropList, SourceLocation Loc) { if (PropList.getKind() != TemplateArgument::ArgKind::Type) return SemaRef.Diag( @@ -1898,16 +1882,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleStructType(ParmVarDecl *PD, QualType ParamTy) final { - IsInvalid |= checkNotCopyableToKernel(PD, ParamTy); - CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); - assert(RD && "Not a RecordDecl inside the handler for struct type"); - if (RD->isLambda()) { - for (const LambdaCapture &LC : RD->captures()) - if (LC.capturesThis() && LC.isImplicit()) { - SemaRef.Diag(LC.getLocation(), diag::err_implicit_this_capture); - IsInvalid = true; - } - } + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; + IsInvalid = true; return isValid(); } @@ -1923,9 +1899,9 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; + IsInvalid = true; + return isValid(); } bool handleArrayType(FieldDecl *FD, QualType FieldTy) final { @@ -1934,9 +1910,9 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleArrayType(ParmVarDecl *PD, QualType ParamTy) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; + Diag.Report(PD->getLocation(), diag::err_bad_kernel_param_type) << ParamTy; + IsInvalid = true; + return isValid(); } bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { @@ -2039,7 +2015,8 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler { } bool enterUnion(const CXXRecordDecl *, ParmVarDecl *) override { - ++UnionCount; + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2049,7 +2026,8 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler { } bool leaveUnion(const CXXRecordDecl *, ParmVarDecl *) override { - --UnionCount; + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2518,6 +2496,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { makeParamDesc(SemaRef.getASTContext(), Name, ParamTy); addParam(newParamDesc, ParamTy); } + // Add a parameter with specified name and type void addParam(StringRef Name, QualType ParamTy) { ParamDesc newParamDesc = diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 54b14bb90651f..fb984d3223a38 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -7,17 +7,11 @@ #include "mock_properties.hpp" #include "sycl.hpp" -struct Simple { - int x; - char c[100]; - float f; -}; - __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int start, int end, struct Simple S) { +void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2] + 66; + ptr[i] = start + 66; } // CHECK: const char* const kernel_names[] = { // CHECK-NEXT: "__free_function_ff_2" @@ -29,7 +23,6 @@ void ff_2(int *ptr, int start, int end, struct Simple S) { // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 108, 16 }, // CHECK: { kernel_param_kind_t::kind_invalid, -987654321, -987654321 }, // CHECK-NEXT: }; diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index c5a80d1ad0fb4..471d6257cfbf4 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -2,64 +2,54 @@ // RUN: %s -o - | FileCheck %s // UNSUPPORTED: system-windows // This test checks parameter rewriting for free functions with parameters -// of type scalar, pointer, simple struct and struct with pointers. +// of type scalar and pointer. // Windows support will be added later. #include "sycl.hpp" -struct Simple { - int x; - char c[100]; - float f; -}; - __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void ff_2(int *ptr, int start, int end, struct Simple S) { +void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2]; + ptr[i] = start; } -// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int, struct Simple)' +// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CallExpr {{.*}} 'void' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int, struct Simple)' -// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int, struct Simple)' Function {{.*}} 'ff_2' 'void (int *, int, int, struct Simple)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' Function {{.*}} 'ff_2' 'void (int *, int, int)' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' // CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' // CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '_arg_ptr' '__global int *' // CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_start' 'int' // CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_end' 'int' -// CHECK-NEXT: DeclRefExpr {{.*}} 'struct Simple':'Simple' ParmVar {{.*}} '_arg_S' 'struct Simple':'Simple' // Templated free function definition. template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] - void ff_3(T* ptr, T start, int end, struct Simple S) { + void ff_3(T* ptr, T start, int end) { for (int i = start; i <= end; i++) - ptr[i] = start + S.x + S.f + S.c[2]; + ptr[i] = start; } // Explicit instantiation with �int*� -template void ff_3(int* ptr, int start, int end, struct Simple S); +template void ff_3(int* ptr, int start, int end); -// CHECK: FunctionDecl {{.*}} __free_function_Z4ff_3IiEvPT_S0_i6Simple 'void (__global int *, int, int, struct Simple)' +// CHECK: FunctionDecl {{.*}} __free_function_Z4ff_3IiEvPT_S0_i 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_S 'struct Simple':'Simple' // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CallExpr {{.*}} 'void' -// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int, struct Simple)' -// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int, struct Simple)' Function {{.*}} 'ff_3' 'void (int *, int, int, struct Simple)' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' Function {{.*}} 'ff_3' 'void (int *, int, int)' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' // CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' // CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '_arg_ptr' '__global int *' // CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_start' 'int' // CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_end' 'int' -// CHECK-NEXT: DeclRefExpr {{.*}} 'struct Simple':'Simple' ParmVar {{.*}} '_arg_S' 'struct Simple':'Simple' diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 566c6e5d3b34d..443dfbd6b2f6e 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -43,12 +43,6 @@ class KernelFinder { } }; -struct Simple { - int x; - char c[100]; - float f; -}; - void printUSM(int *usmPtr, int size) { std::cout << "usmPtr[] = {"; for (int i = 0; i < size; i++) { @@ -137,9 +131,6 @@ bool test_1(queue Queue, KernelFinder &KF) { constexpr int Range = 10; int *usmPtr = malloc_shared(Range, Queue); int start = 3; - struct Simple S { - 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 - }; int Result[Range] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; nd_range<1> R1{{Range}, {1}}; @@ -173,24 +164,20 @@ bool test_1(queue Queue, KernelFinder &KF) { SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<2>)) -void ff_2(int *ptr, int start, struct Simple S) { +void ff_2(int *ptr, int start) { int(&ptr2D)[4][4] = *reinterpret_cast(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) + start + S.x + S.f + S.c[2]; + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + start; } bool test_2(queue Queue, KernelFinder &KF) { constexpr int Range = 16; int *usmPtr = malloc_shared(Range, Queue); int value = 55; - struct Simple S { - 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 - }; - int Result[Range] = {130, 131, 130, 131, 131, 132, 131, 132, - 130, 131, 130, 131, 131, 132, 131, 132}; + 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)); @@ -199,8 +186,7 @@ bool test_2(queue Queue, KernelFinder &KF) { 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 + S.x + S.f + S.c[2]; + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + value; }); }); Queue.wait(); @@ -212,7 +198,6 @@ bool test_2(queue Queue, KernelFinder &KF) { Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); Handler.set_arg(1, value); - Handler.set_arg(2, S); Handler.parallel_for(R2, Kernel); }); Queue.wait(); @@ -226,28 +211,23 @@ bool test_2(queue Queue, KernelFinder &KF) { // Templated free function definition. template SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( - ext::oneapi::experimental::nd_range_kernel<2>)) void ff_3(T *ptr, T start, - struct Simple S) { + ext::oneapi::experimental::nd_range_kernel<2>)) void ff_3(T *ptr, T start) { int(&ptr2D)[4][4] = *reinterpret_cast(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) + start + S.x + S.f + S.c[2]; + ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + start; } // Explicit instantiation with �int*� -template void ff_3(int *ptr, int start, struct Simple S); +template void ff_3(int *ptr, int start); bool test_3(queue Queue, KernelFinder &KF) { constexpr int Range = 16; int *usmPtr = malloc_shared(Range, Queue); int value = 55; - struct Simple S { - 66, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 7.1 - }; - int Result[Range] = {130, 131, 130, 131, 131, 132, 131, 132, - 130, 131, 130, 131, 131, 132, 131, 132}; + 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)); @@ -256,20 +236,18 @@ bool test_3(queue Queue, KernelFinder &KF) { 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 + S.x + S.f + S.c[2]; + 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 3a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__free_function_Z4ff_3IiEvPT_S0_6Simple"); + kernel Kernel = KF.get_kernel("__free_function_Z4ff_3IiEvPT_S0_"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); Handler.set_arg(1, value); - Handler.set_arg(2, S); Handler.parallel_for(R2, Kernel); }); Queue.wait(); From 73a4392d7e0bcddd1bcc0a0d27da7b824c2dc21b Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 23 Apr 2024 20:43:42 -0700 Subject: [PATCH 30/52] Fixed unintended format corrections. --- clang/lib/Sema/SemaSYCL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 8722b781dfef5..9481f943caf8d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1325,16 +1325,16 @@ class KernelObjVisitor { template void visitFirstArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, - QualType ElementTy, HandlerTys &...Handlers) { + QualType ElementTy, HandlerTys &... Handlers) { visitArrayElementImpl(Owner, ArrayField, ElementTy, 0, Handlers...); } template void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &...Handlers); + HandlerTys &... Handlers); template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType ArrayTy, HandlerTys &...Handlers) { + QualType ArrayTy, HandlerTys &... Handlers) { (void)std::initializer_list{ (Handlers.handleSimpleArrayType(Field, ArrayTy), 0)...}; } From c35ec7f82a6927dd6cea52ec4372806f446bf0b1 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 23 Apr 2024 23:31:27 -0700 Subject: [PATCH 31/52] Formatting changes. --- clang/include/clang/Sema/SemaSYCL.h | 2 +- clang/lib/Sema/SemaSYCL.cpp | 2 +- sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 85e38138f47a4..6bec0ad1f87bd 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -318,7 +318,7 @@ class SemaSYCL : public SemaBase { void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC); void SetSYCLKernelNames(); void MarkDevices(); - void ProcessFreeFunction(FunctionDecl* FD); + void ProcessFreeFunction(FunctionDecl *FD); /// Get the number of fields or captures within the parsed type. ExprResult ActOnSYCLBuiltinNumFieldsExpr(ParsedType PT); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index acdff427995e8..7aba24c5362b0 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1341,7 +1341,7 @@ class KernelObjVisitor { template void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &... Handlers); + HandlerTys &...Handlers); template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, QualType ArrayTy, HandlerTys &... Handlers) { diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 443dfbd6b2f6e..a8d208bcb93b4 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -9,7 +9,7 @@ using namespace sycl; -// Kernel finder +// Kernel finder. class KernelFinder { queue &Queue; std::vector AllKernelIDs; @@ -219,7 +219,7 @@ SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY(( ptr2D[GId.get(0)][GId.get(1)] = LId.get(0) + LId.get(1) + start; } -// Explicit instantiation with �int*� +// Explicit instantiation with �int*�. template void ff_3(int *ptr, int start); bool test_3(queue Queue, KernelFinder &KF) { From 6e87103dd1c60da7c2208005e3c385d8aaea2f48 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Wed, 24 Apr 2024 15:09:39 -0700 Subject: [PATCH 32/52] Removed some more unneeded code, now that structs will be supported later. --- clang/lib/Sema/SemaSYCL.cpp | 122 ++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 7aba24c5362b0..cb41a51aa6d01 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1075,7 +1075,7 @@ static target getAccessTarget(QualType FieldTy, AccTy->getTemplateArgs()[3].getAsIntegral().getExtValue()); } -static bool IsFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { +static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { for (auto *IRAttr : FD->specific_attrs()) { SmallVector, 4> NameValuePairs = IRAttr->getAttributeNameValuePairs(SemaSYCLRef.getASTContext()); @@ -1341,7 +1341,8 @@ class KernelObjVisitor { template void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField, QualType ElementTy, uint64_t Index, - HandlerTys &...Handlers); + HandlerTys &... Handlers); + template void visitSimpleArray(const CXXRecordDecl *Owner, FieldDecl *Field, QualType ArrayTy, HandlerTys &... Handlers) { @@ -1413,17 +1414,11 @@ class KernelObjVisitor { HandlerTys &...Handlers) { if (isSyclSpecialType(ParamTy, SemaSYCLRef)) KP_FOR_EACH(handleOtherType, Param, ParamTy); - else if (ParamTy->isStructureOrClassType()) { - if (KP_FOR_EACH(handleStructType, Param, ParamTy)) { - CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); - visitRecord(nullptr, Param, RD, ParamTy, Handlers...); - } - } else if (ParamTy->isUnionType()) { - if (KP_FOR_EACH(handleUnionType, Param, ParamTy)) { - CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); - VisitUnion(nullptr, Param, RD, Handlers...); - } - } else if (ParamTy->isReferenceType()) + else if (ParamTy->isStructureOrClassType()) + KP_FOR_EACH(handleOtherType, Param, ParamTy); + else if (ParamTy->isUnionType()) + KP_FOR_EACH(handleOtherType, Param, ParamTy); + else if (ParamTy->isReferenceType()) KP_FOR_EACH(handleOtherType, Param, ParamTy); else if (ParamTy->isPointerType()) KP_FOR_EACH(handlePointerType, Param, ParamTy); @@ -1972,14 +1967,14 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // Define this function to prevent diagnostic about hidden overloaded - // virtual function. + // TODO + unsupportedFreeFunctionParamType(); return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // Define this function to prevent diagnostic about hidden overloaded - // virtual function. + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2908,10 +2903,8 @@ 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"); - addParam(PD, ParamTy); + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -2934,7 +2927,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { - return handleScalarType(PD, ParamTy); + // TODO + unsupportedFreeFunctionParamType(); + return true; } // Generate kernel argument to initialize specialization constants. @@ -3089,7 +3084,9 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { - return handleSpecialType(ParamTy); + // TODO + unsupportedFreeFunctionParamType(); + return true; } bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, @@ -3130,7 +3127,8 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { - addParam(ParamTy); + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -3145,7 +3143,9 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { } bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { - return handleScalarType(PD, ParamTy); + // TODO + unsupportedFreeFunctionParamType(); + return true; } }; @@ -4077,35 +4077,38 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SyclKernelDeclCreator &DeclCreator; llvm::SmallVector BodyStmts; FunctionDecl *FreeFunc; - SourceLocation KernelCallerSrcLoc; // KernelCallerFunc source location. + SourceLocation FreeFunctionSrcLoc; // Free function source location. llvm::SmallVector ArgExprs; - // Creates a DeclRefExpr to the ParmVar that represents the current field. + // Creates a DeclRefExpr to the ParmVar that represents the current free + // function parameter. Expr *createParamReferenceExpr() { - ParmVarDecl *KernelParameter = + ParmVarDecl *FreeFunctionParameter = DeclCreator.getParamVarDeclsForCurrentField()[0]; - QualType ParamType = KernelParameter->getOriginalType(); + QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - KernelParameter, ParamType, VK_PRValue, KernelCallerSrcLoc); + FreeFunctionParameter, FreeFunctionParamType, VK_PRValue, + FreeFunctionSrcLoc); return DRE; } // Creates a DeclRefExpr to the ParmVar that represents the current pointer - // field. + // parameter. Expr *createPointerParamReferenceExpr(QualType PointerTy, bool Wrapped) { - ParmVarDecl *KernelParameter = + ParmVarDecl *FreeFunctionParameter = DeclCreator.getParamVarDeclsForCurrentField()[0]; - QualType ParamType = KernelParameter->getOriginalType(); + QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - KernelParameter, ParamType, VK_LValue, KernelCallerSrcLoc); - DRE = ImplicitCastExpr::Create(SemaSYCLRef.getASTContext(), ParamType, - CK_LValueToRValue, DRE, /*BasePath=*/nullptr, - VK_PRValue, FPOptionsOverride()); + FreeFunctionParameter, FreeFunctionParamType, VK_LValue, + FreeFunctionSrcLoc); + DRE = ImplicitCastExpr::Create( + SemaSYCLRef.getASTContext(), FreeFunctionParamType, CK_LValueToRValue, + DRE, /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride()); if (PointerTy->getPointeeType().getAddressSpace() != - ParamType->getPointeeType().getAddressSpace()) + FreeFunctionParamType->getPointeeType().getAddressSpace()) DRE = ImplicitCastExpr::Create(SemaSYCLRef.getASTContext(), PointerTy, CK_AddressSpaceConversion, DRE, nullptr, VK_PRValue, FPOptionsOverride()); @@ -4127,7 +4130,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { CompoundStmt *createFreeFunctionKernelBody() { SemaSYCLRef.SemaRef.PushFunctionScope(); Expr *Fn = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - FreeFunc, FreeFunc->getType(), VK_PRValue, KernelCallerSrcLoc); + FreeFunc, FreeFunc->getType(), VK_PRValue, FreeFunctionSrcLoc); ASTContext &Context = SemaSYCLRef.getASTContext(); QualType ResultTy = FreeFunc->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultTy); @@ -4137,7 +4140,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { CK_FunctionToPointerDecay, Fn, nullptr, VK_PRValue, FPOptionsOverride()); auto CallExpr = CallExpr::Create(Context, Fn, ArgExprs, ResultTy, VK, - KernelCallerSrcLoc, FPOptionsOverride()); + FreeFunctionSrcLoc, FPOptionsOverride()); BodyStmts.push_back(CallExpr); return CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, {}); @@ -4149,7 +4152,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { FreeFunctionKernelBodyCreator(SemaSYCL &S, SyclKernelDeclCreator &DC, FunctionDecl *FF) : SyclKernelFieldHandler(S), DeclCreator(DC), FreeFunc(FF), - KernelCallerSrcLoc(FF->getLocation()) {} + FreeFunctionSrcLoc(FF->getLocation()) {} ~FreeFunctionKernelBodyCreator() { CompoundStmt *KernelBody = createFreeFunctionKernelBody(); @@ -4202,8 +4205,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - Expr *ParamRef = createParamReferenceExpr(); - ArgExprs.push_back(ParamRef); + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4233,8 +4236,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool handleUnionType(ParmVarDecl *, QualType) final { - Expr *ParamRef = createParamReferenceExpr(); - ArgExprs.push_back(ParamRef); + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4310,7 +4313,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // functor type. static bool IsSYCLUnnamedKernel(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { // If free function then remaining checks are not applicable. - if (IsFreeFunction(SemaSYCLRef, FD)) + if (isFreeFunction(SemaSYCLRef, FD)) return false; if (!SemaSYCLRef.getLangOpts().SYCLUnnamedLambda) @@ -4385,12 +4388,11 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } SyclKernelIntHeaderCreator(SemaSYCL &S, SYCLIntegrationHeader &H, - int64_t ObjSize, QualType NameType, - FunctionDecl *FreeFunc) + QualType NameType, FunctionDecl *FreeFunc) : SyclKernelFieldHandler(S), Header(H) { Header.startKernel(FreeFunc, NameType, FreeFunc->getLocation(), false /*IsESIMD*/, true /*IsSYCLUnnamedKernel*/, - ObjSize); + 0 /*ObjSize*/); } bool handleSyclSpecialType(const CXXRecordDecl *RD, @@ -4460,9 +4462,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { - addParam(PD, ParamTy, - ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout - : SYCLIntegrationHeader::kind_pointer)); + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_pointer); return true; } @@ -4491,7 +4491,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); + // TODO + unsupportedFreeFunctionParamType(); return true; } @@ -4507,7 +4508,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handleUnionType(ParmVarDecl *PD, QualType ParamTy) final { - return handleScalarType(PD, ParamTy); + // TODO + unsupportedFreeFunctionParamType(); + return true; } void handleSyclKernelHandlerType(QualType Ty) { @@ -4913,7 +4916,7 @@ void SemaSYCL::SetSYCLKernelNames() { for (const std::pair &Pair : SyclKernelsToOpenCLKernels) { std::string CalculatedName, StableName; - if (IsFreeFunction(*this, Pair.first)) + if (isFreeFunction(*this, Pair.first)) std::tie(CalculatedName, StableName) = constructFreeFunctionKernelName(*this, Pair.first, *MangleCtx); else @@ -4994,6 +4997,7 @@ void SemaSYCL::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, IsSIMDKernel); ESIMDKernelDiagnostics esimdKernel(*this, KernelObj->getLocation(), IsSIMDKernel); + SyclKernelDeclCreator kernel_decl(*this, KernelObj->getLocation(), KernelCallerFunc->isInlined(), IsSIMDKernel, false /*IsFreeFunction*/, KernelCallerFunc); @@ -5046,10 +5050,8 @@ void ConstructFreeFunctionKernel(SemaSYCL &SemaSYCLRef, FunctionDecl *FD) { FreeFunctionKernelBodyCreator kernel_body(SemaSYCLRef, kernel_decl, FD); - // Kernel object size is irrelevant, so set to 0. - SyclKernelIntHeaderCreator int_header(SemaSYCLRef, - SemaSYCLRef.getSyclIntegrationHeader(), - 0, FD->getType(), FD); + SyclKernelIntHeaderCreator int_header( + SemaSYCLRef, SemaSYCLRef.getSyclIntegrationHeader(), FD->getType(), FD); SyclKernelIntFooterCreator int_footer(SemaSYCLRef, SemaSYCLRef.getSyclIntegrationFooter()); @@ -5342,7 +5344,7 @@ void SemaSYCL::MarkDevices() { } void SemaSYCL::ProcessFreeFunction(FunctionDecl *FD) { - if (IsFreeFunction(*this, FD)) { + if (isFreeFunction(*this, FD)) { SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); From 703b7cbd6f3a900922c2e5d18449974e9ea436e9 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 25 Apr 2024 13:26:09 -0700 Subject: [PATCH 33/52] Added lvalue to rvalue casts. --- clang/lib/Sema/SemaSYCL.cpp | 14 ++++---- .../SemaSYCL/free_function_kernel_params.cpp | 32 +++++++++++-------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index cb41a51aa6d01..2fdb6714f588c 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -955,13 +955,13 @@ class KernelBodyTransform : public TreeTransform { /// \return the constructed descriptor static ParamDesc makeParamDesc(const FieldDecl *Src, QualType Ty) { ASTContext &Ctx = Src->getASTContext(); - std::string Name = (Twine("_arg_") + Src->getName()).str(); + std::string Name = (Twine("__arg_") + Src->getName()).str(); return std::make_tuple(Ty, &Ctx.Idents.get(Name), Ctx.getTrivialTypeSourceInfo(Ty)); } static ParamDesc makeParamDesc(const ParmVarDecl *Src, QualType Ty) { ASTContext &Ctx = Src->getASTContext(); - std::string Name = (Twine("_arg_") + Src->getName()).str(); + std::string Name = (Twine("__arg_") + Src->getName()).str(); return std::make_tuple(Ty, &Ctx.Idents.get(Name), Ctx.getTrivialTypeSourceInfo(Ty)); } @@ -3422,7 +3422,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addScopeAttrToLocalVars(*CallOperator); } } - + // Creates a DeclRefExpr to the ParmVar that represents the current field. Expr *createParamReferenceExpr() { ParmVarDecl *KernelParameter = @@ -4088,8 +4088,9 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - FreeFunctionParameter, FreeFunctionParamType, VK_PRValue, + FreeFunctionParameter, FreeFunctionParamType, VK_LValue, FreeFunctionSrcLoc); + DRE = SemaSYCLRef.SemaRef.DefaultLvalueConversion(DRE).get(); return DRE; } @@ -4103,16 +4104,13 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( FreeFunctionParameter, FreeFunctionParamType, VK_LValue, FreeFunctionSrcLoc); - DRE = ImplicitCastExpr::Create( - SemaSYCLRef.getASTContext(), FreeFunctionParamType, CK_LValueToRValue, - DRE, /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride()); + DRE = SemaSYCLRef.SemaRef.DefaultLvalueConversion(DRE).get(); if (PointerTy->getPointeeType().getAddressSpace() != FreeFunctionParamType->getPointeeType().getAddressSpace()) DRE = ImplicitCastExpr::Create(SemaSYCLRef.getASTContext(), PointerTy, CK_AddressSpaceConversion, DRE, nullptr, VK_PRValue, FPOptionsOverride()); - return DRE; } diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 471d6257cfbf4..9f6e88fcb9990 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -14,18 +14,20 @@ void ff_2(int *ptr, int start, int end) { ptr[i] = start; } // CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int)' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' +// CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' Function {{.*}} 'ff_2' 'void (int *, int, int)' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' -// CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' -// CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '_arg_ptr' '__global int *' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_start' 'int' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_end' 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' +// CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '__arg_ptr' '__global int *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_start' 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_end' 'int' // Templated free function definition. @@ -41,15 +43,17 @@ __attribute__((sycl_device)) template void ff_3(int* ptr, int start, int end); // CHECK: FunctionDecl {{.*}} __free_function_Z4ff_3IiEvPT_S0_i 'void (__global int *, int, int)' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_ptr '__global int *' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_start 'int' -// CHECK-NEXT: ParmVarDecl {{.*}} _arg_end 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' +// CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' +// CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int)' // CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' Function {{.*}} 'ff_3' 'void (int *, int, int)' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' -// CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' -// CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '_arg_ptr' '__global int *' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_start' 'int' -// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} '_arg_end' 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' +// CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '__arg_ptr' '__global int *' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_start' 'int' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' +// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} '__arg_end' 'int' From 7b0ae9718dda969fe42c68274ac004586c1b0ee1 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 25 Apr 2024 13:32:58 -0700 Subject: [PATCH 34/52] Formatting change. --- clang/lib/Sema/SemaSYCL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 2fdb6714f588c..5530a662bb2ce 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -3422,7 +3422,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addScopeAttrToLocalVars(*CallOperator); } } - + // Creates a DeclRefExpr to the ParmVar that represents the current field. Expr *createParamReferenceExpr() { ParmVarDecl *KernelParameter = From d20fa731fe6fb2df649a6bf560bbeb06bf4d2007 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 25 Apr 2024 13:45:34 -0700 Subject: [PATCH 35/52] Formatting change. --- clang/lib/Sema/SemaSYCL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 5530a662bb2ce..94b64f55ce51d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -3422,7 +3422,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addScopeAttrToLocalVars(*CallOperator); } } - + // Creates a DeclRefExpr to the ParmVar that represents the current field. Expr *createParamReferenceExpr() { ParmVarDecl *KernelParameter = From e0f8470fff59e1c41c602d06bafc57d93d8553fd Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Thu, 25 Apr 2024 16:05:26 -0700 Subject: [PATCH 36/52] Reverted an argument name change that is not a part of this PR. --- clang/lib/Sema/SemaSYCL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 94b64f55ce51d..64d88c29a0f76 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -955,7 +955,7 @@ class KernelBodyTransform : public TreeTransform { /// \return the constructed descriptor static ParamDesc makeParamDesc(const FieldDecl *Src, QualType Ty) { ASTContext &Ctx = Src->getASTContext(); - std::string Name = (Twine("__arg_") + Src->getName()).str(); + std::string Name = (Twine("_arg_") + Src->getName()).str(); return std::make_tuple(Ty, &Ctx.Idents.get(Name), Ctx.getTrivialTypeSourceInfo(Ty)); } From 10d27eee622c2522457646bce2287eebbdfd4fe3 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 29 Apr 2024 18:03:30 -0700 Subject: [PATCH 37/52] Changed name of free function kernel. --- clang/lib/Sema/SemaSYCL.cpp | 49 ++++++++++++++++--- .../CodeGenSYCL/free_function_int_header.cpp | 4 +- .../SemaSYCL/free_function_kernel_params.cpp | 4 +- .../free_function_kernels.cpp | 8 +-- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 64d88c29a0f76..1aa6a113953b0 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1090,12 +1090,15 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { static std::string constructFFKernelName(const FunctionDecl *FD) { IdentifierInfo *Id = FD->getIdentifier(); - std::string NewIdent = (Twine("__free_function_") + Id->getName()).str(); + std::string NewIdent = (Twine("__sycl_kernel_") + Id->getName()).str(); return NewIdent; } -// Gets a name for the free function kernel function. The suffix allows a normal -// device function to coexist with the kernel function. +// Creates a name for the free function kernel function. +// Non-templated functions get a simple __sycl_kernel_ prefix. +// For templated functions we add __sycl_kernel_ to the original function name +// and then use the mangled name as the kernel name. The renaming allows a +// normal device function to coexist with the kernel function. static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; @@ -1104,8 +1107,38 @@ static std::pair constructFreeFunctionKernelName( std::string StableName; if (FreeFunc->getTemplateSpecializationArgs()) { - MC.mangleName(FreeFunc, Out); - MangledName = (Twine("__free_function") + Out.str()).str(); + ASTContext &Ctx = SemaSYCLRef.getASTContext(); + FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); + QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); + std::string FFName = + (Twine("__sycl_kernel_") + FreeFunc->getIdentifier()->getName()).str(); + const IdentifierInfo *FFIdent = &Ctx.Idents.get(FFName); + FunctionDecl *NewFD = FunctionDecl::Create( + Ctx, Ctx.getTranslationUnitDecl(), {}, {}, DeclarationName(FFIdent), + FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); + llvm::SmallVector Params; + for (ParmVarDecl *Param : FreeFunc->parameters()) { + QualType Ty = Param->getType(); + ParamDesc newParamDesc = + std::make_tuple(Ty, &Ctx.Idents.get(Param->getName()), + Ctx.getTrivialTypeSourceInfo(Ty)); + auto *NewParam = ParmVarDecl::Create( + Ctx, NewFD, SourceLocation(), SourceLocation(), + std::get<1>(newParamDesc), std::get<0>(newParamDesc), + std::get<2>(newParamDesc), SC_None, /*DefArg*/ nullptr); + NewParam->setScopeInfo(0, Params.size()); + NewParam->setIsUsed(); + Params.push_back(NewParam); + } + SmallVector ArgTys; + std::transform(std::begin(Params), std::end(Params), + std::back_inserter(ArgTys), + [](const ParmVarDecl *PVD) { return PVD->getType(); }); + FuncType = Ctx.getFunctionType(Ctx.VoidTy, ArgTys, Info); + NewFD->setType(FuncType); + NewFD->setParams(Params); + MC.mangleName(NewFD, Out); + MangledName = Out.str(); } else { MangledName = constructFFKernelName(FreeFunc); } @@ -4115,13 +4148,13 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } // For a free function such as: - // void f(int i, int* p, struct Simple S) { … } + // void f(int i, int* p, struct Simple S) { ... } // // Keep the function as-is for the version callable from device code. - // void f(int i, int *p, struct Simple S) { … } + // void f(int i, int *p, struct Simple S) { ... } // // For the host-callable kernel function generate this: - // void __free_function_f(int _arg_i, int* _arg_p, struct Simple _arg_S) + // void __sycl_kernel_f(int _arg_i, int* _arg_p, struct Simple _arg_S) // { // f(_arg_i, _arg_p, _arg_S); // } diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index fb984d3223a38..cd28363d900b2 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -14,12 +14,12 @@ void ff_2(int *ptr, int start, int end) { ptr[i] = start + 66; } // CHECK: const char* const kernel_names[] = { -// CHECK-NEXT: "__free_function_ff_2" +// CHECK-NEXT: "__sycl_kernel_ff_2" // CHECK-NEXT: }; // CHECK: const kernel_param_desc_t kernel_signatures[] = { -// CHECK-NEXT: //--- __free_function_ff_2 +// CHECK-NEXT: //--- __sycl_kernel_ff_2 // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 9f6e88fcb9990..a93292a5532c2 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -13,7 +13,7 @@ void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) ptr[i] = start; } -// CHECK: FunctionDecl {{.*}} __free_function_ff_2 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}} __sycl_kernel_ff_2 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' @@ -42,7 +42,7 @@ __attribute__((sycl_device)) // Explicit instantiation with �int*� template void ff_3(int* ptr, int start, int end); -// CHECK: FunctionDecl {{.*}} __free_function_Z4ff_3IiEvPT_S0_i 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_3Piii 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index a8d208bcb93b4..675661efd95b2 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -102,7 +102,7 @@ bool test_0(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 0a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__free_function_ff_0"); + kernel Kernel = KF.get_kernel("__sycl_kernel_ff_0"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -145,7 +145,7 @@ bool test_1(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 1a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__free_function_ff_1"); + kernel Kernel = KF.get_kernel("__sycl_kernel_ff_1"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -193,7 +193,7 @@ bool test_2(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 2a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__free_function_ff_2"); + kernel Kernel = KF.get_kernel("__sycl_kernel_ff_2"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -243,7 +243,7 @@ bool test_3(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 3a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__free_function_Z4ff_3IiEvPT_S0_"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_3Pii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); From 9c0ee62d909d4a3463158e0cba4cdf9e621b39ec Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 30 Apr 2024 21:45:24 -0700 Subject: [PATCH 38/52] Correction to how function-address is taken. --- clang/lib/Sema/SemaSYCL.cpp | 6 +++--- clang/test/SemaSYCL/free_function_kernel_params.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 36705f285cc31..c6c72622f228e 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4153,14 +4153,14 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // void f(int i, int *p, struct Simple S) { ... } // // For the host-callable kernel function generate this: - // void __sycl_kernel_f(int _arg_i, int* _arg_p, struct Simple _arg_S) + // void __sycl_kernel_f(int __arg_i, int* __arg_p, struct Simple __arg_S) // { - // f(_arg_i, _arg_p, _arg_S); + // f(__arg_i, __arg_p, __arg_S); // } CompoundStmt *createFreeFunctionKernelBody() { SemaSYCLRef.SemaRef.PushFunctionScope(); Expr *Fn = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - FreeFunc, FreeFunc->getType(), VK_PRValue, FreeFunctionSrcLoc); + FreeFunc, FreeFunc->getType(), VK_LValue, FreeFunctionSrcLoc); ASTContext &Context = SemaSYCLRef.getASTContext(); QualType ResultTy = FreeFunc->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultTy); diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index a93292a5532c2..a034796771500 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -20,7 +20,7 @@ void ff_2(int *ptr, int start, int end) { // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int)' -// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' Function {{.*}} 'ff_2' 'void (int *, int, int)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' lvalue Function {{.*}} 'ff_2' 'void (int *, int, int)' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' // CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' // CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '__arg_ptr' '__global int *' @@ -49,7 +49,7 @@ template void ff_3(int* ptr, int start, int end); // CHECK-NEXT: CompoundStmt // CHECK-NEXT: CallExpr {{.*}} 'void' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(int *, int, int)' -// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' Function {{.*}} 'ff_3' 'void (int *, int, int)' +// CHECK-NEXT: DeclRefExpr {{.*}} 'void (int *, int, int)' lvalue Function {{.*}} 'ff_3' 'void (int *, int, int)' // CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' // CHECK-NEXT: ImplicitCastExpr {{.*}} '__global int *' // CHECK-NEXT: DeclRefExpr {{.*}} '__global int *' lvalue ParmVar {{.*}} '__arg_ptr' '__global int *' From cc44aafca2f786b00a5078b3268179e11fbd06d0 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Wed, 1 May 2024 08:51:26 -0700 Subject: [PATCH 39/52] Changed kernel naming to account for non-templated but overloaded functions. --- clang/lib/Sema/SemaSYCL.cpp | 73 +++++++++---------- .../CodeGenSYCL/free_function_int_header.cpp | 4 +- .../SemaSYCL/free_function_kernel_params.cpp | 2 +- .../free_function_kernels.cpp | 10 ++- 4 files changed, 43 insertions(+), 46 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c6c72622f228e..5d62b2e68571e 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1095,10 +1095,9 @@ static std::string constructFFKernelName(const FunctionDecl *FD) { } // Creates a name for the free function kernel function. -// Non-templated functions get a simple __sycl_kernel_ prefix. -// For templated functions we add __sycl_kernel_ to the original function name -// and then use the mangled name as the kernel name. The renaming allows a -// normal device function to coexist with the kernel function. +// We add __sycl_kernel_ to the original function name and then use the mangled +// name as the kernel name. The renaming allows a normal device function to +// coexist with the kernel function. static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; @@ -1106,42 +1105,38 @@ static std::pair constructFreeFunctionKernelName( std::string MangledName; std::string StableName; - if (FreeFunc->getTemplateSpecializationArgs()) { - ASTContext &Ctx = SemaSYCLRef.getASTContext(); - FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); - QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); - std::string FFName = - (Twine("__sycl_kernel_") + FreeFunc->getIdentifier()->getName()).str(); - const IdentifierInfo *FFIdent = &Ctx.Idents.get(FFName); - FunctionDecl *NewFD = FunctionDecl::Create( - Ctx, Ctx.getTranslationUnitDecl(), {}, {}, DeclarationName(FFIdent), - FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); - llvm::SmallVector Params; - for (ParmVarDecl *Param : FreeFunc->parameters()) { - QualType Ty = Param->getType(); - ParamDesc newParamDesc = - std::make_tuple(Ty, &Ctx.Idents.get(Param->getName()), - Ctx.getTrivialTypeSourceInfo(Ty)); - auto *NewParam = ParmVarDecl::Create( - Ctx, NewFD, SourceLocation(), SourceLocation(), - std::get<1>(newParamDesc), std::get<0>(newParamDesc), - std::get<2>(newParamDesc), SC_None, /*DefArg*/ nullptr); - NewParam->setScopeInfo(0, Params.size()); - NewParam->setIsUsed(); - Params.push_back(NewParam); - } - SmallVector ArgTys; - std::transform(std::begin(Params), std::end(Params), - std::back_inserter(ArgTys), - [](const ParmVarDecl *PVD) { return PVD->getType(); }); - FuncType = Ctx.getFunctionType(Ctx.VoidTy, ArgTys, Info); - NewFD->setType(FuncType); - NewFD->setParams(Params); - MC.mangleName(NewFD, Out); - MangledName = Out.str(); - } else { - MangledName = constructFFKernelName(FreeFunc); + ASTContext &Ctx = SemaSYCLRef.getASTContext(); + FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); + QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); + std::string FFName = + (Twine("__sycl_kernel_") + FreeFunc->getIdentifier()->getName()).str(); + const IdentifierInfo *FFIdent = &Ctx.Idents.get(FFName); + FunctionDecl *NewFD = FunctionDecl::Create( + Ctx, Ctx.getTranslationUnitDecl(), {}, {}, DeclarationName(FFIdent), + FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); + llvm::SmallVector Params; + for (ParmVarDecl *Param : FreeFunc->parameters()) { + QualType Ty = Param->getType(); + ParamDesc newParamDesc = + std::make_tuple(Ty, &Ctx.Idents.get(Param->getName()), + Ctx.getTrivialTypeSourceInfo(Ty)); + auto *NewParam = ParmVarDecl::Create( + Ctx, NewFD, SourceLocation(), SourceLocation(), + std::get<1>(newParamDesc), std::get<0>(newParamDesc), + std::get<2>(newParamDesc), SC_None, /*DefArg*/ nullptr); + NewParam->setScopeInfo(0, Params.size()); + NewParam->setIsUsed(); + Params.push_back(NewParam); } + SmallVector ArgTys; + std::transform(std::begin(Params), std::end(Params), + std::back_inserter(ArgTys), + [](const ParmVarDecl *PVD) { return PVD->getType(); }); + FuncType = Ctx.getFunctionType(Ctx.VoidTy, ArgTys, Info); + NewFD->setType(FuncType); + NewFD->setParams(Params); + MC.mangleName(NewFD, Out); + MangledName = Out.str(); StableName = MangledName; return {MangledName, StableName}; } diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index cd28363d900b2..7623a087840d9 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -14,12 +14,12 @@ void ff_2(int *ptr, int start, int end) { ptr[i] = start + 66; } // CHECK: const char* const kernel_names[] = { -// CHECK-NEXT: "__sycl_kernel_ff_2" +// CHECK-NEXT: "_Z18__sycl_kernel_ff_2Piii" // CHECK-NEXT: }; // CHECK: const kernel_param_desc_t kernel_signatures[] = { -// CHECK-NEXT: //--- __sycl_kernel_ff_2 +// CHECK-NEXT: //--- _Z18__sycl_kernel_ff_2Piii // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index a034796771500..969bb8ce323e4 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -13,7 +13,7 @@ void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) ptr[i] = start; } -// CHECK: FunctionDecl {{.*}} __sycl_kernel_ff_2 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_2Piii 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 675661efd95b2..f148cfb61ce0f 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -102,7 +102,7 @@ bool test_0(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 0a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__sycl_kernel_ff_0"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_0Piii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -118,6 +118,7 @@ bool test_0(queue Queue, KernelFinder &KF) { return PassA && PassB; } +// Overloaded free function definition. SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<1>)) @@ -145,7 +146,7 @@ bool test_1(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 1a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__sycl_kernel_ff_1"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_1Piii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -161,10 +162,11 @@ bool test_1(queue Queue, KernelFinder &KF) { return PassA && PassB; } +// Overloaded free function definition. SYCL_EXTERNAL SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<2>)) -void ff_2(int *ptr, int start) { +void ff_1(int *ptr, int start) { int(&ptr2D)[4][4] = *reinterpret_cast(ptr); nd_item<2> Item = ext::oneapi::this_work_item::get_nd_item<2>(); id<2> GId = Item.get_global_id(); @@ -193,7 +195,7 @@ bool test_2(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 2a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("__sycl_kernel_ff_2"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_1Pii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); From e186994a419287f44d601e98083f243a5e29c32e Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Wed, 1 May 2024 13:56:56 -0700 Subject: [PATCH 40/52] Restored a line that had been accidentally deleted. --- clang/lib/Sema/SemaSYCL.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 5d62b2e68571e..6b0f26a140bbe 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1901,6 +1901,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleStructType(FieldDecl *FD, QualType FieldTy) final { + IsInvalid |= checkNotCopyableToKernel(FD, FieldTy); CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl(); assert(RD && "Not a RecordDecl inside the handler for struct type"); if (RD->isLambda()) { From 567987059bff3f337c47a5ce3e417c09cbc44c24 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Fri, 3 May 2024 13:24:47 -0700 Subject: [PATCH 41/52] Removed some more unneeded code. --- clang/lib/Sema/SemaSYCL.cpp | 33 +--------------- .../CodeGenSYCL/free_function_int_header.cpp | 38 ++++++++++++++----- .../SemaSYCL/free_function_kernel_params.cpp | 6 +-- 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 6b0f26a140bbe..b1abb4b3eeeae 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1088,12 +1088,6 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { return false; } -static std::string constructFFKernelName(const FunctionDecl *FD) { - IdentifierInfo *Id = FD->getIdentifier(); - std::string NewIdent = (Twine("__sycl_kernel_") + Id->getName()).str(); - return NewIdent; -} - // Creates a name for the free function kernel function. // We add __sycl_kernel_ to the original function name and then use the mangled // name as the kernel name. The renaming allows a normal device function to @@ -1901,7 +1895,6 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool handleStructType(FieldDecl *FD, QualType FieldTy) final { - IsInvalid |= checkNotCopyableToKernel(FD, FieldTy); CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl(); assert(RD && "Not a RecordDecl inside the handler for struct type"); if (RD->isLambda()) { @@ -2691,25 +2684,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return FD; } - static FunctionDecl *createFreeFunctionDecl(ASTContext &Ctx, FunctionDecl *FD, - SourceLocation Loc, - bool IsInline) { - // Create this with no prototype, and we can fix this up after we've seen - // all the params. - FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); - QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); - const IdentifierInfo *NewIdent = &Ctx.Idents.get(constructFFKernelName(FD)); - FD = FunctionDecl::Create( - Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), - FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); - FD->setImplicitlyInline(IsInline); - setKernelImplicitAttrs(Ctx, FD, false); - - // Add kernel to translation unit to see it in AST-dump. - Ctx.getTranslationUnitDecl()->addDecl(FD); - return FD; - } - // If the record has been marked with SYCLGenerateNewTypeAttr, // it implies that it contains a pointer within. This function // defines a PointerHandler visitor which visits this record @@ -2743,11 +2717,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool IsSIMDKernel, bool IsFreeFunction, FunctionDecl *SYCLKernel) : SyclKernelFieldHandler(S), IsFreeFunction(IsFreeFunction), - KernelDecl(IsFreeFunction - ? createFreeFunctionDecl(S.getASTContext(), SYCLKernel, - Loc, IsInline) - : createKernelDecl(S.getASTContext(), Loc, IsInline, - IsSIMDKernel)), + KernelDecl( + createKernelDecl(S.getASTContext(), Loc, IsInline, IsSIMDKernel)), FuncContext(SemaSYCLRef.SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); for (auto *IRAttr : diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 7623a087840d9..02595ad3130ac 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -1,28 +1,48 @@ -// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown -sycl-std=2020 -fsycl-int-header=%t.h %s -emit-llvm -o %t.ll +// 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, -// pointer, simple struct parameters. +// This test checks integration header contents for free functions with scalar +// and pointer parameters. #include "mock_properties.hpp" #include "sycl.hpp" __attribute__((sycl_device)) -[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] -void ff_2(int *ptr, int start, int end) { +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", + 2)]] void +ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) ptr[i] = start + 66; } + +template +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 2)]] void +ff_3(T *ptr, T start, int end) { + for (int i = start; i <= end; i++) + ptr[i] = start; +} + +// Explicit instantiation with "int*" +template void ff_3(int *ptr, int start, int end); + // CHECK: const char* const kernel_names[] = { -// CHECK-NEXT: "_Z18__sycl_kernel_ff_2Piii" +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2{{.*}} +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3{{.*}} +// C HECK-NEXT: "_Z18__sycl_kernel_ff_2Piii", +// C HECK-NEXT: "_Z18__sycl_kernel_ff_3Piii" // CHECK-NEXT: }; - // CHECK: const kernel_param_desc_t kernel_signatures[] = { -// CHECK-NEXT: //--- _Z18__sycl_kernel_ff_2Piii +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2{{.*}} +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, + +// CHECK: {{.*}}__sycl_kernel_ff_3{{.*}} // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, // CHECK: { kernel_param_kind_t::kind_invalid, -987654321, -987654321 }, -// CHECK-NEXT: }; +// CHECK-NEXT: }; \ No newline at end of file diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 969bb8ce323e4..8c5285452d78f 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -13,7 +13,7 @@ void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) ptr[i] = start; } -// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_2Piii 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}}__sycl_kernel_ff_2{{.*}} 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' @@ -39,10 +39,10 @@ __attribute__((sycl_device)) ptr[i] = start; } -// Explicit instantiation with �int*� +// Explicit instantiation with "int*" template void ff_3(int* ptr, int start, int end); -// CHECK: FunctionDecl {{.*}} _Z18__sycl_kernel_ff_3Piii 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}}__sycl_kernel_ff_3{{.*}} 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' From 8044a18f46ef41c542ce159eda88838a49b33382 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Sat, 4 May 2024 17:34:35 -0700 Subject: [PATCH 42/52] Minor changes. --- clang/lib/Sema/SemaSYCL.cpp | 13 +++-- .../CodeGenSYCL/free_function_int_header.cpp | 58 ++++++++++++++++--- .../SemaSYCL/free_function_kernel_params.cpp | 7 ++- .../free_function_kernels.cpp | 6 +- 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b1abb4b3eeeae..efaceb209fbbb 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1106,8 +1106,9 @@ static std::pair constructFreeFunctionKernelName( (Twine("__sycl_kernel_") + FreeFunc->getIdentifier()->getName()).str(); const IdentifierInfo *FFIdent = &Ctx.Idents.get(FFName); FunctionDecl *NewFD = FunctionDecl::Create( - Ctx, Ctx.getTranslationUnitDecl(), {}, {}, DeclarationName(FFIdent), - FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); + Ctx, const_cast(FreeFunc->getDeclContext()), {}, {}, + DeclarationName(FFIdent), FuncType, + Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); llvm::SmallVector Params; for (ParmVarDecl *Param : FreeFunc->parameters()) { QualType Ty = Param->getType(); @@ -2494,8 +2495,8 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { // A type to Create and own the FunctionDecl for the kernel. class SyclKernelDeclCreator : public SyclKernelFieldHandler { - bool IsFreeFunction; - FunctionDecl *KernelDecl; + bool IsFreeFunction = false; + FunctionDecl *KernelDecl = nullptr; llvm::SmallVector Params; Sema::ContextRAII FuncContext; // Holds the last handled field's first parameter. This doesn't store an @@ -2721,7 +2722,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { createKernelDecl(S.getASTContext(), Loc, IsInline, IsSIMDKernel)), FuncContext(SemaSYCLRef.SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); - for (auto *IRAttr : + for (const auto *IRAttr : SYCLKernel->specific_attrs()) { KernelDecl->addAttr(IRAttr->clone(SemaSYCLRef.getASTContext())); } @@ -4075,7 +4076,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SyclKernelDeclCreator &DeclCreator; llvm::SmallVector BodyStmts; - FunctionDecl *FreeFunc; + FunctionDecl *FreeFunc = nullptr; SourceLocation FreeFunctionSrcLoc; // Free function source location. llvm::SmallVector ArgExprs; diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 02595ad3130ac..af198f2d87d56 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -4,9 +4,15 @@ // This test checks integration header contents for free functions with scalar // and pointer parameters. +// The names of kernels depend on the host OS name mangling scheme. This test +// will be adjusted to account for Linux/Windows name mangling differences in +// the future. For now we check only on Linux. +// UNSUPPORTED: system-windows + #include "mock_properties.hpp" #include "sycl.hpp" +// First overload of function ff_2. __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 2)]] void @@ -15,34 +21,70 @@ ff_2(int *ptr, int start, int end) { ptr[i] = start + 66; } +// Second overload of function ff_2. +__attribute__((sycl_device)) +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", + 2)]] void + ff_2(int* ptr, int start, int end, int value) { + for (int i = start; i <= end; i++) + ptr[i] = start + value; +} + +// Templated definition of function ff_3. template __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-nd-range-kernel", 2)]] void -ff_3(T *ptr, T start, int end) { +ff_3(T *ptr, T start, T end) { for (int i = start; i <= end; i++) ptr[i] = start; } -// Explicit instantiation with "int*" +// Explicit instantiation of ff_3 with int type. template void ff_3(int *ptr, int start, int end); +// Explicit instantiation of ff_3 with float type. +template void ff_3(float* ptr, float start, float end); + +// Specialization of ff_3 with double type. +template <> void ff_3(double *ptr, double start, double end) { + for (int i = start; i <= end; i++) + ptr[i] = end; +} + // CHECK: const char* const kernel_names[] = { -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2{{.*}} -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3{{.*}} -// C HECK-NEXT: "_Z18__sycl_kernel_ff_2Piii", -// C HECK-NEXT: "_Z18__sycl_kernel_ff_3Piii" +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piiii +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3Piii +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3Pfff +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3Pddd // CHECK-NEXT: }; // CHECK: const kernel_param_desc_t kernel_signatures[] = { -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2{{.*}} +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}__sycl_kernel_ff_3{{.*}} +// CHECK: {{.*}}__sycl_kernel_ff_2Piiii // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 16 }, + +// CHECK: {{.*}}__sycl_kernel_ff_3Piii +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, + +// CHECK: {{.*}}__sycl_kernel_ff_3Pfff +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, + +// CHECK: {{.*}}__sycl_kernel_ff_3Pddd +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 8 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 16 }, // CHECK: { kernel_param_kind_t::kind_invalid, -987654321, -987654321 }, // CHECK-NEXT: }; \ No newline at end of file diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 8c5285452d78f..d657602c7aed4 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -1,9 +1,12 @@ // RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -ast-dump \ // RUN: %s -o - | FileCheck %s -// UNSUPPORTED: system-windows // This test checks parameter rewriting for free functions with parameters // of type scalar and pointer. -// Windows support will be added later. + +// The names of kernels depend on the host OS name mangling scheme. This test +// will be adjusted to account for Linux/Windows name mangling differences in +// the future. For now we check only on Linux. +// UNSUPPORTED: system-windows #include "sycl.hpp" diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index f148cfb61ce0f..87a00f81f13c0 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -1,9 +1,13 @@ // RUN: %{build} -o %t.out // RUN: %{run} %t.out -// UNSUPPORTED: hip // This test tests free function kernel code generation and execution. +// The names of kernels depend on the host OS name mangling scheme. This test +// will be adjusted to account for Linux/Windows name mangling differences in +// the future. For now we check only on Linux. +// UNSUPPORTED: system-windows + #include #include From fbf72b077aa23815f80df5d0e9e74e38e7f1f150 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Sat, 4 May 2024 23:54:43 -0700 Subject: [PATCH 43/52] Added dependency in a test on USM shared allocations. --- sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 87a00f81f13c0..ef448e17ce5a4 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -1,3 +1,4 @@ +// REQUIRES: aspect-usm_shared_allocations // RUN: %{build} -o %t.out // RUN: %{run} %t.out From 5ecceea299f2be49c5202b653e24dc1100fed535 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Mon, 6 May 2024 15:30:06 -0700 Subject: [PATCH 44/52] Now using a string manipulation scheme to generate the free function kernel name. --- clang/lib/Sema/SemaSYCL.cpp | 49 +++++-------------- .../CodeGenSYCL/free_function_int_header.cpp | 17 +++---- .../SemaSYCL/free_function_kernel_params.cpp | 5 -- .../free_function_kernels.cpp | 7 +-- 4 files changed, 20 insertions(+), 58 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index efaceb209fbbb..a86544c4ea310 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -36,6 +36,7 @@ #include #include #include +#include using namespace clang; using namespace std::placeholders; @@ -1096,44 +1097,20 @@ static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; llvm::raw_svector_ostream Out(Result); - std::string MangledName; std::string StableName; - ASTContext &Ctx = SemaSYCLRef.getASTContext(); - FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); - QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); - std::string FFName = - (Twine("__sycl_kernel_") + FreeFunc->getIdentifier()->getName()).str(); - const IdentifierInfo *FFIdent = &Ctx.Idents.get(FFName); - FunctionDecl *NewFD = FunctionDecl::Create( - Ctx, const_cast(FreeFunc->getDeclContext()), {}, {}, - DeclarationName(FFIdent), FuncType, - Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); - llvm::SmallVector Params; - for (ParmVarDecl *Param : FreeFunc->parameters()) { - QualType Ty = Param->getType(); - ParamDesc newParamDesc = - std::make_tuple(Ty, &Ctx.Idents.get(Param->getName()), - Ctx.getTrivialTypeSourceInfo(Ty)); - auto *NewParam = ParmVarDecl::Create( - Ctx, NewFD, SourceLocation(), SourceLocation(), - std::get<1>(newParamDesc), std::get<0>(newParamDesc), - std::get<2>(newParamDesc), SC_None, /*DefArg*/ nullptr); - NewParam->setScopeInfo(0, Params.size()); - NewParam->setIsUsed(); - Params.push_back(NewParam); - } - SmallVector ArgTys; - std::transform(std::begin(Params), std::end(Params), - std::back_inserter(ArgTys), - [](const ParmVarDecl *PVD) { return PVD->getType(); }); - FuncType = Ctx.getFunctionType(Ctx.VoidTy, ArgTys, Info); - NewFD->setType(FuncType); - NewFD->setParams(Params); - MC.mangleName(NewFD, Out); - MangledName = Out.str(); - StableName = MangledName; - return {MangledName, StableName}; + MC.mangleName(FreeFunc, Out); + std::string MangledName(Out.str()); + size_t StartNums = MangledName.find_first_of("0123456789"); + size_t EndNums = MangledName.find_first_not_of("0123456789", StartNums); + size_t NameLength = + std::stoi(MangledName.substr(StartNums, EndNums - StartNums)); + size_t NewNameLength = 14 /*length of __sycl_kernel_*/ + NameLength; + std::string NewName = MangledName.substr(0, StartNums) + + std::to_string(NewNameLength) + "__sycl_kernel_" + + MangledName.substr(EndNums); + StableName = NewName; + return {NewName, StableName}; } // The first template argument to the kernel caller function is used to identify diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index af198f2d87d56..9cc154086f6ef 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -4,11 +4,6 @@ // This test checks integration header contents for free functions with scalar // and pointer parameters. -// The names of kernels depend on the host OS name mangling scheme. This test -// will be adjusted to account for Linux/Windows name mangling differences in -// the future. For now we check only on Linux. -// UNSUPPORTED: system-windows - #include "mock_properties.hpp" #include "sycl.hpp" @@ -54,9 +49,9 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK: const char* const kernel_names[] = { // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piiii -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3Piii -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3Pfff -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_3Pddd +// 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: }; // CHECK: const kernel_param_desc_t kernel_signatures[] = { @@ -71,17 +66,17 @@ template <> void ff_3(double *ptr, double start, double end) { // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 16 }, -// CHECK: {{.*}}__sycl_kernel_ff_3Piii +// CHECK: {{.*}}__sycl_kernel_ff_3IiEvPT_S0_S0_ // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}__sycl_kernel_ff_3Pfff +// CHECK: {{.*}}__sycl_kernel_ff_3IfEvPT_S0_S0_ // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}__sycl_kernel_ff_3Pddd +// CHECK: {{.*}}__sycl_kernel_ff_3IdEvPT_S0_S0_ // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 16 }, diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index d657602c7aed4..ab2bf28300a05 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -3,11 +3,6 @@ // This test checks parameter rewriting for free functions with parameters // of type scalar and pointer. -// The names of kernels depend on the host OS name mangling scheme. This test -// will be adjusted to account for Linux/Windows name mangling differences in -// the future. For now we check only on Linux. -// UNSUPPORTED: system-windows - #include "sycl.hpp" __attribute__((sycl_device)) diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index ef448e17ce5a4..80385472cc4e3 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -4,11 +4,6 @@ // This test tests free function kernel code generation and execution. -// The names of kernels depend on the host OS name mangling scheme. This test -// will be adjusted to account for Linux/Windows name mangling differences in -// the future. For now we check only on Linux. -// UNSUPPORTED: system-windows - #include #include @@ -250,7 +245,7 @@ bool test_3(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 3a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_3Pii"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_3IiEvPT_S0_"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); From 5e62a60c61a1eb5e00ebd6ea879a91c139615c6f Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 7 May 2024 13:52:00 -0700 Subject: [PATCH 45/52] Correction to test for windows. --- 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 ab2bf28300a05..902f7f8517ab8 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -ast-dump \ -// RUN: %s -o - | FileCheck %s +// RUN: %clang -fsycl-device-only -Xclang -ast-dump %s | FileCheck %s + // This test checks parameter rewriting for free functions with parameters // of type scalar and pointer. From 81b529decea1ee47205e722fbc89cb5b7cdbbaef Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 7 May 2024 14:14:37 -0700 Subject: [PATCH 46/52] Removed unneeded #include. --- 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 a86544c4ea310..e698a3a4f65c1 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -36,7 +36,6 @@ #include #include #include -#include using namespace clang; using namespace std::placeholders; From a3cc69014b5dbede9f896d92da383d38cce8481e Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Fri, 10 May 2024 09:45:25 -0700 Subject: [PATCH 47/52] Minor changes. --- clang/lib/Sema/SemaSYCL.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e698a3a4f65c1..5179a9eb2a9c8 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1092,6 +1092,11 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { // We add __sycl_kernel_ to the original function name and then use the mangled // name as the kernel name. The renaming allows a normal device function to // coexist with the kernel function. +// FIXME: Free functions are allowed only at file scope currently, thus there +// are no namespace prefixes to the function name. That is why the number +// following _Z is the length of the function name. In the future, namespaces +// will be allowed and then this function will be modified to ensure a unique +// name is constructed for the free function kernel. static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; @@ -4286,10 +4291,6 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // the first template argument has been corrected by the library to match the // functor type. static bool IsSYCLUnnamedKernel(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { - // If free function then remaining checks are not applicable. - if (isFreeFunction(SemaSYCLRef, FD)) - return false; - if (!SemaSYCLRef.getLangOpts().SYCLUnnamedLambda) return false; @@ -4890,14 +4891,17 @@ void SemaSYCL::SetSYCLKernelNames() { for (const std::pair &Pair : SyclKernelsToOpenCLKernels) { std::string CalculatedName, StableName; - if (isFreeFunction(*this, Pair.first)) + StringRef KernelName; + if (isFreeFunction(*this, Pair.first)) { std::tie(CalculatedName, StableName) = constructFreeFunctionKernelName(*this, Pair.first, *MangleCtx); - else + KernelName = CalculatedName; + } else { std::tie(CalculatedName, StableName) = constructKernelName(*this, Pair.first, *MangleCtx); - StringRef KernelName( - IsSYCLUnnamedKernel(*this, Pair.first) ? StableName : CalculatedName); + KernelName = + IsSYCLUnnamedKernel(*this, Pair.first) ? StableName : CalculatedName; + } getSyclIntegrationHeader().updateKernelNames(Pair.first, KernelName, StableName); From c38c74e2daa818435b0e22d4c06cbe7ffaa90297 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Sat, 11 May 2024 14:37:31 -0700 Subject: [PATCH 48/52] Changed kernel naming scheme. --- clang/lib/Sema/SemaSYCL.cpp | 48 ++++++++++++------- .../CodeGenSYCL/free_function_int_header.cpp | 20 ++++---- .../SemaSYCL/free_function_kernel_params.cpp | 4 +- .../free_function_kernels.cpp | 8 ++-- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 5179a9eb2a9c8..ebdbdd447052b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1089,14 +1089,9 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { } // Creates a name for the free function kernel function. -// We add __sycl_kernel_ to the original function name and then use the mangled -// name as the kernel name. The renaming allows a normal device function to -// coexist with the kernel function. -// FIXME: Free functions are allowed only at file scope currently, thus there -// are no namespace prefixes to the function name. That is why the number -// following _Z is the length of the function name. In the future, namespaces -// will be allowed and then this function will be modified to ensure a unique -// name is constructed for the free function kernel. +// We add .sycl_kernel to the original function name and use it's mangled name +// as the kernel name. The renaming allows a normal device function to coexist +// with the kernel function. static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; @@ -1105,14 +1100,7 @@ static std::pair constructFreeFunctionKernelName( MC.mangleName(FreeFunc, Out); std::string MangledName(Out.str()); - size_t StartNums = MangledName.find_first_of("0123456789"); - size_t EndNums = MangledName.find_first_not_of("0123456789", StartNums); - size_t NameLength = - std::stoi(MangledName.substr(StartNums, EndNums - StartNums)); - size_t NewNameLength = 14 /*length of __sycl_kernel_*/ + NameLength; - std::string NewName = MangledName.substr(0, StartNums) + - std::to_string(NewNameLength) + "__sycl_kernel_" + - MangledName.substr(EndNums); + std::string NewName = MangledName + ".sycl_kernel"; StableName = NewName; return {NewName, StableName}; } @@ -2666,6 +2654,27 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return FD; } + static FunctionDecl *createFreeFunctionDecl(ASTContext &Ctx, FunctionDecl *FD, + SourceLocation Loc, + bool IsInline) { + // Create this with no prototype, and we can fix this up after we've seen + // all the params. + FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); + QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); + IdentifierInfo *Id = FD->getIdentifier(); + std::string NewName = (Id->getName() + Twine(".sycl_kernel")).str(); + const IdentifierInfo *NewIdent = &Ctx.Idents.get(NewName); + FD = FunctionDecl::Create( + Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), + FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); + FD->setImplicitlyInline(IsInline); + setKernelImplicitAttrs(Ctx, FD, false); + + // Add kernel to translation unit to see it in AST-dump. + Ctx.getTranslationUnitDecl()->addDecl(FD); + return FD; + } + // If the record has been marked with SYCLGenerateNewTypeAttr, // it implies that it contains a pointer within. This function // defines a PointerHandler visitor which visits this record @@ -2699,8 +2708,11 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool IsSIMDKernel, bool IsFreeFunction, FunctionDecl *SYCLKernel) : SyclKernelFieldHandler(S), IsFreeFunction(IsFreeFunction), - KernelDecl( - createKernelDecl(S.getASTContext(), Loc, IsInline, IsSIMDKernel)), + KernelDecl(IsFreeFunction + ? createFreeFunctionDecl(S.getASTContext(), SYCLKernel, + Loc, IsInline) + : createKernelDecl(S.getASTContext(), Loc, IsInline, + IsSIMDKernel)), FuncContext(SemaSYCLRef.SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); for (const auto *IRAttr : diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 9cc154086f6ef..325a47740997d 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -47,36 +47,36 @@ template <> void ff_3(double *ptr, double start, double end) { } // 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: {{.*}}ff_2Piii.sycl_kernel +// CHECK-NEXT: {{.*}}ff_2Piiii.sycl_kernel +// CHECK-NEXT: {{.*}}ff_3IiEvPT_S0_S0_.sycl_kernel +// CHECK-NEXT: {{.*}}ff_3IfEvPT_S0_S0_.sycl_kernel +// CHECK-NEXT: {{.*}}ff_3IdEvPT_S0_S0_.sycl_kernel // CHECK-NEXT: }; // CHECK: const kernel_param_desc_t kernel_signatures[] = { -// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii +// CHECK-NEXT: {{.*}}ff_2Piii.sycl_kernel // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}__sycl_kernel_ff_2Piiii +// CHECK: {{.*}}ff_2Piiii.sycl_kernel // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 16 }, -// CHECK: {{.*}}__sycl_kernel_ff_3IiEvPT_S0_S0_ +// CHECK: {{.*}}ff_3IiEvPT_S0_S0_.sycl_kernel // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}__sycl_kernel_ff_3IfEvPT_S0_S0_ +// CHECK: {{.*}}ff_3IfEvPT_S0_S0_.sycl_kernel // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}__sycl_kernel_ff_3IdEvPT_S0_S0_ +// CHECK: {{.*}}ff_3IdEvPT_S0_S0_.sycl_kernel // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 16 }, diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 6f73d6f172aa6..2a8d70871d7f6 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -11,7 +11,7 @@ void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) ptr[i] = start; } -// CHECK: FunctionDecl {{.*}}__sycl_kernel_{{.*}} 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}}.sycl_kernel{{.*}} 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' @@ -40,7 +40,7 @@ __attribute__((sycl_device)) // Explicit instantiation with "int*" template void ff_3(int* ptr, int start, int end); -// CHECK: FunctionDecl {{.*}}__sycl_kernel_{{.*}} 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}}.sycl_kernel{{.*}} 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 80385472cc4e3..5ab8dae301c46 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -102,7 +102,7 @@ bool test_0(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 0a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_0Piii"); + kernel Kernel = KF.get_kernel("_Z4ff_0Piii.sycl_kernel"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -146,7 +146,7 @@ bool test_1(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 1a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_1Piii"); + kernel Kernel = KF.get_kernel("_Z4ff_1Piii.sycl_kernel"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -195,7 +195,7 @@ bool test_2(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 2a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_1Pii"); + kernel Kernel = KF.get_kernel("_Z4ff_1Pii.sycl_kernel"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -245,7 +245,7 @@ bool test_3(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 3a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_3IiEvPT_S0_"); + kernel Kernel = KF.get_kernel("_Z4ff_3IiEvPT_S0_.sycl_kernel"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); From a4762de0a1e5c3c2131721423b2c6588f95ad7a3 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Sun, 12 May 2024 23:15:32 -0700 Subject: [PATCH 49/52] Changed naming scheme and disabled testing on CUDA. --- clang/lib/Sema/SemaSYCL.cpp | 63 ++++++++++--------- .../CodeGenSYCL/free_function_int_header.cpp | 20 +++--- .../SemaSYCL/free_function_kernel_params.cpp | 4 +- .../free_function_kernels.cpp | 11 ++-- 4 files changed, 54 insertions(+), 44 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ebdbdd447052b..94ed641c8baae 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1089,9 +1089,9 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { } // Creates a name for the free function kernel function. -// We add .sycl_kernel to the original function name and use it's mangled name -// as the kernel name. The renaming allows a normal device function to coexist -// with the kernel function. +// We add __sycl_kernel_ to the original function name and then use the mangled +// name as the kernel name. The renaming allows a normal device function to +// coexist with the kernel function. static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; @@ -1100,7 +1100,14 @@ static std::pair constructFreeFunctionKernelName( MC.mangleName(FreeFunc, Out); std::string MangledName(Out.str()); - std::string NewName = MangledName + ".sycl_kernel"; + size_t StartNums = MangledName.find_first_of("0123456789"); + size_t EndNums = MangledName.find_first_not_of("0123456789", StartNums); + size_t NameLength = + std::stoi(MangledName.substr(StartNums, EndNums - StartNums)); + size_t NewNameLength = 14 /*length of __sycl_kernel_*/ + NameLength; + std::string NewName = MangledName.substr(0, StartNums) + + std::to_string(NewNameLength) + "__sycl_kernel_" + + MangledName.substr(EndNums); StableName = NewName; return {NewName, StableName}; } @@ -2654,25 +2661,28 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return FD; } - static FunctionDecl *createFreeFunctionDecl(ASTContext &Ctx, FunctionDecl *FD, - SourceLocation Loc, - bool IsInline) { - // Create this with no prototype, and we can fix this up after we've seen - // all the params. - FunctionProtoType::ExtProtoInfo Info(CC_OpenCLKernel); - QualType FuncType = Ctx.getFunctionType(Ctx.VoidTy, {}, Info); - IdentifierInfo *Id = FD->getIdentifier(); - std::string NewName = (Id->getName() + Twine(".sycl_kernel")).str(); - const IdentifierInfo *NewIdent = &Ctx.Idents.get(NewName); - FD = FunctionDecl::Create( - Ctx, Ctx.getTranslationUnitDecl(), Loc, Loc, DeclarationName(NewIdent), - FuncType, Ctx.getTrivialTypeSourceInfo(Ctx.VoidTy), SC_None); - FD->setImplicitlyInline(IsInline); - setKernelImplicitAttrs(Ctx, FD, false); - - // Add kernel to translation unit to see it in AST-dump. - Ctx.getTranslationUnitDecl()->addDecl(FD); - return FD; + // Creates a name for the free function kernel function. + // We add __sycl_kernel_ to the original function name and then use the + // mangled name as the kernel name. The renaming allows a normal device + // function to coexist with the kernel function. + static std::pair constructFreeFunctionKernelName( + SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { + SmallString<256> Result; + llvm::raw_svector_ostream Out(Result); + std::string StableName; + + MC.mangleName(FreeFunc, Out); + std::string MangledName(Out.str()); + size_t StartNums = MangledName.find_first_of("0123456789"); + size_t EndNums = MangledName.find_first_not_of("0123456789", StartNums); + size_t NameLength = + std::stoi(MangledName.substr(StartNums, EndNums - StartNums)); + size_t NewNameLength = 14 /*length of __sycl_kernel_*/ + NameLength; + std::string NewName = MangledName.substr(0, StartNums) + + std::to_string(NewNameLength) + "__sycl_kernel_" + + MangledName.substr(EndNums); + StableName = NewName; + return {NewName, StableName}; } // If the record has been marked with SYCLGenerateNewTypeAttr, @@ -2708,11 +2718,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool IsSIMDKernel, bool IsFreeFunction, FunctionDecl *SYCLKernel) : SyclKernelFieldHandler(S), IsFreeFunction(IsFreeFunction), - KernelDecl(IsFreeFunction - ? createFreeFunctionDecl(S.getASTContext(), SYCLKernel, - Loc, IsInline) - : createKernelDecl(S.getASTContext(), Loc, IsInline, - IsSIMDKernel)), + KernelDecl( + createKernelDecl(S.getASTContext(), Loc, IsInline, IsSIMDKernel)), FuncContext(SemaSYCLRef.SemaRef, KernelDecl) { S.addSyclOpenCLKernel(SYCLKernel, KernelDecl); for (const auto *IRAttr : diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 325a47740997d..9cc154086f6ef 100755 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -47,36 +47,36 @@ template <> void ff_3(double *ptr, double start, double end) { } // CHECK: const char* const kernel_names[] = { -// CHECK-NEXT: {{.*}}ff_2Piii.sycl_kernel -// CHECK-NEXT: {{.*}}ff_2Piiii.sycl_kernel -// CHECK-NEXT: {{.*}}ff_3IiEvPT_S0_S0_.sycl_kernel -// CHECK-NEXT: {{.*}}ff_3IfEvPT_S0_S0_.sycl_kernel -// CHECK-NEXT: {{.*}}ff_3IdEvPT_S0_S0_.sycl_kernel +// 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: }; // CHECK: const kernel_param_desc_t kernel_signatures[] = { -// CHECK-NEXT: {{.*}}ff_2Piii.sycl_kernel +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}ff_2Piiii.sycl_kernel +// CHECK: {{.*}}__sycl_kernel_ff_2Piiii // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 16 }, -// CHECK: {{.*}}ff_3IiEvPT_S0_S0_.sycl_kernel +// CHECK: {{.*}}__sycl_kernel_ff_3IiEvPT_S0_S0_ // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}ff_3IfEvPT_S0_S0_.sycl_kernel +// CHECK: {{.*}}__sycl_kernel_ff_3IfEvPT_S0_S0_ // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, -// CHECK: {{.*}}ff_3IdEvPT_S0_S0_.sycl_kernel +// CHECK: {{.*}}__sycl_kernel_ff_3IdEvPT_S0_S0_ // CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 8 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 16 }, diff --git a/clang/test/SemaSYCL/free_function_kernel_params.cpp b/clang/test/SemaSYCL/free_function_kernel_params.cpp index 2a8d70871d7f6..6f73d6f172aa6 100755 --- a/clang/test/SemaSYCL/free_function_kernel_params.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params.cpp @@ -11,7 +11,7 @@ void ff_2(int *ptr, int start, int end) { for (int i = start; i <= end; i++) ptr[i] = start; } -// CHECK: FunctionDecl {{.*}}.sycl_kernel{{.*}} 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}}__sycl_kernel_{{.*}} 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' @@ -40,7 +40,7 @@ __attribute__((sycl_device)) // Explicit instantiation with "int*" template void ff_3(int* ptr, int start, int end); -// CHECK: FunctionDecl {{.*}}.sycl_kernel{{.*}} 'void (__global int *, int, int)' +// CHECK: FunctionDecl {{.*}}__sycl_kernel_{{.*}} 'void (__global int *, int, int)' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_ptr '__global int *' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_start 'int' // CHECK-NEXT: ParmVarDecl {{.*}} __arg_end 'int' diff --git a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp index 5ab8dae301c46..d8478d3f56e35 100755 --- a/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp +++ b/sycl/test-e2e/KernelAndProgram/free_function_kernels.cpp @@ -2,6 +2,9 @@ // RUN: %{build} -o %t.out // RUN: %{run} %t.out +// The name mangling for free function kernels currently does not work with PTX. +// UNSUPPORTED: cuda + // This test tests free function kernel code generation and execution. #include @@ -102,7 +105,7 @@ bool test_0(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 0a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z4ff_0Piii.sycl_kernel"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_0Piii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -146,7 +149,7 @@ bool test_1(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 1a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z4ff_1Piii.sycl_kernel"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_1Piii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -195,7 +198,7 @@ bool test_2(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 2a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z4ff_1Pii.sycl_kernel"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_1Pii"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); @@ -245,7 +248,7 @@ bool test_3(queue Queue, KernelFinder &KF) { bool PassA = checkUSM(usmPtr, Range, Result); std::cout << "Test 3a: " << (PassA ? "PASS" : "FAIL") << std::endl; - kernel Kernel = KF.get_kernel("_Z4ff_3IiEvPT_S0_.sycl_kernel"); + kernel Kernel = KF.get_kernel("_Z18__sycl_kernel_ff_3IiEvPT_S0_"); memset(usmPtr, 0, Range * sizeof(int)); Queue.submit([&](handler &Handler) { Handler.set_arg(0, usmPtr); From 19e58d79b3b2c8481a1d028379468c8da7444fd2 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 14 May 2024 09:18:57 -0700 Subject: [PATCH 50/52] Added a diagnostic for non-void free function. --- clang/lib/Sema/SemaSYCL.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 94ed641c8baae..2ae9e94425d9b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1081,8 +1081,15 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { IRAttr->getAttributeNameValuePairs(SemaSYCLRef.getASTContext()); for (const auto &NameValuePair : NameValuePairs) { if (NameValuePair.first == "sycl-nd-range-kernel" || - NameValuePair.first == "sycl-single-task-kernel") + NameValuePair.first == "sycl-single-task-kernel") { + if (!FD->getReturnType()->isVoidType()) { + llvm::report_fatal_error( + "Only functions at file scope with void return " + "type are permitted as free functions"); + return false; + } return true; + } } } return false; From ecda3d84286d00490db94916eb7bf89141fa3046 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 14 May 2024 09:28:39 -0700 Subject: [PATCH 51/52] Added a comment. --- clang/lib/Sema/SemaSYCL.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 2ae9e94425d9b..c0f8e1617ccca 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1075,6 +1075,8 @@ static target getAccessTarget(QualType FieldTy, AccTy->getTemplateArgs()[3].getAsIntegral().getExtValue()); } +// FIXME: Free functions are only supported at file scope, outside any +// namespaces. static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { for (auto *IRAttr : FD->specific_attrs()) { SmallVector, 4> NameValuePairs = From 10000f3377f8b4d303359443bdd8849cea928905 Mon Sep 17 00:00:00 2001 From: Rajiv Deodhar Date: Tue, 14 May 2024 13:48:19 -0700 Subject: [PATCH 52/52] Removed some duplicate code, enhanced a comment. --- clang/lib/Sema/SemaSYCL.cpp | 45 +++++++++++++------------------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c0f8e1617ccca..1b08bcdc4265a 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1075,8 +1075,10 @@ static target getAccessTarget(QualType FieldTy, AccTy->getTemplateArgs()[3].getAsIntegral().getExtValue()); } -// FIXME: Free functions are only supported at file scope, outside any -// namespaces. +// FIXME: Free functions must have void return type, be declared at file scope, +// outside any namespaces, and with the SYCL_DEVICE attribute. If the +// SYCL_DEVICE attribute is not specified this function is not entered since the +// possibility of the function being a free function is ruled out already. static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { for (auto *IRAttr : FD->specific_attrs()) { SmallVector, 4> NameValuePairs = @@ -1098,9 +1100,18 @@ static bool isFreeFunction(SemaSYCL &SemaSYCLRef, const FunctionDecl *FD) { } // Creates a name for the free function kernel function. -// We add __sycl_kernel_ to the original function name and then use the mangled -// name as the kernel name. The renaming allows a normal device function to -// coexist with the kernel function. +// Consider a free function named "MyFunction". The normal device function will +// be given its mangled name, say "_Z10MyFunctionIiEvPT_S0_". The corresponding +// kernel function for this free function will be named +// "_Z24__sycl_kernel_MyFunctionIiEvPT_S0_". This is the mangled name of a +// fictitious function that has the same template and function parameters as the +// original free function but with identifier prefixed with __sycl_kernel_. +// We generate this name by starting with the mangled name of the free function +// and adjusting it textually to simulate the __sycl_kernel_ prefix. +// Because free functions are allowed only at file scope and cannot be within +// namespaces the mangled name has the format _Z... where +// length is the identifier's length. The text manipulation inserts the prefix +// __sycl_kernel_ and adjusts the length, leaving the rest of the name as-is. static std::pair constructFreeFunctionKernelName( SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { SmallString<256> Result; @@ -2670,30 +2681,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return FD; } - // Creates a name for the free function kernel function. - // We add __sycl_kernel_ to the original function name and then use the - // mangled name as the kernel name. The renaming allows a normal device - // function to coexist with the kernel function. - static std::pair constructFreeFunctionKernelName( - SemaSYCL &SemaSYCLRef, const FunctionDecl *FreeFunc, MangleContext &MC) { - SmallString<256> Result; - llvm::raw_svector_ostream Out(Result); - std::string StableName; - - MC.mangleName(FreeFunc, Out); - std::string MangledName(Out.str()); - size_t StartNums = MangledName.find_first_of("0123456789"); - size_t EndNums = MangledName.find_first_not_of("0123456789", StartNums); - size_t NameLength = - std::stoi(MangledName.substr(StartNums, EndNums - StartNums)); - size_t NewNameLength = 14 /*length of __sycl_kernel_*/ + NameLength; - std::string NewName = MangledName.substr(0, StartNums) + - std::to_string(NewNameLength) + "__sycl_kernel_" + - MangledName.substr(EndNums); - StableName = NewName; - return {NewName, StableName}; - } - // If the record has been marked with SYCLGenerateNewTypeAttr, // it implies that it contains a pointer within. This function // defines a PointerHandler visitor which visits this record