From 34a11ca5577b49d74daa67ed40b866cefed8b45c Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 27 May 2025 19:10:48 -0700 Subject: [PATCH 01/69] Provide supports for decomposable structs --- clang/lib/Sema/SemaSYCL.cpp | 206 +++++++++++------- .../experimental/free_function_traits.hpp | 10 + sycl/include/sycl/handler.hpp | 4 +- 3 files changed, 146 insertions(+), 74 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 9a30b3e693ec2..7c2f2762e2133 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -8,6 +8,7 @@ // This implements Semantic Analysis for SYCL constructs. //===----------------------------------------------------------------------===// +#include #include "clang/Sema/SemaSYCL.h" #include "TreeTransform.h" #include "clang/AST/AST.h" @@ -1387,13 +1388,13 @@ 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...); - VisitRecordHelper(Wrapper, Wrapper->fields(), Handlers...); - (void)std::initializer_list{ - (Handlers.leaveStruct(Owner, Parent, RecordTy), 0)...}; + VisitRecordHelper(Wrapper, Wrapper->fields(), Handlers...), + (void)std::initializer_list{ + (Handlers.leaveStruct(Owner, Parent, RecordTy), 0)...}; } template @@ -1499,7 +1500,9 @@ class KernelObjVisitor { void visitField(const CXXRecordDecl *Owner, FieldDecl *Field, QualType FieldTy, HandlerTys &... Handlers) { if (isSyclSpecialType(FieldTy, SemaSYCLRef)) + { FieldTy->dump(); KF_FOR_EACH(handleSyclSpecialType, Field, FieldTy); +} else if (FieldTy->isStructureOrClassType()) { if (KF_FOR_EACH(handleStructType, Field, FieldTy)) { CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl(); @@ -1526,9 +1529,12 @@ class KernelObjVisitor { void visitParam(ParmVarDecl *Param, QualType ParamTy, HandlerTys &...Handlers) { if (isSyclSpecialType(ParamTy, SemaSYCLRef)) + {ParamTy->dump(); KP_FOR_EACH(handleSyclSpecialType, Param, ParamTy); +} else if (ParamTy->isStructureOrClassType()) { if (KP_FOR_EACH(handleStructType, Param, ParamTy)) { + ParamTy->dump(); CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); visitRecord(nullptr, Param, RD, ParamTy, Handlers...); } @@ -1607,8 +1613,12 @@ class KernelObjVisitor { template void VisitFunctionParameters(FunctionDecl *FreeFunc, HandlerTys &...Handlers) { - for (ParmVarDecl *Param : FreeFunc->parameters()) + for (ParmVarDecl *Param : FreeFunc->parameters()) { +std::cout << "starting!" << std::endl; +Param->getType()->dump(); visitParam(Param, Param->getType(), Handlers...); +std::cout << "ending!" << std::endl; +} } #undef KF_FOR_EACH @@ -1731,10 +1741,6 @@ class SyclKernelFieldHandlerBase { virtual ~SyclKernelFieldHandlerBase() = default; }; - -// A class to act as the direct base for all the SYCL OpenCL Kernel construction -// tasks that contains a reference to Sema (and potentially any other -// universally required data). class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { protected: SemaSYCL &SemaSYCLRef; @@ -1818,7 +1824,11 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, // If this container requires decomposition, we have to visit it as // 'complex', so all handlers are called in this case with the 'complex' // case. + //RecordTy->dump(); visitComplexRecord(Owner, Parent, Wrapper, RecordTy, Handlers...); + // 'complex', so all handlers are called in this case with the 'complex' + // case. + //RecordTy->dump(); } else if (AnyTrue:: Value) { // We are currently in PointerHandler visitor. @@ -2141,31 +2151,14 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO manipulate struct depth once special types are supported for free - // function kernels. - // ++StructFieldDepth; + ++StructFieldDepth; return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { - // TODO manipulate struct depth once special types are supported for free - // function kernels. - // --StructFieldDepth; - // TODO We don't yet support special types and therefore structs that - // require decomposition and leaving/entering. Diagnose for better user - // experience. - CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); - if (RD->hasAttr()) { - Diag.Report(PD->getLocation(), - diag::err_bad_kernel_param_type) - << ParamTy; - Diag.Report(PD->getLocation(), - diag::note_free_function_kernel_param_type_not_supported) - << ParamTy; - IsInvalid = true; - } - return isValid(); + --StructFieldDepth; + return true; } bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &BS, @@ -2269,8 +2262,6 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { } bool handleSyclSpecialType(ParmVarDecl *, QualType) final { - // TODO We don't support special types in free function kernel parameters, - // but track them to diagnose the case properly. CollectionStack.back() = true; return true; } @@ -2542,7 +2533,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -2563,7 +2553,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -2660,7 +2649,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -2694,6 +2682,9 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionDecl *KernelDecl = nullptr; llvm::SmallVector Params; + // Holds the last handled kernel struct parameter that contains a special type. + // Set in the enterStruct functions. + ParmVarDecl * CurrentStruct; Sema::ContextRAII FuncContext; // Holds the last handled field's first parameter. This doesn't store an // iterator as push_back invalidates iterators. @@ -2711,6 +2702,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { addParam(newParamDesc, ParamTy); } + void addParam(const CXXBaseSpecifier &BS, QualType FieldTy) { // 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. @@ -2798,7 +2790,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SourceLocation Loc) { handleAccessorPropertyList(Params.back(), RecordDecl, Loc); - // If "accessor" type check if read only + // If "accessor" type check if read only if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::accessor)) { // Get access mode of accessor. const auto *AccessorSpecializationDecl = @@ -2824,6 +2816,8 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // lambda kernel by taking the value ParmVarDecl or FieldDecl respectively. template bool handleSpecialType(ParentDecl *decl, QualType Ty) { +std::cout << "Important one!" << std::endl; +Ty->dump(); const auto *RD = Ty->getAsCXXRecordDecl(); assert(RD && "The type must be a RecordDecl"); llvm::StringLiteral MethodName = @@ -2837,7 +2831,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // (if any). size_t ParamIndex = Params.size(); for (const ParmVarDecl *Param : InitMethod->parameters()) { - QualType ParamTy = Param->getType(); + QualType ParamTy = Param->getType(); // For lambda kernels the arguments to the OpenCL kernel are named // based on the position they have as fields in the definition of the // special type structure i.e __arg_field1, __arg_field2 and so on. @@ -2863,6 +2857,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { handleAccessorType(Ty, RD, decl->getBeginLoc()); } LastParamIndex = ParamIndex; + std::cout << LastParamIndex << std::endl; return true; } @@ -2956,6 +2951,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernelAttr::CreateImplicit(SemaSYCLRef.getASTContext())); SemaSYCLRef.addSyclDeviceDecl(KernelDecl); + //KernelDecl->dump(); } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { @@ -2963,9 +2959,11 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - // ++StructDepth; + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + ++StructDepth; + //StringRef Name = "_arg_struct"; + //addParam(Name, Ty); + //CurrentStruct = Params.back(); return true; } @@ -2975,8 +2973,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - // --StructDepth; + --StructDepth; return true; } @@ -2992,6 +2989,15 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } + bool handleStructType(ParmVarDecl *PD, QualType Ty) final { + StringRef Name = "_arg_struct"; + addParam(Name, Ty); + CurrentStruct = Params.back(); + return true; + } + + bool handleStructType(FieldDecl *, QualType) final { return true; } + bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { const auto *RecordDecl = FieldTy->getAsCXXRecordDecl(); @@ -3166,6 +3172,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return ArrayRef(std::begin(Params) + LastParamIndex, std::end(Params)); } + ParmVarDecl *getParentStructForCurrentField() { return CurrentStruct; } }; // This Visitor traverses the AST of the function with @@ -3619,8 +3626,11 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { SourceLocation LL = NewBody ? NewBody->getBeginLoc() : SourceLocation(); SourceLocation LR = NewBody ? NewBody->getEndLoc() : SourceLocation(); - return CompoundStmt::Create(SemaSYCLRef.getASTContext(), BodyStmts, + CompoundStmt::Create(SemaSYCLRef.getASTContext(), BodyStmts, + FPOptionsOverride(), LL, LR)->dumpPretty(SemaSYCLRef.getASTContext()); +return CompoundStmt::Create(SemaSYCLRef.getASTContext(), BodyStmts, FPOptionsOverride(), LL, LR); + } void annotateHierarchicalParallelismAPICalls() { @@ -4342,16 +4352,14 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SyclKernelDeclCreator &DeclCreator; llvm::SmallVector BodyStmts; + llvm::SmallVector CurrentStructs; FunctionDecl *FreeFunc = nullptr; SourceLocation FreeFunctionSrcLoc; // Free function source location. llvm::SmallVector ArgExprs; - // Creates a DeclRefExpr to the ParmVar that represents the current free - // function parameter. - Expr *createParamReferenceExpr() { - ParmVarDecl *FreeFunctionParameter = - DeclCreator.getParamVarDeclsForCurrentField()[0]; - + // Creates a DeclRefExpr to the ParmVar that represents an arbitrary + // free function parameter + Expr *createParamReferenceExpr(ParmVarDecl *FreeFunctionParameter) { QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( FreeFunctionParameter, FreeFunctionParamType, VK_LValue, @@ -4360,6 +4368,14 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return DRE; } + // Creates a DeclRefExpr to the ParmVar that represents the current free + // function parameter. + Expr *createParamReferenceExpr() { + ParmVarDecl *FreeFunctionParameter = + DeclCreator.getParamVarDeclsForCurrentField()[0]; + return createParamReferenceExpr(FreeFunctionParameter); + } + // Creates a DeclRefExpr to the ParmVar that represents the current pointer // parameter. Expr *createPointerParamReferenceExpr(QualType PointerTy) { @@ -4416,6 +4432,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { DRE = createReinterpretCastExpr( createGetAddressOf(DRE), SemaSYCLRef.getASTContext().getPointerType( OrigFunctionParameter->getType())); + DRE = createDerefOp(DRE); } @@ -4450,8 +4467,12 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { auto CallExpr = CallExpr::Create(Context, Fn, ArgExprs, ResultTy, VK, FreeFunctionSrcLoc, FPOptionsOverride()); BodyStmts.push_back(CallExpr); +CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, + {})->dumpPretty(Context); + return CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, {}); + } MemberExpr *buildMemberExpr(Expr *Base, ValueDecl *Member) { @@ -4468,15 +4489,17 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { void createSpecialMethodCall(const CXXRecordDecl *RD, StringRef MethodName, Expr *MemberBaseExpr, SmallVectorImpl &AddTo) { - CXXMethodDecl *Method = getMethodByName(RD, MethodName); +CXXMethodDecl *Method = getMethodByName(RD, MethodName); if (!Method) return; unsigned NumParams = Method->getNumParams(); llvm::SmallVector ParamDREs(NumParams); llvm::ArrayRef KernelParameters = DeclCreator.getParamVarDeclsForCurrentField(); + //std::cout << KernelParameters.size() << std::endl; for (size_t I = 0; I < NumParams; ++I) { QualType ParamType = KernelParameters[I]->getOriginalType(); + //ParamType->dump(); ParamDREs[I] = SemaSYCLRef.SemaRef.BuildDeclRefExpr( KernelParameters[I], ParamType, VK_LValue, FreeFunctionSrcLoc); } @@ -4495,7 +4518,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { public: static constexpr const bool VisitInsideSimpleContainers = false; - + FreeFunctionKernelBodyCreator(SemaSYCL &S, SyclKernelDeclCreator &DC, FunctionDecl *FF) : SyclKernelFieldHandler(S), DeclCreator(DC), FreeFunc(FF), @@ -4506,9 +4529,20 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { DeclCreator.setBody(KernelBody); } - bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { - // TODO - unsupportedFreeFunctionParamType(); + bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { + // Being inside this function means there is a struct parameter to the free + // function kernel that contains a special type. +std::cout << "Body!" << std::endl; +FieldTy->dump(); + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + // special_type_wrapper_map[ParentStruct->getType()] = true; + Expr *Base = createParamReferenceExpr(ParentStruct); + for (const auto &child : CurrentStructs) { + Base = buildMemberExpr(Base, child); + } + MemberExpr *MemberAccess = buildMemberExpr(Base, FD); + createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, + MemberAccess, BodyStmts); return true; } @@ -4527,6 +4561,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // wgm.__init(arg); // user_kernel(some arguments..., wgm, some arguments...); // } + std::cout << "Body!" << std::endl; + ParamTy->dump(); const auto *RecordDecl = ParamTy->getAsCXXRecordDecl(); AccessSpecifier DefaultConstructorAccess; auto DefaultConstructor = @@ -4559,8 +4595,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { BodyStmts.push_back(DS); Expr *MemberBaseExpr = SemaSYCLRef.SemaRef.BuildDeclRefExpr( SpecialObjectClone, ParamTy, VK_PRValue, FreeFunctionSrcLoc); - createSpecialMethodCall(RecordDecl, InitMethodName, MemberBaseExpr, - BodyStmts); + createSpecialMethodCall(RecordDecl, InitMethodName, MemberBaseExpr, + BodyStmts); ArgExprs.push_back(MemberBaseExpr); return true; } @@ -4636,26 +4672,24 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { - // TODO - unsupportedFreeFunctionParamType(); + CurrentStructs.push_back(FD); return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + QualType Ty) final { return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - // TODO - unsupportedFreeFunctionParamType(); + CurrentStructs.pop_back(); return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( + ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4700,6 +4734,11 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { unsupportedFreeFunctionParamType(); return true; } + FieldDecl *getCurrentStruct() { + assert(CurrentStructs.size() && + "Current free function parameter is not inside a structure!"); + return CurrentStructs.back(); + } }; // Kernels are only the unnamed-lambda feature if the feature is enabled, AND @@ -4979,7 +5018,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -4991,7 +5029,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -5488,22 +5525,25 @@ void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, StringRef NameStr) { if (!checkAndAddRegisteredKernelName(*this, FD, NameStr)) return; - SyclKernelArgsSizeChecker argsSizeChecker(*this, FD->getLocation(), false /*IsSIMDKernel*/); SyclKernelDeclCreator kernel_decl(*this, FD->getLocation(), FD->isInlined(), false /*IsSIMDKernel */, FD); - FreeFunctionKernelBodyCreator kernel_body(*this, kernel_decl, FD); - SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), FD->getType(), FD); - SyclKernelIntFooterCreator int_footer(*this, getSyclIntegrationFooter()); KernelObjVisitor Visitor{*this}; - Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, - int_header, int_footer); + Visitor.VisitFunctionParameters(FD, argsSizeChecker); + +Visitor.VisitFunctionParameters(FD, kernel_decl); + +Visitor.VisitFunctionParameters(FD, kernel_body); + +Visitor.VisitFunctionParameters(FD, int_header); + +Visitor.VisitFunctionParameters(FD, int_footer); assert(getKernelFDPairs().back().first == FD && "OpenCL Kernel not found for free function entry"); @@ -6984,6 +7024,26 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } } ParmListWithNamesOstream.flush(); + for (ParmVarDecl *Param : K.SyclKernel->parameters()) { + // if (FreeFunctionKernelBodyCreator::isSpecialTypeWrapper( + // Param->getType())) { + // this is a struct that contains a special type so its neither a + // special type nor a trivially copyable type. We therefore need to + // explicitly communicate to the runtime that this argument should be + // allowed as a free function kernel argument. We do this by defining + // a certain trait recognized by the runtime to be true. + O << "template <>\n"; + O << "struct " + "sycl::ext::oneapi::experimental::detail::is_explicitly_allowed_" + "arg<"; + Policy.SuppressTagKeyword = true; + + Param->getType().print(O, Policy); + Policy.SuppressTagKeyword = false; + O << "> {\n"; + O << " static constexpr bool value = true;\n};\n"; + //} + } FunctionTemplateDecl *FTD = K.SyclKernel->getPrimaryTemplate(); Policy.PrintCanonicalTypes = false; Policy.SuppressDefinition = true; @@ -7720,7 +7780,7 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap); Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get(); - OFD->setBody(OFDBody); +OFD->setBody(OFDBody); OFD->setNothrow(); Stmt *NewBody = new (getASTContext()) SYCLKernelCallStmt(Body, OFD); diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 2b5d1f4190d21..0ca1c234c9070 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -44,6 +44,16 @@ template struct is_kernel { template inline constexpr bool is_kernel_v = is_kernel::value; +namespace detail { +template struct is_explicitly_allowed_arg { + static constexpr bool value = false; +}; + +template +inline constexpr bool is_explicitly_allowed_arg_v = + is_explicitly_allowed_arg::value; + +} // namespace detail } // namespace ext::oneapi::experimental } // namespace _V1 } // namespace sycl diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index d7b304a130c83..54b093f05000a 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1766,7 +1767,8 @@ class __SYCL_EXPORT handler { || (!is_same_type::value && std::is_pointer_v>) // USM || is_same_type::value // Interop - || is_same_type::value; // Stream + || is_same_type::value // Stream + || ext::oneapi::experimental::detail::is_explicitly_allowed_arg>::value; }; /// Sets argument for OpenCL interoperability kernels. From c87f239bf2855a4a689658d530845b7ca5966a6f Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 28 May 2025 07:47:38 -0700 Subject: [PATCH 02/69] Remove debugging statements and apply clang-format --- clang/lib/Sema/SemaSYCL.cpp | 86 ++++++------------- .../experimental/free_function_traits.hpp | 4 +- sycl/include/sycl/handler.hpp | 3 +- 3 files changed, 29 insertions(+), 64 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b1a7b3cedf70f..a43894b19fd73 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -8,7 +8,6 @@ // This implements Semantic Analysis for SYCL constructs. //===----------------------------------------------------------------------===// -#include #include "clang/Sema/SemaSYCL.h" #include "TreeTransform.h" #include "clang/AST/AST.h" @@ -1409,13 +1408,13 @@ 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...); - VisitRecordHelper(Wrapper, Wrapper->fields(), Handlers...), - (void)std::initializer_list{ - (Handlers.leaveStruct(Owner, Parent, RecordTy), 0)...}; + VisitRecordHelper(Wrapper, Wrapper->fields(), Handlers...); + (void)std::initializer_list{ + (Handlers.leaveStruct(Owner, Parent, RecordTy), 0)...}; } template @@ -1519,11 +1518,9 @@ class KernelObjVisitor { template void visitField(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType FieldTy, HandlerTys &... Handlers) { + QualType FieldTy, HandlerTys &...Handlers) { if (isSyclSpecialType(FieldTy, SemaSYCLRef)) - { FieldTy->dump(); KF_FOR_EACH(handleSyclSpecialType, Field, FieldTy); -} else if (FieldTy->isStructureOrClassType()) { if (KF_FOR_EACH(handleStructType, Field, FieldTy)) { CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl(); @@ -1550,12 +1547,9 @@ class KernelObjVisitor { void visitParam(ParmVarDecl *Param, QualType ParamTy, HandlerTys &...Handlers) { if (isSyclSpecialType(ParamTy, SemaSYCLRef)) - {ParamTy->dump(); KP_FOR_EACH(handleSyclSpecialType, Param, ParamTy); -} else if (ParamTy->isStructureOrClassType()) { if (KP_FOR_EACH(handleStructType, Param, ParamTy)) { - ParamTy->dump(); CXXRecordDecl *RD = ParamTy->getAsCXXRecordDecl(); visitRecord(nullptr, Param, RD, ParamTy, Handlers...); } @@ -1634,12 +1628,8 @@ class KernelObjVisitor { template void VisitFunctionParameters(FunctionDecl *FreeFunc, HandlerTys &...Handlers) { - for (ParmVarDecl *Param : FreeFunc->parameters()) { -std::cout << "starting!" << std::endl; -Param->getType()->dump(); + for (ParmVarDecl *Param : FreeFunc->parameters()) visitParam(Param, Param->getType(), Handlers...); -std::cout << "ending!" << std::endl; -} } #undef KF_FOR_EACH @@ -1762,6 +1752,10 @@ class SyclKernelFieldHandlerBase { virtual ~SyclKernelFieldHandlerBase() = default; }; + +// A class to act as the direct base for all the SYCL OpenCL Kernel construction +// tasks that contains a reference to Sema (and potentially any other +// universally required data). class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { protected: SemaSYCL &SemaSYCLRef; @@ -1845,11 +1839,7 @@ void KernelObjVisitor::visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent, // If this container requires decomposition, we have to visit it as // 'complex', so all handlers are called in this case with the 'complex' // case. - //RecordTy->dump(); visitComplexRecord(Owner, Parent, Wrapper, RecordTy, Handlers...); - // 'complex', so all handlers are called in this case with the 'complex' - // case. - //RecordTy->dump(); } else if (AnyTrue:: Value) { // We are currently in PointerHandler visitor. @@ -2723,7 +2713,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { addParam(newParamDesc, ParamTy); } - void addParam(const CXXBaseSpecifier &BS, QualType FieldTy) { // 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. @@ -2811,7 +2800,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SourceLocation Loc) { handleAccessorPropertyList(Params.back(), RecordDecl, Loc); - // If "accessor" type check if read only + // If "accessor" type check if read only if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::accessor)) { // Get access mode of accessor. const auto *AccessorSpecializationDecl = @@ -2837,8 +2826,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // lambda kernel by taking the value ParmVarDecl or FieldDecl respectively. template bool handleSpecialType(ParentDecl *decl, QualType Ty) { -std::cout << "Important one!" << std::endl; -Ty->dump(); const auto *RD = Ty->getAsCXXRecordDecl(); assert(RD && "The type must be a RecordDecl"); llvm::StringLiteral MethodName = @@ -2852,7 +2839,7 @@ Ty->dump(); // (if any). size_t ParamIndex = Params.size(); for (const ParmVarDecl *Param : InitMethod->parameters()) { - QualType ParamTy = Param->getType(); + QualType ParamTy = Param->getType(); // For lambda kernels the arguments to the OpenCL kernel are named // based on the position they have as fields in the definition of the // special type structure i.e __arg_field1, __arg_field2 and so on. @@ -2878,7 +2865,6 @@ Ty->dump(); handleAccessorType(Ty, RD, decl->getBeginLoc()); } LastParamIndex = ParamIndex; - std::cout << LastParamIndex << std::endl; return true; } @@ -2972,7 +2958,6 @@ Ty->dump(); SYCLKernelAttr::CreateImplicit(SemaSYCLRef.getASTContext())); SemaSYCLRef.addSyclDeviceDecl(KernelDecl); - //KernelDecl->dump(); } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { @@ -2982,9 +2967,6 @@ Ty->dump(); bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { ++StructDepth; - //StringRef Name = "_arg_struct"; - //addParam(Name, Ty); - //CurrentStruct = Params.back(); return true; } @@ -3647,11 +3629,8 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { SourceLocation LL = NewBody ? NewBody->getBeginLoc() : SourceLocation(); SourceLocation LR = NewBody ? NewBody->getEndLoc() : SourceLocation(); - CompoundStmt::Create(SemaSYCLRef.getASTContext(), BodyStmts, - FPOptionsOverride(), LL, LR)->dumpPretty(SemaSYCLRef.getASTContext()); -return CompoundStmt::Create(SemaSYCLRef.getASTContext(), BodyStmts, + return CompoundStmt::Create(SemaSYCLRef.getASTContext(), BodyStmts, FPOptionsOverride(), LL, LR); - } void annotateHierarchicalParallelismAPICalls() { @@ -4453,7 +4432,6 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { DRE = createReinterpretCastExpr( createGetAddressOf(DRE), SemaSYCLRef.getASTContext().getPointerType( OrigFunctionParameter->getType())); - DRE = createDerefOp(DRE); } @@ -4488,12 +4466,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { auto CallExpr = CallExpr::Create(Context, Fn, ArgExprs, ResultTy, VK, FreeFunctionSrcLoc, FPOptionsOverride()); BodyStmts.push_back(CallExpr); -CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, - {})->dumpPretty(Context); - return CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, {}); - } MemberExpr *buildMemberExpr(Expr *Base, ValueDecl *Member) { @@ -4510,17 +4484,15 @@ CompoundStmt::Create(Context, BodyStmts, FPOptionsOverride(), {}, void createSpecialMethodCall(const CXXRecordDecl *RD, StringRef MethodName, Expr *MemberBaseExpr, SmallVectorImpl &AddTo) { -CXXMethodDecl *Method = getMethodByName(RD, MethodName); + CXXMethodDecl *Method = getMethodByName(RD, MethodName); if (!Method) return; unsigned NumParams = Method->getNumParams(); llvm::SmallVector ParamDREs(NumParams); llvm::ArrayRef KernelParameters = DeclCreator.getParamVarDeclsForCurrentField(); - //std::cout << KernelParameters.size() << std::endl; for (size_t I = 0; I < NumParams; ++I) { QualType ParamType = KernelParameters[I]->getOriginalType(); - //ParamType->dump(); ParamDREs[I] = SemaSYCLRef.SemaRef.BuildDeclRefExpr( KernelParameters[I], ParamType, VK_LValue, FreeFunctionSrcLoc); } @@ -4539,7 +4511,7 @@ CXXMethodDecl *Method = getMethodByName(RD, MethodName); public: static constexpr const bool VisitInsideSimpleContainers = false; - + FreeFunctionKernelBodyCreator(SemaSYCL &S, SyclKernelDeclCreator &DC, FunctionDecl *FF) : SyclKernelFieldHandler(S), DeclCreator(DC), FreeFunc(FF), @@ -4553,8 +4525,6 @@ CXXMethodDecl *Method = getMethodByName(RD, MethodName); bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { // Being inside this function means there is a struct parameter to the free // function kernel that contains a special type. -std::cout << "Body!" << std::endl; -FieldTy->dump(); ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); // special_type_wrapper_map[ParentStruct->getType()] = true; Expr *Base = createParamReferenceExpr(ParentStruct); @@ -4582,8 +4552,6 @@ FieldTy->dump(); // wgm.__init(arg); // user_kernel(some arguments..., wgm, some arguments...); // } - std::cout << "Body!" << std::endl; - ParamTy->dump(); const auto *RecordDecl = ParamTy->getAsCXXRecordDecl(); AccessSpecifier DefaultConstructorAccess; auto DefaultConstructor = @@ -4616,8 +4584,8 @@ FieldTy->dump(); BodyStmts.push_back(DS); Expr *MemberBaseExpr = SemaSYCLRef.SemaRef.BuildDeclRefExpr( SpecialObjectClone, ParamTy, VK_PRValue, FreeFunctionSrcLoc); - createSpecialMethodCall(RecordDecl, InitMethodName, MemberBaseExpr, - BodyStmts); + createSpecialMethodCall(RecordDecl, InitMethodName, MemberBaseExpr, + BodyStmts); ArgExprs.push_back(MemberBaseExpr); return true; } @@ -5556,27 +5524,23 @@ void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, StringRef NameStr) { if (!checkAndAddRegisteredKernelName(*this, FD, NameStr)) return; + SyclKernelArgsSizeChecker argsSizeChecker(*this, FD->getLocation(), false /*IsSIMDKernel*/); SyclKernelDeclCreator kernel_decl(*this, FD->getLocation(), FD->isInlined(), false /*IsSIMDKernel */, FD); + FreeFunctionKernelBodyCreator kernel_body(*this, kernel_decl, FD); + SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), FD->getType(), FD); + SyclKernelIntFooterCreator int_footer(*this, getSyclIntegrationFooter()); KernelObjVisitor Visitor{*this}; - Visitor.VisitFunctionParameters(FD, argsSizeChecker); - -Visitor.VisitFunctionParameters(FD, kernel_decl); - -Visitor.VisitFunctionParameters(FD, kernel_body); - -Visitor.VisitFunctionParameters(FD, int_header); - -Visitor.VisitFunctionParameters(FD, int_footer); - - assert(getKernelFDPairs().back().first == FD && + Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, int_header, int_footer); + +assert(getKernelFDPairs().back().first == FD && "OpenCL Kernel not found for free function entry"); // Register the kernel name with the OpenCL kernel generated for the // free function. @@ -7812,7 +7776,7 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap); Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get(); -OFD->setBody(OFDBody); + OFD->setBody(OFDBody); OFD->setNothrow(); Stmt *NewBody = new (getASTContext()) SYCLKernelCallStmt(Body, OFD); diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 0ca1c234c9070..c564d6239ec80 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -46,11 +46,11 @@ inline constexpr bool is_kernel_v = is_kernel::value; namespace detail { template struct is_explicitly_allowed_arg { - static constexpr bool value = false; + static constexpr bool value = false; }; template -inline constexpr bool is_explicitly_allowed_arg_v = +inline constexpr bool is_explicitly_allowed_arg_v = is_explicitly_allowed_arg::value; } // namespace detail diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 3506d1f34f493..f4935fe5d3e46 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1817,7 +1817,8 @@ class __SYCL_EXPORT handler { std::is_pointer_v>) // USM || is_same_type::value // Interop || is_same_type::value // Stream - || ext::oneapi::experimental::detail::is_explicitly_allowed_arg>::value; + || ext::oneapi::experimental::detail::is_explicitly_allowed_arg< + remove_cv_ref_t>::value; }; /// Sets argument for OpenCL interoperability kernels. From 6255cf25017fb57c6a3129fbeb60a67d3f3a69fb Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 28 May 2025 07:48:24 -0700 Subject: [PATCH 03/69] Remove debugging statements and apply clang-format --- 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 a43894b19fd73..6da3f8fab2f28 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1518,7 +1518,7 @@ class KernelObjVisitor { template void visitField(const CXXRecordDecl *Owner, FieldDecl *Field, - QualType FieldTy, HandlerTys &...Handlers) { + QualType FieldTy, HandlerTys &... Handlers) { if (isSyclSpecialType(FieldTy, SemaSYCLRef)) KF_FOR_EACH(handleSyclSpecialType, Field, FieldTy); else if (FieldTy->isStructureOrClassType()) { From 4de6a524801110392755f681548e7d9f61bb1b6d Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 28 May 2025 07:49:21 -0700 Subject: [PATCH 04/69] Remove debugging statements and apply clang-format --- 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 6da3f8fab2f28..b9cb7bff98577 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5540,7 +5540,7 @@ void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, int_header, int_footer); -assert(getKernelFDPairs().back().first == FD && + assert(getKernelFDPairs().back().first == FD && "OpenCL Kernel not found for free function entry"); // Register the kernel name with the OpenCL kernel generated for the // free function. From 5800d46725b615cf20dd680428893389db0f48f9 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 28 May 2025 07:51:01 -0700 Subject: [PATCH 05/69] Remove TODO statements from code --- clang/lib/Sema/SemaSYCL.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b9cb7bff98577..f628132db4f08 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2543,7 +2543,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType ParamTy) final { - // TODO return true; } @@ -2563,7 +2562,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { - // TODO return true; } @@ -2659,7 +2657,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { - // TODO return true; } @@ -5016,7 +5013,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO return true; } @@ -5027,7 +5023,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - // TODO return true; } From d1d43f185634882eea3cd68b3f174af9a770291a Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 3 Jun 2025 11:45:42 -0700 Subject: [PATCH 06/69] Wrapped speaicl types support --- clang/include/clang/Sema/SemaSYCL.h | 9 +- clang/lib/Sema/SemaSYCL.cpp | 279 +++++++++++++++--- .../experimental/free_function_traits.hpp | 9 +- sycl/include/sycl/handler.hpp | 35 ++- sycl/source/detail/scheduler/commands.cpp | 2 + sycl/source/handler.cpp | 7 +- .../free_function_special_types.cpp | 70 +++-- 7 files changed, 337 insertions(+), 74 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 8aac24b8d0079..5dabb01abac20 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -65,7 +65,8 @@ class SYCLIntegrationHeader { kind_work_group_memory, kind_dynamic_work_group_memory, kind_dynamic_accessor, - kind_last = kind_dynamic_accessor + kind_special_type_wrapper, + kind_last = kind_special_type_wrapper }; public: @@ -118,6 +119,9 @@ class SYCLIntegrationHeader { /// integration header is required. void addHostPipeRegistration() { NeedToEmitHostPipeRegistration = true; } +void addFreeFunctionParamDecomposition(QualType Ty, MemberExpr *expr) { + DecompositionMap[Ty.getAsOpaquePtr()].push_back(expr); +} private: // Kernel actual parameter descriptor. struct KernelParamDesc { @@ -183,7 +187,6 @@ class SYCLIntegrationHeader { return KernelDescs.size() > 0 ? &KernelDescs[KernelDescs.size() - 1] : nullptr; } - private: /// Keeps invocation descriptors for each kernel invocation started by /// SYCLIntegrationHeader::startKernel @@ -205,6 +208,8 @@ class SYCLIntegrationHeader { /// Keeps track of whether declaration of __sycl_host_pipe_registration /// type and __sycl_host_pipe_registrar variable are required to emit. bool NeedToEmitHostPipeRegistration = false; + + llvm::DenseMap> DecompositionMap; }; class SYCLIntegrationFooter { diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index f628132db4f08..425eab478d775 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2634,8 +2634,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { } bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { - // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -2843,9 +2841,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // For free function kernels the arguments are named in direct mapping // with the names they have in the __init method i.e __arg_Ptr for work // group memory since its init function takes a parameter with Ptr name. - if constexpr (std::is_same_v) - addParam(decl, ParamTy.getCanonicalType()); - else addParam(Param, ParamTy.getCanonicalType()); // Propagate add_ir_attributes_kernel_parameter attribute. if (const auto *AddIRAttr = @@ -2955,6 +2950,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernelAttr::CreateImplicit(SemaSYCLRef.getASTContext())); SemaSYCLRef.addSyclDeviceDecl(KernelDecl); + KernelDecl->dump(); } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { @@ -2990,7 +2986,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleStructType(ParmVarDecl *PD, QualType Ty) final { - StringRef Name = "_arg_struct"; + StringRef Name = "_arg_struct"; addParam(Name, Ty); CurrentStruct = Params.back(); return true; @@ -4349,6 +4345,10 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { SyclKernelDeclCreator &DeclCreator; llvm::SmallVector BodyStmts; + // Keep track of the structs we have encountered on our way to a special type. + // They will be needed to properly generate the __init call. Note that the + // top-level struct parameter is not kept track here because that is done by + // the DeclCreator. llvm::SmallVector CurrentStructs; FunctionDecl *FreeFunc = nullptr; SourceLocation FreeFunctionSrcLoc; // Free function source location. @@ -4516,15 +4516,15 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { ~FreeFunctionKernelBodyCreator() { CompoundStmt *KernelBody = createFreeFunctionKernelBody(); + KernelBody->dumpPretty(SemaSYCLRef.SemaRef.getASTContext()); DeclCreator.setBody(KernelBody); } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { // Being inside this function means there is a struct parameter to the free // function kernel that contains a special type. - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - // special_type_wrapper_map[ParentStruct->getType()] = true; - Expr *Base = createParamReferenceExpr(ParentStruct); + //ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + Expr *Base = ArgExprs.back(); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } @@ -4634,8 +4634,6 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - // TODO - unsupportedFreeFunctionParamType(); return true; } @@ -4663,8 +4661,41 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType Ty) final { - return true; + QualType ParamTy) final { + const auto *RecordDecl = ParamTy->getAsCXXRecordDecl(); + AccessSpecifier DefaultConstructorAccess; + auto DefaultConstructor = + std::find_if(RecordDecl->ctor_begin(), RecordDecl->ctor_end(), + [](auto it) { return it->isDefaultConstructor(); }); + DefaultConstructorAccess = DefaultConstructor->getAccess(); + DefaultConstructor->setAccess(AS_public); + + ASTContext &Ctx = SemaSYCLRef.SemaRef.getASTContext(); + VarDecl *SpecialObjectClone = + VarDecl::Create(Ctx, DeclCreator.getKernelDecl(), FreeFunctionSrcLoc, + FreeFunctionSrcLoc, PD->getIdentifier(), ParamTy, + Ctx.getTrivialTypeSourceInfo(ParamTy), SC_None); + InitializedEntity VarEntity = + InitializedEntity::InitializeVariable(SpecialObjectClone); + InitializationKind InitKind = + InitializationKind::CreateDefault(FreeFunctionSrcLoc); + InitializationSequence InitSeq(SemaSYCLRef.SemaRef, VarEntity, InitKind, + std::nullopt); + ExprResult Init = + InitSeq.Perform(SemaSYCLRef.SemaRef, VarEntity, InitKind, std::nullopt); + SpecialObjectClone->setInit( + SemaSYCLRef.SemaRef.MaybeCreateExprWithCleanups(Init.get())); + SpecialObjectClone->setInitStyle(VarDecl::CallInit); + DefaultConstructor->setAccess(DefaultConstructorAccess); + + Stmt *DS = new (SemaSYCLRef.getASTContext()) + DeclStmt(DeclGroupRef(SpecialObjectClone), FreeFunctionSrcLoc, + FreeFunctionSrcLoc); + BodyStmts.push_back(DS); + Expr *MemberBaseExpr = SemaSYCLRef.SemaRef.BuildDeclRefExpr( + SpecialObjectClone, ParamTy, VK_PRValue, FreeFunctionSrcLoc); + ArgExprs.push_back(MemberBaseExpr); +return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { @@ -4673,9 +4704,9 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); + //ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + //ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( + // ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4727,6 +4758,153 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } }; +class FreeFunctionKernelParamDecomposer : public SyclKernelFieldHandler { + ParmVarDecl *TopLevelStruct; + llvm::SmallVector CurrentStructs; + SourceLocation FreeFunctionSrcLoc; + FunctionDecl *FreeFunction; + SYCLIntegrationHeader &H; + SyclKernelDeclCreator &DeclCreator; + + // Creates a DeclRefExpr to the ParmVar that represents an arbitrary + // free function parameter + Expr *createParamReferenceExpr(ParmVarDecl *FreeFunctionParameter) { + QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); + Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( + FreeFunctionParameter, FreeFunctionParamType, VK_LValue, + FreeFunctionSrcLoc); + DRE = SemaSYCLRef.SemaRef.DefaultLvalueConversion(DRE).get(); + return DRE; + } + + MemberExpr *buildMemberExpr(Expr *Base, ValueDecl *Member) { + return MemberExpr::CreateImplicit( + SemaSYCLRef.getASTContext(), Base, /*IsArrow */ false, Member, + Member->getType(), VK_LValue, OK_Ordinary); + } + +public: + static constexpr const bool VisitInsideSimpleContainers = false; + + FreeFunctionKernelParamDecomposer(SemaSYCL &S, SYCLIntegrationHeader &Header, FunctionDecl *FF, SyclKernelDeclCreator &DC) + : SyclKernelFieldHandler(S), FreeFunctionSrcLoc(FF->getLocation()), FreeFunction(FF), H(Header), DeclCreator(DC) {} + +bool handleSyclSpecialType(ParmVarDecl *, QualType) final { return true; } + + bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { + ParmVarDecl * ParentStruct = DeclCreator.getParentStructForCurrentField(); + Expr *Base = createParamReferenceExpr(ParentStruct); + for (const auto &child : CurrentStructs) { + Base = buildMemberExpr(Base, child); + } + MemberExpr *MemberAccess = buildMemberExpr(Base, FD); + H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), MemberAccess); + return true; + } + + bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { + CurrentStructs.push_back(FD); + return true; + } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + CurrentStructs.pop_back(); + return true; + } + bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + QualType Ty) final { + TopLevelStruct = PD; + 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 ParamTy) final { + return true; + } + + bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { + return true; + } + + bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, + QualType Ty) final { + return true; + } + + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType) final { + return true; + } + + bool handleNonDecompStruct(const CXXRecordDecl *RD, + const CXXBaseSpecifier &BS, QualType Ty) final { + return true; + } + + bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { + ParmVarDecl * ParentStruct = DeclCreator.getParentStructForCurrentField(); + Expr *Base = createParamReferenceExpr(ParentStruct); + for (const auto &child : CurrentStructs) { + Base = buildMemberExpr(Base, child); + } + MemberExpr *MemberAccess = buildMemberExpr(Base, FD); + H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), MemberAccess); + return true; + } + + bool handleScalarType(ParmVarDecl *, QualType) final { + return true; + } + + bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { + return true; + } + + bool handleUnionType(ParmVarDecl *, QualType) final { + return true; + } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *FD, QualType Ty) final { + 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. @@ -5012,7 +5190,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + bool enterStruct(const CXXRecordDecl *, ParmVarDecl * PD, QualType Ty) final { + addParam(PD, Ty, SYCLIntegrationHeader::kind_std_layout); return true; } @@ -5527,14 +5706,16 @@ void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, FreeFunctionKernelBodyCreator kernel_body(*this, kernel_decl, FD); - SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), - FD->getType(), FD); + FreeFunctionKernelParamDecomposer decomposer(*this, getSyclIntegrationHeader(), FD, kernel_decl); + + SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), FD->getType(), FD); SyclKernelIntFooterCreator int_footer(*this, getSyclIntegrationFooter()); KernelObjVisitor Visitor{*this}; - Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, int_header, int_footer); - + Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, decomposer, + int_header, int_footer); + assert(getKernelFDPairs().back().first == FD && "OpenCL Kernel not found for free function entry"); // Register the kernel name with the OpenCL kernel generated for the @@ -6068,6 +6249,7 @@ static const char *paramKind2Str(KernelParamKind K) { CASE(work_group_memory); CASE(dynamic_work_group_memory); CASE(dynamic_accessor); + CASE(special_type_wrapper); } return ""; @@ -6710,6 +6892,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "#include \n"; O << "#include \n"; O << "#include \n"; + O << "#include \n"; O << "\n"; LangOptions LO; @@ -7016,25 +7199,45 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } ParmListWithNamesOstream.flush(); for (ParmVarDecl *Param : K.SyclKernel->parameters()) { - // if (FreeFunctionKernelBodyCreator::isSpecialTypeWrapper( - // Param->getType())) { - // this is a struct that contains a special type so its neither a - // special type nor a trivially copyable type. We therefore need to - // explicitly communicate to the runtime that this argument should be - // allowed as a free function kernel argument. We do this by defining - // a certain trait recognized by the runtime to be true. - O << "template <>\n"; - O << "struct " - "sycl::ext::oneapi::experimental::detail::is_explicitly_allowed_" - "arg<"; - Policy.SuppressTagKeyword = true; + if (DecompositionMap.count(Param->getType().getAsOpaquePtr())) { + // this is a struct that contains a special type so its neither a + // special type nor a trivially copyable type. We therefore need to + // explicitly communicate to the runtime that this argument should be + // allowed as a free function kernel argument. We do this by defining + // a certain trait recognized by the runtime to be true. + O << "template <>\n"; + O << "struct " + "sycl::ext::oneapi::experimental::detail::is_special_type_" + "wrapper<"; + Policy.SuppressTagKeyword = true; - Param->getType().print(O, Policy); - Policy.SuppressTagKeyword = false; - O << "> {\n"; - O << " static constexpr bool value = true;\n};\n"; - //} + Param->getType().print(O, Policy); + O << "> {\n"; + O << " inline static constexpr bool value = true;\n};\n\n"; + O << " namespace sycl { inline namespace _V1 { namespace ext { namespace oneapi { namespace " + "experimental { namespace detail { \n"; + O << "template <> struct special_type_wrapper_info<"; + Param->getType().print(O, Policy); + O << "> {\n"; + O << "template< typename DataT, typename HandlerT, typename = " + "std::enable_if_t, "; + Param->getType().print(O, Policy); + O << ">>>\n"; + O << "static void set_arg(int ArgIndex, DataT& "; + O << "_arg_struct"; + O << ", HandlerT& cgh, int &Shift) {\n"; + for (const MemberExpr *wrappedSpecialType : + DecompositionMap[Param->getType().getAsOpaquePtr()]) { + O << " cgh.set_arg(ArgIndex, "; + wrappedSpecialType->printPretty(O, nullptr, Policy); + O << ");\n"; + O << " ++ArgIndex;\n"; + } + O << " Shift = " << DecompositionMap[Param->getType().getAsOpaquePtr()].size() << ";\n"; + O << "}\n };\n} // namespace detail \n} // namespace experimental \n} // namespace oneapi \n} // namespace ext \n} // namespace _V1\n} //namespace sycl\n"; + } } + Policy.SuppressTagKeyword = false; FunctionTemplateDecl *FTD = K.SyclKernel->getPrimaryTemplate(); Policy.PrintAsCanonical = false; Policy.SuppressDefinition = true; diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index c564d6239ec80..c6489c70009d0 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #pragma once +#include +#include namespace sycl { inline namespace _V1 { @@ -45,13 +47,12 @@ template inline constexpr bool is_kernel_v = is_kernel::value; namespace detail { -template struct is_explicitly_allowed_arg { - static constexpr bool value = false; +template struct is_special_type_wrapper { + inline static constexpr bool value = false; }; template -inline constexpr bool is_explicitly_allowed_arg_v = - is_explicitly_allowed_arg::value; +struct special_type_wrapper_info {}; } // namespace detail } // namespace ext::oneapi::experimental diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index f4935fe5d3e46..30e484c007992 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #pragma once - +#include #include #include #include @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -163,6 +162,10 @@ __SYCL_EXPORT void *async_malloc_from_pool(sycl::handler &h, size_t size, } // namespace ext::oneapi::experimental namespace ext::oneapi::experimental::detail { +template +struct is_special_type_wrapper; +template +struct special_type_wrapper_info; class dynamic_parameter_base; class dynamic_work_group_memory_base; class dynamic_local_accessor_base; @@ -666,6 +669,7 @@ class __SYCL_EXPORT handler { void setArgHelper(int ArgIndex, detail::work_group_memory_impl &Arg); + // setArgHelper for non local accessor argument. template @@ -673,6 +677,7 @@ class __SYCL_EXPORT handler { setArgHelper( int ArgIndex, accessor &&Arg) { + std::cout << "Called accessor " << ArgIndex << std::endl; detail::AccessorBaseHost *AccBase = (detail::AccessorBaseHost *)&Arg; const detail::AccessorImplPtr &AccImpl = detail::getSyclObjImpl(*AccBase); detail::AccessorImplHost *Req = AccImpl.get(); @@ -683,7 +688,7 @@ class __SYCL_EXPORT handler { template void setArgHelper(int ArgIndex, T &&Arg) { void *StoredArg = storePlainArg(Arg); - + std::cout << "Called " << ArgIndex << std::endl; if (!std::is_same::value && std::is_pointer::value) { addArg(detail::kernel_param_kind_t::kind_pointer, StoredArg, sizeof(T), ArgIndex); @@ -1816,9 +1821,7 @@ class __SYCL_EXPORT handler { || (!is_same_type::value && std::is_pointer_v>) // USM || is_same_type::value // Interop - || is_same_type::value // Stream - || ext::oneapi::experimental::detail::is_explicitly_allowed_arg< - remove_cv_ref_t>::value; + || is_same_type::value; // Stream }; /// Sets argument for OpenCL interoperability kernels. @@ -1838,7 +1841,7 @@ class __SYCL_EXPORT handler { void set_arg(int ArgIndex, accessor Arg) { - setArgHelper(ArgIndex, std::move(Arg)); + setArgHelper(ArgIndex, std::move(Arg)); } template @@ -1856,6 +1859,19 @@ class __SYCL_EXPORT handler { setArgHelper(ArgIndex, ArgImpl); } + template + typename std::enable_if_t< + ext::oneapi::experimental::detail::is_special_type_wrapper< + remove_cv_ref_t>::value, + void> + set_arg(int ArgIndex, T &Arg) { + setArgHelper(ArgIndex, Arg); + int Shift; + ext::oneapi::experimental::detail::special_type_wrapper_info< + remove_cv_ref_t>::template set_arg(ArgIndex + 1, Arg, *this, Shift); + MArgShift += Shift; + } + // set_arg for graph dynamic_parameters template void set_arg(int argIndex, @@ -3386,6 +3402,8 @@ class __SYCL_EXPORT handler { bool MIsFinalized = false; event MLastEvent; + int MArgShift = 0; + // Make queue_impl class friend to be able to call finalize method. friend class detail::queue_impl; // Make accessor class friend to keep the list of associated accessors. @@ -3395,7 +3413,8 @@ class __SYCL_EXPORT handler { friend class accessor; friend device detail::getDeviceFromHandler(handler &); friend detail::device_impl &detail::getDeviceImplFromHandler(handler &); - + //template + //friend struct ext::oneapi::experimental::detail::special_type_wrapper_info; template friend class detail::image_accessor; diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 739242128f0a2..8ac2bd8499ad0 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2308,6 +2308,8 @@ void SetArgBasedOnType( const ContextImplPtr &ContextImpl, detail::ArgDesc &Arg, size_t NextTrueIndex) { switch (Arg.MType) { + case kernel_param_kind_t::kind_special_type_wrapper: + break; case kernel_param_kind_t::kind_dynamic_work_group_memory: break; case kernel_param_kind_t::kind_work_group_memory: diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 80db373592be4..13a75d1cef97c 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1153,6 +1153,7 @@ void handler::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, "Invalid kernel param kind"); break; } + std::cout << impl->MArgs.size() << std::endl; } void handler::setArgHelper(int ArgIndex, detail::work_group_memory_impl &Arg) { @@ -1177,12 +1178,12 @@ void handler::setArgHelper(int ArgIndex, stream &&Str) { // TODO: the constant can be removed if the size of MArgs will be calculated at // compile time. inline constexpr size_t MaxNumAdditionalArgs = 13; - void handler::extractArgsAndReqs() { assert(MKernel && "MKernel is not initialized"); std::vector UnPreparedArgs = std::move(impl->MArgs); clearArgs(); - + MArgShift = 0; + std::cout << detail::KernelInfoData::getNumParams() << std::endl; std::sort( UnPreparedArgs.begin(), UnPreparedArgs.end(), [](const detail::ArgDesc &first, const detail::ArgDesc &second) -> bool { @@ -2299,7 +2300,7 @@ void handler::addLifetimeSharedPtrStorage(std::shared_ptr SPtr) { void handler::addArg(detail::kernel_param_kind_t ArgKind, void *Req, int AccessTarget, int ArgIndex) { - impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, ArgIndex); + impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, ArgIndex + MArgShift); } void handler::clearArgs() { impl->MArgs.clear(); } diff --git a/sycl/test/extensions/free_function_special_types.cpp b/sycl/test/extensions/free_function_special_types.cpp index 5a9f9df4a1c83..71d7f2ec31a7c 100644 --- a/sycl/test/extensions/free_function_special_types.cpp +++ b/sycl/test/extensions/free_function_special_types.cpp @@ -5,31 +5,63 @@ #include +struct Baz { +// int a; + sycl::accessor accA; + sycl::accessor accB; + sycl::accessor accC; +}; + +struct Foo { + Baz b; + sycl::accessor Acc; +}; + +Baz b; + using namespace sycl; SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( (ext::oneapi::experimental::nd_range_kernel<1>)) -void foo(accessor acc, local_accessor lacc, sampler S, +void foo(Baz b) { + for (int i = 0; i < 10; ++i) { + b.accC[i] = b.accA[i] * b.accB[i] + 25; + } + //str << "Done!" << sycl::endl; +} /*, sampler S, stream str, ext::oneapi::experimental::annotated_arg arg, - ext::oneapi::experimental::annotated_ptr ptr) {} + ext::oneapi::experimental::annotated_ptr ptr, Foo f) {}*/ int main() { - queue Q; - kernel_bundle bundle = - get_kernel_bundle(Q.get_context()); - kernel_id id = ext::oneapi::experimental::get_kernel_id(); - kernel Kernel = bundle.get_kernel(id); - Q.submit([&](handler &h) { - accessor acc; - local_accessor lacc; - sycl::sampler S(sycl::coordinate_normalization_mode::unnormalized, - sycl::addressing_mode::clamp, - sycl::filtering_mode::nearest); - ext::oneapi::experimental::annotated_ptr ptr; - ext::oneapi::experimental::annotated_arg arg; - sycl::stream str(8192, 1024, h); - h.set_args(acc, lacc, S, str, arg, ptr); - h.parallel_for(nd_range{{1}, {1}}, Kernel); - }); + int Data[10]; + for (int i = 0; i < 10; ++i) { + Data[i] = i; + } + int Sum[10]; + { + buffer bufA(&Data[0], 10); + buffer bufB(&Data[0], 10); + buffer bufC(&Sum[0], 10); + queue Q; + kernel_bundle bundle = + get_kernel_bundle(Q.get_context()); + kernel_id id = ext::oneapi::experimental::get_kernel_id(); + kernel Kernel = bundle.get_kernel(id); + Q.submit([&](handler &h) { + sycl::stream str(8192, 1024, h); + accessor accA(bufA, h); + accessor accB(bufB, h); + accessor accC(bufC, h); + // local_accessor lacc; + // local_accessor macc; + b = Baz{accA, accB, accC}; + // Foo f; + h.set_args(b); + h.parallel_for(nd_range{{1}, {1}}, Kernel); + }); + } +for (int i = 0;i < 10; ++i) { + std::cout << Sum[i] << std::endl; +} return 0; } From 290288c6f45772671f7c739987b8ea118356c125 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 11 Jul 2025 09:37:08 -0700 Subject: [PATCH 07/69] Test --- sycl/source/detail/scheduler/commands.cpp | 2 -- sycl/source/handler.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 8ac2bd8499ad0..739242128f0a2 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2308,8 +2308,6 @@ void SetArgBasedOnType( const ContextImplPtr &ContextImpl, detail::ArgDesc &Arg, size_t NextTrueIndex) { switch (Arg.MType) { - case kernel_param_kind_t::kind_special_type_wrapper: - break; case kernel_param_kind_t::kind_dynamic_work_group_memory: break; case kernel_param_kind_t::kind_work_group_memory: diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 13a75d1cef97c..fa14c75fa5d01 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1183,7 +1183,7 @@ void handler::extractArgsAndReqs() { std::vector UnPreparedArgs = std::move(impl->MArgs); clearArgs(); MArgShift = 0; - std::cout << detail::KernelInfoData::getNumParams() << std::endl; + //std::cout << detail::KernelInfo::getNumParams() << std::endl; std::sort( UnPreparedArgs.begin(), UnPreparedArgs.end(), [](const detail::ArgDesc &first, const detail::ArgDesc &second) -> bool { From 5a2faeac0bc748619926fe39b7198f872413012a Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 16 Jul 2025 19:59:35 +0000 Subject: [PATCH 08/69] Fix offsets in integration header --- sycl/include/sycl/detail/kernel_desc.hpp | 1 + sycl/include/sycl/handler.hpp | 5 ++++- sycl/source/handler.cpp | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sycl/include/sycl/detail/kernel_desc.hpp b/sycl/include/sycl/detail/kernel_desc.hpp index a3324cb567d25..16dd7fdc8f033 100644 --- a/sycl/include/sycl/detail/kernel_desc.hpp +++ b/sycl/include/sycl/detail/kernel_desc.hpp @@ -61,6 +61,7 @@ enum class kernel_param_kind_t { kind_work_group_memory = 6, kind_dynamic_work_group_memory = 7, kind_dynamic_accessor = 8, + kind_special_type_wrapper = 9, kind_invalid = 0xf, // not a valid kernel kind }; diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 5dc43a3dbe2af..4e3db18f7fb98 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -707,10 +707,13 @@ class __SYCL_EXPORT handler { template void setArgHelper(int ArgIndex, T &&Arg) { void *StoredArg = storePlainArg(Arg); - std::cout << "Called " << ArgIndex << std::endl; if (!std::is_same::value && std::is_pointer::value) { addArg(detail::kernel_param_kind_t::kind_pointer, StoredArg, sizeof(T), ArgIndex); + } else if (ext::oneapi::experimental::detail::is_special_type_wrapper< + remove_cv_ref_t>::value) { + addArg(detail::kernel_param_kind_t::kind_special_type_wrapper, StoredArg, + sizeof(T), ArgIndex); } else { addArg(detail::kernel_param_kind_t::kind_std_layout, StoredArg, sizeof(T), ArgIndex); diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 2ba349d90b4b8..aedd6d91c8e2a 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1066,6 +1066,7 @@ void handler::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, } switch (Kind) { + case kernel_param_kind_t::kind_special_type_wrapper: case kernel_param_kind_t::kind_std_layout: case kernel_param_kind_t::kind_pointer: { addArg(Kind, Ptr, Size, Index + IndexShift); From dcac4426b9ce498c2b72897ab552d18dad2605fb Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 16 Jul 2025 20:01:39 +0000 Subject: [PATCH 09/69] Fix offsets in integration header --- clang/lib/Sema/SemaSYCL.cpp | 59 ++++++++++--------------------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ddd05e609c8b5..9a0fbaeb30431 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4531,8 +4531,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { // Being inside this function means there is a struct parameter to the free // function kernel that contains a special type. - //ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - Expr *Base = ArgExprs.back(); + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + Expr *Base = createParamReferenceExpr(ParentStruct); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } @@ -4670,39 +4670,6 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) final { - const auto *RecordDecl = ParamTy->getAsCXXRecordDecl(); - AccessSpecifier DefaultConstructorAccess; - auto DefaultConstructor = - std::find_if(RecordDecl->ctor_begin(), RecordDecl->ctor_end(), - [](auto it) { return it->isDefaultConstructor(); }); - DefaultConstructorAccess = DefaultConstructor->getAccess(); - DefaultConstructor->setAccess(AS_public); - - ASTContext &Ctx = SemaSYCLRef.SemaRef.getASTContext(); - VarDecl *SpecialObjectClone = - VarDecl::Create(Ctx, DeclCreator.getKernelDecl(), FreeFunctionSrcLoc, - FreeFunctionSrcLoc, PD->getIdentifier(), ParamTy, - Ctx.getTrivialTypeSourceInfo(ParamTy), SC_None); - InitializedEntity VarEntity = - InitializedEntity::InitializeVariable(SpecialObjectClone); - InitializationKind InitKind = - InitializationKind::CreateDefault(FreeFunctionSrcLoc); - InitializationSequence InitSeq(SemaSYCLRef.SemaRef, VarEntity, InitKind, - std::nullopt); - ExprResult Init = - InitSeq.Perform(SemaSYCLRef.SemaRef, VarEntity, InitKind, std::nullopt); - SpecialObjectClone->setInit( - SemaSYCLRef.SemaRef.MaybeCreateExprWithCleanups(Init.get())); - SpecialObjectClone->setInitStyle(VarDecl::CallInit); - DefaultConstructor->setAccess(DefaultConstructorAccess); - - Stmt *DS = new (SemaSYCLRef.getASTContext()) - DeclStmt(DeclGroupRef(SpecialObjectClone), FreeFunctionSrcLoc, - FreeFunctionSrcLoc); - BodyStmts.push_back(DS); - Expr *MemberBaseExpr = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - SpecialObjectClone, ParamTy, VK_PRValue, FreeFunctionSrcLoc); - ArgExprs.push_back(MemberBaseExpr); return true; } @@ -4712,9 +4679,9 @@ return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - //ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - //ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - // ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( + ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4926,7 +4893,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { int64_t CurOffset = 0; llvm::SmallVector ArrayBaseOffsets; int StructDepth = 0; - + bool SpecialTypeWrapper = false; // A series of functions to calculate the change in offset based on the type. int64_t offsetOf(const FieldDecl *FD, QualType ArgTy) const { return isArrayElement(FD, ArgTy) @@ -4965,7 +4932,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { Size = SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); Header.addParamDesc(Kind, static_cast(Size), - static_cast(CurOffset + OffsetAdj)); + static_cast( + (SpecialTypeWrapper ? 0 : CurOffset) + OffsetAdj)); } public: @@ -5040,7 +5008,10 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; - Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); + if (SpecialTypeWrapper) + Header.addParamDesc(ParamKind, Info, static_cast(offsetOf(FD, FieldTy))); + else + Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::work_group_memory)) { @@ -5195,7 +5166,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl * PD, QualType Ty) final { - addParam(PD, Ty, SYCLIntegrationHeader::kind_std_layout); + addParam(PD, Ty, SYCLIntegrationHeader::kind_special_type_wrapper); + SpecialTypeWrapper = true; return true; } @@ -5206,7 +5178,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - return true; + SpecialTypeWrapper = false; +return true; } bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, From dff980bab70d01a34b538b49e4a4bde29179fa97 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 14:31:57 +0000 Subject: [PATCH 10/69] Refine changes --- clang/lib/Sema/SemaSYCL.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 9a0fbaeb30431..070544febbe66 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7238,7 +7238,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } ParmListWithNamesOstream.flush(); for (ParmVarDecl *Param : K.SyclKernel->parameters()) { - if (DecompositionMap.count(Param->getType().getAsOpaquePtr())) { + if (DecompositionMap.count(Param->getType().getTypePtr())) { // this is a struct that contains a special type so its neither a // special type nor a trivially copyable type. We therefore need to // explicitly communicate to the runtime that this argument should be @@ -7253,7 +7253,8 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { Param->getType().print(O, Policy); O << "> {\n"; O << " inline static constexpr bool value = true;\n};\n\n"; - O << " namespace sycl { inline namespace _V1 { namespace ext { namespace oneapi { namespace " + O << "namespace sycl { inline namespace _V1 { namespace ext { " + "namespace oneapi { namespace " "experimental { namespace detail { \n"; O << "template <> struct special_type_wrapper_info<"; Param->getType().print(O, Policy); @@ -7263,17 +7264,21 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { Param->getType().print(O, Policy); O << ">>>\n"; O << "static void set_arg(int ArgIndex, DataT& "; - O << "_arg_struct"; - O << ", HandlerT& cgh, int &Shift) {\n"; + O << "arg"; + O << ", HandlerT& cgh, int &NumArgs) {\n"; for (const MemberExpr *wrappedSpecialType : - DecompositionMap[Param->getType().getAsOpaquePtr()]) { + DecompositionMap[Param->getType().getTypePtr()]) { O << " cgh.set_arg(ArgIndex, "; wrappedSpecialType->printPretty(O, nullptr, Policy); O << ");\n"; O << " ++ArgIndex;\n"; } - O << " Shift = " << DecompositionMap[Param->getType().getAsOpaquePtr()].size() << ";\n"; - O << "}\n };\n} // namespace detail \n} // namespace experimental \n} // namespace oneapi \n} // namespace ext \n} // namespace _V1\n} //namespace sycl\n"; + O << " NumArgs = " + << DecompositionMap[Param->getType().getTypePtr()].size() + << ";\n"; + O << "}\n};\n} // namespace detail \n} // namespace experimental \n} " + "// namespace oneapi \n} // namespace ext \n} // namespace _V1\n} " + "//namespace sycl\n"; } } Policy.SuppressTagKeyword = false; From b3e935f6ff3d9eba3e0bc5bea5f3faab95037aae Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 14:35:41 +0000 Subject: [PATCH 11/69] Formatting an comments --- sycl/include/sycl/handler.hpp | 11 ++++++++--- sycl/source/handler.cpp | 7 ++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 4e3db18f7fb98..3d77d71a46df0 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1919,10 +1919,10 @@ class __SYCL_EXPORT handler { void> set_arg(int ArgIndex, T &Arg) { setArgHelper(ArgIndex, Arg); - int Shift; + int NumArgs; ext::oneapi::experimental::detail::special_type_wrapper_info< - remove_cv_ref_t>::template set_arg(ArgIndex + 1, Arg, *this, Shift); - MArgShift += Shift; + remove_cv_ref_t>::template set_arg(ArgIndex + 1, Arg, *this, NumArgs); + MArgShift += NumArgs; } // set_arg for graph dynamic_parameters @@ -3455,6 +3455,11 @@ class __SYCL_EXPORT handler { event MLastEventDoNotUse; #endif + // Certain arguments such as structs that contain SYCL special types entail + // several hidden set_arg calls for every set_arg called by the user. This + // shift is required to make sure the following arguments set by the user have + // the correct index. It keeps track of how many of these hidden set_arg calls + // have been made so far. int MArgShift = 0; // Make queue_impl class friend to be able to call finalize method. diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 91c9bcec56699..8cedcd5c0b5d3 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1253,8 +1253,6 @@ void handler::extractArgsAndReqs() { assert(MKernel && "MKernel is not initialized"); std::vector UnPreparedArgs = std::move(impl->MArgs); clearArgs(); - MArgShift = 0; - //std::cout << detail::KernelInfo::getNumParams() << std::endl; std::sort( UnPreparedArgs.begin(), UnPreparedArgs.end(), [](const detail::ArgDesc &first, const detail::ArgDesc &second) -> bool { @@ -2420,7 +2418,10 @@ void handler::addArg(detail::kernel_param_kind_t ArgKind, void *Req, impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, ArgIndex + MArgShift); } -void handler::clearArgs() { impl->MArgs.clear(); } +void handler::clearArgs() { + impl->MArgs.clear(); + MArgShift = 0; +} void handler::setArgsToAssociatedAccessors() { impl->MArgs = impl->MAssociatedAccesors; From 4659ec2a5b7644c8fbf7b3636d1a35b49fd73cc5 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 14:44:20 +0000 Subject: [PATCH 12/69] Formatting --- clang/lib/Sema/SemaSYCL.cpp | 48 +++++++------ .../free_function_special_types.cpp | 67 ------------------- 2 files changed, 23 insertions(+), 92 deletions(-) delete mode 100644 sycl/test/extensions/free_function_special_types.cpp diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 742b60031c121..66c6afe39424f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2570,7 +2570,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { return true; @@ -2851,6 +2850,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // For free function kernels the arguments are named in direct mapping // with the names they have in the __init method i.e __arg_Ptr for work // group memory since its init function takes a parameter with Ptr name. + if constexpr (std::is_same_v) + addParam(decl, ParamTy.getCanonicalType()); + else addParam(Param, ParamTy.getCanonicalType()); // Propagate add_ir_attributes_kernel_parameter attribute. if (const auto *AddIRAttr = @@ -2996,7 +2998,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleStructType(ParmVarDecl *PD, QualType Ty) final { - StringRef Name = "_arg_struct"; + StringRef Name = "_arg_struct"; addParam(Name, Ty); CurrentStruct = Params.back(); return true; @@ -4524,7 +4526,6 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { ~FreeFunctionKernelBodyCreator() { CompoundStmt *KernelBody = createFreeFunctionKernelBody(); - KernelBody->dumpPretty(SemaSYCLRef.SemaRef.getASTContext()); DeclCreator.setBody(KernelBody); } @@ -4757,19 +4758,22 @@ class FreeFunctionKernelParamDecomposer : public SyclKernelFieldHandler { public: static constexpr const bool VisitInsideSimpleContainers = false; - FreeFunctionKernelParamDecomposer(SemaSYCL &S, SYCLIntegrationHeader &Header, FunctionDecl *FF, SyclKernelDeclCreator &DC) - : SyclKernelFieldHandler(S), FreeFunctionSrcLoc(FF->getLocation()), FreeFunction(FF), H(Header), DeclCreator(DC) {} + FreeFunctionKernelParamDecomposer(SemaSYCL &S, SYCLIntegrationHeader &Header, + FunctionDecl *FF, SyclKernelDeclCreator &DC) + : SyclKernelFieldHandler(S), FreeFunctionSrcLoc(FF->getLocation()), + FreeFunction(FF), H(Header), DeclCreator(DC) {} -bool handleSyclSpecialType(ParmVarDecl *, QualType) final { return true; } + bool handleSyclSpecialType(ParmVarDecl *, QualType) final { return true; } bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { - ParmVarDecl * ParentStruct = DeclCreator.getParentStructForCurrentField(); + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); Expr *Base = createParamReferenceExpr(ParentStruct); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } MemberExpr *MemberAccess = buildMemberExpr(Base, FD); - H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), MemberAccess); + H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), + MemberAccess); return true; } @@ -4787,14 +4791,12 @@ bool handleSyclSpecialType(ParmVarDecl *, QualType) final { return true; } return true; } -bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, + bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType Ty) final { return true; } - bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { - return true; - } + bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { return true; } bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { return true; @@ -4820,27 +4822,22 @@ bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - ParmVarDecl * ParentStruct = DeclCreator.getParentStructForCurrentField(); + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); Expr *Base = createParamReferenceExpr(ParentStruct); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } MemberExpr *MemberAccess = buildMemberExpr(Base, FD); - H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), MemberAccess); + H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), + MemberAccess); return true; } - bool handleScalarType(ParmVarDecl *, QualType) final { - return true; - } + bool handleScalarType(ParmVarDecl *, QualType) final { return true; } - bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { - return true; - } + bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return true; } - bool handleUnionType(ParmVarDecl *, QualType) final { - return true; - } + bool handleUnionType(ParmVarDecl *, QualType) final { return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *FD, QualType Ty) final { return true; } @@ -4893,6 +4890,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { int64_t CurOffset = 0; llvm::SmallVector ArrayBaseOffsets; int StructDepth = 0; + // Set if we are currently exploring fields of a struct that contains special types bool SpecialTypeWrapper = false; // A series of functions to calculate the change in offset based on the type. int64_t offsetOf(const FieldDecl *FD, QualType ArgTy) const { @@ -5178,8 +5176,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - SpecialTypeWrapper = false; -return true; + SpecialTypeWrapper = false; + return true; } bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, diff --git a/sycl/test/extensions/free_function_special_types.cpp b/sycl/test/extensions/free_function_special_types.cpp deleted file mode 100644 index 71d7f2ec31a7c..0000000000000 --- a/sycl/test/extensions/free_function_special_types.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// RUN: %clangxx -fsyntax-only -fsycl %s - -// Verify that we can pass top-level special type parameters to free function -// kernels. - -#include - -struct Baz { -// int a; - sycl::accessor accA; - sycl::accessor accB; - sycl::accessor accC; -}; - -struct Foo { - Baz b; - sycl::accessor Acc; -}; - -Baz b; - -using namespace sycl; - -SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( - (ext::oneapi::experimental::nd_range_kernel<1>)) -void foo(Baz b) { - for (int i = 0; i < 10; ++i) { - b.accC[i] = b.accA[i] * b.accB[i] + 25; - } - //str << "Done!" << sycl::endl; -} /*, sampler S, - stream str, ext::oneapi::experimental::annotated_arg arg, - ext::oneapi::experimental::annotated_ptr ptr, Foo f) {}*/ - -int main() { - int Data[10]; - for (int i = 0; i < 10; ++i) { - Data[i] = i; - } - int Sum[10]; - { - buffer bufA(&Data[0], 10); - buffer bufB(&Data[0], 10); - buffer bufC(&Sum[0], 10); - queue Q; - kernel_bundle bundle = - get_kernel_bundle(Q.get_context()); - kernel_id id = ext::oneapi::experimental::get_kernel_id(); - kernel Kernel = bundle.get_kernel(id); - Q.submit([&](handler &h) { - sycl::stream str(8192, 1024, h); - accessor accA(bufA, h); - accessor accB(bufB, h); - accessor accC(bufC, h); - // local_accessor lacc; - // local_accessor macc; - b = Baz{accA, accB, accC}; - // Foo f; - h.set_args(b); - h.parallel_for(nd_range{{1}, {1}}, Kernel); - }); - } -for (int i = 0;i < 10; ++i) { - std::cout << Sum[i] << std::endl; -} - return 0; -} From 18c185a61ab3f3546070260b6d9708943283c14f Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 11:13:57 -0700 Subject: [PATCH 13/69] More formatting --- clang/include/clang/Sema/SemaSYCL.h | 15 +- clang/lib/Sema/SemaSYCL.cpp | 233 ++++-------------- .../experimental/free_function_traits.hpp | 14 +- sycl/include/sycl/handler.hpp | 14 +- sycl/source/handler.cpp | 1 - 5 files changed, 78 insertions(+), 199 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 3c12032691a4b..4667932eedef6 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -119,9 +119,12 @@ class SYCLIntegrationHeader { /// integration header is required. void addHostPipeRegistration() { NeedToEmitHostPipeRegistration = true; } -void addFreeFunctionParamDecomposition(QualType Ty, MemberExpr *expr) { - DecompositionMap[Ty.getAsOpaquePtr()].push_back(expr); -} + // Add the entry (Ty, Offset) to the SpecialTypeOffsetMap. + void addSpecialTypeOffset(const Type *ParentStruct, QualType Ty, + int64_t offset) { + SpecialTypeOffsetMap[ParentStruct].push_back(std::make_pair(Ty, offset)); + } + private: // Kernel actual parameter descriptor. struct KernelParamDesc { @@ -209,7 +212,11 @@ void addFreeFunctionParamDecomposition(QualType Ty, MemberExpr *expr) { /// type and __sycl_host_pipe_registrar variable are required to emit. bool NeedToEmitHostPipeRegistration = false; - llvm::DenseMap> DecompositionMap; + // A map that keeps track of type and offset of each special class contained + // inside a struct + llvm::DenseMap, 8>> + SpecialTypeOffsetMap; }; class SYCLIntegrationFooter { diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 66c6afe39424f..d208a083a274c 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2698,9 +2698,9 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionDecl *KernelDecl = nullptr; llvm::SmallVector Params; - // Holds the last handled kernel struct parameter that contains a special type. - // Set in the enterStruct functions. - ParmVarDecl * CurrentStruct; + // Holds the last handled kernel struct parameter that contains a special + // type. Set in the enterStruct functions. + ParmVarDecl *CurrentStruct; Sema::ContextRAII FuncContext; // Holds the last handled field's first parameter. This doesn't store an // iterator as push_back invalidates iterators. @@ -2962,7 +2962,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { SYCLKernelAttr::CreateImplicit(SemaSYCLRef.getASTContext())); SemaSYCLRef.addSyclDeviceDecl(KernelDecl); - KernelDecl->dump(); } bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) final { @@ -4538,8 +4537,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { Base = buildMemberExpr(Base, child); } MemberExpr *MemberAccess = buildMemberExpr(Base, FD); - createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, - MemberAccess, BodyStmts); + createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, + MemberAccess, BodyStmts); return true; } @@ -4642,9 +4641,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - return true; - } + bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { return true; } bool handleScalarType(ParmVarDecl *, QualType) final { Expr *ParamRef = createParamReferenceExpr(); @@ -4671,7 +4668,7 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) final { -return true; + return true; } bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { @@ -4682,7 +4679,7 @@ return true; bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); + ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4730,149 +4727,6 @@ return true; } }; -class FreeFunctionKernelParamDecomposer : public SyclKernelFieldHandler { - ParmVarDecl *TopLevelStruct; - llvm::SmallVector CurrentStructs; - SourceLocation FreeFunctionSrcLoc; - FunctionDecl *FreeFunction; - SYCLIntegrationHeader &H; - SyclKernelDeclCreator &DeclCreator; - - // Creates a DeclRefExpr to the ParmVar that represents an arbitrary - // free function parameter - Expr *createParamReferenceExpr(ParmVarDecl *FreeFunctionParameter) { - QualType FreeFunctionParamType = FreeFunctionParameter->getOriginalType(); - Expr *DRE = SemaSYCLRef.SemaRef.BuildDeclRefExpr( - FreeFunctionParameter, FreeFunctionParamType, VK_LValue, - FreeFunctionSrcLoc); - DRE = SemaSYCLRef.SemaRef.DefaultLvalueConversion(DRE).get(); - return DRE; - } - - MemberExpr *buildMemberExpr(Expr *Base, ValueDecl *Member) { - return MemberExpr::CreateImplicit( - SemaSYCLRef.getASTContext(), Base, /*IsArrow */ false, Member, - Member->getType(), VK_LValue, OK_Ordinary); - } - -public: - static constexpr const bool VisitInsideSimpleContainers = false; - - FreeFunctionKernelParamDecomposer(SemaSYCL &S, SYCLIntegrationHeader &Header, - FunctionDecl *FF, SyclKernelDeclCreator &DC) - : SyclKernelFieldHandler(S), FreeFunctionSrcLoc(FF->getLocation()), - FreeFunction(FF), H(Header), DeclCreator(DC) {} - - bool handleSyclSpecialType(ParmVarDecl *, QualType) final { return true; } - - bool handleSyclSpecialType(FieldDecl *FD, QualType Ty) final { - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - Expr *Base = createParamReferenceExpr(ParentStruct); - for (const auto &child : CurrentStructs) { - Base = buildMemberExpr(Base, child); - } - MemberExpr *MemberAccess = buildMemberExpr(Base, FD); - H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), - MemberAccess); - return true; - } - - bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { - CurrentStructs.push_back(FD); - return true; - } - bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - CurrentStructs.pop_back(); - return true; - } - bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType Ty) final { - TopLevelStruct = PD; - 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 ParamTy) final { - return true; - } - - bool handleSimpleArrayType(FieldDecl *FD, QualType FieldTy) final { - return true; - } - - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, - QualType Ty) final { - return true; - } - - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType) final { - return true; - } - - bool handleNonDecompStruct(const CXXRecordDecl *RD, - const CXXBaseSpecifier &BS, QualType Ty) final { - return true; - } - - bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - Expr *Base = createParamReferenceExpr(ParentStruct); - for (const auto &child : CurrentStructs) { - Base = buildMemberExpr(Base, child); - } - MemberExpr *MemberAccess = buildMemberExpr(Base, FD); - H.addFreeFunctionParamDecomposition(TopLevelStruct->getType(), - MemberAccess); - return true; - } - - bool handleScalarType(ParmVarDecl *, QualType) final { return true; } - - bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { return true; } - - bool handleUnionType(ParmVarDecl *, QualType) final { return true; } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *FD, QualType Ty) final { - 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. @@ -4890,8 +4744,11 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { int64_t CurOffset = 0; llvm::SmallVector ArrayBaseOffsets; int StructDepth = 0; - // Set if we are currently exploring fields of a struct that contains special types - bool SpecialTypeWrapper = false; + + // Set if we are currently exploring fields of a struct that is a free + // function kernel parameter + const Type *ParentStruct = nullptr; + // A series of functions to calculate the change in offset based on the type. int64_t offsetOf(const FieldDecl *FD, QualType ArgTy) const { return isArrayElement(FD, ArgTy) @@ -4929,9 +4786,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { uint64_t Size; Size = SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); - Header.addParamDesc(Kind, static_cast(Size), - static_cast( - (SpecialTypeWrapper ? 0 : CurOffset) + OffsetAdj)); + Header.addParamDesc( + Kind, static_cast(Size), + static_cast((ParentStruct ? 0 : CurOffset) + OffsetAdj)); } public: @@ -5006,9 +4863,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; - if (SpecialTypeWrapper) - Header.addParamDesc(ParamKind, Info, static_cast(offsetOf(FD, FieldTy))); - else + if (ParentStruct) + Header.addParamDesc(ParamKind, Info, offsetOf(FD, FieldTy)); + else Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); @@ -5037,6 +4894,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { llvm_unreachable( "Unexpected SYCL special class when generating integration header"); } + if (ParentStruct) + Header.addSpecialTypeOffset(ParentStruct, FieldTy, offsetOf(FD, FieldTy)); + return true; } @@ -5163,9 +5023,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl * PD, QualType Ty) final { + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { addParam(PD, Ty, SYCLIntegrationHeader::kind_special_type_wrapper); - SpecialTypeWrapper = true; + ParentStruct = Ty.getTypePtr(); return true; } @@ -5176,7 +5036,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - SpecialTypeWrapper = false; + ParentStruct = nullptr; return true; } @@ -5678,14 +5538,13 @@ void SemaSYCL::constructFreeFunctionKernel(FunctionDecl *FD, FreeFunctionKernelBodyCreator kernel_body(*this, kernel_decl, FD); - FreeFunctionKernelParamDecomposer decomposer(*this, getSyclIntegrationHeader(), FD, kernel_decl); - - SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), FD->getType(), FD); + SyclKernelIntHeaderCreator int_header(*this, getSyclIntegrationHeader(), + FD->getType(), FD); SyclKernelIntFooterCreator int_footer(*this, getSyclIntegrationFooter()); KernelObjVisitor Visitor{*this}; - Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, decomposer, + Visitor.VisitFunctionParameters(FD, argsSizeChecker, kernel_decl, kernel_body, int_header, int_footer); assert(getKernelFDPairs().back().first == FD && @@ -7235,13 +7094,20 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } } ParmListWithNamesOstream.flush(); + + // Now we handle all parameters that are structs that contain special types + // inside. Their information is coontained in SpecialTypeOffsetMap with keys + // the structs and values a vector of pairs representing the type and the + // offset of each special type inside this struct. + llvm::DenseMap visited; for (ParmVarDecl *Param : K.SyclKernel->parameters()) { - if (DecompositionMap.count(Param->getType().getTypePtr())) { + if (SpecialTypeOffsetMap.count(Param->getType().getTypePtr()) && + !visited[Param->getType().getTypePtr()]) { // this is a struct that contains a special type so its neither a // special type nor a trivially copyable type. We therefore need to // explicitly communicate to the runtime that this argument should be // allowed as a free function kernel argument. We do this by defining - // a certain trait recognized by the runtime to be true. + // is_special_type_wrapper to be true. O << "template <>\n"; O << "struct " "sycl::ext::oneapi::experimental::detail::is_special_type_" @@ -7257,26 +7123,29 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "template <> struct special_type_wrapper_info<"; Param->getType().print(O, Policy); O << "> {\n"; - O << "template< typename DataT, typename HandlerT, typename = " + O << "template< typename ArgT, typename HandlerT, typename = " "std::enable_if_t, "; Param->getType().print(O, Policy); O << ">>>\n"; - O << "static void set_arg(int ArgIndex, DataT& "; + O << " static void set_arg(int ArgIndex, ArgT& "; O << "arg"; O << ", HandlerT& cgh, int &NumArgs) {\n"; - for (const MemberExpr *wrappedSpecialType : - DecompositionMap[Param->getType().getTypePtr()]) { - O << " cgh.set_arg(ArgIndex, "; - wrappedSpecialType->printPretty(O, nullptr, Policy); + for (const auto TypeOffsetPair : + SpecialTypeOffsetMap[Param->getType().getTypePtr()]) { + O << " cgh.set_arg(ArgIndex, *("; + TypeOffsetPair.first.print(O, Policy); + O << " *)"; + O << "((char *)(&arg) + " << TypeOffsetPair.second << ")"; O << ");\n"; - O << " ++ArgIndex;\n"; + O << " ++ArgIndex;\n"; } - O << " NumArgs = " - << DecompositionMap[Param->getType().getTypePtr()].size() + O << " NumArgs = " + << SpecialTypeOffsetMap[Param->getType().getTypePtr()].size() << ";\n"; - O << "}\n};\n} // namespace detail \n} // namespace experimental \n} " + O << " }\n};\n} // namespace detail \n} // namespace experimental \n} " "// namespace oneapi \n} // namespace ext \n} // namespace _V1\n} " - "//namespace sycl\n"; + "// namespace sycl\n\n"; + visited[Param->getType().getTypePtr()] = true; } } Policy.SuppressTagKeyword = false; diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index c6489c70009d0..274f1f08c4a99 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -8,7 +8,6 @@ #pragma once #include -#include namespace sycl { inline namespace _V1 { @@ -47,12 +46,21 @@ template inline constexpr bool is_kernel_v = is_kernel::value; namespace detail { +// A special type wrapper is a struct type that contains special types. +// The frontend defines this trait to be true after analyzing the struct at compile time. template struct is_special_type_wrapper { inline static constexpr bool value = false; }; -template -struct special_type_wrapper_info {}; +// This struct is made to be specialized in the integration header. +// It calls set_arg for every special type contained in the struct regardless of +// the level of nesting. So if type Foo contains two accessors inside and the +// user calls set_arg(Foo), that call will call this function which will call +// set_arg for each of those two accessors. +template struct special_type_wrapper_info { + template + static void set_arg(int ArgIndex, ArgT &arg, HandlerT &cgh, int &NumArgs) {} +}; } // namespace detail } // namespace ext::oneapi::experimental diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 3d77d71a46df0..b7264e99e987b 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -162,10 +162,8 @@ __SYCL_EXPORT void *async_malloc_from_pool(sycl::handler &h, size_t size, } // namespace ext::oneapi::experimental namespace ext::oneapi::experimental::detail { -template -struct is_special_type_wrapper; -template -struct special_type_wrapper_info; +template struct is_special_type_wrapper; +template struct special_type_wrapper_info; class dynamic_parameter_base; class dynamic_work_group_memory_base; class dynamic_local_accessor_base; @@ -688,7 +686,6 @@ class __SYCL_EXPORT handler { void setArgHelper(int ArgIndex, detail::work_group_memory_impl &Arg); - // setArgHelper for non local accessor argument. template @@ -1894,7 +1891,7 @@ class __SYCL_EXPORT handler { void set_arg(int ArgIndex, accessor Arg) { - setArgHelper(ArgIndex, std::move(Arg)); + setArgHelper(ArgIndex, std::move(Arg)); } template @@ -1921,7 +1918,8 @@ class __SYCL_EXPORT handler { setArgHelper(ArgIndex, Arg); int NumArgs; ext::oneapi::experimental::detail::special_type_wrapper_info< - remove_cv_ref_t>::template set_arg(ArgIndex + 1, Arg, *this, NumArgs); + remove_cv_ref_t>::template set_arg(ArgIndex + 1, Arg, *this, + NumArgs); MArgShift += NumArgs; } @@ -3471,8 +3469,6 @@ class __SYCL_EXPORT handler { friend class accessor; friend device detail::getDeviceFromHandler(handler &); friend detail::device_impl &detail::getDeviceImplFromHandler(handler &); - //template - //friend struct ext::oneapi::experimental::detail::special_type_wrapper_info; template friend class detail::image_accessor; diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 8cedcd5c0b5d3..0d6e802128fc5 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1224,7 +1224,6 @@ void handler::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, "Invalid kernel param kind"); break; } - std::cout << impl->MArgs.size() << std::endl; } void handler::setArgHelper(int ArgIndex, detail::work_group_memory_impl &Arg) { From 9a32eac955ddf6d267d12b54b75221e849bc6ffa Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 11:18:56 -0700 Subject: [PATCH 14/69] More formatting --- clang/include/clang/Sema/SemaSYCL.h | 1 + sycl/include/sycl/handler.hpp | 4 ++-- sycl/source/handler.cpp | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 4667932eedef6..2d717929a04af 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -190,6 +190,7 @@ class SYCLIntegrationHeader { return KernelDescs.size() > 0 ? &KernelDescs[KernelDescs.size() - 1] : nullptr; } + private: /// Keeps invocation descriptors for each kernel invocation started by /// SYCLIntegrationHeader::startKernel diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index b7264e99e987b..10b389a3a3089 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #pragma once -#include #include #include #include @@ -693,7 +692,6 @@ class __SYCL_EXPORT handler { setArgHelper( int ArgIndex, accessor &&Arg) { - std::cout << "Called accessor " << ArgIndex << std::endl; detail::AccessorBaseHost *AccBase = (detail::AccessorBaseHost *)&Arg; const detail::AccessorImplPtr &AccImpl = detail::getSyclObjImpl(*AccBase); detail::AccessorImplHost *Req = AccImpl.get(); @@ -704,6 +702,7 @@ class __SYCL_EXPORT handler { template void setArgHelper(int ArgIndex, T &&Arg) { void *StoredArg = storePlainArg(Arg); + if (!std::is_same::value && std::is_pointer::value) { addArg(detail::kernel_param_kind_t::kind_pointer, StoredArg, sizeof(T), ArgIndex); @@ -3469,6 +3468,7 @@ class __SYCL_EXPORT handler { friend class accessor; friend device detail::getDeviceFromHandler(handler &); friend detail::device_impl &detail::getDeviceImplFromHandler(handler &); + template friend class detail::image_accessor; diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 0d6e802128fc5..fdc619414c008 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1248,10 +1248,12 @@ void handler::setArgHelper(int ArgIndex, stream &&Str) { // TODO: the constant can be removed if the size of MArgs will be calculated at // compile time. inline constexpr size_t MaxNumAdditionalArgs = 13; + void handler::extractArgsAndReqs() { assert(MKernel && "MKernel is not initialized"); std::vector UnPreparedArgs = std::move(impl->MArgs); clearArgs(); + std::sort( UnPreparedArgs.begin(), UnPreparedArgs.end(), [](const detail::ArgDesc &first, const detail::ArgDesc &second) -> bool { From 60764b6de9d92e6c6324c11c270bcd8d4c45bc61 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 11:19:33 -0700 Subject: [PATCH 15/69] More formatting --- sycl/include/sycl/handler.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 10b389a3a3089..77b319ae3268b 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #pragma once + #include #include #include From 4056a8a793cf68244aae8e17bb4205a93d7a1f86 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 11:20:39 -0700 Subject: [PATCH 16/69] Remove rogue changes --- .../free_function_special_types.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 sycl/test/extensions/free_function_special_types.cpp diff --git a/sycl/test/extensions/free_function_special_types.cpp b/sycl/test/extensions/free_function_special_types.cpp new file mode 100644 index 0000000000000..a392131f6caff --- /dev/null +++ b/sycl/test/extensions/free_function_special_types.cpp @@ -0,0 +1,35 @@ +// RUN: %clangxx -fsyntax-only -fsycl %s + +// Verify that we can pass top-level special type parameters to free function +// kernels. + +#include + +using namespace sycl; + +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( + (ext::oneapi::experimental::nd_range_kernel<1>)) +void foo(accessor acc, local_accessor lacc, sampler S, + stream str, ext::oneapi::experimental::annotated_arg arg, + ext::oneapi::experimental::annotated_ptr ptr) {} + +int main() { + queue Q; + kernel_bundle bundle = + get_kernel_bundle(Q.get_context()); + kernel_id id = ext::oneapi::experimental::get_kernel_id(); + kernel Kernel = bundle.get_kernel(id); + Q.submit([&](handler &h) { + accessor acc; + local_accessor lacc; + sycl::sampler S(sycl::coordinate_normalization_mode::unnormalized, + sycl::addressing_mode::clamp, + sycl::filtering_mode::nearest); + ext::oneapi::experimental::annotated_ptr ptr; + ext::oneapi::experimental::annotated_arg arg; + sycl::stream str(8192, 1024, h); + h.set_args(acc, lacc, S, str, arg, ptr); + h.parallel_for(nd_range{{1}, {1}}, Kernel); + }); + return 0; +} From f2e21a3ccbc29f048af8c10779039d3fc16ba9d1 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 11:21:31 -0700 Subject: [PATCH 17/69] More formatting --- .../free_function_special_types.cpp | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/sycl/test/extensions/free_function_special_types.cpp b/sycl/test/extensions/free_function_special_types.cpp index a392131f6caff..5a9f9df4a1c83 100644 --- a/sycl/test/extensions/free_function_special_types.cpp +++ b/sycl/test/extensions/free_function_special_types.cpp @@ -1,35 +1,35 @@ -// RUN: %clangxx -fsyntax-only -fsycl %s +// RUN: %clangxx -fsyntax-only -fsycl %s -// Verify that we can pass top-level special type parameters to free function -// kernels. +// Verify that we can pass top-level special type parameters to free function +// kernels. -#include +#include -using namespace sycl; +using namespace sycl; -SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( - (ext::oneapi::experimental::nd_range_kernel<1>)) -void foo(accessor acc, local_accessor lacc, sampler S, - stream str, ext::oneapi::experimental::annotated_arg arg, - ext::oneapi::experimental::annotated_ptr ptr) {} +SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( + (ext::oneapi::experimental::nd_range_kernel<1>)) +void foo(accessor acc, local_accessor lacc, sampler S, + stream str, ext::oneapi::experimental::annotated_arg arg, + ext::oneapi::experimental::annotated_ptr ptr) {} -int main() { - queue Q; - kernel_bundle bundle = - get_kernel_bundle(Q.get_context()); - kernel_id id = ext::oneapi::experimental::get_kernel_id(); - kernel Kernel = bundle.get_kernel(id); - Q.submit([&](handler &h) { - accessor acc; - local_accessor lacc; - sycl::sampler S(sycl::coordinate_normalization_mode::unnormalized, - sycl::addressing_mode::clamp, - sycl::filtering_mode::nearest); - ext::oneapi::experimental::annotated_ptr ptr; - ext::oneapi::experimental::annotated_arg arg; - sycl::stream str(8192, 1024, h); - h.set_args(acc, lacc, S, str, arg, ptr); - h.parallel_for(nd_range{{1}, {1}}, Kernel); - }); - return 0; +int main() { + queue Q; + kernel_bundle bundle = + get_kernel_bundle(Q.get_context()); + kernel_id id = ext::oneapi::experimental::get_kernel_id(); + kernel Kernel = bundle.get_kernel(id); + Q.submit([&](handler &h) { + accessor acc; + local_accessor lacc; + sycl::sampler S(sycl::coordinate_normalization_mode::unnormalized, + sycl::addressing_mode::clamp, + sycl::filtering_mode::nearest); + ext::oneapi::experimental::annotated_ptr ptr; + ext::oneapi::experimental::annotated_arg arg; + sycl::stream str(8192, 1024, h); + h.set_args(acc, lacc, S, str, arg, ptr); + h.parallel_for(nd_range{{1}, {1}}, Kernel); + }); + return 0; } From f0e9e1d46e7fbff1916811bedd3fe728b13839a8 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 19:29:06 -0700 Subject: [PATCH 18/69] Use offsets to access struct member in runtime --- clang/lib/Sema/SemaSYCL.cpp | 100 ++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d208a083a274c..2e3776ff9a5e9 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -6257,7 +6257,7 @@ class SYCLFwdDeclEmitter } void Visit(QualType T) { - if (T.isNull()) +if (T.isNull()) return; InnerTypeVisitor::Visit(T.getTypePtr()); } @@ -7095,6 +7095,52 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } ParmListWithNamesOstream.flush(); + Policy.SuppressTagKeyword = false; + FunctionTemplateDecl *FTD = K.SyclKernel->getPrimaryTemplate(); + Policy.PrintAsCanonical = false; + Policy.SuppressDefinition = true; + Policy.PolishForDeclaration = true; + Policy.FullyQualifiedName = true; + Policy.EnforceScopeForElaboratedTypes = true; + Policy.UseFullyQualifiedEnumerators = true; + + // Now we need to print the declaration of the kernel itself. + // Example: + // template struct Arg { + // T val; + // }; + // For the following free function kernel: + // template + // SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( + // (ext::oneapi::experimental::nd_range_kernel<1>)) + // void foo(Arg arg) {} + // Integration header must contain the following declaration: + // template + // void foo(Arg arg); + // SuppressDefaultTemplateArguments is a downstream addition that suppresses + // default template arguments in the function declaration. It should be set + // to true to emit function declaration that won't cause any compilation + // errors when present in the integration header. + // To print Arg in the function declaration and shim functions we + // need to disable default arguments printing suppression via community flag + // SuppressDefaultTemplateArgs, otherwise they will be suppressed even for + // canonical types or if even written in the original source code. + Policy.SuppressDefaultTemplateArguments = true; + // EnforceDefaultTemplateArgs is a downstream addition that forces printing + // template arguments that match default template arguments while printing + // template-ids, even if the source code doesn't reference them. + Policy.EnforceDefaultTemplateArgs = true; + FreeFunctionPrinter FFPrinter(O, Policy); + if (FTD) { + FFPrinter.printFreeFunctionDeclaration(FTD); + if (const auto kind = K.SyclKernel->getTemplateSpecializationKind(); + K.SyclKernel->isFunctionTemplateSpecialization() && + kind == TSK_ExplicitSpecialization) + FFPrinter.printFreeFunctionDeclaration(K.SyclKernel, ParmListWithNames); + } else { + FFPrinter.printFreeFunctionDeclaration(K.SyclKernel, ParmListWithNames); + } + // Now we handle all parameters that are structs that contain special types // inside. Their information is coontained in SpecialTypeOffsetMap with keys // the structs and values a vector of pairs representing the type and the @@ -7113,7 +7159,6 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { "sycl::ext::oneapi::experimental::detail::is_special_type_" "wrapper<"; Policy.SuppressTagKeyword = true; - Param->getType().print(O, Policy); O << "> {\n"; O << " inline static constexpr bool value = true;\n};\n\n"; @@ -7142,57 +7187,14 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << " NumArgs = " << SpecialTypeOffsetMap[Param->getType().getTypePtr()].size() << ";\n"; - O << " }\n};\n} // namespace detail \n} // namespace experimental \n} " - "// namespace oneapi \n} // namespace ext \n} // namespace _V1\n} " + O << " }\n};\n} // namespace detail \n} // namespace experimental " + "\n} " + "// namespace oneapi \n} // namespace ext \n} // namespace " + "_V1\n} " "// namespace sycl\n\n"; visited[Param->getType().getTypePtr()] = true; } } - Policy.SuppressTagKeyword = false; - FunctionTemplateDecl *FTD = K.SyclKernel->getPrimaryTemplate(); - Policy.PrintAsCanonical = false; - Policy.SuppressDefinition = true; - Policy.PolishForDeclaration = true; - Policy.FullyQualifiedName = true; - Policy.EnforceScopeForElaboratedTypes = true; - Policy.UseFullyQualifiedEnumerators = true; - - // Now we need to print the declaration of the kernel itself. - // Example: - // template struct Arg { - // T val; - // }; - // For the following free function kernel: - // template - // SYCL_EXT_ONEAPI_FUNCTION_PROPERTY( - // (ext::oneapi::experimental::nd_range_kernel<1>)) - // void foo(Arg arg) {} - // Integration header must contain the following declaration: - // template - // void foo(Arg arg); - // SuppressDefaultTemplateArguments is a downstream addition that suppresses - // default template arguments in the function declaration. It should be set - // to true to emit function declaration that won't cause any compilation - // errors when present in the integration header. - // To print Arg in the function declaration and shim functions we - // need to disable default arguments printing suppression via community flag - // SuppressDefaultTemplateArgs, otherwise they will be suppressed even for - // canonical types or if even written in the original source code. - Policy.SuppressDefaultTemplateArguments = true; - // EnforceDefaultTemplateArgs is a downstream addition that forces printing - // template arguments that match default template arguments while printing - // template-ids, even if the source code doesn't reference them. - Policy.EnforceDefaultTemplateArgs = true; - FreeFunctionPrinter FFPrinter(O, Policy); - if (FTD) { - FFPrinter.printFreeFunctionDeclaration(FTD); - if (const auto kind = K.SyclKernel->getTemplateSpecializationKind(); - K.SyclKernel->isFunctionTemplateSpecialization() && - kind == TSK_ExplicitSpecialization) - FFPrinter.printFreeFunctionDeclaration(K.SyclKernel, ParmListWithNames); - } else { - FFPrinter.printFreeFunctionDeclaration(K.SyclKernel, ParmListWithNames); - } FFPrinter.printFreeFunctionShim(K.SyclKernel, ShimCounter, ParmList); O << ";\n"; From 453ca5e0c0b6613a34088f5311d575a5c77a745e Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 17 Jul 2025 22:32:40 -0400 Subject: [PATCH 19/69] Update SemaSYCL.cpp --- 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 2e3776ff9a5e9..110c0c4e114ae 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7094,8 +7094,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } } ParmListWithNamesOstream.flush(); - - Policy.SuppressTagKeyword = false; + FunctionTemplateDecl *FTD = K.SyclKernel->getPrimaryTemplate(); Policy.PrintAsCanonical = false; Policy.SuppressDefinition = true; From 923c9496b6fb83dd0521d6520e805530d26a5f32 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 18 Jul 2025 07:26:34 -0700 Subject: [PATCH 20/69] Apply feedback --- clang/include/clang/Sema/SemaSYCL.h | 4 +-- clang/lib/Sema/SemaSYCL.cpp | 17 +++++----- sycl/include/sycl/detail/kernel_desc.hpp | 2 +- .../experimental/free_function_traits.hpp | 9 ++--- sycl/include/sycl/handler.hpp | 33 ++++++++----------- sycl/source/detail/scheduler/commands.cpp | 5 +++ sycl/source/handler.cpp | 2 +- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 2d717929a04af..a115fa032bf79 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -65,8 +65,8 @@ class SYCLIntegrationHeader { kind_work_group_memory, kind_dynamic_work_group_memory, kind_dynamic_accessor, - kind_special_type_wrapper, - kind_last = kind_special_type_wrapper + kind_struct_with_special_type, + kind_last = kind_struct_with_special_type }; public: diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 2e3776ff9a5e9..ac31586a94a48 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5024,7 +5024,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - addParam(PD, Ty, SYCLIntegrationHeader::kind_special_type_wrapper); + addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); ParentStruct = Ty.getTypePtr(); return true; } @@ -6124,7 +6124,7 @@ static const char *paramKind2Str(KernelParamKind K) { CASE(work_group_memory); CASE(dynamic_work_group_memory); CASE(dynamic_accessor); - CASE(special_type_wrapper); + CASE(struct_with_special_type); } return ""; @@ -6257,7 +6257,7 @@ class SYCLFwdDeclEmitter } void Visit(QualType T) { -if (T.isNull()) + if (T.isNull()) return; InnerTypeVisitor::Visit(T.getTypePtr()); } @@ -7094,7 +7094,6 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } } ParmListWithNamesOstream.flush(); - Policy.SuppressTagKeyword = false; FunctionTemplateDecl *FTD = K.SyclKernel->getPrimaryTemplate(); Policy.PrintAsCanonical = false; @@ -7142,7 +7141,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } // Now we handle all parameters that are structs that contain special types - // inside. Their information is coontained in SpecialTypeOffsetMap with keys + // inside. Their information is contained in SpecialTypeOffsetMap with keys // the structs and values a vector of pairs representing the type and the // offset of each special type inside this struct. llvm::DenseMap visited; @@ -7153,11 +7152,11 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { // special type nor a trivially copyable type. We therefore need to // explicitly communicate to the runtime that this argument should be // allowed as a free function kernel argument. We do this by defining - // is_special_type_wrapper to be true. + // is_struct_with_special_type to be true. O << "template <>\n"; O << "struct " - "sycl::ext::oneapi::experimental::detail::is_special_type_" - "wrapper<"; + "sycl::ext::oneapi::experimental::detail::is_struct_with_special_" + "type"; Policy.SuppressTagKeyword = true; Param->getType().print(O, Policy); O << "> {\n"; @@ -7165,7 +7164,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "namespace sycl { inline namespace _V1 { namespace ext { " "namespace oneapi { namespace " "experimental { namespace detail { \n"; - O << "template <> struct special_type_wrapper_info<"; + O << "template <> struct struct_with_special_type_info<"; Param->getType().print(O, Policy); O << "> {\n"; O << "template< typename ArgT, typename HandlerT, typename = " diff --git a/sycl/include/sycl/detail/kernel_desc.hpp b/sycl/include/sycl/detail/kernel_desc.hpp index 16dd7fdc8f033..ab255497a02ae 100644 --- a/sycl/include/sycl/detail/kernel_desc.hpp +++ b/sycl/include/sycl/detail/kernel_desc.hpp @@ -61,7 +61,7 @@ enum class kernel_param_kind_t { kind_work_group_memory = 6, kind_dynamic_work_group_memory = 7, kind_dynamic_accessor = 8, - kind_special_type_wrapper = 9, + kind_struct_with_special_type = 9, kind_invalid = 0xf, // not a valid kernel kind }; diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 274f1f08c4a99..1c2508a897370 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -46,9 +46,10 @@ template inline constexpr bool is_kernel_v = is_kernel::value; namespace detail { -// A special type wrapper is a struct type that contains special types. -// The frontend defines this trait to be true after analyzing the struct at compile time. -template struct is_special_type_wrapper { +// A struct with special type is a struct type that contains special types. +// The frontend defines this trait to be true after analyzing the struct at +// compile time. +template struct is_struct_with_special_type { inline static constexpr bool value = false; }; @@ -57,7 +58,7 @@ template struct is_special_type_wrapper { // the level of nesting. So if type Foo contains two accessors inside and the // user calls set_arg(Foo), that call will call this function which will call // set_arg for each of those two accessors. -template struct special_type_wrapper_info { +template struct struct_with_special_type_info { template static void set_arg(int ArgIndex, ArgT &arg, HandlerT &cgh, int &NumArgs) {} }; diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 77b319ae3268b..9fada0865993c 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -162,8 +162,8 @@ __SYCL_EXPORT void *async_malloc_from_pool(sycl::handler &h, size_t size, } // namespace ext::oneapi::experimental namespace ext::oneapi::experimental::detail { -template struct is_special_type_wrapper; -template struct special_type_wrapper_info; +template struct is_struct_with_special_type; +template struct struct_with_special_type_info; class dynamic_parameter_base; class dynamic_work_group_memory_base; class dynamic_local_accessor_base; @@ -707,9 +707,9 @@ class __SYCL_EXPORT handler { if (!std::is_same::value && std::is_pointer::value) { addArg(detail::kernel_param_kind_t::kind_pointer, StoredArg, sizeof(T), ArgIndex); - } else if (ext::oneapi::experimental::detail::is_special_type_wrapper< + } else if (ext::oneapi::experimental::detail::is_struct_with_special_type< remove_cv_ref_t>::value) { - addArg(detail::kernel_param_kind_t::kind_special_type_wrapper, StoredArg, + addArg(detail::kernel_param_kind_t::kind_struct_with_special_type, StoredArg, sizeof(T), ArgIndex); } else { addArg(detail::kernel_param_kind_t::kind_std_layout, StoredArg, sizeof(T), @@ -1871,7 +1871,9 @@ class __SYCL_EXPORT handler { || (!is_same_type::value && std::is_pointer_v>) // USM || is_same_type::value // Interop - || is_same_type::value; // Stream + || is_same_type::value // Stream + || ext::oneapi::experimental::detail::is_struct_with_special_type< + remove_cv_ref_t>::value; // Structs that contain special types }; /// Sets argument for OpenCL interoperability kernels. @@ -1884,6 +1886,13 @@ class __SYCL_EXPORT handler { typename std::enable_if_t::value, void> set_arg(int ArgIndex, T &&Arg) { setArgHelper(ArgIndex, std::move(Arg)); + if constexpr (ext::oneapi::experimental::detail:: + is_struct_with_special_type>::value) { + int NumArgs; + ext::oneapi::experimental::detail::struct_with_special_type_info< + remove_cv_ref_t>::set_arg(ArgIndex + 1, Arg, *this, NumArgs); + MArgShift += NumArgs; + } } template - typename std::enable_if_t< - ext::oneapi::experimental::detail::is_special_type_wrapper< - remove_cv_ref_t>::value, - void> - set_arg(int ArgIndex, T &Arg) { - setArgHelper(ArgIndex, Arg); - int NumArgs; - ext::oneapi::experimental::detail::special_type_wrapper_info< - remove_cv_ref_t>::template set_arg(ArgIndex + 1, Arg, *this, - NumArgs); - MArgShift += NumArgs; - } - // set_arg for graph dynamic_parameters template void set_arg(int argIndex, diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 4ac11b25c9ff2..5acae4bd9c80b 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2360,6 +2360,11 @@ static void SetArgBasedOnType( break; } + case kernel_param_kind_t::kind_struct_with_special_type: { + Adapter.call(Kernel, NextTrueIndex, + Arg.MSize, nullptr, Arg.MPtr); + break; + } case kernel_param_kind_t::kind_sampler: { sampler *SamplerPtr = (sampler *)Arg.MPtr; ur_sampler_handle_t Sampler = diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index fdc619414c008..a55eaa2956f3c 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -1066,7 +1066,7 @@ void handler::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, } switch (Kind) { - case kernel_param_kind_t::kind_special_type_wrapper: + case kernel_param_kind_t::kind_struct_with_special_type: case kernel_param_kind_t::kind_std_layout: case kernel_param_kind_t::kind_pointer: { addArg(Kind, Ptr, Size, Index + IndexShift); From a72ff0ad80a025ce7a37b350f783833e709104b4 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 18 Jul 2025 07:29:39 -0700 Subject: [PATCH 21/69] Fix unused parameter errors --- .../sycl/ext/oneapi/experimental/free_function_traits.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 1c2508a897370..f219829c6e7e1 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -60,7 +60,12 @@ template struct is_struct_with_special_type { // set_arg for each of those two accessors. template struct struct_with_special_type_info { template - static void set_arg(int ArgIndex, ArgT &arg, HandlerT &cgh, int &NumArgs) {} + static void set_arg(int ArgIndex, ArgT &arg, HandlerT &cgh, int &NumArgs) { + (void)ArgIndex; + (void)arg; + (void)cgh; + (void)NumArgs; + } }; } // namespace detail From 71c8c10527b8869404c16a280f19201d3d86ea78 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 18 Jul 2025 07:33:47 -0700 Subject: [PATCH 22/69] Apply feedback --- sycl/include/sycl/handler.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 9fada0865993c..e67a7f0288d9f 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -709,8 +709,8 @@ class __SYCL_EXPORT handler { ArgIndex); } else if (ext::oneapi::experimental::detail::is_struct_with_special_type< remove_cv_ref_t>::value) { - addArg(detail::kernel_param_kind_t::kind_struct_with_special_type, StoredArg, - sizeof(T), ArgIndex); + addArg(detail::kernel_param_kind_t::kind_struct_with_special_type, + StoredArg, sizeof(T), ArgIndex); } else { addArg(detail::kernel_param_kind_t::kind_std_layout, StoredArg, sizeof(T), ArgIndex); From 77900d8e5430671dd199f77517586a1685256227 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 18 Jul 2025 10:57:01 -0700 Subject: [PATCH 23/69] Finish implementation --- clang/lib/Sema/SemaSYCL.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ac07e81dcecb2..6a13335a0f7ec 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2971,6 +2971,10 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { ++StructDepth; + StringRef Name = "_arg_struct"; + addParam(Name, Ty); + CurrentStruct = Params.back(); + return true; } @@ -2996,15 +3000,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return true; } - bool handleStructType(ParmVarDecl *PD, QualType Ty) final { - StringRef Name = "_arg_struct"; - addParam(Name, Ty); - CurrentStruct = Params.back(); - return true; - } - - bool handleStructType(FieldDecl *, QualType) final { return true; } - bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &BS, QualType FieldTy) final { const auto *RecordDecl = FieldTy->getAsCXXRecordDecl(); @@ -7155,11 +7150,20 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "template <>\n"; O << "struct " "sycl::ext::oneapi::experimental::detail::is_struct_with_special_" - "type"; + "type<"; Policy.SuppressTagKeyword = true; Param->getType().print(O, Policy); O << "> {\n"; O << " inline static constexpr bool value = true;\n};\n\n"; + // Now we define the set_arg function for this struct that contains + // special types. It takes the handler as an argument so that we can + // ultimately call set_arg on the handler for each special type + // contained in the struct. First, emit forward declarations for the + // special types contained within. + for (const auto TypeOffsetPair : + SpecialTypeOffsetMap[Param->getType().getTypePtr()]) + FwdDeclEmitter.Visit( + TypeOffsetPair.first.getDesugaredType(S.getASTContext())); O << "namespace sycl { inline namespace _V1 { namespace ext { " "namespace oneapi { namespace " "experimental { namespace detail { \n"; @@ -7167,7 +7171,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { Param->getType().print(O, Policy); O << "> {\n"; O << "template< typename ArgT, typename HandlerT, typename = " - "std::enable_if_t, "; + "std::enable_if_t, "; Param->getType().print(O, Policy); O << ">>>\n"; O << " static void set_arg(int ArgIndex, ArgT& "; @@ -7175,6 +7179,8 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << ", HandlerT& cgh, int &NumArgs) {\n"; for (const auto TypeOffsetPair : SpecialTypeOffsetMap[Param->getType().getTypePtr()]) { + FwdDeclEmitter.Visit( + TypeOffsetPair.first.getDesugaredType(S.getASTContext())); O << " cgh.set_arg(ArgIndex, *("; TypeOffsetPair.first.print(O, Policy); O << " *)"; @@ -7193,7 +7199,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { visited[Param->getType().getTypePtr()] = true; } } - + Policy.SuppressTagKeyword = false; FFPrinter.printFreeFunctionShim(K.SyclKernel, ShimCounter, ParmList); O << ";\n"; O << "}\n"; @@ -7222,7 +7228,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "};\n"; O << "}\n"; ++ShimCounter; - } + } if (FreeFunctionCount > 0) { O << "\n#include \n"; From 03bb317835228fcb1d546cb05488ee46e70b17c7 Mon Sep 17 00:00:00 2001 From: "Bushi, Lorenc" Date: Fri, 18 Jul 2025 20:03:39 +0200 Subject: [PATCH 24/69] Formatting --- 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 6a13335a0f7ec..114cf523e30b3 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7228,7 +7228,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "};\n"; O << "}\n"; ++ShimCounter; - } + } if (FreeFunctionCount > 0) { O << "\n#include \n"; From 0b0cc869c296b345d46eae2fc595e258e59b8df1 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 18 Jul 2025 14:19:17 -0700 Subject: [PATCH 25/69] Improve implementation --- clang/include/clang/Sema/SemaSYCL.h | 15 +++--- clang/lib/Sema/SemaSYCL.cpp | 48 +++++++++---------- .../experimental/free_function_traits.hpp | 8 ++-- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index a115fa032bf79..e2611303c2a88 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -119,10 +119,9 @@ class SYCLIntegrationHeader { /// integration header is required. void addHostPipeRegistration() { NeedToEmitHostPipeRegistration = true; } - // Add the entry (Ty, Offset) to the SpecialTypeOffsetMap. - void addSpecialTypeOffset(const Type *ParentStruct, QualType Ty, - int64_t offset) { - SpecialTypeOffsetMap[ParentStruct].push_back(std::make_pair(Ty, offset)); + // Add ParentStruct to StructsWithSpecialTypes. + void addStructWithSpecialType(const RecordDecl *ParentStruct) { + StructsWithSpecialTypes[ParentStruct] = true; } private: @@ -213,11 +212,9 @@ class SYCLIntegrationHeader { /// type and __sycl_host_pipe_registrar variable are required to emit. bool NeedToEmitHostPipeRegistration = false; - // A map that keeps track of type and offset of each special class contained - // inside a struct - llvm::DenseMap, 8>> - SpecialTypeOffsetMap; + // A map that keeps track of all structs encountered with + // special types inside. + llvm::DenseMap StructsWithSpecialTypes; }; class SYCLIntegrationFooter { diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 6a13335a0f7ec..e698f723721b8 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2960,7 +2960,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // diagnosed on the actual kernel. KernelDecl->addAttr( SYCLKernelAttr::CreateImplicit(SemaSYCLRef.getASTContext())); - + KernelDecl->dump(); SemaSYCLRef.addSyclDeviceDecl(KernelDecl); } @@ -2974,7 +2974,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { StringRef Name = "_arg_struct"; addParam(Name, Ty); CurrentStruct = Params.back(); - return true; } @@ -4890,7 +4889,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { "Unexpected SYCL special class when generating integration header"); } if (ParentStruct) - Header.addSpecialTypeOffset(ParentStruct, FieldTy, offsetOf(FD, FieldTy)); + Header.addStructWithSpecialType(ParentStruct->getAsCXXRecordDecl()); return true; } @@ -7135,13 +7134,16 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { } // Now we handle all parameters that are structs that contain special types - // inside. Their information is contained in SpecialTypeOffsetMap with keys - // the structs and values a vector of pairs representing the type and the - // offset of each special type inside this struct. - llvm::DenseMap visited; + // inside. Their information is contained in StructsWithSpecialTypes. + llvm::DenseMap visited; for (ParmVarDecl *Param : K.SyclKernel->parameters()) { - if (SpecialTypeOffsetMap.count(Param->getType().getTypePtr()) && - !visited[Param->getType().getTypePtr()]) { + if (StructsWithSpecialTypes.count( + Param->getType()->getAsCXXRecordDecl()) && + !visited[Param->getType()->getAsCXXRecordDecl()]) { + const RecordDecl *decl = Param->getType()->getAsCXXRecordDecl(); + int NumFields = 0; + for (const auto member : decl->fields()) + ++NumFields; // this is a struct that contains a special type so its neither a // special type nor a trivially copyable type. We therefore need to // explicitly communicate to the runtime that this argument should be @@ -7157,13 +7159,13 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << " inline static constexpr bool value = true;\n};\n\n"; // Now we define the set_arg function for this struct that contains // special types. It takes the handler as an argument so that we can - // ultimately call set_arg on the handler for each special type + // ultimately call set_arg on the handler for each member // contained in the struct. First, emit forward declarations for the - // special types contained within. - for (const auto TypeOffsetPair : - SpecialTypeOffsetMap[Param->getType().getTypePtr()]) - FwdDeclEmitter.Visit( - TypeOffsetPair.first.getDesugaredType(S.getASTContext())); + // types contained within. + for (const auto member : decl->fields()) + if (isSyclSpecialType(member->getType(), S)) + FwdDeclEmitter.Visit( + member->getType().getDesugaredType(S.getASTContext())); O << "namespace sycl { inline namespace _V1 { namespace ext { " "namespace oneapi { namespace " "experimental { namespace detail { \n"; @@ -7177,26 +7179,22 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << " static void set_arg(int ArgIndex, ArgT& "; O << "arg"; O << ", HandlerT& cgh, int &NumArgs) {\n"; - for (const auto TypeOffsetPair : - SpecialTypeOffsetMap[Param->getType().getTypePtr()]) { - FwdDeclEmitter.Visit( - TypeOffsetPair.first.getDesugaredType(S.getASTContext())); + for (const auto member : decl->fields()) { O << " cgh.set_arg(ArgIndex, *("; - TypeOffsetPair.first.print(O, Policy); + member->getType().print(O, Policy); O << " *)"; - O << "((char *)(&arg) + " << TypeOffsetPair.second << ")"; + O << "((char *)(&arg) + " + << S.getASTContext().getFieldOffset(member) / 8 << ")"; O << ");\n"; O << " ++ArgIndex;\n"; } - O << " NumArgs = " - << SpecialTypeOffsetMap[Param->getType().getTypePtr()].size() - << ";\n"; + O << " NumArgs = " << NumFields << ";\n"; O << " }\n};\n} // namespace detail \n} // namespace experimental " "\n} " "// namespace oneapi \n} // namespace ext \n} // namespace " "_V1\n} " "// namespace sycl\n\n"; - visited[Param->getType().getTypePtr()] = true; + visited[Param->getType()->getAsCXXRecordDecl()] = true; } } Policy.SuppressTagKeyword = false; diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index f219829c6e7e1..b45f3fd596bd3 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -54,10 +54,10 @@ template struct is_struct_with_special_type { }; // This struct is made to be specialized in the integration header. -// It calls set_arg for every special type contained in the struct regardless of -// the level of nesting. So if type Foo contains two accessors inside and the -// user calls set_arg(Foo), that call will call this function which will call -// set_arg for each of those two accessors. +// It calls set_arg for every member contained in the struct at any level of +// composition. So if type Foo contains two accessors and an integer inside and +// the user calls set_arg(Foo), that call will call this function which will +// call set_arg for each of those two accessors and for the int. template struct struct_with_special_type_info { template static void set_arg(int ArgIndex, ArgT &arg, HandlerT &cgh, int &NumArgs) { From ca2310d4c3862a0754d61a845ea9eae324caeefa Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Mon, 21 Jul 2025 12:57:18 -0700 Subject: [PATCH 26/69] Apply more suggestions --- clang/include/clang/Sema/SemaSYCL.h | 19 +- clang/lib/Sema/SemaSYCL.cpp | 410 ++++++++++-------- .../experimental/free_function_traits.hpp | 9 +- sycl/include/sycl/handler.hpp | 12 +- sycl/source/detail/handler_impl.hpp | 7 + sycl/source/handler.cpp | 11 +- 6 files changed, 253 insertions(+), 215 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index e2611303c2a88..561e169890361 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -119,11 +119,6 @@ class SYCLIntegrationHeader { /// integration header is required. void addHostPipeRegistration() { NeedToEmitHostPipeRegistration = true; } - // Add ParentStruct to StructsWithSpecialTypes. - void addStructWithSpecialType(const RecordDecl *ParentStruct) { - StructsWithSpecialTypes[ParentStruct] = true; - } - private: // Kernel actual parameter descriptor. struct KernelParamDesc { @@ -211,10 +206,6 @@ class SYCLIntegrationHeader { /// Keeps track of whether declaration of __sycl_host_pipe_registration /// type and __sycl_host_pipe_registrar variable are required to emit. bool NeedToEmitHostPipeRegistration = false; - - // A map that keeps track of all structs encountered with - // special types inside. - llvm::DenseMap StructsWithSpecialTypes; }; class SYCLIntegrationFooter { @@ -277,6 +268,9 @@ class SemaSYCL : public SemaBase { llvm::DenseSet FreeFunctionDeclarations; + // A map that keeps track of all structs encountered with + // special types inside. Relevant for free function kernels only + llvm::DenseMap StructsWithSpecialTypes; public: SemaSYCL(Sema &S); @@ -327,6 +321,13 @@ class SemaSYCL : public SemaBase { SYCLKernelFunctions.insert(FD); } + /// Add ParentStruct to StructsWithSpecialTypes. + void addStructWithSpecialType(const RecordDecl *ParentStruct, QualType Ty) { + StructsWithSpecialTypes[ParentStruct] = Ty; + } + + auto &getStructsWithSpecialType() const { return StructsWithSpecialTypes; } + /// Lazily creates and returns SYCL integration header instance. SYCLIntegrationHeader &getSyclIntegrationHeader() { if (SyclIntHeader == nullptr) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 2eff6c0e11c1a..24983dc49c036 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2277,7 +2277,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { CollectionStack.back() = true; return true; } - bool handleSyclSpecialType(FieldDecl *, QualType) final { + bool handleSyclSpecialType(FieldDecl *FD, QualType) final { CollectionStack.back() = true; return true; } @@ -2960,7 +2960,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { // diagnosed on the actual kernel. KernelDecl->addAttr( SYCLKernelAttr::CreateImplicit(SemaSYCLRef.getASTContext())); - KernelDecl->dump(); SemaSYCLRef.addSyclDeviceDecl(KernelDecl); } @@ -3090,7 +3089,12 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - addParam(FD, FieldTy); + // if ParentStruct is non-null, we are dealing with a + // free function kernel. + // In this case, do not pass the scalar as a separate argument since it + // can be passed directly as part of its parent struct + if (!CurrentStruct) + addParam(FD, FieldTy); return true; } @@ -4530,9 +4534,18 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } + for (auto it = CurrentStructs.rbegin(); it != CurrentStructs.rend(); ++it) + SemaSYCLRef.addStructWithSpecialType((*it)->getParent(), + (it + 1) == CurrentStructs.rend() + ? ParentStruct->getType() + : (*(it + 1))->getType()); MemberExpr *MemberAccess = buildMemberExpr(Base, FD); createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, MemberAccess, BodyStmts); + SemaSYCLRef.addStructWithSpecialType(FD->getParent(), + CurrentStructs.size() + ? CurrentStructs.back()->getType() + : ParentStruct->getType()); return true; } @@ -4541,8 +4554,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { // typically if this is the case the default constructor will be private and // in such cases we must manually override the access specifier from private // to public just for the duration of this default initialization. - // TODO: Revisit this approach once https://github.com/intel/llvm/issues/16061 - // is closed. + // TODO: Revisit this approach once + // https://github.com/intel/llvm/issues/16061 is closed. bool handleSyclSpecialType(ParmVarDecl *PD, QualType ParamTy) final { // The code produced looks like this in the case of a work group memory // parameter: @@ -4589,137 +4602,141 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handlePointerType(FieldDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handlePointerType(FieldDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handlePointerType(ParmVarDecl *, QualType ParamTy) final { - Expr *PointerRef = createPointerParamReferenceExpr(ParamTy); - ArgExprs.push_back(PointerRef); - return true; - } + bool handlePointerType(ParmVarDecl *, QualType ParamTy) final { + Expr *PointerRef = createPointerParamReferenceExpr(ParamTy); + ArgExprs.push_back(PointerRef); + return true; + } - bool handleSimpleArrayType(FieldDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleSimpleArrayType(FieldDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *, QualType) + final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType) final { - Expr *TempCopy = createCopyInitExpr(PD); - ArgExprs.push_back(TempCopy); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType) + final { + Expr *TempCopy = createCopyInitExpr(PD); + ArgExprs.push_back(TempCopy); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { return true; } + bool handleScalarType(FieldDecl * FD, QualType FieldTy) final { + return true; + } - bool handleScalarType(ParmVarDecl *, QualType) final { - Expr *ParamRef = createParamReferenceExpr(); - ArgExprs.push_back(ParamRef); - return true; - } + bool handleScalarType(ParmVarDecl *, QualType) final { + Expr *ParamRef = createParamReferenceExpr(); + ArgExprs.push_back(ParamRef); + return true; + } - bool handleUnionType(FieldDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleUnionType(FieldDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleUnionType(ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleUnionType(ParmVarDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { - CurrentStructs.push_back(FD); - return true; - } + bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) + final { + CurrentStructs.push_back(FD); + return true; + } - bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, - QualType ParamTy) final { - return true; - } + bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) + final { + return true; + } - bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - CurrentStructs.pop_back(); - return true; - } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + CurrentStructs.pop_back(); + return true; + } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); - return true; - } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( + ParentStruct, ParentStruct->getType(), VK_PRValue, + FreeFunctionSrcLoc)); + return true; + } - bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) + final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) + final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool enterArray(FieldDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterArray(FieldDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool enterArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool leaveArray(FieldDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool leaveArray(FieldDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool leaveArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } - FieldDecl *getCurrentStruct() { - assert(CurrentStructs.size() && - "Current free function parameter is not inside a structure!"); - return CurrentStructs.back(); - } -}; + bool leaveArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } + FieldDecl *getCurrentStruct() { + assert(CurrentStructs.size() && + "Current free function parameter is not inside a structure!"); + return CurrentStructs.back(); + } + }; // 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 @@ -4739,9 +4756,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { llvm::SmallVector ArrayBaseOffsets; int StructDepth = 0; - // Set if we are currently exploring fields of a struct that is a free - // function kernel parameter - const Type *ParentStruct = nullptr; // A series of functions to calculate the change in offset based on the type. int64_t offsetOf(const FieldDecl *FD, QualType ArgTy) const { @@ -4780,9 +4794,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { uint64_t Size; Size = SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); - Header.addParamDesc( - Kind, static_cast(Size), - static_cast((ParentStruct ? 0 : CurOffset) + OffsetAdj)); + Header.addParamDesc(Kind, static_cast(Size), + static_cast(CurOffset + OffsetAdj)); } public: @@ -4857,10 +4870,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; - if (ParentStruct) - Header.addParamDesc(ParamKind, Info, offsetOf(FD, FieldTy)); - else - Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); + Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::work_group_memory)) { @@ -4888,9 +4898,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { llvm_unreachable( "Unexpected SYCL special class when generating integration header"); } - if (ParentStruct) - Header.addStructWithSpecialType(ParentStruct->getAsCXXRecordDecl()); - return true; } @@ -5019,7 +5026,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); - ParentStruct = Ty.getTypePtr(); return true; } @@ -5030,7 +5036,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ParentStruct = nullptr; return true; } @@ -7048,6 +7053,11 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { unsigned ShimCounter = 1; int FreeFunctionCount = 0; + // Structs with special types inside needs some special code generation in the + // header and we keep this visited map to not have duplicates in case several + // free function kernels + // use the same structs as parameters. + llvm::DenseMap visitedStructWithSpecialType; for (const KernelDesc &K : KernelDescs) { if (!S.isFreeFunction(K.SyclKernel)) continue; @@ -7133,69 +7143,91 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { FFPrinter.printFreeFunctionDeclaration(K.SyclKernel, ParmListWithNames); } - // Now we handle all parameters that are structs that contain special types - // inside. Their information is contained in StructsWithSpecialTypes. - llvm::DenseMap visited; + // Now we handle all structs that contain special types + // inside. Their information is contained in StructsWithSpecialTypes of + // SemaSYCL. for (ParmVarDecl *Param : K.SyclKernel->parameters()) { - if (StructsWithSpecialTypes.count( - Param->getType()->getAsCXXRecordDecl()) && - !visited[Param->getType()->getAsCXXRecordDecl()]) { - const RecordDecl *decl = Param->getType()->getAsCXXRecordDecl(); - int NumFields = 0; - for (const auto member : decl->fields()) - ++NumFields; - // this is a struct that contains a special type so its neither a - // special type nor a trivially copyable type. We therefore need to - // explicitly communicate to the runtime that this argument should be - // allowed as a free function kernel argument. We do this by defining - // is_struct_with_special_type to be true. - O << "template <>\n"; - O << "struct " - "sycl::ext::oneapi::experimental::detail::is_struct_with_special_" - "type<"; - Policy.SuppressTagKeyword = true; - Param->getType().print(O, Policy); - O << "> {\n"; - O << " inline static constexpr bool value = true;\n};\n\n"; - // Now we define the set_arg function for this struct that contains - // special types. It takes the handler as an argument so that we can - // ultimately call set_arg on the handler for each member - // contained in the struct. First, emit forward declarations for the - // types contained within. - for (const auto member : decl->fields()) - if (isSyclSpecialType(member->getType(), S)) + if (!Param->getType()->isStructureType()) + continue; + const RecordDecl *Struct = + Param->getType()->getAsStructureType()->getDecl(); + QualType type = Param->getType(); + if (!S.getStructsWithSpecialType().count(Struct) || + visitedStructWithSpecialType.count(Struct)) + continue; + + FwdDeclEmitter.Visit(type.getDesugaredType(S.getASTContext())); + + // this is a struct that contains a special type so its neither a + // special type nor a trivially copyable type. We therefore need to + // explicitly communicate to the runtime that this argument should be + // allowed as a free function kernel argument. We do this by defining + // is_struct_with_special_type to be true. + O << "template <>\n"; + O << "struct " + "sycl::ext::oneapi::experimental::detail::is_struct_with_special_" + "type<"; + Policy.SuppressTagKeyword = true; + type.print(O, Policy); + O << "> {\n"; + O << " inline static constexpr bool value = true;\n};\n\n"; + // Now we define the set_arg function for this struct that contains + // special types. It takes the handler as an argument so that we can + // ultimately call set_arg on the handler for each special type member + // contained in the struct. First, emit needed forward declarations for + // all special types contained in the struct by doing a depth first search + // exploration of the struct. Also collect the offsets of all special + // types inside the struct while we're at it. + llvm::SmallVector, 8> offsets; + llvm::SmallVector dfs; + dfs.emplace_back(Struct); + while (!dfs.empty()) { + const auto top = dfs.pop_back_val(); + for (const auto member : top->fields()) { + if (isSyclSpecialType(member->getType(), S)) { FwdDeclEmitter.Visit( member->getType().getDesugaredType(S.getASTContext())); - O << "namespace sycl { inline namespace _V1 { namespace ext { " - "namespace oneapi { namespace " - "experimental { namespace detail { \n"; - O << "template <> struct struct_with_special_type_info<"; - Param->getType().print(O, Policy); - O << "> {\n"; - O << "template< typename ArgT, typename HandlerT, typename = " - "std::enable_if_t, "; - Param->getType().print(O, Policy); - O << ">>>\n"; - O << " static void set_arg(int ArgIndex, ArgT& "; - O << "arg"; - O << ", HandlerT& cgh, int &NumArgs) {\n"; - for (const auto member : decl->fields()) { - O << " cgh.set_arg(ArgIndex, *("; - member->getType().print(O, Policy); - O << " *)"; - O << "((char *)(&arg) + " - << S.getASTContext().getFieldOffset(member) / 8 << ")"; - O << ");\n"; - O << " ++ArgIndex;\n"; + offsets.emplace_back(std::make_pair( + member, S.getASTContext().getFieldOffset(member) / 8)); + } else if (member->getType()->isStructureType() && + S.getStructsWithSpecialType().count( + member->getType()->getAsStructureType()->getDecl())) { + dfs.emplace_back( + member->getType()->getAsStructureType()->getDecl()); + } } - O << " NumArgs = " << NumFields << ";\n"; - O << " }\n};\n} // namespace detail \n} // namespace experimental " - "\n} " - "// namespace oneapi \n} // namespace ext \n} // namespace " - "_V1\n} " - "// namespace sycl\n\n"; - visited[Param->getType()->getAsCXXRecordDecl()] = true; } + + O << "namespace sycl { inline namespace _V1 { namespace ext { " + "namespace oneapi { namespace " + "experimental { namespace detail { \n"; + O << "template <> struct struct_with_special_type_info<"; + type.print(O, Policy); + O << "> {\n"; + O << "template< typename ArgT, typename HandlerT, typename = " + "std::enable_if_t, "; + type.print(O, Policy); + O << ">>>\n"; + O << " static void set_arg(int ArgIndex, ArgT& "; + O << "arg"; + O << ", HandlerT& cgh, int &NumArgs) {\n"; + int NumFields = 0; + for (const auto fieldoffset : offsets) { + O << " cgh.set_arg(ArgIndex, *("; + fieldoffset.first->getType().print(O, Policy); + O << " *)"; + O << "((char *)(&arg) + " << fieldoffset.second << ")"; + O << ");\n"; + O << " ++ArgIndex;\n"; + ++NumFields; + } + O << " NumArgs = " << NumFields << ";\n"; + O << " }\n};\n} // namespace detail \n} // namespace experimental " + "\n} " + "// namespace oneapi \n} // namespace ext \n} // namespace " + "_V1\n} " + "// namespace sycl\n\n"; + visitedStructWithSpecialType[Struct] = true; } Policy.SuppressTagKeyword = false; FFPrinter.printFreeFunctionShim(K.SyclKernel, ShimCounter, ParmList); diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index b45f3fd596bd3..338122319dc0d 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -60,12 +60,9 @@ template struct is_struct_with_special_type { // call set_arg for each of those two accessors and for the int. template struct struct_with_special_type_info { template - static void set_arg(int ArgIndex, ArgT &arg, HandlerT &cgh, int &NumArgs) { - (void)ArgIndex; - (void)arg; - (void)cgh; - (void)NumArgs; - } + static void set_arg([[maybe_unused]] int ArgIndex, [[maybe_unused]] ArgT &arg, + [[maybe_unused]] HandlerT &cgh, + [[maybe_unused]] int &NumArgs) {} }; } // namespace detail diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index e67a7f0288d9f..ccb417105a3c0 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1891,7 +1891,7 @@ class __SYCL_EXPORT handler { int NumArgs; ext::oneapi::experimental::detail::struct_with_special_type_info< remove_cv_ref_t>::set_arg(ArgIndex + 1, Arg, *this, NumArgs); - MArgShift += NumArgs; + updateArgShift(NumArgs); } } @@ -3448,13 +3448,6 @@ class __SYCL_EXPORT handler { event MLastEventDoNotUse; #endif - // Certain arguments such as structs that contain SYCL special types entail - // several hidden set_arg calls for every set_arg called by the user. This - // shift is required to make sure the following arguments set by the user have - // the correct index. It keeps track of how many of these hidden set_arg calls - // have been made so far. - int MArgShift = 0; - // Make queue_impl class friend to be able to call finalize method. friend class detail::queue_impl; // Make accessor class friend to keep the list of associated accessors. @@ -3844,6 +3837,9 @@ class __SYCL_EXPORT handler { void addArg(detail::kernel_param_kind_t ArgKind, void *Req, int AccessTarget, int ArgIndex); void clearArgs(); + + void updateArgShift(int); + void setArgsToAssociatedAccessors(); bool HasAssociatedAccessor(detail::AccessorImplHost *Req, diff --git a/sycl/source/detail/handler_impl.hpp b/sycl/source/detail/handler_impl.hpp index 0fda3dd4f2769..e50bd7c144028 100644 --- a/sycl/source/detail/handler_impl.hpp +++ b/sycl/source/detail/handler_impl.hpp @@ -149,6 +149,13 @@ class handler_impl { /// The list of arguments for the kernel. std::vector MArgs; + // Certain arguments such as structs that contain SYCL special types entail + // several hidden set_arg calls for every set_arg called by the user. This + // shift is required to make sure the following arguments set by the user have + // the correct index. It keeps track of how many of these hidden set_arg calls + // have been made so far. + int MArgShift = 0; + /// The list of associated accessors with this handler. /// These accessors were created with this handler as argument or /// have become required for this handler via require method. diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index a55eaa2956f3c..08fb8ba45bbfb 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -9,7 +9,7 @@ #include "sycl/detail/helpers.hpp" #include "ur_api.h" #include - +#include #include #include #include @@ -1067,6 +1067,9 @@ void handler::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, switch (Kind) { case kernel_param_kind_t::kind_struct_with_special_type: + addArg(kernel_param_kind_t::kind_struct_with_special_type, Ptr, Size, + Index + IndexShift); + break; case kernel_param_kind_t::kind_std_layout: case kernel_param_kind_t::kind_pointer: { addArg(Kind, Ptr, Size, Index + IndexShift); @@ -2416,14 +2419,16 @@ void handler::addLifetimeSharedPtrStorage(std::shared_ptr SPtr) { void handler::addArg(detail::kernel_param_kind_t ArgKind, void *Req, int AccessTarget, int ArgIndex) { - impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, ArgIndex + MArgShift); + impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, ArgIndex + impl->MArgShift); } void handler::clearArgs() { impl->MArgs.clear(); - MArgShift = 0; + impl->MArgShift = 0; } +void handler::updateArgShift(int add) { impl->MArgShift += add; } + void handler::setArgsToAssociatedAccessors() { impl->MArgs = impl->MAssociatedAccesors; } From b99314996f22ec6e31376ee04dfffd10b03f9633 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Mon, 21 Jul 2025 19:11:03 -0700 Subject: [PATCH 27/69] Improve implementation --- sycl/source/handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 08fb8ba45bbfb..0de2129d113f1 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -9,7 +9,7 @@ #include "sycl/detail/helpers.hpp" #include "ur_api.h" #include -#include + #include #include #include From 1eb1c446ac3ed72b926be4d61251906ba27c1dc6 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 23 Jul 2025 09:30:08 -0700 Subject: [PATCH 28/69] Improve comments --- clang/lib/Sema/SemaSYCL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 24983dc49c036..2f2612491f821 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -3089,10 +3089,10 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - // if ParentStruct is non-null, we are dealing with a + // if CurrentStruct is non-null, we are dealing with a // free function kernel. // In this case, do not pass the scalar as a separate argument since it - // can be passed directly as part of its parent struct + // can be passed directly as part of the struct that contains it. if (!CurrentStruct) addParam(FD, FieldTy); return true; From 08c2808101714bad1635910fadb197c8f9228e60 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 23 Jul 2025 09:41:56 -0700 Subject: [PATCH 29/69] Fix formatting --- clang/include/clang/Sema/SemaSYCL.h | 5 +- clang/lib/Sema/SemaSYCL.cpp | 227 +++++++++--------- .../experimental/free_function_traits.hpp | 9 +- sycl/source/handler.cpp | 3 +- 4 files changed, 122 insertions(+), 122 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 1eb1f293928af..4b33116587fa6 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -269,8 +269,11 @@ class SemaSYCL : public SemaBase { llvm::DenseSet FreeFunctionDeclarations; // A map that keeps track of all structs encountered with - // special types inside. Relevant for free function kernels only + // special types inside. Relevant for free function kernels only. + // The key stores the struct as a declaration and the value stores the struct + // as a QualType just to make it easier to use it. llvm::DenseMap StructsWithSpecialTypes; + public: SemaSYCL(Sema &S); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 0c11ef19a931c..66be26aee131b 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4603,141 +4603,137 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { return true; } - bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleSyclSpecialType(const CXXRecordDecl *, const CXXBaseSpecifier &, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handlePointerType(FieldDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handlePointerType(FieldDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handlePointerType(ParmVarDecl *, QualType ParamTy) final { - Expr *PointerRef = createPointerParamReferenceExpr(ParamTy); - ArgExprs.push_back(PointerRef); - return true; - } + bool handlePointerType(ParmVarDecl *, QualType ParamTy) final { + Expr *PointerRef = createPointerParamReferenceExpr(ParamTy); + ArgExprs.push_back(PointerRef); + return true; + } - bool handleSimpleArrayType(FieldDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleSimpleArrayType(FieldDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *, QualType) - final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType) - final { - Expr *TempCopy = createCopyInitExpr(PD); - ArgExprs.push_back(TempCopy); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType) final { + Expr *TempCopy = createCopyInitExpr(PD); + ArgExprs.push_back(TempCopy); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, - QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleScalarType(FieldDecl * FD, QualType FieldTy) final { - return true; - } + bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { return true; } - bool handleScalarType(ParmVarDecl *, QualType) final { - Expr *ParamRef = createParamReferenceExpr(); - ArgExprs.push_back(ParamRef); - return true; - } + bool handleScalarType(ParmVarDecl *, QualType) final { + Expr *ParamRef = createParamReferenceExpr(); + ArgExprs.push_back(ParamRef); + return true; + } - bool handleUnionType(FieldDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleUnionType(FieldDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool handleUnionType(ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleUnionType(ParmVarDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) - final { - CurrentStructs.push_back(FD); - return true; - } + bool enterStruct(const CXXRecordDecl *RD, FieldDecl *FD, QualType Ty) final { + CurrentStructs.push_back(FD); + return true; + } - bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, QualType ParamTy) - final { - return true; - } + bool enterStruct(const CXXRecordDecl *RD, ParmVarDecl *PD, + QualType ParamTy) final { + return true; + } - bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - CurrentStructs.pop_back(); - return true; - } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + CurrentStructs.pop_back(); + return true; + } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - ParentStruct, ParentStruct->getType(), VK_PRValue, - FreeFunctionSrcLoc)); - return true; - } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); + ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( + ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); + return true; + } - bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) - final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, QualType) - final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &, + QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool enterArray(FieldDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterArray(FieldDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool enterArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool leaveArray(FieldDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool leaveArray(FieldDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool leaveArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } - FieldDecl *getCurrentStruct() { - assert(CurrentStructs.size() && - "Current free function parameter is not inside a structure!"); - return CurrentStructs.back(); - } - }; + bool leaveArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } + FieldDecl *getCurrentStruct() { + assert(CurrentStructs.size() && + "Current free function parameter is not inside a structure!"); + return CurrentStructs.back(); + } +}; // 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 @@ -4757,7 +4753,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { llvm::SmallVector ArrayBaseOffsets; int StructDepth = 0; - // A series of functions to calculate the change in offset based on the type. int64_t offsetOf(const FieldDecl *FD, QualType ArgTy) const { return isArrayElement(FD, ArgTy) diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 338122319dc0d..7e9ae8d6d0ac6 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -54,10 +54,11 @@ template struct is_struct_with_special_type { }; // This struct is made to be specialized in the integration header. -// It calls set_arg for every member contained in the struct at any level of -// composition. So if type Foo contains two accessors and an integer inside and -// the user calls set_arg(Foo), that call will call this function which will -// call set_arg for each of those two accessors and for the int. +// It calls set_arg for every member of special type contained in the struct at +// any level of composition. The non-special type members can just be passed as +// part of the struct. So if type Foo contains two accessors and an integer +// inside and the user calls set_arg(Foo), that call will call this function +// which will call set_arg for each of those two accessors and not the int. template struct struct_with_special_type_info { template static void set_arg([[maybe_unused]] int ArgIndex, [[maybe_unused]] ArgT &arg, diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 8142c76b4a0b5..d9619ab2c2503 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -2445,7 +2445,8 @@ void handler::addLifetimeSharedPtrStorage(std::shared_ptr SPtr) { void handler::addArg(detail::kernel_param_kind_t ArgKind, void *Req, int AccessTarget, int ArgIndex) { - impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, ArgIndex + impl->MArgShift); + impl->MArgs.emplace_back(ArgKind, Req, AccessTarget, + ArgIndex + impl->MArgShift); } void handler::clearArgs() { From b9904200e70fc9f410e7246d306acccf0df58d44 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 23 Jul 2025 09:45:37 -0700 Subject: [PATCH 30/69] Improve comments further --- .../sycl/ext/oneapi/experimental/free_function_traits.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 7e9ae8d6d0ac6..fb8bebf6c36c6 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -59,6 +59,10 @@ template struct is_struct_with_special_type { // part of the struct. So if type Foo contains two accessors and an integer // inside and the user calls set_arg(Foo), that call will call this function // which will call set_arg for each of those two accessors and not the int. +// The function stores in NumArgs the number of set_arg calls that it made so +// that subsequent set_arg calls initiated by the user can have the correct +// index. If the user provides the index ArgIndex the correct index will be +// ArgIndex + NumArgs template struct struct_with_special_type_info { template static void set_arg([[maybe_unused]] int ArgIndex, [[maybe_unused]] ArgT &arg, From eb0925fd3e3f66667fc0f7424f3706ed9dd434fc Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 31 Jul 2025 07:24:32 -0700 Subject: [PATCH 31/69] Add tests --- clang/lib/Sema/SemaSYCL.cpp | 28 ++++++++----------- ...with_special_types_as_kernel_paramters.cpp | 3 -- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 66be26aee131b..d43ac0766ec67 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2277,7 +2277,7 @@ class SyclKernelDecompMarker : public SyclKernelFieldHandler { CollectionStack.back() = true; return true; } - bool handleSyclSpecialType(FieldDecl *FD, QualType) final { + bool handleSyclSpecialType(FieldDecl *, QualType) final { CollectionStack.back() = true; return true; } @@ -3090,12 +3090,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { } bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - // if CurrentStruct is non-null, we are dealing with a - // free function kernel. - // In this case, do not pass the scalar as a separate argument since it - // can be passed directly as part of the struct that contains it. - if (!CurrentStruct) - addParam(FD, FieldTy); + addParam(FD, FieldTy); return true; } @@ -7051,8 +7046,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { int FreeFunctionCount = 0; // Structs with special types inside needs some special code generation in the // header and we keep this visited map to not have duplicates in case several - // free function kernels - // use the same structs as parameters. + // free function kernels use the same struct type as parameters. llvm::DenseMap visitedStructWithSpecialType; for (const KernelDesc &K : KernelDescs) { if (!S.isFreeFunction(K.SyclKernel)) @@ -7169,25 +7163,25 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << " inline static constexpr bool value = true;\n};\n\n"; // Now we define the set_arg function for this struct that contains // special types. It takes the handler as an argument so that we can - // ultimately call set_arg on the handler for each special type member + // ultimately call set_arg on the handler for each member // contained in the struct. First, emit needed forward declarations for - // all special types contained in the struct by doing a depth first search - // exploration of the struct. Also collect the offsets of all special - // types inside the struct while we're at it. + // all types contained in the struct by doing a depth first search + // exploration of the struct. Also collect the offsets of all the + // members inside the struct while we're at it so that we can call + // set_arg for each one of those. llvm::SmallVector, 8> offsets; llvm::SmallVector dfs; dfs.emplace_back(Struct); while (!dfs.empty()) { const auto top = dfs.pop_back_val(); for (const auto member : top->fields()) { - if (isSyclSpecialType(member->getType(), S)) { + if (isSyclSpecialType(member->getType(), S) || + !member->getType()->isStructureType()) { FwdDeclEmitter.Visit( member->getType().getDesugaredType(S.getASTContext())); offsets.emplace_back(std::make_pair( member, S.getASTContext().getFieldOffset(member) / 8)); - } else if (member->getType()->isStructureType() && - S.getStructsWithSpecialType().count( - member->getType()->getAsStructureType()->getDecl())) { + } else if (member->getType()->isStructureType()) { dfs.emplace_back( member->getType()->getAsStructureType()->getDecl()); } diff --git a/sycl/test-e2e/FreeFunctionKernels/structs_with_special_types_as_kernel_paramters.cpp b/sycl/test-e2e/FreeFunctionKernels/structs_with_special_types_as_kernel_paramters.cpp index 72f4ca099fee3..81019f1e548c6 100644 --- a/sycl/test-e2e/FreeFunctionKernels/structs_with_special_types_as_kernel_paramters.cpp +++ b/sycl/test-e2e/FreeFunctionKernels/structs_with_special_types_as_kernel_paramters.cpp @@ -4,9 +4,6 @@ // This test verifies whether struct that contains either sycl::local_accesor or // sycl::accessor can be used with free function kernels extension. -// XFAIL: * -// XFAIL-TRACKER: CMPLRLLVM-67737 - #include #include #include From 6932522922d9fe455c867b4aac00b120bf95ed80 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 31 Jul 2025 07:24:50 -0700 Subject: [PATCH 32/69] Add tests --- .../CodeGenSYCL/free_function_int_header.cpp | 204 +++++++++++++++++- 1 file changed, 199 insertions(+), 5 deletions(-) diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 48a03c6c65916..1cd5100102284 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -278,6 +278,39 @@ void ff_24(int arg); void ff_24(int arg) { } +// Tests with parameter types that are structs that contain special types inside e.g accessor + +struct AccessorAndLocalAccessor { + sycl::accessor acc; + sycl::local_accessor lacc; +}; + +struct AccessorAndInt { + sycl::accessor acc; + int a; +}; + +struct IntAndAccessor { + int a; + sycl::accessor acc; +}; + +struct SecondLevelAccessor { + AccessorAndInt accAndInt; +}; + +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_25(AccessorAndLocalAccessor arg1) { +} + +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_26(AccessorAndLocalAccessor arg1, SecondLevelAccessor arg2) { +} + +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_27(IntAndAccessor arg1, AccessorAndInt) { +} + // CHECK: const char* const kernel_names[] = { // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piiii @@ -313,6 +346,10 @@ void ff_24(int arg) { // CHECK-NEXT: {{.*}}__sycl_kernel_ff_217DerivedPS_ // CHECK-NEXT: {{.*}}__sycl_kernel_ff_227DerivedPS_ // CHECK-NEXT: {{.*}}__sycl_kernel_ff_24i" +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2524AccessorAndLocalAccessor", +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor", +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt", + // CHECK-NEXT: {{.*}}__sycl_kernel_ff_23i" // CHECK-NEXT: "" @@ -436,6 +473,27 @@ void ff_24(int arg) { // CHECK: //--- _Z19__sycl_kernel_ff_24i // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK: //--- _Z19__sycl_kernel_ff_2524AccessorAndLocalAccessor +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 36, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 36 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 48 }, + +// CHECK: //--- _Z19__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 36, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 36 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 48 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 36 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 52 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 64 }, + +// CHECK: //--- _Z19__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 16 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 20 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 16 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 32 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 44 }, + // CHECK: //--- _Z19__sycl_kernel_ff_23i // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, @@ -1059,19 +1117,131 @@ void ff_24(int arg) { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; +// CHECK: Definition of _Z19__sycl_kernel_ff_2524AccessorAndLocalAccessor as a free function kernel +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: void ff_25(AccessorAndLocalAccessor arg1); +// CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { +// CHECK-NEXT: inline static constexpr bool value = true; +// CHECK-NEXT: }; + +// CHECK: template <> struct struct_with_special_type_info { +// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, AccessorAndLocalAccessor>>> +// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::local_accessor *)((char *)(&arg) + 12)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: NumArgs = 2; +// CHECK-NEXT: } +// CHECK-NEXT: }; + +// CHECK: static constexpr auto __sycl_shim33() { +// CHECK-NEXT: return (void (*)(struct AccessorAndLocalAccessor))ff_25; +// CHECK-NEXT: } +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim33()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim33()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; + +// CHECK: Definition of _Z19__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor as a free function kernel +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: void ff_26(AccessorAndLocalAccessor arg1, SecondLevelAccessor arg2); +// CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { +// CHECK-NEXT: inline static constexpr bool value = true; +// CHECK-NEXT: }; + +// CHECK: template <> struct struct_with_special_type_info { +// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, SecondLevelAccessor>>> +// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 12)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: NumArgs = 2; +// CHECK-NEXT: } +// CHECK-NEXT: }; + +// CHECK: static constexpr auto __sycl_shim34() { +// CHECK-NEXT: return (void (*)(struct AccessorAndLocalAccessor, struct SecondLevelAccessor))ff_26; +// CHECK-NEXT:} +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim34()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim34()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT }; + +// CHECK: Definition of _Z19__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt as a free function kernel +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: void ff_27(IntAndAccessor arg1, AccessorAndInt ); +// CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { +// CHECK-NEXT: inline static constexpr bool value = true; +// CHECK-NEXT: }; + +// CHECK: template <> struct struct_with_special_type_info { +// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, IntAndAccessor>>> +// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 0)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 4)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: NumArgs = 2; +// CHECK-NEXT: } +// CHECK-NEXT: }; + +// CHECK: template <> +// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { +// CHECK-NEXT: inline static constexpr bool value = true; +// CHECK-NEXT: }; + +// CHECK: template <> struct struct_with_special_type_info { +// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, AccessorAndInt>>> +// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 12)); +// CHECK-NEXT: ++ArgIndex; +// CHECK-NEXT: NumArgs = 2; +// CHECK-NEXT: } +// CHECK-NEXT: }; + +// CHECK: static constexpr auto __sycl_shim35() { +// CHECK-NEXT: return (void (*)(struct IntAndAccessor, struct AccessorAndInt))ff_27; +// CHECK-NEXT: } +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim35()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim35()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; + // CHECK: Definition of _Z19__sycl_kernel_ff_23i as a free function kernel // CHECK: Forward declarations of kernel and its argument types: // CHECK: void ff_23(int arg); -// CHECK-NEXT: static constexpr auto __sycl_shim33() { +// CHECK-NEXT: static constexpr auto __sycl_shim36() { // CHECK-NEXT: return (void (*)(int))ff_23; // CHECK-NEXT: } // CHECK-NEXT: namespace sycl { // CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim33()> { +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim36()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; // CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim33()> { +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim36()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; @@ -1309,15 +1479,39 @@ void ff_24(int arg) { // CHECK: // Definition of kernel_id of _Z19__sycl_kernel_ff_24i // CHECK-NEXT: namespace sycl { // CHECK-NEXT: template <> -// CHECK-NEXT: inline kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim32()>() { +// CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim32()>() { // CHECK-NEXT return sycl::detail::get_kernel_id_impl(std::string_view{"_Z19__sycl_kernel_ff_24i"}); // CHECK-NEXT: } // CHECK-NEXT: } +// CHECK: // Definition of kernel_id of _Z19__sycl_kernel_ff_2524AccessorAndLocalAccessor +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim33()>() { +// CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z19__sycl_kernel_ff_2524AccessorAndLocalAccessor"}); +// CHECK-NEXT: } +// CHECK-NEXT: } + +// CHECK: // Definition of kernel_id of _Z19__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim34()>() { +// CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z19__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor"}); +// CHECK-NEXT: } +// CHECK-NEXT: } + +// CHECK: // Definition of kernel_id of _Z19__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt +// CHECK-NEXT: namespace sycl { +// CHECK-NEXT: template <> +// CHECK-NEXT: kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim35()>() { +// CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z19__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt"}); +// CHECK-NEXT: } +// CHECK-NEXT: } + // CHECK: // Definition of kernel_id of _Z19__sycl_kernel_ff_23i // CHECK-NEXT: namespace sycl { // CHECK-NEXT: template <> -// CHECK-NEXT: inline kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim33()>() { +// CHECK-NEXT: inline kernel_id ext::oneapi::experimental::get_kernel_id<__sycl_shim36()>() { // CHECK-NEXT: return sycl::detail::get_kernel_id_impl(std::string_view{"_Z19__sycl_kernel_ff_23i"}); // CHECK-NEXT: } From 22484765b24ab1dd42510b7d5b9580c92beee299 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 31 Jul 2025 10:57:37 -0700 Subject: [PATCH 33/69] Fix warnings --- sycl/source/detail/scheduler/commands.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index ade9760109b24..176ae5126e756 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2360,6 +2360,16 @@ static void GetUrArgsBasedOnType( break; } + case kernel_param_kind_t::kind_struct_with_special_type: { + ur_exp_kernel_arg_type_t Type; + ur_exp_kernel_arg_value_t Value = {}; + Value.value = {Arg.MPtr}; + UrArgs.push_back({UR_STRUCTURE_TYPE_EXP_KERNEL_ARG_PROPERTIES, nullptr, + Type, static_cast(NextTrueIndex), + static_cast(Arg.MSize), Value}); + + break; + } case kernel_param_kind_t::kind_sampler: { sampler *SamplerPtr = (sampler *)Arg.MPtr; ur_exp_kernel_arg_value_t Value = {}; From f475e4d8d953c2c787fc74adb1a9761d63be5028 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 31 Jul 2025 11:24:45 -0700 Subject: [PATCH 34/69] Fix more warnings --- sycl/source/detail/scheduler/commands.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 176ae5126e756..65755404ee4f1 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2361,11 +2361,11 @@ static void GetUrArgsBasedOnType( break; } case kernel_param_kind_t::kind_struct_with_special_type: { - ur_exp_kernel_arg_type_t Type; ur_exp_kernel_arg_value_t Value = {}; Value.value = {Arg.MPtr}; UrArgs.push_back({UR_STRUCTURE_TYPE_EXP_KERNEL_ARG_PROPERTIES, nullptr, - Type, static_cast(NextTrueIndex), + UR_EXP_KERNEL_ARG_TYPE_VALUE, + static_cast(NextTrueIndex), static_cast(Arg.MSize), Value}); break; From f95f7fd56f21737e11a97dd562284f9eb3512641 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 31 Jul 2025 12:14:54 -0700 Subject: [PATCH 35/69] Fix pre-commit failures in test --- .../CodeGenSYCL/free_function_int_header.cpp | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 0c29462bcb001..be1acd1debb6e 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -1611,9 +1611,8 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: static constexpr auto __sycl_shim33() { // CHECK-NEXT: return (void (*)(struct AccessorAndLocalAccessor))ff_25; // CHECK-NEXT: } -// CHECK-NEXT: namespace sycl { -// CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim33()> { + +// CHECK: struct ext::oneapi::experimental::is_kernel<__sycl_shim33()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; // CHECK-NEXT: template <> @@ -1642,10 +1641,9 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: static constexpr auto __sycl_shim34() { // CHECK-NEXT: return (void (*)(struct AccessorAndLocalAccessor, struct SecondLevelAccessor))ff_26; -// CHECK-NEXT:} -// CHECK-NEXT: namespace sycl { -// CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim34()> { +// CHECK-NEXT: } + +// CHECK: struct ext::oneapi::experimental::is_kernel<__sycl_shim34()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; // CHECK-NEXT: template <> @@ -1691,9 +1689,8 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: static constexpr auto __sycl_shim35() { // CHECK-NEXT: return (void (*)(struct IntAndAccessor, struct AccessorAndInt))ff_27; // CHECK-NEXT: } -// CHECK-NEXT: namespace sycl { -// CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim35()> { + +// CHECK: struct ext::oneapi::experimental::is_kernel<__sycl_shim35()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; // CHECK-NEXT: template <> @@ -1711,8 +1708,8 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: namespace sycl { // CHECK-NEXT: inline namespace _V1 { // CHECK-NEXT: namespace detail { -// CHECK-NEXT: //Free Function Kernel info specialization for shim33 -// CHECK-NEXT: template <> struct FreeFunctionInfoData<__sycl_shim33()> { +// CHECK-NEXT: //Free Function Kernel info specialization for shim36 +// CHECK-NEXT: template <> struct FreeFunctionInfoData<__sycl_shim36()> { // CHECK-NEXT: __SYCL_DLL_LOCAL // CHECK-NEXT: static constexpr unsigned getNumParams() { return 1; } // CHECK-NEXT: __SYCL_DLL_LOCAL @@ -1742,7 +1739,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: namespace detail { // CHECK-NEXT: struct GlobalMapUpdater { // CHECK-NEXT: GlobalMapUpdater() { -// CHECK-NEXT: sycl::detail::free_function_info_map::add(sycl::detail::kernel_names, sycl::detail::kernel_args_sizes, 33); +// CHECK-NEXT: sycl::detail::free_function_info_map::add(sycl::detail::kernel_names, sycl::detail::kernel_args_sizes, 36); // CHECK-NEXT: } // CHECK-NEXT: }; // CHECK-NEXT: static GlobalMapUpdater updater; From c7b3696e42259c09fe0446ef50cc070932ed65e6 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 09:24:34 -0700 Subject: [PATCH 36/69] Address compilation errors --- clang/lib/Sema/SemaSYCL.cpp | 6 +----- sycl/include/sycl/handler.hpp | 1 + sycl/source/detail/scheduler/commands.cpp | 9 ++------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 530b4ff9ea29a..a61fbe93d53c2 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -6806,7 +6806,6 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "#include \n"; O << "#include \n"; O << "#include \n"; - O << "#include \n"; O << "\n"; LangOptions LO; @@ -7231,10 +7230,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "template <> struct struct_with_special_type_info<"; type.print(O, Policy); O << "> {\n"; - O << "template< typename ArgT, typename HandlerT, typename = " - "std::enable_if_t, "; - type.print(O, Policy); - O << ">>>\n"; + O << "template\n"; O << " static void set_arg(int ArgIndex, ArgT& "; O << "arg"; O << ", HandlerT& cgh, int &NumArgs) {\n"; diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 3ec8a247d7990..68a035d0f2e1f 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index a6edaa930fe66..64caf48afbe24 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -2356,13 +2356,8 @@ static void SetArgBasedOnType( break; } case kernel_param_kind_t::kind_struct_with_special_type: { - ur_exp_kernel_arg_value_t Value = {}; - Value.value = {Arg.MPtr}; - UrArgs.push_back({UR_STRUCTURE_TYPE_EXP_KERNEL_ARG_PROPERTIES, nullptr, - UR_EXP_KERNEL_ARG_TYPE_VALUE, - static_cast(NextTrueIndex), - static_cast(Arg.MSize), Value}); - + Adapter.call(Kernel, NextTrueIndex, + Arg.MSize, nullptr, Arg.MPtr); break; } case kernel_param_kind_t::kind_sampler: { From 0a017c1a012d7867020ac1bb706deb6e1472a3c1 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 10:44:28 -0700 Subject: [PATCH 37/69] Update ABI --- .../CodeGenSYCL/free_function_int_header.cpp | 8 ++++---- ...free_function_kernel_params_restrictions.cpp | 17 ----------------- sycl/test/abi/sycl_symbols_linux.dump | 1 + sycl/test/abi/sycl_symbols_windows.dump | 1 + sycl/test/include_deps/sycl_detail_core.hpp.cpp | 1 + 5 files changed, 7 insertions(+), 21 deletions(-) diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index be1acd1debb6e..2c54df8d485ce 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -1598,7 +1598,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, AccessorAndLocalAccessor>>> +// CHECK-NEXT: template< typename ArgT, typename HandlerT> // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; @@ -1629,7 +1629,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, SecondLevelAccessor>>> +// CHECK-NEXT: template< typename ArgT, typename HandlerT> // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; @@ -1660,7 +1660,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, IntAndAccessor>>> +// CHECK-NEXT: template< typename ArgT, typename HandlerT> // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; @@ -1676,7 +1676,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT, typename = std::enable_if_t, AccessorAndInt>>> +// CHECK-NEXT: template< typename ArgT, typename HandlerT> // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; diff --git a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp index d1bdc0e3da475..c7b2d2de8921c 100644 --- a/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp +++ b/clang/test/SemaSYCL/free_function_kernel_params_restrictions.cpp @@ -42,20 +42,3 @@ __attribute__((sycl_device)) [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void ff_5(A S1) { } - - - -struct StructWithAccessor { - sycl::accessor acc; - int *ptr; -}; - -struct Wrapper { - StructWithAccessor SWA; - -}; - -[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] -void ff_6(Wrapper S1) { // expected-error {{cannot be used as the type of a kernel parameter}} - // expected-note@-1 {{'Wrapper' is not yet supported as a free function kernel parameter}} -} diff --git a/sycl/test/abi/sycl_symbols_linux.dump b/sycl/test/abi/sycl_symbols_linux.dump index 71269e088a88a..6fa7edbd12b59 100644 --- a/sycl/test/abi/sycl_symbols_linux.dump +++ b/sycl/test/abi/sycl_symbols_linux.dump @@ -3633,6 +3633,7 @@ _ZN4sycl3_V17handler8finalizeEv _ZN4sycl3_V17handler8getQueueEv _ZN4sycl3_V17handler8prefetchEPKvm _ZN4sycl3_V17handler9clearArgsEv +_ZN4sycl3_V17handler14updateArgShiftEi _ZN4sycl3_V17handler9fill_implEPvPKvmm _ZN4sycl3_V17handlerC1EOSt10unique_ptrINS0_6detail12handler_implESt14default_deleteIS4_EE _ZN4sycl3_V17handlerC1ESt10shared_ptrINS0_3ext6oneapi12experimental6detail10graph_implEE diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index 195b20a66d934..4b4ee8db9c023 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -3830,6 +3830,7 @@ ?category@exception@_V1@sycl@@QEBAAEBVerror_category@std@@XZ ?checkNodePropertiesAndThrow@modifiable_command_graph@detail@experimental@oneapi@ext@_V1@sycl@@KAXAEBVproperty_list@67@@Z ?clearArgs@handler@_V1@sycl@@AEAAXXZ +?updateArgShift@handler@_V1@sycl@@AEAAXH@Z ?code@exception@_V1@sycl@@QEBAAEBVerror_code@std@@XZ ?compile_from_source@detail@experimental@oneapi@ext@_V1@sycl@@YA?AV?$kernel_bundle@$00@56@AEAV?$kernel_bundle@$02@56@AEBV?$vector@Vdevice@_V1@sycl@@V?$allocator@Vdevice@_V1@sycl@@@std@@@std@@AEBV?$vector@Vstring_view@detail@_V1@sycl@@V?$allocator@Vstring_view@detail@_V1@sycl@@@std@@@std@@PEAVstring@156@2@Z ?compile_impl@detail@_V1@sycl@@YA?AV?$shared_ptr@Vkernel_bundle_impl@detail@_V1@sycl@@@std@@AEBV?$kernel_bundle@$0A@@23@AEBV?$vector@Vdevice@_V1@sycl@@V?$allocator@Vdevice@_V1@sycl@@@std@@@5@AEBVproperty_list@23@@Z diff --git a/sycl/test/include_deps/sycl_detail_core.hpp.cpp b/sycl/test/include_deps/sycl_detail_core.hpp.cpp index 3087928f17c3f..f36771b1089ae 100644 --- a/sycl/test/include_deps/sycl_detail_core.hpp.cpp +++ b/sycl/test/include_deps/sycl_detail_core.hpp.cpp @@ -147,6 +147,7 @@ // CHECK-NEXT: ext/oneapi/interop_common.hpp // CHECK-NEXT: ext/oneapi/bindless_images_mem_handle.hpp // CHECK-NEXT: ext/oneapi/experimental/cluster_group_prop.hpp +// CHECK-NEXT: ext/oneapi/experimental/free_function_traits.hpp // CHECK-NEXT: ext/oneapi/experimental/raw_kernel_arg.hpp // CHECK-NEXT: ext/oneapi/experimental/use_root_sync_prop.hpp // CHECK-NEXT: kernel.hpp From de4b02f526f2b88cfbbbed4b56b0d952b7474126 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 12:30:13 -0700 Subject: [PATCH 38/69] Fix pre-commit failures --- clang/test/CodeGenSYCL/free_function_int_header.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 2c54df8d485ce..4731d92bbeed0 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -1598,7 +1598,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT> +// CHECK-NEXT: template // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; @@ -1629,7 +1629,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT> +// CHECK-NEXT: template // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; @@ -1660,7 +1660,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT> +// CHECK-NEXT: template // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; @@ -1676,7 +1676,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: }; // CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template< typename ArgT, typename HandlerT> +// CHECK-NEXT: template // CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { // CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); // CHECK-NEXT: ++ArgIndex; From b093093026161ae4116ced4e4e011cc1f9d125ed Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 22:18:54 -0400 Subject: [PATCH 39/69] Update free_function_traits.hpp --- .../ext/oneapi/experimental/free_function_traits.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index fb8bebf6c36c6..08a73c4487200 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -54,15 +54,13 @@ template struct is_struct_with_special_type { }; // This struct is made to be specialized in the integration header. -// It calls set_arg for every member of special type contained in the struct at -// any level of composition. The non-special type members can just be passed as -// part of the struct. So if type Foo contains two accessors and an integer -// inside and the user calls set_arg(Foo), that call will call this function -// which will call set_arg for each of those two accessors and not the int. +// It calls set_arg for every member of contained in the struct at +// any level of composition. So if type Foo contains two accessors and an integer +// inside and the user calls set_arg(Foo) which calls this function with T = Foo +// which will call set_arg for each of those two accessors and the int. // The function stores in NumArgs the number of set_arg calls that it made so // that subsequent set_arg calls initiated by the user can have the correct -// index. If the user provides the index ArgIndex the correct index will be -// ArgIndex + NumArgs +// index. template struct struct_with_special_type_info { template static void set_arg([[maybe_unused]] int ArgIndex, [[maybe_unused]] ArgT &arg, From 1280da070ae33d4774074f56840f2a0cfba32d06 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 22:19:48 -0400 Subject: [PATCH 40/69] Update handler.hpp --- sycl/include/sycl/handler.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 68a035d0f2e1f..9a1a6aff897b4 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -158,8 +158,6 @@ __SYCL_EXPORT void *async_malloc_from_pool(sycl::handler &h, size_t size, } // namespace ext::oneapi::experimental namespace ext::oneapi::experimental::detail { -template struct is_struct_with_special_type; -template struct struct_with_special_type_info; class dynamic_parameter_base; class dynamic_work_group_memory_base; class dynamic_local_accessor_base; From cbdf97dab229cd59a571033f4fc4343cb54ab92d Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 22:21:55 -0400 Subject: [PATCH 41/69] Update handler_impl.hpp --- sycl/source/detail/handler_impl.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sycl/source/detail/handler_impl.hpp b/sycl/source/detail/handler_impl.hpp index e50bd7c144028..8d01dd5692da8 100644 --- a/sycl/source/detail/handler_impl.hpp +++ b/sycl/source/detail/handler_impl.hpp @@ -153,7 +153,8 @@ class handler_impl { // several hidden set_arg calls for every set_arg called by the user. This // shift is required to make sure the following arguments set by the user have // the correct index. It keeps track of how many of these hidden set_arg calls - // have been made so far. + // have been made so far. The user cannot possibly know this, hence we need to + // keep track of this information. int MArgShift = 0; /// The list of associated accessors with this handler. From d2efe9854ac48a76d27f878d715e8309335854c8 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 6 Aug 2025 22:30:44 -0400 Subject: [PATCH 42/69] Formatting --- .../sycl/ext/oneapi/experimental/free_function_traits.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 08a73c4487200..7194f24dfcb52 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -55,9 +55,9 @@ template struct is_struct_with_special_type { // This struct is made to be specialized in the integration header. // It calls set_arg for every member of contained in the struct at -// any level of composition. So if type Foo contains two accessors and an integer -// inside and the user calls set_arg(Foo) which calls this function with T = Foo -// which will call set_arg for each of those two accessors and the int. +// any level of composition. So if type Foo contains two accessors and an +// integer inside and the user calls set_arg(Foo) which calls this function with +// T = Foo which will call set_arg for each of those two accessors and the int. // The function stores in NumArgs the number of set_arg calls that it made so // that subsequent set_arg calls initiated by the user can have the correct // index. From 4fdec2c7198590f6d0e1c91b3bff48f2bda1a2bd Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 8 Aug 2025 13:13:37 -0700 Subject: [PATCH 43/69] Apply initial suggestions --- clang/include/clang/Sema/SemaSYCL.h | 8 +++----- clang/lib/Sema/SemaSYCL.cpp | 12 ++---------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 4b33116587fa6..c623cd35d43c6 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -270,9 +270,7 @@ class SemaSYCL : public SemaBase { // A map that keeps track of all structs encountered with // special types inside. Relevant for free function kernels only. - // The key stores the struct as a declaration and the value stores the struct - // as a QualType just to make it easier to use it. - llvm::DenseMap StructsWithSpecialTypes; + llvm::DenseSet StructsWithSpecialTypes; public: SemaSYCL(Sema &S); @@ -325,8 +323,8 @@ class SemaSYCL : public SemaBase { } /// Add ParentStruct to StructsWithSpecialTypes. - void addStructWithSpecialType(const RecordDecl *ParentStruct, QualType Ty) { - StructsWithSpecialTypes[ParentStruct] = Ty; + void addStructWithSpecialType(const RecordDecl *ParentStruct) { + StructsWithSpecialTypes.insert(ParentStruct); } auto &getStructsWithSpecialType() const { return StructsWithSpecialTypes; } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index a61fbe93d53c2..c59f2874cf33f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2172,13 +2172,11 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler { } bool enterStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ++StructFieldDepth; return true; } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType ParamTy) final { - --StructFieldDepth; return true; } @@ -4531,17 +4529,11 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { Base = buildMemberExpr(Base, child); } for (auto it = CurrentStructs.rbegin(); it != CurrentStructs.rend(); ++it) - SemaSYCLRef.addStructWithSpecialType((*it)->getParent(), - (it + 1) == CurrentStructs.rend() - ? ParentStruct->getType() - : (*(it + 1))->getType()); + SemaSYCLRef.addStructWithSpecialType((*it)->getParent()); MemberExpr *MemberAccess = buildMemberExpr(Base, FD); createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, MemberAccess, BodyStmts); - SemaSYCLRef.addStructWithSpecialType(FD->getParent(), - CurrentStructs.size() - ? CurrentStructs.back()->getType() - : ParentStruct->getType()); + SemaSYCLRef.addStructWithSpecialType(FD->getParent()); return true; } From f029707fd477f7041f906ca16152f663d3a417b7 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 25 Sep 2025 07:28:35 -0700 Subject: [PATCH 44/69] Simplify integration header --- clang/lib/Sema/SemaSYCL.cpp | 371 +++++++++--------- .../experimental/free_function_traits.hpp | 23 +- 2 files changed, 195 insertions(+), 199 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c59f2874cf33f..b7fa8a4482ff8 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1771,6 +1771,11 @@ class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { SemaSYCL &SemaSYCLRef; SyclKernelFieldHandler(SemaSYCL &S) : SemaSYCLRef(S) {} + // Holds the last handled kernel struct parameter that contains a special + // type. Set in the enterStruct functions. Only relevant for free function + // kernels + ParmVarDecl *TopLevelStruct = nullptr; + // Returns 'true' if the thing we're visiting (Based on the FD/QualType pair) // is an element of an array. FD will always be the array field. When // traversing the array field, Ty will be the type of the array field or the @@ -1778,6 +1783,8 @@ class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { bool isArrayElement(const FieldDecl *FD, QualType Ty) const { return !SemaSYCLRef.getASTContext().hasSameType(FD->getType(), Ty); } + + ParmVarDecl *getTopLevelStructForCurrentField() { return TopLevelStruct; } }; // A class to represent the 'do nothing' case for filtering purposes. @@ -2696,9 +2703,6 @@ class SyclKernelPointerHandler : public SyclKernelFieldHandler { class SyclKernelDeclCreator : public SyclKernelFieldHandler { FunctionDecl *KernelDecl = nullptr; llvm::SmallVector Params; - // Holds the last handled kernel struct parameter that contains a special - // type. Set in the enterStruct functions. - ParmVarDecl *CurrentStruct; Sema::ContextRAII FuncContext; // Holds the last handled field's first parameter. This doesn't store an // iterator as push_back invalidates iterators. @@ -2971,7 +2975,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { ++StructDepth; StringRef Name = "_arg_struct"; addParam(Name, Ty); - CurrentStruct = Params.back(); + TopLevelStruct = Params.back(); return true; } @@ -3171,7 +3175,6 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return ArrayRef(std::begin(Params) + LastParamIndex, std::end(Params)); } - ParmVarDecl *getParentStructForCurrentField() { return CurrentStruct; } }; // This Visitor traverses the AST of the function with @@ -4523,17 +4526,14 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { // Being inside this function means there is a struct parameter to the free // function kernel that contains a special type. - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); - Expr *Base = createParamReferenceExpr(ParentStruct); + Expr *Base = createParamReferenceExpr(TopLevelStruct); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } - for (auto it = CurrentStructs.rbegin(); it != CurrentStructs.rend(); ++it) - SemaSYCLRef.addStructWithSpecialType((*it)->getParent()); MemberExpr *MemberAccess = buildMemberExpr(Base, FD); createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, MemberAccess, BodyStmts); - SemaSYCLRef.addStructWithSpecialType(FD->getParent()); + SemaSYCLRef.addStructWithSpecialType(TopLevelStruct->getOriginalType()->getAsCXXRecordDecl()); return true; } @@ -4672,9 +4672,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - ParmVarDecl *ParentStruct = DeclCreator.getParentStructForCurrentField(); ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - ParentStruct, ParentStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); + TopLevelStruct, TopLevelStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4738,6 +4737,13 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { SYCLIntegrationHeader &Header; int64_t CurOffset = 0; llvm::SmallVector ArrayBaseOffsets; + // For every struct that contains a special type, record the offset and size + // of every special type inside of it at any nesting level. Store the + // information in the variable below. + llvm::DenseMap>> + OffsetSizeInfo; + // Likewise for the kind of a special type i.e accessor etc... + llvm::DenseMap> KindInfo; int StructDepth = 0; // A series of functions to calculate the change in offset based on the type. @@ -4759,7 +4765,11 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { void addParam(const FieldDecl *FD, QualType ArgTy, SYCLIntegrationHeader::kernel_param_kind_t Kind) { - addParam(ArgTy, Kind, offsetOf(FD, ArgTy)); + // If we are dealing with a field of a free function kernel parameter struct + // do not add the parameter. The offset, Size, Kind information has been + // stored in OffsetSizeInfo and KindInfo + if (TopLevelStruct) + addParam(ArgTy, Kind, offsetOf(FD, ArgTy)); } // For free functions we increment the current offset as each parameter is @@ -4837,6 +4847,16 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { + // If TopLevelStruct is set, it means we are traversing the fields of a free + // function parameter struct. In this case, we simply record the current + // field's offset and size in OffsetSizeInfo and Kind in KindInfo. + if (TopLevelStruct) { + OffsetSizeInfo[TopLevelStruct].emplace_back( + make_pair(offsetOf(FD, FieldTy), SemaSYCLRef.getASTContext() + .getTypeSizeInChars(FieldTy) + .getQuantity())); + } + const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); assert(ClassTy && "Type must be a C++ record type"); if (isSyclAccessorType(FieldTy)) { @@ -4852,17 +4872,22 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::dynamic_local_accessor) ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; - Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); + KindInfo[TopLevelStruct].emplace_back(ParamKind); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); + KindInfo[TopLevelStruct].emplace_back(SYCLIntegrationHeader::kind_stream); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::work_group_memory)) { addParam(FieldTy, SYCLIntegrationHeader::kind_work_group_memory, offsetOf(FD, FieldTy)); + KindInfo[TopLevelStruct].emplace_back( + SYCLIntegrationHeader::kind_work_group_memory); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::dynamic_work_group_memory)) { addParam(FieldTy, SYCLIntegrationHeader::kind_dynamic_work_group_memory, offsetOf(FD, FieldTy)); + KindInfo[TopLevelStruct].emplace_back( + SYCLIntegrationHeader::kind_dynamic_work_group_memory); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::sampler) || SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::annotated_ptr) || SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::annotated_arg)) { @@ -4877,6 +4902,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { : (T->isPointerType() ? SYCLIntegrationHeader::kind_pointer : SYCLIntegrationHeader::kind_std_layout); addParam(T, ParamKind, offsetOf(FD, FieldTy)); + KindInfo[TopLevelStruct].emplace_back(ParamKind); } else { llvm_unreachable( "Unexpected SYCL special class when generating integration header"); @@ -4927,146 +4953,148 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { - addParam(FD, FieldTy, - ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout - : SYCLIntegrationHeader::kind_pointer)); - return true; - } + bool handlePointerType(FieldDecl * FD, QualType FieldTy) final { + addParam(FD, FieldTy, + ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout + : SYCLIntegrationHeader::kind_pointer)); + return true; + } - bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_pointer); - return true; - } + bool handlePointerType(ParmVarDecl * PD, QualType ParamTy) final { + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_pointer); + return true; + } - bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { - addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } + bool handleScalarType(FieldDecl * FD, QualType FieldTy) final { + addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } - bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } + bool handleScalarType(ParmVarDecl * PD, QualType ParamTy) final { + addParam(PD, ParamTy, 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 - // struct. - addParam(FD, 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 struct. + addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } - bool handleTopLevelStruct(const CXXRecordDecl *, QualType Ty) final { - addParam(Ty, SYCLIntegrationHeader::kind_std_layout, /*Offset=*/0); - return true; - } + bool handleTopLevelStruct(const CXXRecordDecl *, QualType Ty) final { + addParam(Ty, SYCLIntegrationHeader::kind_std_layout, /*Offset=*/0); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, - QualType Ty) final { - addParam(FD, Ty, 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 ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType ParamTy) final { + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *Base, - const CXXBaseSpecifier &, QualType Ty) final { - addParam(Ty, SYCLIntegrationHeader::kind_std_layout, - offsetOf(Base, Ty->getAsCXXRecordDecl())); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *Base, + const CXXBaseSpecifier &, QualType Ty) final { + addParam(Ty, SYCLIntegrationHeader::kind_std_layout, + offsetOf(Base, Ty->getAsCXXRecordDecl())); + return true; + } - bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { - return handleScalarType(FD, FieldTy); - } + bool handleUnionType(FieldDecl * FD, QualType FieldTy) final { + return handleScalarType(FD, FieldTy); + } - bool handleUnionType(ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleUnionType(ParmVarDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - void handleSyclKernelHandlerType(QualType) { - // The compiler generated kernel argument used to initialize SYCL 2020 - // specialization constants, `specialization_constants_buffer`, should - // have corresponding entry in integration header. - ASTContext &Context = SemaSYCLRef.getASTContext(); - // Offset is zero since kernel_handler argument is not part of - // kernel object (i.e. it is not captured) - addParam(Context.getPointerType(Context.CharTy), - SYCLIntegrationHeader::kind_specialization_constants_buffer, 0); - } + void handleSyclKernelHandlerType(QualType) { + // The compiler generated kernel argument used to initialize SYCL 2020 + // specialization constants, `specialization_constants_buffer`, should + // have corresponding entry in integration header. + ASTContext &Context = SemaSYCLRef.getASTContext(); + // Offset is zero since kernel_handler argument is not part of + // kernel object (i.e. it is not captured) + addParam(Context.getPointerType(Context.CharTy), + SYCLIntegrationHeader::kind_specialization_constants_buffer, 0); + } - bool enterStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - ++StructDepth; - CurOffset += offsetOf(FD, Ty); - return true; - } + bool enterStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + ++StructDepth; + CurOffset += offsetOf(FD, Ty); + return true; + } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { - addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); - return true; - } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) + final { + addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); + TopLevelStruct = PD; + return true; + } - bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - --StructDepth; - CurOffset -= offsetOf(FD, Ty); - return true; - } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + --StructDepth; + CurOffset -= offsetOf(FD, Ty); + return true; + } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - return true; - } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + return true; + } - bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, - QualType) final { - CurOffset += offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); - return true; - } + bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, + QualType) final { + CurOffset += offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); + return true; + } - bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, - QualType) final { - CurOffset -= offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); - return true; - } + bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, + QualType) final { + CurOffset -= offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); + return true; + } - bool enterArray(FieldDecl *FD, QualType ArrayTy, QualType) final { - ArrayBaseOffsets.push_back(CurOffset + offsetOf(FD, ArrayTy)); - return true; - } + bool enterArray(FieldDecl * FD, QualType ArrayTy, QualType) final { + ArrayBaseOffsets.push_back(CurOffset + offsetOf(FD, ArrayTy)); + return true; + } - bool enterArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool nextElement(QualType ET, uint64_t Index) final { - int64_t Size = - SemaSYCLRef.getASTContext().getTypeSizeInChars(ET).getQuantity(); - CurOffset = ArrayBaseOffsets.back() + Size * Index; - return true; - } + bool nextElement(QualType ET, uint64_t Index) final { + int64_t Size = + SemaSYCLRef.getASTContext().getTypeSizeInChars(ET).getQuantity(); + CurOffset = ArrayBaseOffsets.back() + Size * Index; + return true; + } - bool leaveArray(FieldDecl *FD, QualType ArrayTy, QualType) final { - CurOffset = ArrayBaseOffsets.pop_back_val(); - CurOffset -= offsetOf(FD, ArrayTy); - return true; - } + bool leaveArray(FieldDecl * FD, QualType ArrayTy, QualType) final { + CurOffset = ArrayBaseOffsets.pop_back_val(); + CurOffset -= offsetOf(FD, ArrayTy); + return true; + } - bool leaveArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool leaveArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - using SyclKernelFieldHandler::enterStruct; - using SyclKernelFieldHandler::leaveStruct; -}; + using SyclKernelFieldHandler::enterStruct; + using SyclKernelFieldHandler::leaveStruct; + }; class SyclKernelIntFooterCreator : public SyclKernelFieldHandler { SYCLIntegrationFooter &Footer; @@ -7188,60 +7216,39 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { Policy.SuppressTagKeyword = true; type.print(O, Policy); O << "> {\n"; - O << " inline static constexpr bool value = true;\n};\n\n"; - // Now we define the set_arg function for this struct that contains - // special types. It takes the handler as an argument so that we can - // ultimately call set_arg on the handler for each member - // contained in the struct. First, emit needed forward declarations for - // all types contained in the struct by doing a depth first search - // exploration of the struct. Also collect the offsets of all the - // members inside the struct while we're at it so that we can call - // set_arg for each one of those. - llvm::SmallVector, 8> offsets; - llvm::SmallVector dfs; - dfs.emplace_back(Struct); - while (!dfs.empty()) { - const auto top = dfs.pop_back_val(); - for (const auto member : top->fields()) { - if (isSyclSpecialType(member->getType(), S) || - !member->getType()->isStructureType()) { - FwdDeclEmitter.Visit( - member->getType().getDesugaredType(S.getASTContext())); - offsets.emplace_back(std::make_pair( - member, S.getASTContext().getFieldOffset(member) / 8)); - } else if (member->getType()->isStructureType()) { - dfs.emplace_back( - member->getType()->getAsStructureType()->getDecl()); - } + O << " inline static constexpr bool value = true;\n"; + O << " static constexpr size_t offsetsSizes[2][] = {\n"; + for (const auto OffsetSize : OffsetSizeInfo[Param]) { + O << "{ " << OffsetSize.first << ", " << OffsetSize.second << "},\n "; + } + O << "{-1, -1} } \n};\n\n "; + O << " static constexpr sycl::detail::kernel_param_kind_t kinds[] = {\n"; + for (const auto Kind : KindInfo[Param]) { + switch (Kind) { + case SYCLIntegrationHeader::kind_accessor: + O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + break; + case SYCLIntegrationHeader::kind_sampler: + O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + break; + case SYCLIntegrationHeader::kind_pointer: + O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + break; + case SYCLIntegrationHeader::kind_stream: + O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + break; + case SYCLIntegrationHeader::kind_work_group_memory: + O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + break; + case SYCLIntegrationHeader::kind_dynamic_accessor: + O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + break; + default: } + O << ",\n "; } + O << "sycl::detail::kernel_param_kind_t::kind_invalid } \n};\n\n "; - O << "namespace sycl { inline namespace _V1 { namespace ext { " - "namespace oneapi { namespace " - "experimental { namespace detail { \n"; - O << "template <> struct struct_with_special_type_info<"; - type.print(O, Policy); - O << "> {\n"; - O << "template\n"; - O << " static void set_arg(int ArgIndex, ArgT& "; - O << "arg"; - O << ", HandlerT& cgh, int &NumArgs) {\n"; - int NumFields = 0; - for (const auto fieldoffset : offsets) { - O << " cgh.set_arg(ArgIndex, *("; - fieldoffset.first->getType().print(O, Policy); - O << " *)"; - O << "((char *)(&arg) + " << fieldoffset.second << ")"; - O << ");\n"; - O << " ++ArgIndex;\n"; - ++NumFields; - } - O << " NumArgs = " << NumFields << ";\n"; - O << " }\n};\n} // namespace detail \n} // namespace experimental " - "\n} " - "// namespace oneapi \n} // namespace ext \n} // namespace " - "_V1\n} " - "// namespace sycl\n\n"; visitedStructWithSpecialType[Struct] = true; } Policy.SuppressTagKeyword = false; diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 7194f24dfcb52..bcf188e8aa429 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include namespace sycl { inline namespace _V1 { @@ -48,24 +49,12 @@ inline constexpr bool is_kernel_v = is_kernel::value; namespace detail { // A struct with special type is a struct type that contains special types. // The frontend defines this trait to be true after analyzing the struct at -// compile time. +// compile time and contains information about Offset, Size and kind(accessor, +// etc...) inside the struct template struct is_struct_with_special_type { - inline static constexpr bool value = false; -}; - -// This struct is made to be specialized in the integration header. -// It calls set_arg for every member of contained in the struct at -// any level of composition. So if type Foo contains two accessors and an -// integer inside and the user calls set_arg(Foo) which calls this function with -// T = Foo which will call set_arg for each of those two accessors and the int. -// The function stores in NumArgs the number of set_arg calls that it made so -// that subsequent set_arg calls initiated by the user can have the correct -// index. -template struct struct_with_special_type_info { - template - static void set_arg([[maybe_unused]] int ArgIndex, [[maybe_unused]] ArgT &arg, - [[maybe_unused]] HandlerT &cgh, - [[maybe_unused]] int &NumArgs) {} + static constexpr bool value = false; + static constexpr size_t offsetsSizes[2][]; + static constexpr detail::kernel_param_kind_t kinds[]; }; } // namespace detail From 3557c1f78970f1bcd8c66e7beb2772724df1882d Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 30 Sep 2025 07:39:55 -0700 Subject: [PATCH 45/69] Fix set_arg function --- clang/include/clang/Sema/SemaSYCL.h | 17 +++++ clang/lib/Sema/SemaSYCL.cpp | 72 ++++++++++++------- .../experimental/free_function_traits.hpp | 6 +- sycl/include/sycl/handler.hpp | 14 +++- 4 files changed, 79 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index c623cd35d43c6..add8282f16a60 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -119,6 +119,13 @@ class SYCLIntegrationHeader { /// integration header is required. void addHostPipeRegistration() { NeedToEmitHostPipeRegistration = true; } + /// Add an Offset and a size entry to the map OffsetSizeInfo with key Struct. + void addOffsetSizeInfo(ParmVarDecl *Struct, + std::pair OffsetSize); + + /// Add a parameter Kind entry to the map KindInfo with key Struct. + void addKindInfo(ParmVarDecl *Struct, kernel_param_kind_t Kind); + private: // Kernel actual parameter descriptor. struct KernelParamDesc { @@ -206,6 +213,16 @@ class SYCLIntegrationHeader { /// Keeps track of whether declaration of __sycl_host_pipe_registration /// type and __sycl_host_pipe_registrar variable are required to emit. bool NeedToEmitHostPipeRegistration = false; + + // For every struct that contains a special type, record the offset and size + // of every special type inside of it at any nesting level. Store the + // information in the variable below. + llvm::DenseMap>> + OffsetSizeInfo; + // Likewise for the kind of a special type i.e accessor etc... + llvm::DenseMap> + KindInfo; }; class SYCLIntegrationFooter { diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index b7fa8a4482ff8..7f36f364476f1 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -3175,6 +3175,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return ArrayRef(std::begin(Params) + LastParamIndex, std::end(Params)); } + ParmVarDecl *getTopLevelStruct() { return TopLevelStruct; } }; // This Visitor traverses the AST of the function with @@ -4526,14 +4527,14 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { // Being inside this function means there is a struct parameter to the free // function kernel that contains a special type. - Expr *Base = createParamReferenceExpr(TopLevelStruct); + Expr *Base = createParamReferenceExpr(DeclCreator.getTopLevelStruct()); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } MemberExpr *MemberAccess = buildMemberExpr(Base, FD); createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, MemberAccess, BodyStmts); - SemaSYCLRef.addStructWithSpecialType(TopLevelStruct->getOriginalType()->getAsCXXRecordDecl()); + SemaSYCLRef.addStructWithSpecialType(DeclCreator.getTopLevelStruct()->getType()->getAsCXXRecordDecl()); return true; } @@ -4673,7 +4674,9 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - TopLevelStruct, TopLevelStruct->getType(), VK_PRValue, FreeFunctionSrcLoc)); + DeclCreator.getTopLevelStruct(), + DeclCreator.getTopLevelStruct()->getType(), VK_PRValue, + FreeFunctionSrcLoc)); return true; } @@ -4851,10 +4854,11 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { // function parameter struct. In this case, we simply record the current // field's offset and size in OffsetSizeInfo and Kind in KindInfo. if (TopLevelStruct) { - OffsetSizeInfo[TopLevelStruct].emplace_back( - make_pair(offsetOf(FD, FieldTy), SemaSYCLRef.getASTContext() - .getTypeSizeInChars(FieldTy) - .getQuantity())); + Header.addOffsetSizeInfo( + TopLevelStruct, + std::make_pair(offsetOf(FD, FieldTy), SemaSYCLRef.getASTContext() + .getTypeSizeInChars(FieldTy) + .getQuantity())); } const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); @@ -4873,21 +4877,21 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); - KindInfo[TopLevelStruct].emplace_back(ParamKind); + Header.addKindInfo(TopLevelStruct, ParamKind); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); - KindInfo[TopLevelStruct].emplace_back(SYCLIntegrationHeader::kind_stream); + Header.addKindInfo(TopLevelStruct, SYCLIntegrationHeader::kind_stream); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::work_group_memory)) { addParam(FieldTy, SYCLIntegrationHeader::kind_work_group_memory, offsetOf(FD, FieldTy)); - KindInfo[TopLevelStruct].emplace_back( - SYCLIntegrationHeader::kind_work_group_memory); + Header.addKindInfo(TopLevelStruct, + SYCLIntegrationHeader::kind_work_group_memory); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::dynamic_work_group_memory)) { addParam(FieldTy, SYCLIntegrationHeader::kind_dynamic_work_group_memory, offsetOf(FD, FieldTy)); - KindInfo[TopLevelStruct].emplace_back( - SYCLIntegrationHeader::kind_dynamic_work_group_memory); + Header.addKindInfo(TopLevelStruct, + SYCLIntegrationHeader::kind_dynamic_work_group_memory); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::sampler) || SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::annotated_ptr) || SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::annotated_arg)) { @@ -4902,7 +4906,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { : (T->isPointerType() ? SYCLIntegrationHeader::kind_pointer : SYCLIntegrationHeader::kind_std_layout); addParam(T, ParamKind, offsetOf(FD, FieldTy)); - KindInfo[TopLevelStruct].emplace_back(ParamKind); + Header.addKindInfo(TopLevelStruct, ParamKind); } else { llvm_unreachable( "Unexpected SYCL special class when generating integration header"); @@ -7217,37 +7221,45 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { type.print(O, Policy); O << "> {\n"; O << " inline static constexpr bool value = true;\n"; - O << " static constexpr size_t offsetsSizes[2][] = {\n"; + O << " static constexpr int offsets[] = {\n"; for (const auto OffsetSize : OffsetSizeInfo[Param]) { - O << "{ " << OffsetSize.first << ", " << OffsetSize.second << "},\n "; + O << OffsetSize.first << ", "; } - O << "{-1, -1} } \n};\n\n "; - O << " static constexpr sycl::detail::kernel_param_kind_t kinds[] = {\n"; + O << "-1};\n\n "; + + O << " static constexpr int sizes[] = {\n"; + for (const auto OffsetSize : OffsetSizeInfo[Param]) { + O << OffsetSize.second << ", "; + } + O << "-1}; \n\n "; + + O << " static constexpr sycl::detail::kernel_param_kind_t kinds[] = {\n "; for (const auto Kind : KindInfo[Param]) { switch (Kind) { case SYCLIntegrationHeader::kind_accessor: - O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + O << "sycl::detail::kernel_param_kind_t::kind_accessor"; break; case SYCLIntegrationHeader::kind_sampler: - O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + O << "sycl::detail::kernel_param_kind_t::kind_accessor"; break; case SYCLIntegrationHeader::kind_pointer: - O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + O << "sycl::detail::kernel_param_kind_t::kind_accessor"; break; case SYCLIntegrationHeader::kind_stream: - O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + O << "sycl::detail::kernel_param_kind_t::kind_accessor"; break; case SYCLIntegrationHeader::kind_work_group_memory: - O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + O << "sycl::detail::kernel_param_kind_t::kind_accessor"; break; case SYCLIntegrationHeader::kind_dynamic_accessor: - O << "sycl::detail::kernel_param_kind_t::kind_accessor,\n"; + O << "sycl::detail::kernel_param_kind_t::kind_accessor"; break; default: + break; } O << ",\n "; } - O << "sycl::detail::kernel_param_kind_t::kind_invalid } \n};\n\n "; + O << "sycl::detail::kernel_param_kind_t::kind_invalid }; \n};\n\n "; visitedStructWithSpecialType[Struct] = true; } @@ -7339,6 +7351,16 @@ void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info, PD.Offset = Offset; } +void SYCLIntegrationHeader::addOffsetSizeInfo( + ParmVarDecl *Struct, std::pair OffsetSize) { + OffsetSizeInfo[Struct].emplace_back(OffsetSize); +} + +void SYCLIntegrationHeader::addKindInfo( + ParmVarDecl *Struct, SYCLIntegrationHeader::kernel_param_kind_t Kind) { + KindInfo[Struct].emplace_back(Kind); +} + void SYCLIntegrationHeader::endKernel() { // nop for now } diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index bcf188e8aa429..3a95e7b8bcf16 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -53,8 +53,10 @@ namespace detail { // etc...) inside the struct template struct is_struct_with_special_type { static constexpr bool value = false; - static constexpr size_t offsetsSizes[2][]; - static constexpr detail::kernel_param_kind_t kinds[]; + static constexpr int offsets[] = {-1}; + static constexpr int sizes[] = {-1}; + static constexpr sycl::detail::kernel_param_kind_t kinds[] = { + sycl::detail::kernel_param_kind_t::kind_invalid}; }; } // namespace detail diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 9a1a6aff897b4..2ad1243a24409 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1661,9 +1661,17 @@ class __SYCL_EXPORT handler { setArgHelper(ArgIndex, std::move(Arg)); if constexpr (ext::oneapi::experimental::detail:: is_struct_with_special_type>::value) { - int NumArgs; - ext::oneapi::experimental::detail::struct_with_special_type_info< - remove_cv_ref_t>::set_arg(ArgIndex + 1, Arg, *this, NumArgs); + int NumArgs = 0; + using type = + ext::oneapi::experimental::detail::is_struct_with_special_type< + remove_cv_ref_t>; + int index = 0; + while (type::offsets[index] != -1) { + ++NumArgs; + addArg(type::kinds[index], (char *)(&Arg) + type::offsets[index], + type::sizes[index], ArgIndex + NumArgs); + ++index; + } updateArgShift(NumArgs); } } From 1dbac8986c76f6466bf4f3c0e619055437cb7122 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 30 Sep 2025 13:52:58 -0700 Subject: [PATCH 46/69] More refactoring --- clang/include/clang/Sema/SemaSYCL.h | 19 ++--- clang/lib/Sema/SemaSYCL.cpp | 88 +++++------------------- sycl/include/sycl/detail/kernel_desc.hpp | 2 +- 3 files changed, 28 insertions(+), 81 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index add8282f16a60..ee45663ab8795 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -119,12 +119,8 @@ class SYCLIntegrationHeader { /// integration header is required. void addHostPipeRegistration() { NeedToEmitHostPipeRegistration = true; } - /// Add an Offset and a size entry to the map OffsetSizeInfo with key Struct. - void addOffsetSizeInfo(ParmVarDecl *Struct, - std::pair OffsetSize); - - /// Add a parameter Kind entry to the map KindInfo with key Struct. - void addKindInfo(ParmVarDecl *Struct, kernel_param_kind_t Kind); + /// Set the ParentStruct field + void setParentStruct(ParmVarDecl *parent); private: // Kernel actual parameter descriptor. @@ -214,9 +210,14 @@ class SYCLIntegrationHeader { /// type and __sycl_host_pipe_registrar variable are required to emit. bool NeedToEmitHostPipeRegistration = false; - // For every struct that contains a special type, record the offset and size - // of every special type inside of it at any nesting level. Store the - // information in the variable below. + // For free function kernels, keeps track of the parameter that is currently + // being analyzed if it is a struct that contains special types. + ParmVarDecl *ParentStruct; + + // For every struct that contains a special type which is given by + // the ParentStruct field above, record the offset and size of every special + // type inside of it at any nesting level. Store the information in the + // variable below. llvm::DenseMap>> OffsetSizeInfo; // Likewise for the kind of a special type i.e accessor etc... diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 7f36f364476f1..599da7418f796 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1774,7 +1774,7 @@ class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { // Holds the last handled kernel struct parameter that contains a special // type. Set in the enterStruct functions. Only relevant for free function // kernels - ParmVarDecl *TopLevelStruct = nullptr; + ParmVarDecl *ParentStruct = nullptr; // Returns 'true' if the thing we're visiting (Based on the FD/QualType pair) // is an element of an array. FD will always be the array field. When @@ -1783,8 +1783,6 @@ class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase { bool isArrayElement(const FieldDecl *FD, QualType Ty) const { return !SemaSYCLRef.getASTContext().hasSameType(FD->getType(), Ty); } - - ParmVarDecl *getTopLevelStructForCurrentField() { return TopLevelStruct; } }; // A class to represent the 'do nothing' case for filtering purposes. @@ -2975,7 +2973,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { ++StructDepth; StringRef Name = "_arg_struct"; addParam(Name, Ty); - TopLevelStruct = Params.back(); + ParentStruct = Params.back(); return true; } @@ -3175,7 +3173,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { return ArrayRef(std::begin(Params) + LastParamIndex, std::end(Params)); } - ParmVarDecl *getTopLevelStruct() { return TopLevelStruct; } + ParmVarDecl *getParentStruct() { return ParentStruct; } }; // This Visitor traverses the AST of the function with @@ -4527,14 +4525,14 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { // Being inside this function means there is a struct parameter to the free // function kernel that contains a special type. - Expr *Base = createParamReferenceExpr(DeclCreator.getTopLevelStruct()); + Expr *Base = createParamReferenceExpr(DeclCreator.getParentStruct()); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); } MemberExpr *MemberAccess = buildMemberExpr(Base, FD); createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, MemberAccess, BodyStmts); - SemaSYCLRef.addStructWithSpecialType(DeclCreator.getTopLevelStruct()->getType()->getAsCXXRecordDecl()); + SemaSYCLRef.addStructWithSpecialType(DeclCreator.getParentStruct()->getType()->getAsCXXRecordDecl()); return true; } @@ -4674,8 +4672,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - DeclCreator.getTopLevelStruct(), - DeclCreator.getTopLevelStruct()->getType(), VK_PRValue, + DeclCreator.getParentStruct(), + DeclCreator.getParentStruct()->getType(), VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4740,13 +4738,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { SYCLIntegrationHeader &Header; int64_t CurOffset = 0; llvm::SmallVector ArrayBaseOffsets; - // For every struct that contains a special type, record the offset and size - // of every special type inside of it at any nesting level. Store the - // information in the variable below. - llvm::DenseMap>> - OffsetSizeInfo; - // Likewise for the kind of a special type i.e accessor etc... - llvm::DenseMap> KindInfo; int StructDepth = 0; // A series of functions to calculate the change in offset based on the type. @@ -4768,11 +4759,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { void addParam(const FieldDecl *FD, QualType ArgTy, SYCLIntegrationHeader::kernel_param_kind_t Kind) { - // If we are dealing with a field of a free function kernel parameter struct - // do not add the parameter. The offset, Size, Kind information has been - // stored in OffsetSizeInfo and KindInfo - if (TopLevelStruct) - addParam(ArgTy, Kind, offsetOf(FD, ArgTy)); + addParam(ArgTy, Kind, offsetOf(FD, ArgTy)); } // For free functions we increment the current offset as each parameter is @@ -4850,16 +4837,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { - // If TopLevelStruct is set, it means we are traversing the fields of a free - // function parameter struct. In this case, we simply record the current - // field's offset and size in OffsetSizeInfo and Kind in KindInfo. - if (TopLevelStruct) { - Header.addOffsetSizeInfo( - TopLevelStruct, - std::make_pair(offsetOf(FD, FieldTy), SemaSYCLRef.getASTContext() - .getTypeSizeInChars(FieldTy) - .getQuantity())); - } const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); assert(ClassTy && "Type must be a C++ record type"); @@ -4877,21 +4854,15 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); - Header.addKindInfo(TopLevelStruct, ParamKind); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); - Header.addKindInfo(TopLevelStruct, SYCLIntegrationHeader::kind_stream); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::work_group_memory)) { addParam(FieldTy, SYCLIntegrationHeader::kind_work_group_memory, offsetOf(FD, FieldTy)); - Header.addKindInfo(TopLevelStruct, - SYCLIntegrationHeader::kind_work_group_memory); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::dynamic_work_group_memory)) { addParam(FieldTy, SYCLIntegrationHeader::kind_dynamic_work_group_memory, offsetOf(FD, FieldTy)); - Header.addKindInfo(TopLevelStruct, - SYCLIntegrationHeader::kind_dynamic_work_group_memory); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::sampler) || SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::annotated_ptr) || SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::annotated_arg)) { @@ -4906,7 +4877,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { : (T->isPointerType() ? SYCLIntegrationHeader::kind_pointer : SYCLIntegrationHeader::kind_std_layout); addParam(T, ParamKind, offsetOf(FD, FieldTy)); - Header.addKindInfo(TopLevelStruct, ParamKind); } else { llvm_unreachable( "Unexpected SYCL special class when generating integration header"); @@ -5037,10 +5007,10 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) - final { + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType Ty) final { addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); - TopLevelStruct = PD; + Header.setParentStruct(PD); return true; } @@ -5051,6 +5021,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + Header.setParentStruct(nullptr); return true; } @@ -7235,28 +7206,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << " static constexpr sycl::detail::kernel_param_kind_t kinds[] = {\n "; for (const auto Kind : KindInfo[Param]) { - switch (Kind) { - case SYCLIntegrationHeader::kind_accessor: - O << "sycl::detail::kernel_param_kind_t::kind_accessor"; - break; - case SYCLIntegrationHeader::kind_sampler: - O << "sycl::detail::kernel_param_kind_t::kind_accessor"; - break; - case SYCLIntegrationHeader::kind_pointer: - O << "sycl::detail::kernel_param_kind_t::kind_accessor"; - break; - case SYCLIntegrationHeader::kind_stream: - O << "sycl::detail::kernel_param_kind_t::kind_accessor"; - break; - case SYCLIntegrationHeader::kind_work_group_memory: - O << "sycl::detail::kernel_param_kind_t::kind_accessor"; - break; - case SYCLIntegrationHeader::kind_dynamic_accessor: - O << "sycl::detail::kernel_param_kind_t::kind_accessor"; - break; - default: - break; - } + O << "sycl::detail::kernel_param_kind_t::" << paramKind2Str(Kind); O << ",\n "; } O << "sycl::detail::kernel_param_kind_t::kind_invalid }; \n};\n\n "; @@ -7349,16 +7299,12 @@ void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info, PD.Kind = Kind; PD.Info = Info; PD.Offset = Offset; + OffsetSizeInfo[ParentStruct].emplace_back(std::make_pair(Offset, Info)); + KindInfo[ParentStruct].emplace_back(Kind); } -void SYCLIntegrationHeader::addOffsetSizeInfo( - ParmVarDecl *Struct, std::pair OffsetSize) { - OffsetSizeInfo[Struct].emplace_back(OffsetSize); -} - -void SYCLIntegrationHeader::addKindInfo( - ParmVarDecl *Struct, SYCLIntegrationHeader::kernel_param_kind_t Kind) { - KindInfo[Struct].emplace_back(Kind); +void SYCLIntegrationHeader::setParentStruct(ParmVarDecl *parent) { + ParentStruct = parent; } void SYCLIntegrationHeader::endKernel() { diff --git a/sycl/include/sycl/detail/kernel_desc.hpp b/sycl/include/sycl/detail/kernel_desc.hpp index 39b38648972cd..1439222cf0633 100644 --- a/sycl/include/sycl/detail/kernel_desc.hpp +++ b/sycl/include/sycl/detail/kernel_desc.hpp @@ -61,7 +61,7 @@ enum class kernel_param_kind_t { kind_work_group_memory = 6, kind_dynamic_work_group_memory = 7, kind_dynamic_accessor = 8, - kind_struct_with_special_type = 9, + kind_struct_with_special_type = 9, // structs that contain special types kind_invalid = 0xf, // not a valid kernel kind }; From bb45df4b7a365ecd926507745ffd1ea9c3c105c2 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 30 Sep 2025 14:04:49 -0700 Subject: [PATCH 47/69] Add comments --- clang/include/clang/Sema/SemaSYCL.h | 2 +- clang/lib/Sema/SemaSYCL.cpp | 10 +++++++--- .../ext/oneapi/experimental/free_function_traits.hpp | 11 +++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index ee45663ab8795..d5687d5f5adfa 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -65,7 +65,7 @@ class SYCLIntegrationHeader { kind_work_group_memory, kind_dynamic_work_group_memory, kind_dynamic_accessor, - kind_struct_with_special_type, + kind_struct_with_special_type, // structs that contain special types kind_last = kind_struct_with_special_type }; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 599da7418f796..e75fd5a9ec54d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4523,8 +4523,11 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { - // Being inside this function means there is a struct parameter to the free - // function kernel that contains a special type. + // FD represents a special type which is a field of a struct parameter + // passed to a free function kernel Get this struct parameter using + // getParentStruct and build the __init call. Also add the struct to the + // list of special structs needed later by the integration header to + // generate some helper structs for the runtime. Expr *Base = createParamReferenceExpr(DeclCreator.getParentStruct()); for (const auto &child : CurrentStructs) { Base = buildMemberExpr(Base, child); @@ -4532,7 +4535,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { MemberExpr *MemberAccess = buildMemberExpr(Base, FD); createSpecialMethodCall(FieldTy->getAsCXXRecordDecl(), InitMethodName, MemberAccess, BodyStmts); - SemaSYCLRef.addStructWithSpecialType(DeclCreator.getParentStruct()->getType()->getAsCXXRecordDecl()); + SemaSYCLRef.addStructWithSpecialType( + DeclCreator.getParentStruct()->getType()->getAsCXXRecordDecl()); return true; } diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 3a95e7b8bcf16..94a34ebf391f4 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -47,10 +47,13 @@ template inline constexpr bool is_kernel_v = is_kernel::value; namespace detail { -// A struct with special type is a struct type that contains special types. -// The frontend defines this trait to be true after analyzing the struct at -// compile time and contains information about Offset, Size and kind(accessor, -// etc...) inside the struct +// A struct with special type is a struct type that contains special types +// passed as a paremeter to a free function kernel. It is decomposed into its +// consituents by the frontend which puts the relevant informaton about each of +// them into the struct below, namely offset, size and parameter kind for each +// one of them. The runtime then calls the addArg function to add each one of +// them as kernel arguments. The value bool is used to distinguish these structs +// from ordinary e.g standard layout structs. template struct is_struct_with_special_type { static constexpr bool value = false; static constexpr int offsets[] = {-1}; From a81350cc50482aa34f78c8094870be35ab3d5663 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 30 Sep 2025 14:10:24 -0700 Subject: [PATCH 48/69] Add comments --- clang/lib/Sema/SemaSYCL.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index e75fd5a9ec54d..76c4a0fd11fa6 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7183,11 +7183,14 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { FwdDeclEmitter.Visit(type.getDesugaredType(S.getASTContext())); - // this is a struct that contains a special type so its neither a - // special type nor a trivially copyable type. We therefore need to - // explicitly communicate to the runtime that this argument should be - // allowed as a free function kernel argument. We do this by defining - // is_struct_with_special_type to be true. + // this is a struct that contains a special type so its neither a + // special type nor a trivially copyable type. We therefore need to + // explicitly communicate to the runtime that this argument should be + // allowed as a free function kernel argument. We do this by defining + // is_struct_with_special_type to be true. This helper struct also + // contains information about the offset, size and parameter + // kind of every field inside the struct at any nesting level + // This facilitates setting the arguments in the runtime. O << "template <>\n"; O << "struct " "sycl::ext::oneapi::experimental::detail::is_struct_with_special_" From 417533d1754ca7670d82af18dabf587197c4d722 Mon Sep 17 00:00:00 2001 From: Nick Sarnie Date: Thu, 2 Oct 2025 03:11:01 +0900 Subject: [PATCH 49/69] [SYCL][ESIMD][E2E] Reenable previously failing tests (#20256) Ran CI 3 times and no fails, so should be fine. Signed-off-by: Sarnie, Nick --- sycl/test-e2e/ESIMD/Prefix_Local_sum2.cpp | 2 -- sycl/test-e2e/ESIMD/matrix_transpose_glb.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/sycl/test-e2e/ESIMD/Prefix_Local_sum2.cpp b/sycl/test-e2e/ESIMD/Prefix_Local_sum2.cpp index 2e15cb5145223..8deb391902501 100644 --- a/sycl/test-e2e/ESIMD/Prefix_Local_sum2.cpp +++ b/sycl/test-e2e/ESIMD/Prefix_Local_sum2.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // RUN: %{build} -o %t.out // RUN: %{run} %t.out 20 -// UNSUPPORTED: gpu-intel-dg2 -// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/17075 #include "esimd_test_utils.hpp" diff --git a/sycl/test-e2e/ESIMD/matrix_transpose_glb.cpp b/sycl/test-e2e/ESIMD/matrix_transpose_glb.cpp index c3a97f3118db2..06848fcea6819 100644 --- a/sycl/test-e2e/ESIMD/matrix_transpose_glb.cpp +++ b/sycl/test-e2e/ESIMD/matrix_transpose_glb.cpp @@ -5,8 +5,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// UNSUPPORTED: gpu -// UNSUPPORTED-TRACKER: https://github.com/intel/llvm/issues/17176 // RUN: %{build} -o %t.out // RUN: %{run} %t.out From c4be04eb25fe8e4a1e5149c9c2b513e99ec6677a Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 12:27:22 -0700 Subject: [PATCH 50/69] Handle set_arg for accessors --- clang/lib/Sema/SemaSYCL.cpp | 4 ++-- sycl/include/sycl/handler.hpp | 44 +++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 76c4a0fd11fa6..a7d2b36e7949a 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4771,8 +4771,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { void addParam(const ParmVarDecl *PD, QualType ParamTy, SYCLIntegrationHeader::kernel_param_kind_t Kind) { addParam(ParamTy, Kind, offsetOf(PD, ParamTy)); - CurOffset += - SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); + //CurOffset += + // SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); } void addParam(QualType ParamTy, diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 2ad1243a24409..e9db11b8bd0cf 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1649,6 +1649,8 @@ class __SYCL_EXPORT handler { remove_cv_ref_t>::value; // Structs that contain special types }; + constexpr static int AccessTargetMask = 0x7ff; + /// Sets argument for OpenCL interoperability kernels. /// /// Registers Arg passed as argument # ArgIndex. @@ -1659,18 +1661,47 @@ class __SYCL_EXPORT handler { typename std::enable_if_t::value, void> set_arg(int ArgIndex, T &&Arg) { setArgHelper(ArgIndex, std::move(Arg)); + ++ArgIndex; + // The following concerns free function kernels only. + // if we are dealing with a struct parameter that contains special types + // inside, we call addArg for each field of the struct(special and standard + // layout included) at any nesting level using the information provided by + // the frontend with the arrays offsets, sizes, and kinds which as the name + // suggests, provide the offset, size and kind of each such field. if constexpr (ext::oneapi::experimental::detail:: is_struct_with_special_type>::value) { - int NumArgs = 0; using type = ext::oneapi::experimental::detail::is_struct_with_special_type< remove_cv_ref_t>; - int index = 0; - while (type::offsets[index] != -1) { + int NumArgs = 0; + while (type::offsets[NumArgs] != -1) { + void *FieldArg = (char *)(&Arg) + type::offsets[NumArgs]; + // treat accessors separately since we have to fetch the data ptr and + // pass that to the addArg function rather than the address of the + // accessor object itself. + if (type::kinds[NumArgs] == + detail::kernel_param_kind_t::kind_accessor) { + const access::target target = static_cast( + type::sizes[NumArgs] & AccessTargetMask); + if (target == target::local) { + detail::LocalAccessorBaseHost *LocalAccBase = + (detail::LocalAccessorBaseHost *)(FieldArg); + setLocalAccessorArgHelper(ArgIndex + NumArgs, *LocalAccBase); + } else { + detail::AccessorBaseHost *AccBase = + (detail::AccessorBaseHost *)(FieldArg); + const detail::AccessorImplPtr &AccImpl = + detail::getSyclObjImpl(*AccBase); + detail::AccessorImplHost *Req = AccImpl.get(); + addArg(type::kinds[NumArgs], Req, type::sizes[NumArgs], + ArgIndex + NumArgs); + } + } else { + // for non-accessors, simply call addArg normally. + addArg(type::kinds[NumArgs], FieldArg, type::sizes[NumArgs], + ArgIndex + NumArgs); + } ++NumArgs; - addArg(type::kinds[index], (char *)(&Arg) + type::offsets[index], - type::sizes[index], ArgIndex + NumArgs); - ++index; } updateArgShift(NumArgs); } @@ -3533,7 +3564,6 @@ class __SYCL_EXPORT handler { // during device compilations (by reducing amount of templates we have to // instantiate), those are only available during host compilation pass. #ifndef __SYCL_DEVICE_ONLY__ - constexpr static int AccessTargetMask = 0x7ff; /// According to section 4.7.6.11. of the SYCL specification, a local accessor /// must not be used in a SYCL kernel function that is invoked via single_task /// or via the simple form of parallel_for that takes a range parameter. From 644b0e961b5e6117ff1b55d2451eeb4a405259c3 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 13:01:34 -0700 Subject: [PATCH 51/69] Formatting --- clang/lib/Sema/SemaSYCL.cpp | 248 +++++++++--------- sycl/include/sycl/detail/kernel_desc.hpp | 2 +- .../experimental/free_function_traits.hpp | 2 +- sycl/include/sycl/handler.hpp | 4 +- sycl/source/detail/handler_impl.hpp | 2 +- sycl/source/detail/kernel_data.hpp | 10 + sycl/source/handler.cpp | 6 +- 7 files changed, 142 insertions(+), 132 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index dc68933125424..2f227531ee8fe 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4708,9 +4708,8 @@ class FreeFunctionKernelBodyCreator : public SyclKernelFieldHandler { bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { ArgExprs.push_back(SemaSYCLRef.SemaRef.BuildDeclRefExpr( - DeclCreator.getParentStruct(), - DeclCreator.getParentStruct()->getType(), VK_PRValue, - FreeFunctionSrcLoc)); + DeclCreator.getParentStruct(), DeclCreator.getParentStruct()->getType(), + VK_PRValue, FreeFunctionSrcLoc)); return true; } @@ -4803,8 +4802,8 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { void addParam(const ParmVarDecl *PD, QualType ParamTy, SYCLIntegrationHeader::kernel_param_kind_t Kind) { addParam(ParamTy, Kind, offsetOf(PD, ParamTy)); - //CurOffset += - // SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); + // CurOffset += + // SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); } void addParam(QualType ParamTy, @@ -4965,149 +4964,148 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { return true; } - bool handlePointerType(FieldDecl * FD, QualType FieldTy) final { - addParam(FD, FieldTy, - ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout - : SYCLIntegrationHeader::kind_pointer)); - return true; - } + bool handlePointerType(FieldDecl *FD, QualType FieldTy) final { + addParam(FD, FieldTy, + ((StructDepth) ? SYCLIntegrationHeader::kind_std_layout + : SYCLIntegrationHeader::kind_pointer)); + return true; + } - bool handlePointerType(ParmVarDecl * PD, QualType ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_pointer); - return true; - } + bool handlePointerType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_pointer); + return true; + } - bool handleScalarType(FieldDecl * FD, QualType FieldTy) final { - addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } + bool handleScalarType(FieldDecl *FD, QualType FieldTy) final { + addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } - bool handleScalarType(ParmVarDecl * PD, QualType ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } + bool handleScalarType(ParmVarDecl *PD, QualType ParamTy) final { + addParam(PD, ParamTy, 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 struct. - addParam(FD, 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 struct. + addParam(FD, FieldTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } - bool handleTopLevelStruct(const CXXRecordDecl *, QualType Ty) final { - addParam(Ty, SYCLIntegrationHeader::kind_std_layout, /*Offset=*/0); - return true; - } + bool handleTopLevelStruct(const CXXRecordDecl *, QualType Ty) final { + addParam(Ty, SYCLIntegrationHeader::kind_std_layout, /*Offset=*/0); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *, FieldDecl *FD, - QualType Ty) final { - addParam(FD, Ty, 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 ParamTy) final { - addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *, ParmVarDecl *PD, + QualType ParamTy) final { + addParam(PD, ParamTy, SYCLIntegrationHeader::kind_std_layout); + return true; + } - bool handleNonDecompStruct(const CXXRecordDecl *Base, - const CXXBaseSpecifier &, QualType Ty) final { - addParam(Ty, SYCLIntegrationHeader::kind_std_layout, - offsetOf(Base, Ty->getAsCXXRecordDecl())); - return true; - } + bool handleNonDecompStruct(const CXXRecordDecl *Base, + const CXXBaseSpecifier &, QualType Ty) final { + addParam(Ty, SYCLIntegrationHeader::kind_std_layout, + offsetOf(Base, Ty->getAsCXXRecordDecl())); + return true; + } - bool handleUnionType(FieldDecl * FD, QualType FieldTy) final { - return handleScalarType(FD, FieldTy); - } + bool handleUnionType(FieldDecl *FD, QualType FieldTy) final { + return handleScalarType(FD, FieldTy); + } - bool handleUnionType(ParmVarDecl *, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool handleUnionType(ParmVarDecl *, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - void handleSyclKernelHandlerType(QualType) { - // The compiler generated kernel argument used to initialize SYCL 2020 - // specialization constants, `specialization_constants_buffer`, should - // have corresponding entry in integration header. - ASTContext &Context = SemaSYCLRef.getASTContext(); - // Offset is zero since kernel_handler argument is not part of - // kernel object (i.e. it is not captured) - addParam(Context.getPointerType(Context.CharTy), - SYCLIntegrationHeader::kind_specialization_constants_buffer, 0); - } + void handleSyclKernelHandlerType(QualType) { + // The compiler generated kernel argument used to initialize SYCL 2020 + // specialization constants, `specialization_constants_buffer`, should + // have corresponding entry in integration header. + ASTContext &Context = SemaSYCLRef.getASTContext(); + // Offset is zero since kernel_handler argument is not part of + // kernel object (i.e. it is not captured) + addParam(Context.getPointerType(Context.CharTy), + SYCLIntegrationHeader::kind_specialization_constants_buffer, 0); + } - bool enterStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - ++StructDepth; - CurOffset += offsetOf(FD, Ty); - return true; - } + bool enterStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + ++StructDepth; + CurOffset += offsetOf(FD, Ty); + return true; + } - bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, - QualType Ty) final { - addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); - Header.setParentStruct(PD); - return true; - } + bool enterStruct(const CXXRecordDecl *, ParmVarDecl *PD, QualType Ty) final { + addParam(PD, Ty, SYCLIntegrationHeader::kind_struct_with_special_type); + Header.setParentStruct(PD); + return true; + } - bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { - --StructDepth; - CurOffset -= offsetOf(FD, Ty); - return true; - } + bool leaveStruct(const CXXRecordDecl *, FieldDecl *FD, QualType Ty) final { + --StructDepth; + CurOffset -= offsetOf(FD, Ty); + return true; + } - bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - Header.setParentStruct(nullptr); - return true; - } + bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + Header.setParentStruct(nullptr); + return true; + } - bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, - QualType) final { - CurOffset += offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); - return true; - } + bool enterStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, + QualType) final { + CurOffset += offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); + return true; + } - bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, - QualType) final { - CurOffset -= offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); - return true; - } + bool leaveStruct(const CXXRecordDecl *RD, const CXXBaseSpecifier &BS, + QualType) final { + CurOffset -= offsetOf(RD, BS.getType()->getAsCXXRecordDecl()); + return true; + } - bool enterArray(FieldDecl * FD, QualType ArrayTy, QualType) final { - ArrayBaseOffsets.push_back(CurOffset + offsetOf(FD, ArrayTy)); - return true; - } + bool enterArray(FieldDecl *FD, QualType ArrayTy, QualType) final { + ArrayBaseOffsets.push_back(CurOffset + offsetOf(FD, ArrayTy)); + return true; + } - bool enterArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool enterArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - bool nextElement(QualType ET, uint64_t Index) final { - int64_t Size = - SemaSYCLRef.getASTContext().getTypeSizeInChars(ET).getQuantity(); - CurOffset = ArrayBaseOffsets.back() + Size * Index; - return true; - } + bool nextElement(QualType ET, uint64_t Index) final { + int64_t Size = + SemaSYCLRef.getASTContext().getTypeSizeInChars(ET).getQuantity(); + CurOffset = ArrayBaseOffsets.back() + Size * Index; + return true; + } - bool leaveArray(FieldDecl * FD, QualType ArrayTy, QualType) final { - CurOffset = ArrayBaseOffsets.pop_back_val(); - CurOffset -= offsetOf(FD, ArrayTy); - return true; - } + bool leaveArray(FieldDecl *FD, QualType ArrayTy, QualType) final { + CurOffset = ArrayBaseOffsets.pop_back_val(); + CurOffset -= offsetOf(FD, ArrayTy); + return true; + } - bool leaveArray(ParmVarDecl *, QualType, QualType) final { - // TODO - unsupportedFreeFunctionParamType(); - return true; - } + bool leaveArray(ParmVarDecl *, QualType, QualType) final { + // TODO + unsupportedFreeFunctionParamType(); + return true; + } - using SyclKernelFieldHandler::enterStruct; - using SyclKernelFieldHandler::leaveStruct; - }; + using SyclKernelFieldHandler::enterStruct; + using SyclKernelFieldHandler::leaveStruct; +}; class SyclKernelIntFooterCreator : public SyclKernelFieldHandler { SYCLIntegrationFooter &Footer; diff --git a/sycl/include/sycl/detail/kernel_desc.hpp b/sycl/include/sycl/detail/kernel_desc.hpp index 082d4346d7e2a..e3134accc29f2 100644 --- a/sycl/include/sycl/detail/kernel_desc.hpp +++ b/sycl/include/sycl/detail/kernel_desc.hpp @@ -62,7 +62,7 @@ enum class kernel_param_kind_t { kind_dynamic_work_group_memory = 7, kind_dynamic_accessor = 8, kind_struct_with_special_type = 9, // structs that contain special types - kind_invalid = 0xf, // not a valid kernel kind + kind_invalid = 0xf, // not a valid kernel kind }; // describes a kernel parameter diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index 94a34ebf391f4..bdbd298750b67 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #pragma once -#include #include +#include namespace sycl { inline namespace _V1 { diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 8c33a46e32560..3e209f1f256b4 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -3660,14 +3660,14 @@ class __SYCL_EXPORT handler { void addArg(detail::kernel_param_kind_t ArgKind, void *Req, int AccessTarget, int ArgIndex); - + #ifndef __INTEL_PREVIEW_BREAKING_CHANGES // TODO: remove in the next ABI-breaking window void clearArgs(); #endif void incrementArgShift(int); - + void setArgsToAssociatedAccessors(); bool HasAssociatedAccessor(detail::AccessorImplHost *Req, diff --git a/sycl/source/detail/handler_impl.hpp b/sycl/source/detail/handler_impl.hpp index 357c0895af1ac..b94fd2996e548 100644 --- a/sycl/source/detail/handler_impl.hpp +++ b/sycl/source/detail/handler_impl.hpp @@ -141,7 +141,7 @@ class handler_impl { /// The list of arguments for the kernel. std::vector MArgs; - + /// The list of associated accessors with this handler. /// These accessors were created with this handler as argument or /// have become required for this handler via require method. diff --git a/sycl/source/detail/kernel_data.hpp b/sycl/source/detail/kernel_data.hpp index 7ba849dc33f1f..fd76cd55fa59d 100644 --- a/sycl/source/detail/kernel_data.hpp +++ b/sycl/source/detail/kernel_data.hpp @@ -181,6 +181,8 @@ class KernelData { void extractArgsAndReqsFromLambda(); + void incrementArgShift(int Shift) { MArgShift += Shift; } + private: // Storage for any SYCL Graph dynamic parameters which have been flagged for // registration in the CG, along with the argument index for the parameter. @@ -204,6 +206,14 @@ class KernelData { // A pointer to device kernel information. Cached on the application side in // headers or retrieved from program manager. DeviceKernelInfo *MDeviceKernelInfoPtr = nullptr; + + // Certain arguments such as structs that contain SYCL special types entail + // several hidden set_arg calls for every set_arg called by the user. This + // shift is required to make sure the following arguments set by the user have + // the correct index. It keeps track of how many of these hidden set_arg calls + // have been made so far. The user cannot possibly know this, hence we need to + // keep track of this information. + int MArgShift = 0; }; } // namespace detail diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index f6e6c0ff1d2a7..15fc75dae71a7 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -2248,8 +2248,10 @@ void handler::addArg(detail::kernel_param_kind_t ArgKind, void *Req, impl->MKernelData.addArg(ArgKind, Req, AccessTarget, ArgIndex); } -void handler::incrementArgShift(int Shift) { impl->MKernelData.incrementArgShift(Shift); } - +void handler::incrementArgShift(int Shift) { + impl->MKernelData.incrementArgShift(Shift); +} + #ifndef __INTEL_PREVIEW_BREAKING_CHANGES void handler::clearArgs() { impl->MKernelData.clearArgs(); } #endif From 22eec279832dd83fa2e17e4259c0c0317150a0d2 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 13:03:28 -0700 Subject: [PATCH 52/69] Improve commenting --- clang/include/clang/Sema/SemaSYCL.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index c1a31f453fa04..67710dd292294 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -215,9 +215,8 @@ class SYCLIntegrationHeader { ParmVarDecl *ParentStruct; // For every struct that contains a special type which is given by - // the ParentStruct field above, record the offset and size of every special - // type inside of it at any nesting level. Store the information in the - // variable below. + // the ParentStruct field above, record the offset and size of its fields + // at any nesting level. Store the information in the variable below. llvm::DenseMap>> OffsetSizeInfo; // Likewise for the kind of a special type i.e accessor etc... From def364178a9a8f8d569fbbb8b8a310ddec29fd2b Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 13:06:08 -0700 Subject: [PATCH 53/69] Improve commenting --- clang/lib/Sema/SemaSYCL.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 2f227531ee8fe..12e905e2b0340 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4797,13 +4797,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { addParam(ArgTy, Kind, offsetOf(FD, ArgTy)); } - // For free functions we increment the current offset as each parameter is - // added. void addParam(const ParmVarDecl *PD, QualType ParamTy, SYCLIntegrationHeader::kernel_param_kind_t Kind) { addParam(ParamTy, Kind, offsetOf(PD, ParamTy)); - // CurOffset += - // SemaSYCLRef.getASTContext().getTypeSizeInChars(ParamTy).getQuantity(); } void addParam(QualType ParamTy, From fcde60e20e4c2169afed9af5f03e0e1a9a5d80d5 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 15:34:12 -0700 Subject: [PATCH 54/69] Fix merge conflicts --- clang/lib/Sema/SemaSYCL.cpp | 5 ++--- sycl/include/sycl/handler.hpp | 5 ++--- sycl/source/detail/handler_impl.hpp | 2 +- sycl/source/detail/kernel_data.cpp | 8 ++++++++ sycl/source/detail/kernel_data.hpp | 9 +++++++-- sycl/source/handler.cpp | 11 ++++++----- 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 12e905e2b0340..7a822f5b55f87 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -4870,7 +4870,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool handleSyclSpecialType(FieldDecl *FD, QualType FieldTy) final { - const auto *ClassTy = FieldTy->getAsCXXRecordDecl(); assert(ClassTy && "Type must be a C++ record type"); if (isSyclAccessorType(FieldTy)) { @@ -4886,6 +4885,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::dynamic_local_accessor) ? SYCLIntegrationHeader::kind_dynamic_accessor : SYCLIntegrationHeader::kind_accessor; + Header.addParamDesc(ParamKind, Info, CurOffset + offsetOf(FD, FieldTy)); } else if (SemaSYCL::isSyclType(FieldTy, SYCLTypeAttr::stream)) { addParam(FD, FieldTy, SYCLIntegrationHeader::kind_stream); @@ -5053,7 +5053,6 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { - Header.setParentStruct(nullptr); return true; } @@ -7278,7 +7277,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { if (!Param->getType()->isStructureType()) continue; const RecordDecl *Struct = - Param->getType()->getAsStructureType()->getDecl(); + Param->getType()->getAsRecordDecl(); QualType type = Param->getType(); if (!S.getStructsWithSpecialType().count(Struct) || visitedStructWithSpecialType.count(Struct)) diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 3e209f1f256b4..c6c61c37bfeaf 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1696,7 +1696,7 @@ class __SYCL_EXPORT handler { } ++NumArgs; } - updateArgShift(NumArgs); + incrementArgShift(NumArgs); } } @@ -3666,8 +3666,6 @@ class __SYCL_EXPORT handler { void clearArgs(); #endif - void incrementArgShift(int); - void setArgsToAssociatedAccessors(); bool HasAssociatedAccessor(detail::AccessorImplHost *Req, @@ -3751,6 +3749,7 @@ class __SYCL_EXPORT handler { queue getQueue(); + void incrementArgShift(int Shift); protected: /// Registers event dependencies in this command group. void depends_on(const detail::EventImplPtr &Event); diff --git a/sycl/source/detail/handler_impl.hpp b/sycl/source/detail/handler_impl.hpp index b94fd2996e548..0a97fb4d3985f 100644 --- a/sycl/source/detail/handler_impl.hpp +++ b/sycl/source/detail/handler_impl.hpp @@ -63,7 +63,7 @@ class handler_impl { KernelNameStrRefT getKernelName() const { return MKernelData.getKernelName(); - } + } /// Registers mutually exclusive submission states. HandlerSubmissionState MSubmissionState = HandlerSubmissionState::NO_STATE; diff --git a/sycl/source/detail/kernel_data.cpp b/sycl/source/detail/kernel_data.cpp index 116321b7b3b8b..c041dceeadcf6 100644 --- a/sycl/source/detail/kernel_data.cpp +++ b/sycl/source/detail/kernel_data.cpp @@ -120,6 +120,10 @@ void KernelData::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, switch (Kind) { case kernel_param_kind_t::kind_std_layout: + case kernel_param_kind_t::kind_struct_with_special_type: { + addArg(Kind, Ptr, Size, Index + IndexShift); + break; + } case kernel_param_kind_t::kind_pointer: { addArg(Kind, Ptr, Size, Index + IndexShift); break; @@ -362,6 +366,10 @@ void KernelData::extractArgsAndReqsFromLambda() { } } +void KernelData::incrementArgShift(int Shift) { MArgShift += Shift; } + +int KernelData::getArgShift() const { return MArgShift; } + } // namespace detail } // namespace _V1 } // namespace sycl diff --git a/sycl/source/detail/kernel_data.hpp b/sycl/source/detail/kernel_data.hpp index fd76cd55fa59d..3fefc302240fd 100644 --- a/sycl/source/detail/kernel_data.hpp +++ b/sycl/source/detail/kernel_data.hpp @@ -59,7 +59,10 @@ class KernelData { MArgs.emplace_back(std::forward(args)...); } - void clearArgs() { MArgs.clear(); } + void clearArgs() { + MArgs.clear(); + MArgShift = 0; + } detail::NDRDescT &getNDRDesc() & { return MNDRDesc; } @@ -181,7 +184,9 @@ class KernelData { void extractArgsAndReqsFromLambda(); - void incrementArgShift(int Shift) { MArgShift += Shift; } + void incrementArgShift(int Shift); + + int getArgShift() const; private: // Storage for any SYCL Graph dynamic parameters which have been flagged for diff --git a/sycl/source/handler.cpp b/sycl/source/handler.cpp index 15fc75dae71a7..ed715724aeac8 100644 --- a/sycl/source/handler.cpp +++ b/sycl/source/handler.cpp @@ -2245,11 +2245,8 @@ void handler::addLifetimeSharedPtrStorage(std::shared_ptr SPtr) { void handler::addArg(detail::kernel_param_kind_t ArgKind, void *Req, int AccessTarget, int ArgIndex) { - impl->MKernelData.addArg(ArgKind, Req, AccessTarget, ArgIndex); -} - -void handler::incrementArgShift(int Shift) { - impl->MKernelData.incrementArgShift(Shift); + impl->MKernelData.addArg(ArgKind, Req, AccessTarget, + ArgIndex + impl->MKernelData.getArgShift()); } #ifndef __INTEL_PREVIEW_BREAKING_CHANGES @@ -2407,6 +2404,10 @@ void handler::setDeviceKernelInfoPtr( impl->MKernelData.setDeviceKernelInfoPtr(DeviceKernelInfoPtr); } +void handler::incrementArgShift(int Shift) { + impl->MKernelData.incrementArgShift(Shift); +} + void handler::setKernelFunc(void *KernelFuncPtr) { impl->MKernelData.setKernelFunc(KernelFuncPtr); } From e863838b31b6ffce640d75359d251c83babcf126 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 15:39:23 -0700 Subject: [PATCH 55/69] Remove dead code --- sycl/source/detail/handler_impl.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/sycl/source/detail/handler_impl.hpp b/sycl/source/detail/handler_impl.hpp index 0a97fb4d3985f..0213e259a52a7 100644 --- a/sycl/source/detail/handler_impl.hpp +++ b/sycl/source/detail/handler_impl.hpp @@ -139,9 +139,6 @@ class handler_impl { /// we exit the method they are passed in. detail::CG::StorageInitHelper CGData; - /// The list of arguments for the kernel. - std::vector MArgs; - /// The list of associated accessors with this handler. /// These accessors were created with this handler as argument or /// have become required for this handler via require method. From a248351e378169970c5c3094f898734ff2cfdf0b Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 22:39:12 -0700 Subject: [PATCH 56/69] More formatting and some bug fixing --- clang/lib/Sema/SemaSYCL.cpp | 16 ++++++++++++---- sycl/include/sycl/handler.hpp | 1 + sycl/source/detail/handler_impl.hpp | 2 +- sycl/source/detail/kernel_data.cpp | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 7a822f5b55f87..59472b259748d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5053,6 +5053,7 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { } bool leaveStruct(const CXXRecordDecl *, ParmVarDecl *, QualType) final { + Header.setParentStruct(nullptr); return true; } @@ -7276,8 +7277,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { for (ParmVarDecl *Param : K.SyclKernel->parameters()) { if (!Param->getType()->isStructureType()) continue; - const RecordDecl *Struct = - Param->getType()->getAsRecordDecl(); + const RecordDecl *Struct = Param->getType()->getAsRecordDecl(); QualType type = Param->getType(); if (!S.getStructsWithSpecialType().count(Struct) || visitedStructWithSpecialType.count(Struct)) @@ -7408,8 +7408,16 @@ void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info, PD.Kind = Kind; PD.Info = Info; PD.Offset = Offset; - OffsetSizeInfo[ParentStruct].emplace_back(std::make_pair(Offset, Info)); - KindInfo[ParentStruct].emplace_back(Kind); + // If we are adding a free function kernel parameter that is a struct that + // contains a special type, a little more work needs to be done in order to + // help the runtime set the kernel arguments properly. Add the offset, size, + // and Kind information to the integration header for each field inside this + // struct. Also, verify that we are actually adding a field and not the struct + // itself by checking the Kind. + if (ParentStruct && Kind != kernel_param_kind_t::kind_struct_with_special_type) { + OffsetSizeInfo[ParentStruct].emplace_back(std::make_pair(Offset, Info)); + KindInfo[ParentStruct].emplace_back(Kind); + } } void SYCLIntegrationHeader::setParentStruct(ParmVarDecl *parent) { diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index c6c61c37bfeaf..9046d9ee41fe5 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -3750,6 +3750,7 @@ class __SYCL_EXPORT handler { queue getQueue(); void incrementArgShift(int Shift); + protected: /// Registers event dependencies in this command group. void depends_on(const detail::EventImplPtr &Event); diff --git a/sycl/source/detail/handler_impl.hpp b/sycl/source/detail/handler_impl.hpp index 0213e259a52a7..d18dc7236790b 100644 --- a/sycl/source/detail/handler_impl.hpp +++ b/sycl/source/detail/handler_impl.hpp @@ -63,7 +63,7 @@ class handler_impl { KernelNameStrRefT getKernelName() const { return MKernelData.getKernelName(); - } + } /// Registers mutually exclusive submission states. HandlerSubmissionState MSubmissionState = HandlerSubmissionState::NO_STATE; diff --git a/sycl/source/detail/kernel_data.cpp b/sycl/source/detail/kernel_data.cpp index c041dceeadcf6..8680035733038 100644 --- a/sycl/source/detail/kernel_data.cpp +++ b/sycl/source/detail/kernel_data.cpp @@ -282,6 +282,7 @@ void KernelData::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, } } + void KernelData::extractArgsAndReqs(bool IsKernelCreatedFromSource) { std::vector UnPreparedArgs = std::move(MArgs); clearArgs(); From 9323fcc73a934ce08b9bf42a8febb95a1783d325 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Wed, 1 Oct 2025 22:44:01 -0700 Subject: [PATCH 57/69] More formatting --- clang/lib/Sema/SemaSYCL.cpp | 3 ++- sycl/source/detail/kernel_data.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 59472b259748d..88347116a7b0f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7414,7 +7414,8 @@ void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info, // and Kind information to the integration header for each field inside this // struct. Also, verify that we are actually adding a field and not the struct // itself by checking the Kind. - if (ParentStruct && Kind != kernel_param_kind_t::kind_struct_with_special_type) { + if (ParentStruct && + Kind != kernel_param_kind_t::kind_struct_with_special_type) { OffsetSizeInfo[ParentStruct].emplace_back(std::make_pair(Offset, Info)); KindInfo[ParentStruct].emplace_back(Kind); } diff --git a/sycl/source/detail/kernel_data.cpp b/sycl/source/detail/kernel_data.cpp index 8680035733038..c041dceeadcf6 100644 --- a/sycl/source/detail/kernel_data.cpp +++ b/sycl/source/detail/kernel_data.cpp @@ -282,7 +282,6 @@ void KernelData::processArg(void *Ptr, const detail::kernel_param_kind_t &Kind, } } - void KernelData::extractArgsAndReqs(bool IsKernelCreatedFromSource) { std::vector UnPreparedArgs = std::move(MArgs); clearArgs(); From 0d29f6d4d4cc7116bb7c10203d5765f115f880cb Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 2 Oct 2025 02:26:59 -0400 Subject: [PATCH 58/69] Update SemaSYCL.h --- clang/include/clang/Sema/SemaSYCL.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 67710dd292294..63914b98f30da 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -219,7 +219,7 @@ class SYCLIntegrationHeader { // at any nesting level. Store the information in the variable below. llvm::DenseMap>> OffsetSizeInfo; - // Likewise for the kind of a special type i.e accessor etc... + // Likewise for the kind of a field i.e accessor, std_layout etc... llvm::DenseMap> KindInfo; From 9a50c64aa7f0a025e6c6ca9234873e85b9c468df Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Thu, 2 Oct 2025 07:09:05 -0700 Subject: [PATCH 59/69] Fix uninitialized pointer --- clang/include/clang/Sema/SemaSYCL.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 67710dd292294..13b54c769a147 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -212,7 +212,7 @@ class SYCLIntegrationHeader { // For free function kernels, keeps track of the parameter that is currently // being analyzed if it is a struct that contains special types. - ParmVarDecl *ParentStruct; + ParmVarDecl * ParentStruct = nullptr; // For every struct that contains a special type which is given by // the ParentStruct field above, record the offset and size of its fields From 1f05d3982a16285c9fb9ae0c4c0767f3db7aaf83 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 3 Oct 2025 13:47:00 -0700 Subject: [PATCH 60/69] Address pre-commit failures --- clang/include/clang/Sema/SemaSYCL.h | 2 +- clang/lib/Sema/SemaSYCL.cpp | 10 +++++----- sycl/test/abi/sycl_symbols_linux.dump | 2 +- sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump | 1 - sycl/test/abi/sycl_symbols_windows.dump | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h index 6044b401ed997..5cbc96a33d173 100644 --- a/clang/include/clang/Sema/SemaSYCL.h +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -212,7 +212,7 @@ class SYCLIntegrationHeader { // For free function kernels, keeps track of the parameter that is currently // being analyzed if it is a struct that contains special types. - ParmVarDecl * ParentStruct = nullptr; + ParmVarDecl *ParentStruct = nullptr; // For every struct that contains a special type which is given by // the ParentStruct field above, record the offset and size of its fields diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 88347116a7b0f..5d4e67447b81f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7301,21 +7301,21 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { type.print(O, Policy); O << "> {\n"; O << " inline static constexpr bool value = true;\n"; - O << " static constexpr int offsets[] = {\n"; + O << " static constexpr int offsets[] = { "; for (const auto OffsetSize : OffsetSizeInfo[Param]) { O << OffsetSize.first << ", "; } - O << "-1};\n\n "; + O << "-1};\n "; - O << " static constexpr int sizes[] = {\n"; + O << " static constexpr int sizes[] = { "; for (const auto OffsetSize : OffsetSizeInfo[Param]) { O << OffsetSize.second << ", "; } - O << "-1}; \n\n "; + O << "-1}; \n "; O << " static constexpr sycl::detail::kernel_param_kind_t kinds[] = {\n "; for (const auto Kind : KindInfo[Param]) { - O << "sycl::detail::kernel_param_kind_t::" << paramKind2Str(Kind); + O << " sycl::detail::kernel_param_kind_t::" << paramKind2Str(Kind); O << ",\n "; } O << "sycl::detail::kernel_param_kind_t::kind_invalid }; \n};\n\n "; diff --git a/sycl/test/abi/sycl_symbols_linux.dump b/sycl/test/abi/sycl_symbols_linux.dump index 7e54f5b4a2f7b..b570960838a36 100644 --- a/sycl/test/abi/sycl_symbols_linux.dump +++ b/sycl/test/abi/sycl_symbols_linux.dump @@ -3647,7 +3647,7 @@ _ZN4sycl3_V17handler8getQueueEv _ZN4sycl3_V17handler8prefetchEPKvm _ZN4sycl3_V17handler8prefetchEPKvmNS0_3ext6oneapi12experimental13prefetch_typeE _ZN4sycl3_V17handler9clearArgsEv -_ZN4sycl3_V17handler14updateArgShiftEi +_ZN4sycl3_V17handler17incrementArgShiftEi _ZN4sycl3_V17handler9fill_implEPvPKvmm _ZN4sycl3_V17handlerC1EOSt10unique_ptrINS0_6detail12handler_implESt14default_deleteIS4_EE _ZN4sycl3_V17handlerC1ESt10shared_ptrINS0_3ext6oneapi12experimental6detail10graph_implEE diff --git a/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump b/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump index 7dce72aee3f18..359506cc8c3db 100644 --- a/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump +++ b/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump @@ -707,7 +707,6 @@ ??_Dexception@_V1@sycl@@QEAAXXZ ??_Fcontext@_V1@sycl@@QEAAXXZ ??_Fqueue@_V1@sycl@@QEAAXXZ -?AccessTargetMask@handler@_V1@sycl@@0HB ?Clear@exception_list@_V1@sycl@@AEAAXXZ ?DirSep@OSUtil@detail@_V1@sycl@@2QEBDEB ?DisableRangeRounding@handler@_V1@sycl@@AEAA_NXZ diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index ae44a73328234..21484d284e648 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -715,7 +715,6 @@ ??_Dexception@_V1@sycl@@QEAAXXZ ??_Fcontext@_V1@sycl@@QEAAXXZ ??_Fqueue@_V1@sycl@@QEAAXXZ -?AccessTargetMask@handler@_V1@sycl@@0HB ?Clear@exception_list@_V1@sycl@@AEAAXXZ ?DirSep@OSUtil@detail@_V1@sycl@@2QEBDEB ?DisableRangeRounding@handler@_V1@sycl@@AEAA_NXZ @@ -3837,7 +3836,8 @@ ?category@exception@_V1@sycl@@QEBAAEBVerror_category@std@@XZ ?checkNodePropertiesAndThrow@modifiable_command_graph@detail@experimental@oneapi@ext@_V1@sycl@@KAXAEBVproperty_list@67@@Z ?clearArgs@handler@_V1@sycl@@AEAAXXZ -?updateArgShift@handler@_V1@sycl@@AEAAXH@Z +?AccessTargetMask@handler@_V1@sycl@@2HB +?incrementArgShift@handler@_V1@sycl@@AEAAXH@Z ?code@exception@_V1@sycl@@QEBAAEBVerror_code@std@@XZ ?compile_from_source@detail@experimental@oneapi@ext@_V1@sycl@@YA?AV?$kernel_bundle@$00@56@AEAV?$kernel_bundle@$02@56@AEBV?$vector@Vdevice@_V1@sycl@@V?$allocator@Vdevice@_V1@sycl@@@std@@@std@@AEBV?$vector@Vstring_view@detail@_V1@sycl@@V?$allocator@Vstring_view@detail@_V1@sycl@@@std@@@std@@PEAVstring@156@2@Z ?compile_impl@detail@_V1@sycl@@YA?AV?$shared_ptr@Vkernel_bundle_impl@detail@_V1@sycl@@@std@@AEBV?$kernel_bundle@$0A@@23@AEBV?$vector@Vdevice@_V1@sycl@@V?$allocator@Vdevice@_V1@sycl@@@std@@@5@AEBVproperty_list@23@@Z From 35f87a77200e344010ff757f08d4d29348c83951 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Fri, 3 Oct 2025 14:38:46 -0700 Subject: [PATCH 61/69] Fix pre-commit failures --- .../CodeGenSYCL/free_function_int_header.cpp | 138 +++++++----------- 1 file changed, 56 insertions(+), 82 deletions(-) diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index f7693cb9af894..a9020631f4506 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -358,39 +358,39 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: const kernel_param_desc_t kernel_signatures[] = { // 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-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, // 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-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, // 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-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, // 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-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, // 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 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 0 }, // CHECK: //--- _Z18__sycl_kernel_ff_410NoPointers8Pointers3Agg // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 16, 4 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 32, 20 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 16, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 32, 0 }, // CHECK: //--- _Z18__sycl_kernel_ff_6I3Agg7DerivedEvT_T0_i // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 32, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 40, 32 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 72 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 40, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, // CHECK: //--- _Z18__sycl_kernel_ff_7ILi3EEv16KArgWithPtrArrayIXT_EE // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 48, 0 }, @@ -401,27 +401,27 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: //--- _ZN28__sycl_kernel_free_functions4ff_9EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5tests5ff_10EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5tests2V15ff_11EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN26__sycl_kernel__GLOBAL__N_15ff_12EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5ff_13EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5tests5ff_13EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _Z18__sycl_kernel_ff_9N4sycl3_V125dynamic_work_group_memoryIiEE // CHECK-NEXT: { kernel_param_kind_t::kind_dynamic_work_group_memory, 8, 0 }, @@ -446,23 +446,23 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: //--- _ZN28__sycl_kernel_free_functions5tests5ff_14EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5ff_15EiPi // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5ff_16E3AggPS0_ // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 32, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 32 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5ff_17E7DerivedPS0_ // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 40, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 40 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _ZN28__sycl_kernel_free_functions5tests5ff_18ENS_3AggEPS1_ // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 8, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 8 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_pointer, 8, 0 }, // CHECK: //--- _Z19__sycl_kernel_ff_19N14free_functions16KArgWithPtrArrayILi50EEE // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 800, 0 }, @@ -475,24 +475,24 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: //--- _Z19__sycl_kernel_ff_2524AccessorAndLocalAccessor // CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 36, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 36 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 48 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 12 }, // CHECK: //--- _Z19__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor // CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 36, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 36 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 48 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 36 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 52 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 64 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 12 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, // CHECK: //--- _Z19__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt // CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 0 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 16 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 20 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 16 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 32 }, -// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 44 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 4 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 16, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, // CHECK: //--- _Z19__sycl_kernel_ff_23i // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, @@ -1595,17 +1595,12 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { // CHECK-NEXT: inline static constexpr bool value = true; -// CHECK-NEXT: }; - -// CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template -// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::local_accessor *)((char *)(&arg) + 12)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: NumArgs = 2; -// CHECK-NEXT: } +// CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; +// CHECK-NEXT: static constexpr int sizes[] = { 4062, 4064, -1}; +// CHECK-NEXT: static constexpr sycl::detail::kernel_param_kind_t kinds[] = { +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_invalid }; // CHECK-NEXT: }; // CHECK: static constexpr auto __sycl_shim33() { @@ -1626,17 +1621,12 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { // CHECK-NEXT: inline static constexpr bool value = true; -// CHECK-NEXT: }; - -// CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template -// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 12)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: NumArgs = 2; -// CHECK-NEXT: } +// CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; +// CHECK-NEXT: static constexpr int sizes[] = { 4062, 4, -1}; +// CHECK-NEXT: static constexpr sycl::detail::kernel_param_kind_t kinds[] = { +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_std_layout, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_invalid }; // CHECK-NEXT: }; // CHECK: static constexpr auto __sycl_shim34() { @@ -1657,17 +1647,12 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { // CHECK-NEXT: inline static constexpr bool value = true; -// CHECK-NEXT: }; - -// CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template -// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 0)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 4)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: NumArgs = 2; -// CHECK-NEXT: } +// CHECK-NEXT: static constexpr int offsets[] = { 0, 4, -1}; +// CHECK-NEXT: static constexpr int sizes[] = { 4, 4062, -1}; +// CHECK-NEXT: static constexpr sycl::detail::kernel_param_kind_t kinds[] = { +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_std_layout, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_invalid }; // CHECK-NEXT: }; // CHECK: template <> @@ -1675,17 +1660,6 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: inline static constexpr bool value = true; // CHECK-NEXT: }; -// CHECK: template <> struct struct_with_special_type_info { -// CHECK-NEXT: template -// CHECK-NEXT: static void set_arg(int ArgIndex, ArgT& arg, HandlerT& cgh, int &NumArgs) { -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(sycl::accessor > *)((char *)(&arg) + 0)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: cgh.set_arg(ArgIndex, *(int *)((char *)(&arg) + 12)); -// CHECK-NEXT: ++ArgIndex; -// CHECK-NEXT: NumArgs = 2; -// CHECK-NEXT: } -// CHECK-NEXT: }; - // CHECK: static constexpr auto __sycl_shim35() { // CHECK-NEXT: return (void (*)(struct IntAndAccessor, struct AccessorAndInt))ff_27; // CHECK-NEXT: } From 2f80b121cafee3b1bf32aa2aefb6e7cefa95c9d1 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Mon, 6 Oct 2025 07:56:52 -0700 Subject: [PATCH 62/69] Revert some ABI breaking changes --- sycl/include/sycl/handler.hpp | 6 +++--- sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump | 1 + sycl/test/abi/sycl_symbols_windows.dump | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index 9046d9ee41fe5..ade583b476fa0 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1641,9 +1641,7 @@ class __SYCL_EXPORT handler { || ext::oneapi::experimental::detail::is_struct_with_special_type< remove_cv_ref_t>::value; // Structs that contain special types }; - - constexpr static int AccessTargetMask = 0x7ff; - + /// Sets argument for OpenCL interoperability kernels. /// /// Registers Arg passed as argument # ArgIndex. @@ -1674,6 +1672,7 @@ class __SYCL_EXPORT handler { // accessor object itself. if (type::kinds[NumArgs] == detail::kernel_param_kind_t::kind_accessor) { + constexpr int AccessTargetMask = 0x7ff; const access::target target = static_cast( type::sizes[NumArgs] & AccessTargetMask); if (target == target::local) { @@ -3571,6 +3570,7 @@ class __SYCL_EXPORT handler { // during device compilations (by reducing amount of templates we have to // instantiate), those are only available during host compilation pass. #ifndef __SYCL_DEVICE_ONLY__ + constexpr static int AccessTargetMask = 0x7ff; /// According to section 4.7.6.11. of the SYCL specification, a local accessor /// must not be used in a SYCL kernel function that is invoked via single_task /// or via the simple form of parallel_for that takes a range parameter. diff --git a/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump b/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump index 359506cc8c3db..7dce72aee3f18 100644 --- a/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump +++ b/sycl/test/abi/sycl_symbols_windows-sycl-rel-6_3.dump @@ -707,6 +707,7 @@ ??_Dexception@_V1@sycl@@QEAAXXZ ??_Fcontext@_V1@sycl@@QEAAXXZ ??_Fqueue@_V1@sycl@@QEAAXXZ +?AccessTargetMask@handler@_V1@sycl@@0HB ?Clear@exception_list@_V1@sycl@@AEAAXXZ ?DirSep@OSUtil@detail@_V1@sycl@@2QEBDEB ?DisableRangeRounding@handler@_V1@sycl@@AEAA_NXZ diff --git a/sycl/test/abi/sycl_symbols_windows.dump b/sycl/test/abi/sycl_symbols_windows.dump index 21484d284e648..61b2e18ecf814 100644 --- a/sycl/test/abi/sycl_symbols_windows.dump +++ b/sycl/test/abi/sycl_symbols_windows.dump @@ -715,6 +715,7 @@ ??_Dexception@_V1@sycl@@QEAAXXZ ??_Fcontext@_V1@sycl@@QEAAXXZ ??_Fqueue@_V1@sycl@@QEAAXXZ +?AccessTargetMask@handler@_V1@sycl@@0HB ?Clear@exception_list@_V1@sycl@@AEAAXXZ ?DirSep@OSUtil@detail@_V1@sycl@@2QEBDEB ?DisableRangeRounding@handler@_V1@sycl@@AEAA_NXZ @@ -3836,7 +3837,6 @@ ?category@exception@_V1@sycl@@QEBAAEBVerror_category@std@@XZ ?checkNodePropertiesAndThrow@modifiable_command_graph@detail@experimental@oneapi@ext@_V1@sycl@@KAXAEBVproperty_list@67@@Z ?clearArgs@handler@_V1@sycl@@AEAAXXZ -?AccessTargetMask@handler@_V1@sycl@@2HB ?incrementArgShift@handler@_V1@sycl@@AEAAXH@Z ?code@exception@_V1@sycl@@QEBAAEBVerror_code@std@@XZ ?compile_from_source@detail@experimental@oneapi@ext@_V1@sycl@@YA?AV?$kernel_bundle@$00@56@AEAV?$kernel_bundle@$02@56@AEBV?$vector@Vdevice@_V1@sycl@@V?$allocator@Vdevice@_V1@sycl@@@std@@@std@@AEBV?$vector@Vstring_view@detail@_V1@sycl@@V?$allocator@Vstring_view@detail@_V1@sycl@@@std@@@std@@PEAVstring@156@2@Z From 50b264d89056dd02457e5490ce8d5ffe6bc1bb37 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Mon, 6 Oct 2025 13:43:41 -0700 Subject: [PATCH 63/69] Add specialization of is_device_copyable in integration header --- clang/lib/Sema/SemaSYCL.cpp | 9 +++ .../CodeGenSYCL/free_function_int_header.cpp | 61 +++++++++++++++---- sycl/include/sycl/handler.hpp | 7 ++- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 5d4e67447b81f..f121d962d2450 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7293,6 +7293,15 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { // contains information about the offset, size and parameter // kind of every field inside the struct at any nesting level // This facilitates setting the arguments in the runtime. + // We also define is_device_copyable trait to be true for this type to + // allow it being passed in device kernels. + O << "template <>\n"; + O << "struct " + "sycl::detail::is_device_copyable<"; + Policy.SuppressTagKeyword = true; + type.print(O, Policy); + O << ">: std::true_type {};\n"; + O << "template <>\n"; O << "struct " "sycl::ext::oneapi::experimental::detail::is_struct_with_special_" diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index a9020631f4506..398a102337ce6 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -299,6 +299,12 @@ struct SecondLevelAccessor { AccessorAndInt accAndInt; }; +template +struct TemplatedAccessorStruct { + sycl::accessor acc; + sycl::local_accessor lacc; +}; + [[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] void ff_25(AccessorAndLocalAccessor arg1) { } @@ -311,6 +317,10 @@ void ff_26(AccessorAndLocalAccessor arg1, SecondLevelAccessor arg2) { void ff_27(IntAndAccessor arg1, AccessorAndInt) { } +[[__sycl_detail__::add_ir_attributes_function("sycl-single-task-kernel", 0)]] +void ff_28(TemplatedAccessorStruct arg1) { +} + // CHECK: const char* const kernel_names[] = { // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piii // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2Piiii @@ -349,6 +359,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2524AccessorAndLocalAccessor", // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2624AccessorAndLocalAccessor19SecondLevelAccessor", // CHECK-NEXT: {{.*}}__sycl_kernel_ff_2714IntAndAccessor14AccessorAndInt", +// CHECK-NEXT: {{.*}}__sycl_kernel_ff_2823TemplatedAccessorStructIiE", // CHECK-NEXT: {{.*}}__sycl_kernel_ff_23i" @@ -494,6 +505,11 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 0 }, // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 12 }, +// CHECK: //--- _Z19__sycl_kernel_ff_2823TemplatedAccessorStructIiE +// CHECK-NEXT: { kernel_param_kind_t::kind_struct_with_special_type, 36, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 0 }, +// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4064, 12 }, + // CHECK: //--- _Z19__sycl_kernel_ff_23i // CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 }, @@ -1655,11 +1671,6 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_invalid }; // CHECK-NEXT: }; -// CHECK: template <> -// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { -// CHECK-NEXT: inline static constexpr bool value = true; -// CHECK-NEXT: }; - // CHECK: static constexpr auto __sycl_shim35() { // CHECK-NEXT: return (void (*)(struct IntAndAccessor, struct AccessorAndInt))ff_27; // CHECK-NEXT: } @@ -1672,18 +1683,46 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; + +// CHECK: Definition of _Z19__sycl_kernel_ff_2823TemplatedAccessorStructIiE as a free function kernel +// CHECK: Forward declarations of kernel and its argument types: +// CHECK: template struct TemplatedAccessorStruct; +// CHECK: void ff_28(TemplatedAccessorStruct arg1); +// CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type> { +// CHECK-NEXT: inline static constexpr bool value = true; +// CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; +// CHECK-NEXT: static constexpr int sizes[] = { 4062, 4064, -1}; +// CHECK-NEXT: static constexpr sycl::detail::kernel_param_kind_t kinds[] = { +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT sycl::detail::kernel_param_kind_t::kind_invalid }; +// CHECK-NEXT: }; + +// CHECK: static constexpr auto __sycl_shim36() { +// CHECK-NEXT: return (void (*)(struct TemplatedAccessorStruct))ff_28; +// CHECK-NEXT: } + +// CHECK: struct ext::oneapi::experimental::is_kernel<__sycl_shim36()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim36()> { +// CHECK-NEXT: static constexpr bool value = true; +// CHECK-NEXT: }; + // CHECK: Definition of _Z19__sycl_kernel_ff_23i as a free function kernel // CHECK: Forward declarations of kernel and its argument types: // CHECK: void ff_23(int arg); -// CHECK-NEXT: static constexpr auto __sycl_shim36() { +// CHECK-NEXT: static constexpr auto __sycl_shim37() { // CHECK-NEXT: return (void (*)(int))ff_23; // CHECK-NEXT: } // CHECK: namespace sycl { // CHECK-NEXT: inline namespace _V1 { // CHECK-NEXT: namespace detail { -// CHECK-NEXT: //Free Function Kernel info specialization for shim36 -// CHECK-NEXT: template <> struct FreeFunctionInfoData<__sycl_shim36()> { +// CHECK-NEXT: //Free Function Kernel info specialization for shim37 +// CHECK-NEXT: template <> struct FreeFunctionInfoData<__sycl_shim37()> { // CHECK-NEXT: __SYCL_DLL_LOCAL // CHECK-NEXT: static constexpr unsigned getNumParams() { return 1; } // CHECK-NEXT: __SYCL_DLL_LOCAL @@ -1695,11 +1734,11 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK: namespace sycl { // CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim36()> { +// CHECK-NEXT: struct ext::oneapi::experimental::is_kernel<__sycl_shim37()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; // CHECK-NEXT: template <> -// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim36()> { +// CHECK-NEXT: struct ext::oneapi::experimental::is_single_task_kernel<__sycl_shim37()> { // CHECK-NEXT: static constexpr bool value = true; // CHECK-NEXT: }; @@ -1713,7 +1752,7 @@ void ff_27(IntAndAccessor arg1, AccessorAndInt) { // CHECK-NEXT: namespace detail { // CHECK-NEXT: struct GlobalMapUpdater { // CHECK-NEXT: GlobalMapUpdater() { -// CHECK-NEXT: sycl::detail::free_function_info_map::add(sycl::detail::kernel_names, sycl::detail::kernel_args_sizes, 36); +// CHECK-NEXT: sycl::detail::free_function_info_map::add(sycl::detail::kernel_names, sycl::detail::kernel_args_sizes, 37); // CHECK-NEXT: } // CHECK-NEXT: }; // CHECK-NEXT: static GlobalMapUpdater updater; diff --git a/sycl/include/sycl/handler.hpp b/sycl/include/sycl/handler.hpp index ade583b476fa0..4e716b25943e3 100644 --- a/sycl/include/sycl/handler.hpp +++ b/sycl/include/sycl/handler.hpp @@ -1638,10 +1638,11 @@ class __SYCL_EXPORT handler { std::is_pointer_v>) // USM || is_same_type::value // Interop || is_same_type::value // Stream - || ext::oneapi::experimental::detail::is_struct_with_special_type< - remove_cv_ref_t>::value; // Structs that contain special types + || + sycl::is_device_copyable_v>; // Structs that contain + // special types }; - + /// Sets argument for OpenCL interoperability kernels. /// /// Registers Arg passed as argument # ArgIndex. From 5861175dd1d030d007dfd29b42bd930bf4d9c74f Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Mon, 6 Oct 2025 14:12:27 -0700 Subject: [PATCH 64/69] Modify tests to check for the device_copyable trait --- clang/lib/Sema/SemaSYCL.cpp | 2 +- .../CodeGenSYCL/free_function_int_header.cpp | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index f121d962d2450..3cad865f7afd2 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -7297,7 +7297,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { // allow it being passed in device kernels. O << "template <>\n"; O << "struct " - "sycl::detail::is_device_copyable<"; + "sycl::is_device_copyable<"; Policy.SuppressTagKeyword = true; type.print(O, Policy); O << ">: std::true_type {};\n"; diff --git a/clang/test/CodeGenSYCL/free_function_int_header.cpp b/clang/test/CodeGenSYCL/free_function_int_header.cpp index 398a102337ce6..250ac721ab583 100644 --- a/clang/test/CodeGenSYCL/free_function_int_header.cpp +++ b/clang/test/CodeGenSYCL/free_function_int_header.cpp @@ -1609,6 +1609,8 @@ void ff_28(TemplatedAccessorStruct arg1) { // CHECK: Forward declarations of kernel and its argument types: // CHECK: void ff_25(AccessorAndLocalAccessor arg1); // CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::is_device_copyable: std::true_type {}; +// CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { // CHECK-NEXT: inline static constexpr bool value = true; // CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; @@ -1635,6 +1637,8 @@ void ff_28(TemplatedAccessorStruct arg1) { // CHECK: Forward declarations of kernel and its argument types: // CHECK: void ff_26(AccessorAndLocalAccessor arg1, SecondLevelAccessor arg2); // CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::is_device_copyable: std::true_type {}; +// CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { // CHECK-NEXT: inline static constexpr bool value = true; // CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; @@ -1661,6 +1665,8 @@ void ff_28(TemplatedAccessorStruct arg1) { // CHECK: Forward declarations of kernel and its argument types: // CHECK: void ff_27(IntAndAccessor arg1, AccessorAndInt ); // CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::is_device_copyable: std::true_type {}; +// CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { // CHECK-NEXT: inline static constexpr bool value = true; // CHECK-NEXT: static constexpr int offsets[] = { 0, 4, -1}; @@ -1671,6 +1677,21 @@ void ff_28(TemplatedAccessorStruct arg1) { // CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_invalid }; // CHECK-NEXT: }; +// CHECK: template <> +// CHECK-NEXT: struct sycl::is_device_copyable: std::true_type {}; +// CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type { +// CHECK-NEXT: inline static constexpr bool value = true; +// CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; +// CHECK-NEXT: static constexpr int sizes[] = { 4062, 4, -1}; +// CHECK-NEXT: static constexpr sycl::detail::kernel_param_kind_t kinds[] = { +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_accessor, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_std_layout, +// CHECK-NEXT: sycl::detail::kernel_param_kind_t::kind_invalid }; +// CHECK-NEXT: }; + + + // CHECK: static constexpr auto __sycl_shim35() { // CHECK-NEXT: return (void (*)(struct IntAndAccessor, struct AccessorAndInt))ff_27; // CHECK-NEXT: } @@ -1689,6 +1710,8 @@ void ff_28(TemplatedAccessorStruct arg1) { // CHECK: template struct TemplatedAccessorStruct; // CHECK: void ff_28(TemplatedAccessorStruct arg1); // CHECK-NEXT: template <> +// CHECK-NEXT: struct sycl::is_device_copyable>: std::true_type {}; +// CHECK-NEXT: template <> // CHECK-NEXT: struct sycl::ext::oneapi::experimental::detail::is_struct_with_special_type> { // CHECK-NEXT: inline static constexpr bool value = true; // CHECK-NEXT: static constexpr int offsets[] = { 0, 12, -1}; From 4396bf9fd520a1cca480da0d78d604825252f15c Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 7 Oct 2025 07:33:25 -0700 Subject: [PATCH 65/69] Fix pre-commit failures --- 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 3cad865f7afd2..31491f6a9c6a3 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -6908,6 +6908,7 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "#include \n"; O << "#include \n"; O << "#include \n"; + O << "#include \n"; O << "\n"; LangOptions LO; From 43076a20c4038a1ea235069dd96a8ec82735a935 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 7 Oct 2025 08:20:48 -0700 Subject: [PATCH 66/69] Fix more pre-commit failures --- .../Inputs/sycl/detail/is_device_copyable.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp diff --git a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp b/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp new file mode 100644 index 0000000000000..874b01e890da0 --- /dev/null +++ b/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp @@ -0,0 +1,14 @@ +//==------------ is_device_copyable.hpp - ----------------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#pragma once + +namespace sycl { +inline namespace _V1 { +template struct is_device_copyable; +} // namespace _V1 +} // namespace sycl From f72f9530bde6ec18e8263f63dc6d3c69d21e5130 Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 7 Oct 2025 12:14:35 -0400 Subject: [PATCH 67/69] Update is_device_copyable.hpp --- clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp b/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp index 874b01e890da0..91cd6816e15ee 100644 --- a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp +++ b/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp @@ -8,7 +8,5 @@ #pragma once namespace sycl { -inline namespace _V1 { template struct is_device_copyable; -} // namespace _V1 } // namespace sycl From 46ab7f20de3a6b24486fe90db3e55d0f1a09703a Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 7 Oct 2025 12:24:25 -0700 Subject: [PATCH 68/69] Fix more pre-commit failures --- clang/lib/Sema/SemaSYCL.cpp | 1 - .../Inputs/sycl/detail/is_device_copyable.hpp | 14 -------------- .../oneapi/experimental/free_function_traits.hpp | 3 +++ 3 files changed, 3 insertions(+), 15 deletions(-) delete mode 100644 clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 31491f6a9c6a3..3cad865f7afd2 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -6908,7 +6908,6 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "#include \n"; O << "#include \n"; O << "#include \n"; - O << "#include \n"; O << "\n"; LangOptions LO; diff --git a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp b/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp deleted file mode 100644 index 874b01e890da0..0000000000000 --- a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp +++ /dev/null @@ -1,14 +0,0 @@ -//==------------ is_device_copyable.hpp - ----------------------------------==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -#pragma once - -namespace sycl { -inline namespace _V1 { -template struct is_device_copyable; -} // namespace _V1 -} // namespace sycl diff --git a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp index bdbd298750b67..f399c380fd5f8 100644 --- a/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp +++ b/sycl/include/sycl/ext/oneapi/experimental/free_function_traits.hpp @@ -64,5 +64,8 @@ template struct is_struct_with_special_type { } // namespace detail } // namespace ext::oneapi::experimental + +template struct is_device_copyable; + } // namespace _V1 } // namespace sycl From cb43003cd958bc315eab2c2ac6966c25f4276cdb Mon Sep 17 00:00:00 2001 From: Lorenc Bushi Date: Tue, 7 Oct 2025 15:27:37 -0400 Subject: [PATCH 69/69] Delete clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp --- .../Inputs/sycl/detail/is_device_copyable.hpp | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp diff --git a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp b/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp deleted file mode 100644 index 91cd6816e15ee..0000000000000 --- a/clang/test/SemaSYCL/Inputs/sycl/detail/is_device_copyable.hpp +++ /dev/null @@ -1,12 +0,0 @@ -//==------------ is_device_copyable.hpp - ----------------------------------==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -#pragma once - -namespace sycl { -template struct is_device_copyable; -} // namespace sycl