diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 05e9f4793abaf..69b8842d3a4f3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1162,6 +1162,16 @@ def SYCLRegisterNum : InheritableAttr { let PragmaAttributeSupport = 0; } +// Used to mark ESIMD kernel pointer parameters originating from accessors. +def SYCLSimdAccessorPtr : InheritableAttr { + // No spelling, as this attribute can't be created in the source code. + let Spellings = []; + let Subjects = SubjectList<[ParmVar]>; + let LangOpts = [SYCLExplicitSIMD]; + let Documentation = [SYCLSimdAccessorPtrDocs]; + let PragmaAttributeSupport = 0; +} + def SYCLScope : Attr { // No spelling, as this attribute can't be created in the source code. let Spellings = []; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index e15e614278280..65c8f3096ab5c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -380,6 +380,18 @@ def SYCLRegisterNumDocs : Documentation { }]; } +def SYCLSimdAccessorPtrDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ + The ``__attribute__((esimd_acc_ptr))`` attribute must be used to mark ESIMD + kernel pointer parameters which correspond to the original + lambda's captured accessors. FE turns the attribute to some metadata + required by the ESIMD Back-End. + Not supposed to be used directly in the source - SYCL device compiler FE + automatically adds it for ESIMD kernels. + }]; +} + def C11NoReturnDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c80fd20a58583..e67a811799f69 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -332,7 +332,8 @@ class SYCLIntegrationHeader { /// Signals that subsequent parameter descriptor additions will go to /// the kernel with given name. Starts new kernel invocation descriptor. void startKernel(StringRef KernelName, QualType KernelNameType, - StringRef KernelStableName, SourceLocation Loc); + StringRef KernelStableName, SourceLocation Loc, + bool IsESIMD); /// Adds a kernel parameter descriptor to current kernel invocation /// descriptor. @@ -375,6 +376,9 @@ class SYCLIntegrationHeader { SourceLocation KernelLocation; + /// Whether this kernel is an ESIMD one. + bool IsESIMDKernel; + /// Descriptor of kernel actual parameters. SmallVector Params; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0a769bcdce49a..c797b502ceb2b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1439,6 +1439,10 @@ void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn, // MDNode for the intel_buffer_location attribute. SmallVector argSYCLBufferLocationAttr; + // MDNode for listing ESIMD kernel pointer arguments originating from + // accessors + SmallVector argESIMDAccPtrs; + if (FD && CGF) for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { const ParmVarDecl *parm = FD->getParamDecl(i); @@ -1570,6 +1574,10 @@ void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn, ? llvm::ConstantAsMetadata::get(CGF->Builder.getInt32( SYCLBufferLocationAttr->getLocationID())) : llvm::ConstantAsMetadata::get(CGF->Builder.getInt32(-1))); + + if (FD->hasAttr()) + argESIMDAccPtrs.push_back(llvm::ConstantAsMetadata::get( + CGF->Builder.getInt1(parm->hasAttr()))); } if (LangOpts.SYCLIsDevice && !LangOpts.SYCLExplicitSIMD) @@ -1586,6 +1594,9 @@ void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn, llvm::MDNode::get(VMContext, argBaseTypeNames)); Fn->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(VMContext, argTypeQuals)); + if (FD && FD->hasAttr()) + Fn->setMetadata("kernel_arg_accessor_ptr", + llvm::MDNode::get(VMContext, argESIMDAccPtrs)); if (getCodeGenOpts().EmitOpenCLArgMetadata) Fn->setMetadata("kernel_arg_name", llvm::MDNode::get(VMContext, argNames)); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 180e25cc130de..320058af3bdfc 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -57,6 +57,7 @@ enum KernelInvocationKind { }; const static std::string InitMethodName = "__init"; +const static std::string InitESIMDMethodName = "__init_esimd"; const static std::string FinalizeMethodName = "__finalize"; constexpr unsigned MaxKernelArgsSize = 2048; @@ -1700,7 +1701,11 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { bool isAccessorType = false) { const auto *RecordDecl = FieldTy->getAsCXXRecordDecl(); assert(RecordDecl && "The accessor/sampler must be a RecordDecl"); - CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, InitMethodName); + const std::string &MethodName = + KernelDecl->hasAttr() && isAccessorType + ? InitESIMDMethodName + : InitMethodName; + CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, MethodName); assert(InitMethod && "The accessor/sampler must have the __init method"); // Don't do -1 here because we count on this to be the first parameter added @@ -1709,9 +1714,14 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { for (const ParmVarDecl *Param : InitMethod->parameters()) { QualType ParamTy = Param->getType(); addParam(FD, ParamTy.getCanonicalType()); - if (ParamTy.getTypePtr()->isPointerType() && isAccessorType) + if (ParamTy.getTypePtr()->isPointerType() && isAccessorType) { handleAccessorPropertyList(Params.back(), RecordDecl, FD->getLocation()); + if (KernelDecl->hasAttr()) + // In ESIMD kernels accessor's pointer argument needs to be marked + Params.back()->addAttr( + SYCLSimdAccessorPtrAttr::CreateImplicit(SemaRef.getASTContext())); + } } LastParamIndex = ParamIndex; return true; @@ -1805,7 +1815,10 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { QualType FieldTy) final { const auto *RecordDecl = FieldTy->getAsCXXRecordDecl(); assert(RecordDecl && "The accessor/sampler must be a RecordDecl"); - CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, InitMethodName); + const std::string MethodName = KernelDecl->hasAttr() + ? InitESIMDMethodName + : InitMethodName; + CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, MethodName); assert(InitMethod && "The accessor/sampler must have the __init method"); // Don't do -1 here because we count on this to be the first parameter added @@ -1937,6 +1950,7 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler { class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { SourceLocation KernelLoc; unsigned SizeOfParams = 0; + bool IsSIMD = false; void addParam(QualType ArgTy) { SizeOfParams += @@ -1946,7 +1960,9 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { bool handleSpecialType(QualType FieldTy) { const CXXRecordDecl *RecordDecl = FieldTy->getAsCXXRecordDecl(); assert(RecordDecl && "The accessor/sampler must be a RecordDecl"); - CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, InitMethodName); + const std::string &MethodName = + IsSIMD ? InitESIMDMethodName : InitMethodName; + CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, MethodName); assert(InitMethod && "The accessor/sampler must have the __init method"); for (const ParmVarDecl *Param : InitMethod->parameters()) addParam(Param->getType()); @@ -1955,8 +1971,8 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { public: static constexpr const bool VisitInsideSimpleContainers = false; - SyclKernelArgsSizeChecker(Sema &S, SourceLocation Loc) - : SyclKernelFieldHandler(S), KernelLoc(Loc) {} + SyclKernelArgsSizeChecker(Sema &S, SourceLocation Loc, bool IsSIMD) + : SyclKernelFieldHandler(S), KernelLoc(Loc), IsSIMD(IsSIMD) {} ~SyclKernelArgsSizeChecker() { if (SizeOfParams > MaxKernelArgsSize) @@ -2030,6 +2046,19 @@ class SyclKernelArgsSizeChecker : public SyclKernelFieldHandler { using SyclKernelFieldHandler::handleSyclHalfType; }; +static const CXXMethodDecl *getOperatorParens(const CXXRecordDecl *Rec) { + for (const auto *MD : Rec->methods()) { + if (MD->getOverloadedOperator() == OO_Call) + return MD; + } + return nullptr; +} + +static bool isESIMDKernelType(const CXXRecordDecl *KernelObjType) { + const CXXMethodDecl *OpParens = getOperatorParens(KernelObjType); + return (OpParens != nullptr) && OpParens->hasAttr(); +} + class SyclKernelBodyCreator : public SyclKernelFieldHandler { SyclKernelDeclCreator &DeclCreator; llvm::SmallVector BodyStmts; @@ -2345,6 +2374,11 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { return VD; } + const std::string &getInitMethodName() const { + bool IsSIMDKernel = isESIMDKernelType(KernelObj); + return IsSIMDKernel ? InitESIMDMethodName : InitMethodName; + } + // Default inits the type, then calls the init-method in the body. bool handleSpecialType(FieldDecl *FD, QualType Ty) { addFieldInit(FD, Ty, None, @@ -2353,7 +2387,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { addFieldMemberExpr(FD, Ty); const auto *RecordDecl = Ty->getAsCXXRecordDecl(); - createSpecialMethodCall(RecordDecl, InitMethodName, BodyStmts); + createSpecialMethodCall(RecordDecl, getInitMethodName(), BodyStmts); removeFieldMemberExpr(FD, Ty); @@ -2363,7 +2397,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { bool handleSpecialType(const CXXBaseSpecifier &BS, QualType Ty) { const auto *RecordDecl = Ty->getAsCXXRecordDecl(); addBaseInit(BS, Ty, InitializationKind::CreateDefault(KernelCallerSrcLoc)); - createSpecialMethodCall(RecordDecl, InitMethodName, BodyStmts); + createSpecialMethodCall(RecordDecl, getInitMethodName(), BodyStmts); return true; } @@ -2487,7 +2521,7 @@ class SyclKernelBodyCreator : public SyclKernelFieldHandler { // calls, so add them here instead. const auto *StreamDecl = Ty->getAsCXXRecordDecl(); - createSpecialMethodCall(StreamDecl, InitMethodName, BodyStmts); + createSpecialMethodCall(StreamDecl, getInitMethodName(), BodyStmts); createSpecialMethodCall(StreamDecl, FinalizeMethodName, FinalizeStmts); removeFieldMemberExpr(FD, Ty); @@ -2645,7 +2679,9 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { const CXXRecordDecl *KernelObj, QualType NameType, StringRef Name, StringRef StableName) : SyclKernelFieldHandler(S), Header(H) { - Header.startKernel(Name, NameType, StableName, KernelObj->getLocation()); + bool IsSIMDKernel = isESIMDKernelType(KernelObj); + Header.startKernel(Name, NameType, StableName, KernelObj->getLocation(), + IsSIMDKernel); } bool handleSyclAccessorType(const CXXRecordDecl *RD, @@ -3012,7 +3048,10 @@ void Sema::CheckSYCLKernelCall(FunctionDecl *KernelFunc, SourceRange CallLoc, SyclKernelDecompMarker DecompMarker(*this); SyclKernelFieldChecker FieldChecker(*this); SyclKernelUnionChecker UnionChecker(*this); - SyclKernelArgsSizeChecker ArgsSizeChecker(*this, Args[0]->getExprLoc()); + + bool IsSIMDKernel = isESIMDKernelType(KernelObj); + SyclKernelArgsSizeChecker ArgsSizeChecker(*this, Args[0]->getExprLoc(), + IsSIMDKernel); KernelObjVisitor Visitor{*this}; SYCLKernelNameTypeVisitor KernelNameTypeVisitor(*this, Args[0]->getExprLoc(), @@ -3073,6 +3112,8 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, if (KernelObj->isInvalidDecl()) return; + bool IsSIMDKernel = isESIMDKernelType(KernelObj); + // Calculate both names, since Integration headers need both. std::string CalculatedName, StableName; std::tie(CalculatedName, StableName) = @@ -3081,7 +3122,7 @@ void Sema::ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, : CalculatedName); SyclKernelDeclCreator kernel_decl(*this, KernelName, KernelObj->getLocation(), KernelCallerFunc->isInlined(), - KernelCallerFunc->hasAttr()); + IsSIMDKernel); SyclKernelBodyCreator kernel_body(*this, kernel_decl, KernelObj, KernelCallerFunc); SyclKernelIntHeaderCreator int_header( @@ -3795,6 +3836,9 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) { O << "getParamDesc(unsigned i) {\n"; O << " return kernel_signatures[i+" << CurStart << "];\n"; O << " }\n"; + O << " __SYCL_DLL_LOCAL\n"; + O << " static constexpr bool isESIMD() { return " << K.IsESIMDKernel + << "; }\n"; O << "};\n"; CurStart += N; } @@ -3824,12 +3868,14 @@ bool SYCLIntegrationHeader::emit(const StringRef &IntHeaderName) { void SYCLIntegrationHeader::startKernel(StringRef KernelName, QualType KernelNameType, StringRef KernelStableName, - SourceLocation KernelLocation) { + SourceLocation KernelLocation, + bool IsESIMDKernel) { KernelDescs.resize(KernelDescs.size() + 1); KernelDescs.back().Name = std::string(KernelName); KernelDescs.back().NameType = KernelNameType; KernelDescs.back().StableName = std::string(KernelStableName); KernelDescs.back().KernelLocation = KernelLocation; + KernelDescs.back().IsESIMDKernel = IsESIMDKernel; } void SYCLIntegrationHeader::addParamDesc(kernel_param_kind_t Kind, int Info,