diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index 6134a70c04bd3..b4a3aac04d453 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -170,6 +170,12 @@ class MangleContext { virtual void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl, raw_ostream &Out) = 0; + /// SYCL kernel caller functions have names equivalent to a function template + /// specialization named "__sycl_kernel_caller" that has a single type + /// template argument, a void return type, and no parameters. + virtual void mangleSYCLKernelCallerName(QualType KernelNameType, + raw_ostream &Out) = 0; + /// Generates a unique string for an externally visible type for use with TBAA /// or type uniquing. /// TODO: Extend this to internal types by generating names that are unique diff --git a/clang/include/clang/AST/SYCLKernelInfo.h b/clang/include/clang/AST/SYCLKernelInfo.h index 4a4827e601053..fea88bfa2cc91 100644 --- a/clang/include/clang/AST/SYCLKernelInfo.h +++ b/clang/include/clang/AST/SYCLKernelInfo.h @@ -19,12 +19,24 @@ namespace clang { +enum class kernel_param_kind_t : int { + kind_accessor = 0, + kind_std_layout = 1, + kind_sampler = 2, + kind_pointer = 3, + kind_specialization_constants_buffer = 4, + kind_stream = 5, + kind_invalid = 0xf, // not a valid kernel kind +}; + class SYCLKernelInfo { public: SYCLKernelInfo(CanQualType KernelNameType, - const FunctionDecl *KernelEntryPointDecl) + const FunctionDecl *KernelEntryPointDecl, + const std::string &KernelName) : KernelNameType(KernelNameType), - KernelEntryPointDecl(KernelEntryPointDecl) {} + KernelEntryPointDecl(KernelEntryPointDecl), + KernelName(KernelName) {} CanQualType getKernelNameType() const { return KernelNameType; } @@ -32,9 +44,37 @@ class SYCLKernelInfo { return KernelEntryPointDecl; } + const std::string& GetKernelName() const { + return KernelName; + } + + size_t GetParamCount() const { return Params.size(); } + + void addParamDesc(kernel_param_kind_t Kind, QualType Ty) { + KernelParamDesc PD; + PD.Kind = Kind; + PD.Type = Ty; + Params.push_back(PD); + } + + const kernel_param_kind_t &GetParamKind(int i) const { + return Params[i].Kind; + } + + const QualType &GetParamTy(int i) const { return Params[i].Type; } + private: + // Kernel caller function parameter descriptor. + struct KernelParamDesc { + kernel_param_kind_t Kind = kernel_param_kind_t::kind_invalid; + QualType Type; + KernelParamDesc() = default; + }; + CanQualType KernelNameType; const FunctionDecl *KernelEntryPointDecl; + std::string KernelName; + SmallVector Params; }; } // namespace clang diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index 12c250afb4c61..dd349f885077c 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -44,6 +44,7 @@ enum LanguageID : uint16_t { OCL_DSE = 0x400, // builtin requires OpenCL device side enqueue. ALL_OCL_LANGUAGES = 0x800, // builtin for OCL languages. HLSL_LANG = 0x1000, // builtin requires HLSL. + SYCL_LANG = 0x2000, // builtin requires SYCL. ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages. ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode. ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode. diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 2268df70927a7..ce398f3522cc0 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4764,6 +4764,67 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> { let Prototype = "char const*(...)"; } +// SYCL +def SYCLKernelName : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_name"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "char const*(...)"; +} + +def SYCLKernelParamCount : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_param_count"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + +def SYCLKernelParamKind : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_param_kind"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + +def SYCLKernelParamSize : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_param_size"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + +def SYCLKernelParamOffset : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_param_offset"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + +def SYCLKernelParamAccessTarget : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_param_access_target"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "int(...)"; +} + +def SYCLKernelFileName : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_file_name"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "char const*(...)"; +} + +def SYCLKernelFunctionName : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_function_name"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "char const*(...)"; +} + +def SYCLKernelLineNumber : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_line_number"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "unsigned int(...)"; +} + +def SYCLKernelColumnNumber : LangBuiltin<"SYCL_LANG"> { + let Spellings = ["__builtin_sycl_kernel_column_number"]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; + let Prototype = "unsigned int(...)"; +} + // HLSL def HLSLAddUint64: LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_adduint64"]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index cf0e9846d4259..63e166757b2bf 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -759,6 +759,9 @@ def warn_unreachable_association : Warning< InGroup; /// Built-in functions. +def err_builtin_invalid_argument_count : Error< + "builtin %plural{0:takes no arguments|1:takes one argument|" + ":requires exactly %0 arguments}0">; def ext_implicit_lib_function_decl : ExtWarn< "implicitly declaring library function '%0' with type %1">, InGroup; @@ -12586,6 +12589,13 @@ def err_sycl_entry_point_deduced_return_type : Error< "'sycl_kernel_entry_point' attribute only applies to functions with a" " non-deduced 'void' return type">; +// SYCL builtins diagnostics +def err_builtin_invalid_argument : Error<"invalid argument; argument must be a class or struct type" + " with a member type alias named 'type'">; +def err_sycl_kernel_name_invalid_arg : Error<"invalid argument; expected a class " + "or structure with a member typedef " + "or type alias alias named 'type'">; + def warn_cuda_maxclusterrank_sm_90 : Warning< "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " "%1 attribute">, InGroup; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fce1c34897da7..99d8f716b0809 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -12790,6 +12790,22 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (!FD->doesThisDeclarationHaveABody()) return FD->doesDeclarationForceExternallyVisibleDefinition(); + // SYCL kernel entry point functions are used to generate and emit + // the offload kernel. + if (LangOpts.SYCLIsDevice) { + if (D->hasAttr()) + return true; + // FIXME: In SYCL device compilation, the only functions that + // must be emitted are the SYCL kernel entry points, functions + // called from the the SYCL kernel, and functions declared with + // SYCL_EXTERNAL. However, some existing tests fail if the set + // of emitted functions is limited to these. Once support is + // implemented for SYCL_EXTERNAL, this check should be modified + // to return false. The tests should be modified to include + // SYCL_EXTERNAL. + // return false; + } + // Constructors and destructors are required. if (FD->hasAttr() || FD->hasAttr()) return true; @@ -14602,9 +14618,70 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, } } -static SYCLKernelInfo BuildSYCLKernelInfo(CanQualType KernelNameType, +static std::string GetSYCLKernelCallerName(ASTContext &Context, + CanQualType KernelNameType) { + // FIXME: Host and device compilations must agree on a name for the generated + // FIXME: SYCL kernel caller function. The name is provided to the SYCL + // FIXME: library on the host via __builtin_sycl_kernel_name() and the SYCL + // FIXME: library is then responsible for dynamically resolving the name to + // FIXME: a function in a device image at run-time. At present, it is assumed + // FIXME: that the device ABI is based on the Itanium ABI and a corresponding + // FIXME: name is generated. However, if the device ABI is not based on the + // FIXME: Itanium ABI, this assumption leads to the existence of oddly named + // FIXME: functions relative to the device ABI. Further, this approach + // FIXME: requires that the same name be generated for every host and device + // FIXME: compilation which is difficult to ensure for context sensitive + // FIXME: "unnamed" types like lambda closure types. A better approach would + // FIXME: be to generate an ABI agnostic name and then emit a map with each + // FIXME: device compilation for the ABI dependent name. Alas, naming is hard + // FIXME: and defining an ABI agnostic naming scheme might devolve into + // FIXME: effectively re-creating a large subset of the Itanium ABI name + // FIXME: mangling scheme. + + // Host and device compilation may use different ABIs and different ABIs may + // allocate discriminators differently. An override is needed to ensure + // consistent discriminators are allocated for host and device compilation. + auto DeviceDiscriminatorOverrider = [](ASTContext &Ctx, const NamedDecl *ND) + -> std::optional { + if (const auto *RD = dyn_cast(ND)) + if (RD->isLambda()) + return RD->getDeviceLambdaManglingNumber(); + return std::nullopt; + }; + std::unique_ptr MC{ItaniumMangleContext::create( + Context, Context.getDiagnostics(), DeviceDiscriminatorOverrider)}; + + // Produce the mangled name. + std::string Buffer; + Buffer.reserve(128); + llvm::raw_string_ostream Out(Buffer); + MC->mangleSYCLKernelCallerName(KernelNameType, Out); + return Out.str(); +} + +static void CreateSYCLKernelParamDesc(ASTContext &Ctx, const FunctionDecl *FD, + SYCLKernelInfo &KernelInfo) { + if (FD->getNumParams() == 0) + return; + + for (const ParmVarDecl *KernelParam : FD->parameters()) { + KernelInfo.addParamDesc(kernel_param_kind_t::kind_std_layout, + KernelParam->getType()); + } +} + +static SYCLKernelInfo BuildSYCLKernelInfo(ASTContext &Context, + CanQualType KernelNameType, const FunctionDecl *FD) { - return {KernelNameType, FD}; + // Get the mangled name. + std::string KernelCallerName = + GetSYCLKernelCallerName(Context, KernelNameType); + + SYCLKernelInfo KernelInfo{KernelNameType, FD, KernelCallerName}; + + CreateSYCLKernelParamDesc(Context, FD, KernelInfo); + + return KernelInfo; } void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) { @@ -14625,8 +14702,8 @@ void ASTContext::registerSYCLEntryPointFunction(FunctionDecl *FD) { declaresSameEntity(FD, IT->second.getKernelEntryPointDecl())) && "SYCL kernel name conflict"); (void)IT; - SYCLKernels.insert( - std::make_pair(KernelNameType, BuildSYCLKernelInfo(KernelNameType, FD))); + SYCLKernels.insert(std::make_pair( + KernelNameType, BuildSYCLKernelInfo(*this, KernelNameType, FD))); } const SYCLKernelInfo &ASTContext::getSYCLKernelInfo(QualType T) const { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d9a1e5bb42343..cf9a333210b3f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -53,6 +53,7 @@ #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/APFixedPoint.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallBitVector.h" @@ -9850,6 +9851,26 @@ static bool isOneByteCharacterType(QualType T) { return T->isCharType() || T->isChar8Type(); } +static const SYCLKernelInfo *GetSYCLKernelInfo(ASTContext &Ctx, + const CallExpr *E) { + // Argument to the builtin is a type trait which is used to retrieve the + // kernel name type. + // FIXME: Improve the comment. + const Expr *NameExpr = E->getArg(0); + // FIXME: Implement diagnostic instead of assert. + assert(NameExpr->isEvaluatable(Ctx) && + "KernelNameType should be evaluatable"); + RecordDecl *RD = NameExpr->getType()->castAs()->getDecl(); + IdentifierTable &IdentTable = Ctx.Idents; + auto Name = DeclarationName(&(IdentTable.get("type"))); + NamedDecl *ND = (RD->lookup(Name)).front(); + TypedefNameDecl *TD = cast(ND); + CanQualType KernelNameType = Ctx.getCanonicalType(TD->getUnderlyingType()); + + // Retrieve KernelInfo using the kernel name. + return Ctx.findSYCLKernelInfo(KernelNameType); +} + bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp) { if (IsOpaqueConstantCall(E)) @@ -10205,6 +10226,42 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return false; } } + case Builtin::BI__builtin_sycl_kernel_name: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + // Retrieve the mangled name corresponding to kernel name type. + std::string ResultStr = KernelInfo->GetKernelName(); + APInt Size(Info.Ctx.getTypeSize(Info.Ctx.getSizeType()), + ResultStr.size() + 1); + QualType StrTy = + Info.Ctx.getConstantArrayType(Info.Ctx.CharTy.withConst(), Size, + nullptr, ArraySizeModifier::Normal, 0); + StringLiteral *SL = + StringLiteral::Create(Info.Ctx, ResultStr, StringLiteralKind::Ordinary, + /*Pascal*/ false, StrTy, SourceLocation()); + evaluateLValue(SL, Result); + Result.addArray(Info, E, cast(StrTy)); + return true; + } + case Builtin::BI__builtin_sycl_kernel_file_name: + case Builtin::BI__builtin_sycl_kernel_function_name: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + // FIXME: Dummy value. + std::string ResultStr = "DummyString"; + APInt Size(Info.Ctx.getTypeSize(Info.Ctx.getSizeType()), + ResultStr.size() + 1); + QualType StrTy = + Info.Ctx.getConstantArrayType(Info.Ctx.CharTy.withConst(), Size, + nullptr, ArraySizeModifier::Normal, 0); + StringLiteral *SL = + StringLiteral::Create(Info.Ctx, ResultStr, StringLiteralKind::Ordinary, + /*Pascal*/ false, StrTy, SourceLocation()); + Result.addArray(Info, E, cast(StrTy)); + return evaluateLValue(SL, Result); + } default: return false; @@ -12900,6 +12957,62 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Layout.size().getQuantity(), E); } + case Builtin::BI__builtin_sycl_kernel_param_count: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + return Success(KernelInfo->GetParamCount(), E); + } + + case Builtin::BI__builtin_sycl_kernel_param_kind: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + const Expr *ParamNoExpr = E->getArg(1); + Expr::EvalResult Result; + // FIXME: Should we add some error checking? + ParamNoExpr->EvaluateAsInt(Result, Info.Ctx); + unsigned ParamNo = Result.Val.getInt().getZExtValue(); + return Success(static_cast(KernelInfo->GetParamKind(ParamNo)), E); + } + + case Builtin::BI__builtin_sycl_kernel_param_size: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + const Expr *ParamNoExpr = E->getArg(1); + Expr::EvalResult Result; + // FIXME: Should we add some error checking? + ParamNoExpr->EvaluateAsInt(Result, Info.Ctx); + unsigned ParamNo = Result.Val.getInt().getZExtValue(); + QualType ParamTy = KernelInfo->GetParamTy(ParamNo); + return Success(Info.Ctx.getTypeSizeInChars(ParamTy).getQuantity(), E); + } + + case Builtin::BI__builtin_sycl_kernel_param_offset: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + const Expr *ParamNoExpr = E->getArg(1); + Expr::EvalResult Result; + // FIXME: Should we add some error checking? + ParamNoExpr->EvaluateAsInt(Result, Info.Ctx); + // FIXME: Offset is used only when kernel object is decomposed to identify + // offset of field in kernel object. What should the offset be for + // additional non-kernel object parameters? + return Success(0, E); + } + + case Builtin::BI__builtin_sycl_kernel_param_access_target: + case Builtin::BI__builtin_sycl_kernel_line_number: + case Builtin::BI__builtin_sycl_kernel_column_number: { + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(Info.Ctx, E); + if (!KernelInfo) + return false; + // FIXME: Dummy value. + return Success(0, E); + } + case Builtin::BI__builtin_is_aligned: { APValue Src; APSInt Alignment; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index b80dd1c86092f..99d294fd82aea 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -134,6 +134,9 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { void mangleModuleInitializer(const Module *Module, raw_ostream &) override; + void mangleSYCLKernelCallerName(QualType KernelNameType, + raw_ostream &Out) override; + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { // Lambda closure types are already numbered. if (isLambda(ND)) @@ -7536,6 +7539,15 @@ void ItaniumMangleContextImpl::mangleModuleInitializer(const Module *M, } } +void ItaniumMangleContextImpl::mangleSYCLKernelCallerName( + QualType KernelNameType, raw_ostream &Out) { + // ::= + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_Z20__sycl_kernel_callerI"; + Mangler.mangleType(KernelNameType); + Mangler.getStream() << "Evv"; +} + ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags, bool IsAux) { diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 6e2be2557d0a7..0851dbec7a301 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -211,6 +211,9 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl, raw_ostream &Out) override; void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override; + void mangleSYCLKernelCallerName(QualType KernelNameType, + raw_ostream &Out) override; + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { const DeclContext *DC = getEffectiveDeclContext(ND); if (!DC->isFunctionOrMethod()) @@ -4357,6 +4360,51 @@ void MicrosoftCXXNameMangler::mangleAutoReturnType(const RValueReferenceType *T, mangleAutoReturnType(PointeeType, QMM_Mangle); } +void MicrosoftMangleContextImpl::mangleSYCLKernelCallerName( + QualType KernelNameType, raw_ostream &Out) { + // The SYCL kernel caller name is mangled like a function template + // specialization with void return type, no parameters, and a single + // type template parameter. Properties of the function are explictly + // mangled per the spec below. + // ::= + // '?' + // ::= + // ::= + // ::= + // + // '?$' + // := + // "__sycl_kernel_caller" + // '@' + // + // ::= + // ::= + // KernelNameType + // '@' + // '@' + // ::= + // ::= + // ::= + // 'Y' # global near + // ::= + // ::= + // ::= + // 'A' # __cdecl) + // ::= + // ::= + // ::= + // 'X' # void + // ::= + // 'X' # void + // ::= + // 'Z' # (default) + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "??$__sycl_kernel_caller@"; + Mangler.mangleType(KernelNameType, SourceRange(), + MicrosoftCXXNameMangler::QMM_Escape); + Mangler.getStream() << "@@YAXXZ"; +} + MicrosoftMangleContext *MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags, bool IsAux) { diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index e7829a461bbc5..ca72c7ffa94a1 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -185,6 +185,9 @@ static bool builtinIsSupported(const llvm::StringTable &Strings, /* CUDA Unsupported */ if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG) return false; + /* SYCL Unsupported */ + if (!LangOpts.isSYCL() && BuiltinInfo.Langs == SYCL_LANG) + return false; /* CPlusPlus Unsupported */ if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) return false; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index b86bb242755be..0dc8516bdc84a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -34,6 +34,7 @@ #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/ADT/APFloat.h" @@ -2927,6 +2928,49 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF, return RValue::get(CGF->Builder.CreateCall(UBF, Args)); } +static const CanQualType GetKernelNameType(ASTContext &Ctx, const CallExpr *E) { + // The first argument to the builtin is an object that designates + // the SYCL kernel. The argument is evaluated and its value is + // discarded; the SYCL kernel is identified based on the argument + // type. The argument type is required to be a class or structure + // with a member typedef or type alias named 'type'. The target + // type of the 'type' member is the SYCL kernel name type. + RecordDecl *RD = E->getArg(0)->getType()->castAs()->getDecl(); + IdentifierTable &IdentTable = Ctx.Idents; + auto Name = DeclarationName(&(IdentTable.get("type"))); + NamedDecl *ND = (RD->lookup(Name)).front(); + TypedefNameDecl *TD = cast(ND); + return Ctx.getCanonicalType(TD->getUnderlyingType()); +} + +static llvm::GlobalVariable * +EmitKernelNameGlobal(CodeGenModule &CGM, ASTContext &Ctx, const CallExpr *E) { + CanQualType KernelNameType = GetKernelNameType(Ctx, E); + + SmallString<256> KernelNameSymbol; + llvm::raw_svector_ostream Out(KernelNameSymbol); + // The mangling used for the name of the global variable storing the offload + // kernel name is identical to the mangling of the offload kernel name. + CGM.getCXXABI().getMangleContext().mangleSYCLKernelCallerName(KernelNameType, + Out); + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + CGM.getModule(), CGM.GlobalsInt8PtrTy, + /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr, + KernelNameSymbol); + + CGM.AddSYCLKernelNameSymbol(KernelNameType, GV); + + return GV; +} + +static const SYCLKernelInfo *GetSYCLKernelInfo(ASTContext &Ctx, + const CallExpr *E) { + CanQualType KernelNameType = GetKernelNameType(Ctx, E); + + // Retrieve KernelInfo using the kernel name. + return Ctx.findSYCLKernelInfo(KernelNameType); +} + RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue) { @@ -6616,6 +6660,88 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto Str = CGM.GetAddrOfConstantCString(Name, ""); return RValue::get(Str.getPointer()); } + case Builtin::BI__builtin_sycl_kernel_name: { + // Retrieve the kernel info corresponding to kernel name type. + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); + + // This indicates that the builtin was called before the kernel was + // invoked. In this case, a global variable is declared, and returned + // as the result of the call to the builtin. This global variable is + // later initialized to hold the name of the offload kernel when kernel + // invocation is processed. + if (!KernelInfo) + return RValue::get(EmitKernelNameGlobal(CGM, getContext(), E)); + + // Emit the mangled name from KernelInfo if available. + auto Str = CGM.GetAddrOfConstantCString(KernelInfo->GetKernelName(), ""); + return RValue::get(Str.getPointer()); + } + case Builtin::BI__builtin_sycl_kernel_param_count: { + // Retrieve the kernel info corresponding to kernel name type. + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); + assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); + return RValue::get( + llvm::ConstantInt::get(IntTy, KernelInfo->GetParamCount())); + } + case Builtin::BI__builtin_sycl_kernel_param_kind: { + // Retrieve the kernel info corresponding to kernel name type. + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); + assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); + // Emit total number of parameters of kernel caller function. + const Expr *ParamNoExpr = E->getArg(1); + Expr::EvalResult Result; + ParamNoExpr->EvaluateAsInt(Result, getContext()); + unsigned ParamNo = Result.Val.getInt().getZExtValue(); + return RValue::get(llvm::ConstantInt::get( + IntTy, static_cast(KernelInfo->GetParamKind(ParamNo)))); + } + case Builtin::BI__builtin_sycl_kernel_param_size: { + // Retrieve the kernel info corresponding to kernel name type. + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); + assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); + // Emit total number of parameters of kernel caller function. + const Expr *ParamNoExpr = E->getArg(1); + Expr::EvalResult Result; + ParamNoExpr->EvaluateAsInt(Result, getContext()); + unsigned ParamNo = Result.Val.getInt().getZExtValue(); + QualType ParamTy = KernelInfo->GetParamTy(ParamNo); + // FIXME: Add check to ensure complete type. + return RValue::get(llvm::ConstantInt::get( + IntTy, getContext().getTypeSizeInChars(ParamTy).getQuantity())); + } + case Builtin::BI__builtin_sycl_kernel_param_offset: { + // Retrieve the kernel info corresponding to kernel name type. + const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E); + assert(KernelInfo && "Type does not correspond to a SYCL kernel name."); + // FIXME: Offset is used only when kernel object is decomposed to identify + // offset of field in kernel object. What should the offset be for + // additional non-kernel object parameters? + return RValue::get(llvm::ConstantInt::get(IntTy, 0)); + } + case Builtin::BI__builtin_sycl_kernel_param_access_target: { + // FIXME: This is a dummy value. This builtin will be implemented when + // support for special sycl types is implemented. + return RValue::get(llvm::ConstantInt::get(IntTy, 0)); + } + case Builtin::BI__builtin_sycl_kernel_file_name: + case Builtin::BI__builtin_sycl_kernel_function_name: { + // FIXME: This is a dummy value. These builtins provide information + // about the kernel object. In the new design, the we do not have + // special status for the kernel object, so it is unclear what these + // builtins should return, or if they even need to exist. Support will + // be added or removed after investigation. + auto Str = CGM.GetAddrOfConstantCString("DummyString", ""); + return RValue::get(Str.getPointer()); + } + case Builtin::BI__builtin_sycl_kernel_line_number: + case Builtin::BI__builtin_sycl_kernel_column_number: { + // FIXME: This is a dummy value. These builtins provide information + // about the kernel object. In the new design, the we do not have + // special status for the kernel object, so it is unclear what these + // builtins should return, or if they even need to exist. Support will + // be added or removed after investigation. + return RValue::get(llvm::ConstantInt::get(IntTy, 0)); + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index bfcbc273dbda7..6ad4dff5fea0d 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -67,7 +67,8 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_AArch64SVEPCS: return llvm::CallingConv::AArch64_SVE_VectorCall; case CC_AMDGPUKernelCall: return llvm::CallingConv::AMDGPU_KERNEL; case CC_SpirFunction: return llvm::CallingConv::SPIR_FUNC; - case CC_OpenCLKernel: return CGM.getTargetCodeGenInfo().getOpenCLKernelCallingConv(); + case CC_OpenCLKernel: + return CGM.getTargetCodeGenInfo().getOpenCLKernelCallingConv(CGM); case CC_PreserveMost: return llvm::CallingConv::PreserveMost; case CC_PreserveAll: return llvm::CallingConv::PreserveAll; case CC_Swift: return llvm::CallingConv::Swift; @@ -732,6 +733,17 @@ CodeGenTypes::arrangeBuiltinFunctionDeclaration(CanQualType resultType, RequiredArgs::All); } +const CGFunctionInfo & +CodeGenTypes::arrangeSYCLKernelCallerDeclaration(QualType resultType, + const FunctionArgList &args) { + auto argTypes = getArgTypesForDeclaration(Context, args); + + return arrangeLLVMFunctionInfo(GetReturnType(resultType), FnInfoOpts::None, + argTypes, + FunctionType::ExtInfo(CC_OpenCLKernel), {}, + RequiredArgs::All); +} + /// Arrange a call to a C++ method, passing the given arguments. /// /// numPrefixArgs is the number of ABI-specific prefix arguments we have. It diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 05ab6671453f8..be6710f4dcb62 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -101,6 +101,7 @@ add_clang_library(clangCodeGen CodeGenFunction.cpp CodeGenModule.cpp CodeGenPGO.cpp + CodeGenSYCL.cpp CodeGenTBAA.cpp CodeGenTypes.cpp ConstantInitBuilder.cpp diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 08165e0b28406..df9c2dea53866 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -619,21 +619,17 @@ CodeGenFunction::getUBSanFunctionTypeHash(QualType Ty) const { CGM.Int32Ty, static_cast(llvm::xxh3_64bits(Mangled))); } -void CodeGenFunction::EmitKernelMetadata(const FunctionDecl *FD, - llvm::Function *Fn) { - if (!FD->hasAttr() && !FD->hasAttr()) - return; - +void CodeGenFunction::EmitKernelMetadata(const Decl *D, llvm::Function *Fn, + const OutlinedFunctionDecl *OFD) { llvm::LLVMContext &Context = getLLVMContext(); - - CGM.GenKernelArgMetadata(Fn, FD, this); + CGM.GenKernelArgMetadata(Fn, D, this, OFD); if (!(getLangOpts().OpenCL || (getLangOpts().CUDA && getContext().getTargetInfo().getTriple().isSPIRV()))) return; - if (const VecTypeHintAttr *A = FD->getAttr()) { + if (const VecTypeHintAttr *A = D->getAttr()) { QualType HintQTy = A->getTypeHint(); const ExtVectorType *HintEltQTy = HintQTy->getAs(); bool IsSignedInteger = @@ -648,7 +644,7 @@ void CodeGenFunction::EmitKernelMetadata(const FunctionDecl *FD, Fn->setMetadata("vec_type_hint", llvm::MDNode::get(Context, AttrMDArgs)); } - if (const WorkGroupSizeHintAttr *A = FD->getAttr()) { + if (const WorkGroupSizeHintAttr *A = D->getAttr()) { llvm::Metadata *AttrMDArgs[] = { llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())), @@ -656,7 +652,7 @@ void CodeGenFunction::EmitKernelMetadata(const FunctionDecl *FD, Fn->setMetadata("work_group_size_hint", llvm::MDNode::get(Context, AttrMDArgs)); } - if (const ReqdWorkGroupSizeAttr *A = FD->getAttr()) { + if (const ReqdWorkGroupSizeAttr *A = D->getAttr()) { llvm::Metadata *AttrMDArgs[] = { llvm::ConstantAsMetadata::get(Builder.getInt32(A->getXDim())), llvm::ConstantAsMetadata::get(Builder.getInt32(A->getYDim())), @@ -665,7 +661,7 @@ void CodeGenFunction::EmitKernelMetadata(const FunctionDecl *FD, } if (const OpenCLIntelReqdSubGroupSizeAttr *A = - FD->getAttr()) { + D->getAttr()) { llvm::Metadata *AttrMDArgs[] = { llvm::ConstantAsMetadata::get(Builder.getInt32(A->getSubGroupSize()))}; Fn->setMetadata("intel_reqd_sub_group_size", @@ -745,17 +741,24 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM, return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM); } -void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, - llvm::Function *Fn, - const CGFunctionInfo &FnInfo, - const FunctionArgList &Args, - SourceLocation Loc, - SourceLocation StartLoc) { +void CodeGenFunction::StartFunction( + GlobalDecl GD, QualType RetTy, llvm::Function *Fn, + const CGFunctionInfo &FnInfo, const FunctionArgList &Args, + SourceLocation Loc, SourceLocation StartLoc, + const OutlinedFunctionDecl *OutlinedFnDecl) { assert(!CurFn && "Do not use a CodeGenFunction object for more than one function"); const Decl *D = GD.getDecl(); + bool GeneratingSYCLOffloadKernel = false; + // The presence of OutlinedFnDecl indicates that we are currently + // generating the SYCL offload kernel. + if (getLangOpts().SYCLIsDevice && OutlinedFnDecl) { + D = OutlinedFnDecl; + GeneratingSYCLOffloadKernel = true; + } + DidCallStackSave = false; CurCodeDecl = D; const FunctionDecl *FD = dyn_cast_or_null(D); @@ -1020,13 +1023,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Fn->addFnAttr(llvm::Attribute::FnRetThunkExtern); } - if (FD && (getLangOpts().OpenCL || - (getLangOpts().CUDA && - getContext().getTargetInfo().getTriple().isSPIRV()) || - ((getLangOpts().HIP || getLangOpts().OffloadViaLLVM) && - getLangOpts().CUDAIsDevice))) { + if (GeneratingSYCLOffloadKernel || + (FD && ((getLangOpts().OpenCL && D->hasAttr()) || + (getLangOpts().CUDA && + getContext().getTargetInfo().getTriple().isSPIRV()) || + ((getLangOpts().HIP || getLangOpts().OffloadViaLLVM) && + getLangOpts().CUDAIsDevice)))) { // Add metadata for a kernel function. - EmitKernelMetadata(FD, Fn); + EmitKernelMetadata(D, Fn, OutlinedFnDecl); } if (FD && FD->hasAttr()) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 018fc66b72a1e..067439ced2719 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2184,9 +2184,10 @@ class CodeGenFunction : public CodeGenTypeCache { /// the constructor, but could be overwritten to true if this is a coroutine. bool ShouldEmitLifetimeMarkers; - /// Add OpenCL kernel arg metadata and the kernel attribute metadata to + /// Add kernel arg metadata and the kernel attribute metadata to /// the function metadata. - void EmitKernelMetadata(const FunctionDecl *FD, llvm::Function *Fn); + void EmitKernelMetadata(const Decl *D, llvm::Function *Fn, + const OutlinedFunctionDecl *OFD); public: CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext = false); @@ -2422,7 +2423,8 @@ class CodeGenFunction : public CodeGenTypeCache { void StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, SourceLocation Loc = SourceLocation(), - SourceLocation StartLoc = SourceLocation()); + SourceLocation StartLoc = SourceLocation(), + const OutlinedFunctionDecl *OutlinedFnDecl = nullptr); static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index bca0a932b3495..aa14f81f4bce8 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2290,15 +2290,17 @@ static unsigned ArgInfoAddressSpace(LangAS AS) { } } -void CodeGenModule::GenKernelArgMetadata(llvm::Function *Fn, - const FunctionDecl *FD, - CodeGenFunction *CGF) { - assert(((FD && CGF) || (!FD && !CGF)) && - "Incorrect use - FD and CGF should either be both null or not!"); +void CodeGenModule::GenKernelArgMetadata(llvm::Function *Fn, const Decl *D, + CodeGenFunction *CGF, + const OutlinedFunctionDecl *OFD) { + assert(((D && CGF) || (!D && !CGF)) && + "Incorrect use - D and CGF should either be both null or not!"); // Create MDNodes that represent the kernel arg metadata. // Each MDNode is a list in the form of "key", N number of values which is // the same number of values as their are kernel arguments. + const FunctionDecl *FD = dyn_cast_or_null(D); + const PrintingPolicy &Policy = Context.getPrintingPolicy(); // MDNode for the kernel argument address space qualifiers. @@ -2319,14 +2321,17 @@ void CodeGenModule::GenKernelArgMetadata(llvm::Function *Fn, // MDNode for the kernel argument names. SmallVector argNames; - if (FD && CGF) - for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { - const ParmVarDecl *parm = FD->getParamDecl(i); + if (D && CGF) { + unsigned NumParam = OFD ? OFD->getNumParams() : FD->getNumParams(); + for (unsigned i = 0, e = NumParam; i != e; ++i) { + const VarDecl *parm = OFD ? cast(OFD->getParam(i)) + : cast(FD->getParamDecl(i)); // Get argument name. argNames.push_back(llvm::MDString::get(VMContext, parm->getName())); - if (!getLangOpts().OpenCL) + if (!getLangOpts().OpenCL && !getLangOpts().SYCLIsDevice) continue; + QualType ty = parm->getType(); std::string typeQuals; @@ -2416,8 +2421,9 @@ void CodeGenModule::GenKernelArgMetadata(llvm::Function *Fn, } argTypeQuals.push_back(llvm::MDString::get(VMContext, typeQuals)); } + } - if (getLangOpts().OpenCL) { + if (getLangOpts().OpenCL || getLangOpts().SYCLIsDevice) { Fn->setMetadata("kernel_arg_addr_space", llvm::MDNode::get(VMContext, addressQuals)); Fn->setMetadata("kernel_arg_access_qual", @@ -3303,6 +3309,34 @@ void CodeGenModule::EmitDeferred() { CurDeclsToEmit.swap(DeferredDeclsToEmit); for (GlobalDecl &D : CurDeclsToEmit) { + // If the Decl corresponds to a SYCL kernel entry point function, generate + // and emit the corresponding SYCL kernel caller function i.e the + // offload kernel. The generation of the offload kernel needs to happen + // first in this loop, in order to avoid generating IR for the SYCL kernel + // entry point function. + if (const auto *FD = D.getDecl()->getAsFunction()) { + if (FD->hasAttr() && FD->isDefined()) { + // FIXME: This check for invalid attribute was added by Tom in his PR + // for upstreaming. It is unclear to me why this is necessary. Verify + // it is required and cleanup the guards here if necessary. + if (!FD->getAttr()->isInvalidAttr()) { + if (LangOpts.SYCLIsDevice) { + // Generate and emit the offload kernel + EmitSYCLKernelCaller(FD, getContext()); + // Recurse to emit any symbols referenced by the SYCL kernel + // caller function. + EmitDeferred(); + // Do not emit the SYCL kernel entry point function. + continue; + } else { + // Initialize the global variables corresponding to SYCL Builtins + // used to obtain information about the offload kernel. + InitSYCLKernelInfoSymbolsForBuiltins(FD, getContext()); + } + } + } + } + // We should call GetAddrOfGlobal with IsForDefinition set to true in order // to get GlobalValue with exactly the type we need, not something that // might had been created for another decl with the same mangled name but @@ -3638,6 +3672,9 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) { // Defer until all versions have been semantically checked. if (FD->hasAttr() && !FD->isMultiVersion()) return false; + // Defer emission of SYCL kernel entry point functions. + if (LangOpts.SYCLIsDevice && FD->hasAttr()) + return false; } if (const auto *VD = dyn_cast(Global)) { if (Context.getInlineVariableDefinitionKind(VD) == diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 83bb5bc54d077..0f0204a612b83 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -680,6 +680,7 @@ class CodeGenModule : public CodeGenTypeCache { computeVTPointerAuthentication(const CXXRecordDecl *ThisClass); AtomicOptions AtomicOpts; + llvm::DenseMap SYCLKernelNameSymbols; public: CodeGenModule(ASTContext &C, IntrusiveRefCntPtr FS, @@ -1510,6 +1511,10 @@ class CodeGenModule : public CodeGenTypeCache { /// annotations are emitted during finalization of the LLVM code. void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); + void AddSYCLKernelNameSymbol(CanQualType, llvm::GlobalVariable *); + + llvm::GlobalVariable *GetSYCLKernelNameSymbol(CanQualType); + bool isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn, SourceLocation Loc) const; @@ -1684,9 +1689,11 @@ class CodeGenModule : public CodeGenTypeCache { /// \param FN is a pointer to IR function being generated. /// \param FD is a pointer to function declaration if any. /// \param CGF is a pointer to CodeGenFunction that generates this function. - void GenKernelArgMetadata(llvm::Function *FN, - const FunctionDecl *FD = nullptr, - CodeGenFunction *CGF = nullptr); + /// \param OFD is a pointer to the outlined function if we are generating a + /// SYCL offload kernel. + void GenKernelArgMetadata(llvm::Function *FN, const Decl *D = nullptr, + CodeGenFunction *CGF = nullptr, + const OutlinedFunctionDecl *OFD = nullptr); /// Get target specific null pointer. /// \param T is the LLVM type of the null pointer. @@ -1978,6 +1985,16 @@ class CodeGenModule : public CodeGenTypeCache { /// .gcda files in a way that persists in .bc files. void EmitCoverageFile(); + /// Emit the offload kernel. + void EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn, + ASTContext &Ctx); + + /// Initialize the global variables corresponding to SYCL Builtins used to + /// obtain information about the offload kernel. + void + InitSYCLKernelInfoSymbolsForBuiltins(const FunctionDecl *KernelEntryPointFn, + ASTContext &Ctx); + /// Determine whether the definition must be emitted; if this returns \c /// false, the definition can be emitted lazily if it's used. bool MustBeEmitted(const ValueDecl *D); diff --git a/clang/lib/CodeGen/CodeGenSYCL.cpp b/clang/lib/CodeGen/CodeGenSYCL.cpp new file mode 100644 index 0000000000000..77d78410f772c --- /dev/null +++ b/clang/lib/CodeGen/CodeGenSYCL.cpp @@ -0,0 +1,114 @@ +//===--------- CodeGenSYCL.cpp - Code for SYCL kernel generation ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This contains code required for SYCL kernel generation. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" + +using namespace clang; +using namespace CodeGen; + +static void SetSYCLKernelAttributes(llvm::Function *Fn, + const CGFunctionInfo &FnInfo, + CodeGenFunction &CGF) { + Fn->setDoesNotRecurse(); + if (CGF.checkIfFunctionMustProgress()) + Fn->addFnAttr(llvm::Attribute::MustProgress); +} + +static CanQualType GetKernelNameType(const FunctionDecl *KernelEntryPointFn, + ASTContext &Ctx) { + const auto *KernelEntryPointAttr = + KernelEntryPointFn->getAttr(); + assert(KernelEntryPointAttr && "Missing sycl_kernel_entry_point attribute"); + CanQualType KernelNameType = + Ctx.getCanonicalType(KernelEntryPointAttr->getKernelName()); + return KernelNameType; +} + +static const SYCLKernelInfo * +GetKernelInfo(const FunctionDecl *KernelEntryPointFn, ASTContext &Ctx) { + CanQualType KernelNameType = GetKernelNameType(KernelEntryPointFn, Ctx); + const SYCLKernelInfo *KernelInfo = Ctx.findSYCLKernelInfo(KernelNameType); + assert(KernelInfo && "Type does not correspond to a kernel name"); + return KernelInfo; +} + +void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn, + ASTContext &Ctx) { + assert(KernelEntryPointFn->getAttr() && + "Missing sycl_kernel_entry_point attribute"); + assert(!KernelEntryPointFn->getAttr() + ->isInvalidAttr() && + "sycl_kernel_entry_point attribute is invalid"); + + SYCLKernelCallStmt *KernelCallStmt = + dyn_cast(KernelEntryPointFn->getBody()); + assert(KernelCallStmt && "SYCLKernelCallStmt must exist"); + + // Build Kernel Arguments from OutlinedFunctionDecl + FunctionArgList Args; + const OutlinedFunctionDecl *OutlinedFnDecl = + KernelCallStmt->getOutlinedFunctionDecl(); + Args.append(OutlinedFnDecl->param_begin(), OutlinedFnDecl->param_end()); + + // Compute the function info and LLVM Type + const CGFunctionInfo &FnInfo = + getTypes().arrangeSYCLKernelCallerDeclaration(Ctx.VoidTy, Args); + llvm::FunctionType *FnTy = getTypes().GetFunctionType(FnInfo); + + // Retrieve the generated name for the SYCL kernel caller function + const SYCLKernelInfo *KernelInfo = GetKernelInfo(KernelEntryPointFn, Ctx); + auto *Fn = llvm::Function::Create(FnTy, llvm::Function::ExternalLinkage, + KernelInfo->GetKernelName(), &getModule()); + + // Emit the SYCL kernel caller function + CodeGenFunction CGF(*this); + SetLLVMFunctionAttributes(GlobalDecl(), FnInfo, Fn, false); + SetSYCLKernelAttributes(Fn, FnInfo, CGF); + CGF.StartFunction(GlobalDecl(), Ctx.VoidTy, Fn, FnInfo, Args, + SourceLocation(), SourceLocation(), OutlinedFnDecl); + CGF.EmitFunctionBody(OutlinedFnDecl->getBody()); + setDSOLocal(Fn); + SetLLVMFunctionAttributesForDefinition(cast(OutlinedFnDecl), Fn); + CGF.FinishFunction(); +} + +void CodeGenModule::AddSYCLKernelNameSymbol(CanQualType KernelNameType, + llvm::GlobalVariable *GV) { + SYCLKernelNameSymbols[KernelNameType] = GV; +} + +llvm::GlobalVariable * +CodeGenModule::GetSYCLKernelNameSymbol(CanQualType KernelNameType) { + auto it = SYCLKernelNameSymbols.find(KernelNameType); + if (it != SYCLKernelNameSymbols.end()) + return it->second; + return nullptr; +} + +void CodeGenModule::InitSYCLKernelInfoSymbolsForBuiltins( + const FunctionDecl *KernelEntryPointFn, ASTContext &Ctx) { + CanQualType KernelNameType = GetKernelNameType(KernelEntryPointFn, Ctx); + llvm::GlobalVariable *GV = GetSYCLKernelNameSymbol(KernelNameType); + if (GV && !GV->hasInitializer()) { + const SYCLKernelInfo *KernelInfo = GetKernelInfo(KernelEntryPointFn, Ctx); + ConstantAddress KernelNameStrConstantAddr = + GetAddrOfConstantCString(KernelInfo->GetKernelName(), ""); + llvm::Constant *KernelNameStr = KernelNameStrConstantAddr.getPointer(); + // FIXME: It is unclear to me whether the right API here is + // replaceInitializer or setInitializer. Unfortunately since the branch I am + // working on is outdated, my workspace does not have replaceInitializer + // Hopefully the person continuing to work on builtins can check this out. + GV->setInitializer(KernelNameStr); + GV->setLinkage(llvm::GlobalValue::PrivateLinkage); + } +} diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h index 5aebf9a212237..aac0c20aaa933 100644 --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -229,6 +229,12 @@ class CodeGenTypes { const CGFunctionInfo &arrangeBuiltinFunctionCall(QualType resultType, const CallArgList &args); + /// A SYCL device kernel function is a free standing function with + /// spir_kernel calling convention + const CGFunctionInfo & + arrangeSYCLKernelCallerDeclaration(QualType resultType, + const FunctionArgList &args); + /// Objective-C methods are C functions with some implicit parameters. const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD); const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD, diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 64a9a5554caf7..dc10d1f28607f 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -103,7 +103,8 @@ TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, Opt += Lib; } -unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const { +unsigned +TargetCodeGenInfo::getOpenCLKernelCallingConv(CodeGenModule &CGM) const { // OpenCL kernels are called via an explicit runtime API with arguments // set with clSetKernelArg(), not as normal sub-functions. // Return SPIR_KERNEL by default as the kernel calling convention to diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 86057c14a549e..ba0a3e4773657 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -295,7 +295,8 @@ class TargetCodeGenInfo { llvm::SmallString<32> &Opt) const {} /// Get LLVM calling convention for OpenCL kernel. - virtual unsigned getOpenCLKernelCallingConv() const; + virtual unsigned + getOpenCLKernelCallingConv(CodeGen::CodeGenModule &CGM) const; /// Get target specific null pointer. /// \param T is the LLVM type of the null pointer. diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 9d29f31c77881..72299f8c6a1de 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -309,7 +309,7 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; - unsigned getOpenCLKernelCallingConv() const override; + unsigned getOpenCLKernelCallingConv(CodeGen::CodeGenModule &M) const override; llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const override; @@ -470,7 +470,8 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( F->addFnAttr("amdgpu-ieee", "false"); } -unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const { +unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv( + CodeGen::CodeGenModule &M) const { return llvm::CallingConv::AMDGPU_KERNEL; } diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index f617e645a9eaf..8bb3f3f65d90f 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -77,6 +77,13 @@ class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo { return true; } + unsigned getOpenCLKernelCallingConv(CodeGenModule &CGM) const override { + if (CGM.getLangOpts().SYCLIsDevice) + return llvm::CallingConv::C; + else + return llvm::CallingConv::SPIR_KERNEL; + } + // Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the // resulting MDNode to the nvvm.annotations MDNode. static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name, diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp index c94db31ae1a89..6008e4595da02 100644 --- a/clang/lib/CodeGen/Targets/SPIR.cpp +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -50,7 +50,7 @@ class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo { getABIInfo().getDataLayout().getAllocaAddrSpace()); } - unsigned getOpenCLKernelCallingConv() const override; + unsigned getOpenCLKernelCallingConv(CodeGenModule &CGM) const override; llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override; llvm::Type *getHLSLType( CodeGenModule &CGM, const Type *Ty, @@ -216,7 +216,8 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { } } -unsigned CommonSPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { +unsigned CommonSPIRTargetCodeGenInfo::getOpenCLKernelCallingConv( + CodeGenModule &CGM) const { return llvm::CallingConv::SPIR_KERNEL; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 9cac9cf5c4df7..c1e1985454276 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2105,6 +2105,26 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { return false; } +// The argument must be a class or struct with a member +// named type. +static bool CheckBuiltinSyclKernelName(Sema &S, CallExpr *TheCall) { + QualType ArgTy = TheCall->getArg(0)->getType(); + const auto *RT = ArgTy->getAs(); + + if(!RT) + return true; + + RecordDecl *RD = RT->getDecl(); + IdentifierTable &IdentTable = S.Context.Idents; + auto Name = DeclarationName(&(IdentTable.get("type"))); + DeclContext::lookup_result Lookup = RD->lookup(Name); + if (Lookup.empty() || !Lookup.isSingleResult() || + !isa(Lookup.front())) + return true; + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -2951,6 +2971,55 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } break; } + case Builtin::BI__builtin_sycl_kernel_name: + case Builtin::BI__builtin_sycl_kernel_param_count: + case Builtin::BI__builtin_sycl_kernel_file_name: + case Builtin::BI__builtin_sycl_kernel_function_name: + case Builtin::BI__builtin_sycl_kernel_line_number: + case Builtin::BI__builtin_sycl_kernel_column_number: { + // Builtin takes 1 argument + if (TheCall->getNumArgs() != 1) { + Diag(TheCall->getBeginLoc(), diag::err_builtin_invalid_argument_count) + << 1; + return ExprError(); + } + + if (CheckBuiltinSyclKernelName(*this, TheCall)) { + Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_sycl_kernel_name_invalid_arg); + return ExprError(); + } + + break; + } + case Builtin::BI__builtin_sycl_kernel_param_kind: + case Builtin::BI__builtin_sycl_kernel_param_offset: + case Builtin::BI__builtin_sycl_kernel_param_size: + case Builtin::BI__builtin_sycl_kernel_param_access_target: { + // Builtin takes 1 argument + if (TheCall->getNumArgs() != 2) { + Diag(TheCall->getBeginLoc(), diag::err_builtin_invalid_argument_count) + << 2; + return ExprError(); + } + + if (CheckBuiltinSyclKernelName(*this, TheCall)) { + Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_sycl_kernel_name_invalid_arg); + return ExprError(); + } + + const Expr *Arg = TheCall->getArg(1); + QualType ArgTy = Arg->getType(); + + if (!ArgTy->isIntegerType()) { + Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 2 << /* integer ty */ 8 << ArgTy; + return ExprError(); + } + + break; + } case Builtin::BI__builtin_popcountg: if (BuiltinPopcountg(*this, TheCall)) return ExprError(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ddd92782366b5..e1ba1c41c178a 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -10,6 +10,7 @@ #include "clang/Sema/SemaSYCL.h" #include "TreeTransform.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" #include "clang/AST/SYCLKernelInfo.h" #include "clang/AST/StmtSYCL.h" diff --git a/clang/test/CodeGenSYCL/builtin-sycl-kernel-name.cpp b/clang/test/CodeGenSYCL/builtin-sycl-kernel-name.cpp new file mode 100644 index 0000000000000..d5d596aea2d3f --- /dev/null +++ b/clang/test/CodeGenSYCL/builtin-sycl-kernel-name.cpp @@ -0,0 +1,102 @@ +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64 %s -o - | FileCheck %s + +// Test IR generated by __builtin_sycl_kernel_name(). This builtin accepts a SYCL +// kernel name type and returns it's mangled name. + +class kernel_name_1; +class kernel_name_2; +typedef kernel_name_2 kernel_name_TD; +class kernel_name_3; +class kernel_name_4; +class kernel_name_5; +typedef kernel_name_4 kernel_name_TD2; +class kernel_name_6; + +struct constexpr_kernel_name; + +template +struct kernel_id_t { + using type = KN; +}; + +struct kernel_id_nt { + using type = kernel_name_3; +}; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +template +void test_template() { + SYCLKernel Obj; + kernel_single_task(Obj); + const char* test6 = __builtin_sycl_kernel_name(kernel_id_t()); + constexpr const char* test7 = __builtin_sycl_kernel_name(kernel_id_t()); +} + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + const char* test1 = __builtin_sycl_kernel_name(kernel_id_t()); + const char* test2 = __builtin_sycl_kernel_name(kernel_id_t()); + const char* test3 = __builtin_sycl_kernel_name(kernel_id_nt()); + const char* test4 = __builtin_sycl_kernel_name(kernel_id_t()); + constexpr const char* test5 = __builtin_sycl_kernel_name(kernel_id_t()); + test_template(); +} + +void testBuiltinBeforeKernelInvocation2(); + +void testBuiltinBeforeKernelInvocation1() { + const char* testBefore1 = __builtin_sycl_kernel_name(kernel_id_t()); +} + +void testBuiltinBeforeKernelInvocation2() { + SYCLKernel Obj; + kernel_single_task(Obj); + testBuiltinBeforeKernelInvocation2(); +} + +// Kernel names retrieved from KernelInfo map +// CHECK: @0 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_1Evv\00", align 1 +// CHECK: @1 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_2Evv\00", align 1 +// CHECK: @2 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_3Evv\00", align 1 +// CHECK: @3 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_4Evv\00", align 1 +// CHECK: @.str = private unnamed_addr constant [52 x i8] c"_Z20__sycl_kernel_callerI21constexpr_kernel_nameEvv\00", align 1 +// CHECK: @_Z20__sycl_kernel_callerI13kernel_name_6Evv = private constant ptr @[[INIT:[0-9]+]] +// CHECK: @4 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_5Evv\00", align 1 +// CHECK: @[[INIT]] = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_6Evv\00", align 1 + +// CHECK: define dso_local void @_Z4testv() +// CHECK: %test1 = alloca ptr, align 8 +// CHECK: %test2 = alloca ptr, align 8 +// CHECK: %test3 = alloca ptr, align 8 +// CHECK: %test4 = alloca ptr, align 8 +// CHECK: %test5 = alloca ptr, align 8 +// CHECK: store ptr @0, ptr %test1, align 8 +// CHECK: store ptr @1, ptr %test2, align 8 +// CHECK: store ptr @2, ptr %test3, align 8 +// CHECK: store ptr @3, ptr %test4, align 8 +// CHECK: store ptr @.str, ptr %test5, align 8 + +// CHECK: define linkonce_odr void @_Z13test_templateI13kernel_name_5Evv() +// CHECK: %test6 = alloca ptr, align 8 +// CHECK: %test7 = alloca ptr, align 8 +// CHECK: store ptr @4, ptr %test6, align 8 +// CHECK: store ptr @4, ptr %test7, align 8 + +// CHECK: define dso_local void @_Z34testBuiltinBeforeKernelInvocation1v() +// CHECK: %testBefore1 = alloca ptr, align 8 +// CHECK: store ptr @_Z20__sycl_kernel_callerI13kernel_name_6Evv, ptr %testBefore1, align 8 diff --git a/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-count.cpp b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-count.cpp new file mode 100644 index 0000000000000..95dc29013e03f --- /dev/null +++ b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-count.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64 %s -o - | FileCheck %s + +// Test IR generated by __builtin_sycl_kernel_param_count(). This builtin accepts +// a SYCL kernel name type and returns the number of parameters in its corresponding +// offload kernel. + +class kernel_name_1; +class kernel_name_2; +class single_purpose_kernel_name; + +template +struct kernel_id_t { + using type = KN; +}; + +struct constexpr_kernel_name; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +// Overloading kernel_single_task +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc, int a) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +__attribute__((sycl_kernel_entry_point(single_purpose_kernel_name))) +void single_purpose_kernel_task(SYCLKernel kernelFunc, int a, int b) { + kernelFunc(); +} + + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj, 1); + single_purpose_kernel_task(Obj, 1, 2); + kernel_single_task(Obj, 1); + int test1 = __builtin_sycl_kernel_param_count(kernel_id_t()); // Returns 1 as corresponding entry point function has 1 argument + int test2 = __builtin_sycl_kernel_param_count(kernel_id_t()); // Returns 2 as corresponding entry point function has 2 arguments + int test3 = __builtin_sycl_kernel_param_count(kernel_id_t()); // Returns 3 as corresponding entry point function has 3 arguments + constexpr const int test4 = __builtin_sycl_kernel_param_count(kernel_id_t()); // Returns 2 as corresponding entry point function has 2 arguments +} + +// CHECK: define dso_local void @_Z4testv() +// CHECK: %test1 = alloca i32, align 4 +// CHECK: %test2 = alloca i32, align 4 +// CHECK: %test3 = alloca i32, align 4 +// CHECK: %test4 = alloca i32, align 4 +// CHECK: store i32 1, ptr %test1, align 4 +// CHECK: store i32 2, ptr %test2, align 4 +// CHECK: store i32 3, ptr %test3, align 4 +// CHECK: store i32 2, ptr %test4, align 4 + diff --git a/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-kind.cpp b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-kind.cpp new file mode 100644 index 0000000000000..1ba8d31f1e92b --- /dev/null +++ b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-kind.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64 %s -o - | FileCheck %s + +// Test IR generated by __builtin_sycl_kernel_param_kind(). This builtin accepts +// a SYCL kernel name type and parameter index. It returns the parameter 'kind' of +// the correponding parameter in the generated offload kernel. + +class kernel_name_1; +class kernel_name_2; +class single_purpose_kernel_name; + +template +struct kernel_id_t { + using type = KN; +}; + +struct constexpr_kernel_name; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +// Overloading kernel_single_task +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc, int a) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +__attribute__((sycl_kernel_entry_point(single_purpose_kernel_name))) +void single_purpose_kernel_task(SYCLKernel kernelFunc, int a, int b) { + kernelFunc(); +} + + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj, 1); + single_purpose_kernel_task(Obj, 1, 2); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_kind(kernel_id_t(), 0); + int test2 = __builtin_sycl_kernel_param_kind(kernel_id_t(), 1); + int test3 = __builtin_sycl_kernel_param_kind(kernel_id_t(),2); + constexpr const int test4 = __builtin_sycl_kernel_param_kind(kernel_id_t(), 0); +} + +// CHECK: define dso_local void @_Z4testv() +// CHECK: %test1 = alloca i32, align 4 +// CHECK: %test2 = alloca i32, align 4 +// CHECK: %test3 = alloca i32, align 4 +// CHECK: %test4 = alloca i32, align 4 +// CHECK: store i32 1, ptr %test1, align 4 +// CHECK: store i32 1, ptr %test2, align 4 +// CHECK: store i32 1, ptr %test3, align 4 +// CHECK: store i32 1, ptr %test4, align 4 + diff --git a/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-offset.cpp b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-offset.cpp new file mode 100644 index 0000000000000..c0d4ec83b7411 --- /dev/null +++ b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-offset.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64 %s -o - | FileCheck %s + +// Test IR generated by __builtin_sycl_kernel_param_offset(). This builtin accepts +// a SYCL kernel name type and parameter index. It returns the offset of the +// corresponding parameter in the SYCL kernel object. Currently, with no support of +// SYCL special types or decomposition, this is always 0. + + +class kernel_name_1; +class kernel_name_2; +class single_purpose_kernel_name; + +template +struct kernel_id_t { + using type = KN; +}; + +struct constexpr_kernel_name; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +// Overloading kernel_single_task +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc, int a) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +__attribute__((sycl_kernel_entry_point(single_purpose_kernel_name))) +void single_purpose_kernel_task(SYCLKernel kernelFunc, int a, int b) { + kernelFunc(); +} + + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj, 1); + single_purpose_kernel_task(Obj, 1, 2); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_offset(kernel_id_t(), 0); + int test2 = __builtin_sycl_kernel_param_offset(kernel_id_t(), 1); + int test3 = __builtin_sycl_kernel_param_offset(kernel_id_t(),2); + constexpr const int test4 = __builtin_sycl_kernel_param_offset(kernel_id_t(), 0); +} + +// CHECK: define dso_local void @_Z4testv() +// CHECK: %test1 = alloca i32, align 4 +// CHECK: %test2 = alloca i32, align 4 +// CHECK: %test3 = alloca i32, align 4 +// CHECK: %test4 = alloca i32, align 4 +// CHECK: store i32 0, ptr %test1, align 4 +// CHECK: store i32 0, ptr %test2, align 4 +// CHECK: store i32 0, ptr %test3, align 4 +// CHECK: store i32 0, ptr %test4, align 4 + diff --git a/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-size.cpp b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-size.cpp new file mode 100644 index 0000000000000..5dac99de26f65 --- /dev/null +++ b/clang/test/CodeGenSYCL/builtin-sycl-kernel-param-size.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64 %s -o - | FileCheck %s + +// Test IR generated by __builtin_sycl_kernel_param_size(). This builtin accepts +// a SYCL kernel name type and parameter index. It returns the parameter size of +// the corresponding parameter in the generated offload kernel. + +class kernel_name_1; +class kernel_name_2; +class single_purpose_kernel_name; + +template +struct kernel_id_t { + using type = KN; +}; + +struct constexpr_kernel_name; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +// Overloading kernel_single_task +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc, int a) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + float n; + public: + void operator()() const {} +}; + +__attribute__((sycl_kernel_entry_point(single_purpose_kernel_name))) +void single_purpose_kernel_task(SYCLKernel kernelFunc, int a, long b) { + kernelFunc(); +} + + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj, 1); + single_purpose_kernel_task(Obj, 1, 2); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_size(kernel_id_t(), 0); + int test2 = __builtin_sycl_kernel_param_size(kernel_id_t(), 1); + int test3 = __builtin_sycl_kernel_param_size(kernel_id_t(),2); + constexpr const int test4 = __builtin_sycl_kernel_param_size(kernel_id_t(), 0); +} + +// CHECK: define dso_local void @_Z4testv() +// CHECK: %test1 = alloca i32, align 4 +// CHECK: %test2 = alloca i32, align 4 +// CHECK: %test3 = alloca i32, align 4 +// CHECK: %test4 = alloca i32, align 4 +// CHECK: store i32 8, ptr %test1, align 4 +// CHECK: store i32 4, ptr %test2, align 4 +// CHECK: store i32 8, ptr %test3, align 4 +// CHECK: store i32 8, ptr %test4, align 4 + diff --git a/clang/test/CodeGenSYCL/debug-info-kernel-variables.cpp b/clang/test/CodeGenSYCL/debug-info-kernel-variables.cpp index 96c0dcfdb75b6..52a146251f16d 100644 --- a/clang/test/CodeGenSYCL/debug-info-kernel-variables.cpp +++ b/clang/test/CodeGenSYCL/debug-info-kernel-variables.cpp @@ -11,10 +11,10 @@ // space. // -#define KERNEL __attribute__((sycl_kernel)) +#define KERNEL(Name) __attribute__((sycl_kernel_entry_point(Name))) template -KERNEL void parallel_for(const KernelType &KernelFunc) { +KERNEL(KernelName) void parallel_for(const KernelType &KernelFunc) { KernelFunc(); } diff --git a/clang/test/CodeGenSYCL/function-attrs.cpp b/clang/test/CodeGenSYCL/function-attrs.cpp index 83a77a617240a..3a9955bbc6aab 100644 --- a/clang/test/CodeGenSYCL/function-attrs.cpp +++ b/clang/test/CodeGenSYCL/function-attrs.cpp @@ -1,4 +1,3 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals --version 3 // RUN: %clang_cc1 -fsycl-is-device -disable-llvm-passes \ // RUN: -triple spir64 -fexceptions -emit-llvm -fno-ident %s -o - | FileCheck %s @@ -29,28 +28,12 @@ int foo() { } template -__attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) { +__attribute__((sycl_kernel_entry_point(Name))) void kernel_single_task(const Func &kernelFunc) { kernelFunc(); } -// CHECK-LABEL: define dso_local noundef i32 @main( -// CHECK-SAME: ) #[[ATTR0]] { -// CHECK-NEXT: entry: -// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 1 -// CHECK-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr [[RETVAL]] to ptr addrspace(4) -// CHECK-NEXT: [[REF_TMP_ASCAST:%.*]] = addrspacecast ptr [[REF_TMP]] to ptr addrspace(4) -// CHECK-NEXT: store i32 0, ptr addrspace(4) [[RETVAL_ASCAST]], align 4 -// CHECK-NEXT: call spir_func void @_Z18kernel_single_taskIZ4mainE11fake_kernelZ4mainEUlvE_EvRKT0_(ptr addrspace(4) noundef align 1 dereferenceable(1) [[REF_TMP_ASCAST]]) #[[ATTR1]] -// CHECK-NEXT: ret i32 0 -// int main() { kernel_single_task([] { bar(); }); return 0; } -//. -// CHECK: attributes #0 = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } -// CHECK: attributes #1 = { convergent nounwind } -//. -// CHECK: !0 = !{i32 1, !"wchar_size", i32 4} -//. +// CHECK: attributes #[[ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } diff --git a/clang/test/CodeGenSYCL/functionptr-addrspace.cpp b/clang/test/CodeGenSYCL/functionptr-addrspace.cpp index a477b4c7d03ab..a652ba9132ca6 100644 --- a/clang/test/CodeGenSYCL/functionptr-addrspace.cpp +++ b/clang/test/CodeGenSYCL/functionptr-addrspace.cpp @@ -3,7 +3,7 @@ // expected-no-diagnostics template -__attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) { +__attribute__((sycl_kernel_entry_point(Name))) void kernel_single_task(const Func &kernelFunc) { kernelFunc(); } diff --git a/clang/test/CodeGenSYCL/kernel-caller-generation.cpp b/clang/test/CodeGenSYCL/kernel-caller-generation.cpp new file mode 100644 index 0000000000000..9e22ad0b09162 --- /dev/null +++ b/clang/test/CodeGenSYCL/kernel-caller-generation.cpp @@ -0,0 +1,129 @@ +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -triple spir64 %s -o - | FileCheck --check-prefix=CHECK-SPIR %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -triple nvptx %s -o - | FileCheck --check-prefix=CHECK-NVPTX %s +// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -triple amdgcn %s -o - | FileCheck --check-prefix=CHECK-AMDGCN %s +// RUN: %clang_cc1 -fsycl-is-host -emit-llvm -triple x86_64 %s -o - | FileCheck --check-prefix=CHECK-HOST %s + +// Test the generation of SYCL kernel caller function. SYCL kernel caller function +// should not be generated during host compilation. + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct single_purpose_kernel_name; +struct single_purpose_kernel { + void operator()() const; +}; + +__attribute__((sycl_kernel_entry_point(single_purpose_kernel_name))) +void single_purpose_kernel_task(single_purpose_kernel kernelFunc) { + kernelFunc(); +} + +int main() { + int capture; + kernel_single_task( + [=]() { + (void) capture; + }); + single_purpose_kernel obj; + single_purpose_kernel_task(obj); +} + +// Verify that no SYCL kernel caller functions are generated for the host. +// CHECK-HOST-NOT: __sycl_kernel_caller + +// Verify that no code is generated for the body of the SYCL kernel entry point +// functions on the host. These functions are used to trigger emission of SYCL +// kernel caller functions on the device; calls to them on the host are intended +// to have no other effect (the body of these functions define a pattern for +// code to be executed on the device). +// +// CHECK-HOST: define dso_local void @_Z26single_purpose_kernel_task21single_purpose_kernel() #0 { +// CHECK-HOST-NEXT: entry: +// CHECK-HOST-NEXT: %kernelFunc = alloca %struct.single_purpose_kernel, align 1 +// CHECK-HOST-NEXT: ret void +// CHECK-HOST-NEXT: } +// +// CHECK-HOST: define internal void @_Z18kernel_single_taskIZ4mainE11test_kernelZ4mainEUlvE_EvT0_(i32 %kernelFunc.coerce) #0 { +// CHECK-HOST-NEXT: entry: +// CHECK-HOST-NEXT: %kernelFunc = alloca %class.anon, align 4 +// CHECK-HOST-NEXT: %coerce.dive = getelementptr inbounds nuw %class.anon, ptr %kernelFunc, i32 0, i32 0 +// CHECK-HOST-NEXT: store i32 %kernelFunc.coerce, ptr %coerce.dive, align 4 +// CHECK-HOST-NEXT: ret void +// CHECK-HOST-NEXT: } + +// FIXME: A match on the next two lines is done to enable skipping over the +// FIXME: declaration of main(). main() shouldn't be emitted in device code, +// FIXME: but that pruning isn't performed yet. Remove these two checks +// FIXME: once it is. +// CHECK-SPIR: Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +// CHECK-SPIR-NEXT: define dso_local noundef i32 @main() #0 +// CHECK-NVPTX: Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +// CHECK-NVPTX-NEXT: define dso_local noundef i32 @main() #0 +// CHECK-AMDGCN: Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +// CHECK-AMDGCN-NEXT: define dso_local noundef i32 @main() #0 + +// IR for compiler generated SYCL kernel caller function corresponding to +// single_purpose_kernel_name: + +// CHECK-SPIR: Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +// CHECK-SPIR-NEXT: define dso_local spir_kernel void @_Z20__sycl_kernel_callerI26single_purpose_kernel_nameEvv +// CHECK-SPIR-SAME: (ptr noundef byval(%struct.single_purpose_kernel) align 1 %kernelFunc) #[[ATTR0:[0-9]+]] +// CHECK-SPIR-SAME: !kernel_arg_addr_space ![[ADDRSP:[0-9]+]] !kernel_arg_access_qual ![[ACCQUAL:[0-9]+]] +// CHECK-SPIR-SAME: !kernel_arg_type ![[ARGTY1:[0-9]+]] !kernel_arg_base_type ![[ARGBASETY1:[0-9]+]] +// CHECK-SPIR-SAME: !kernel_arg_type_qual ![[ARGTYQUAL:[0-9]+]] +// CHECK-SPIR-NEXT: entry: +// CHECK-SPIR-NEXT: %kernelFunc.ascast = addrspacecast ptr %kernelFunc to ptr addrspace(4) +// CHECK-SPIR-NEXT: call spir_func void @_ZNK21single_purpose_kernelclEv +// CHECK-SPIR-SAME: (ptr addrspace(4) noundef align 1 dereferenceable_or_null(1) %kernelFunc.ascast) #[[ATTR1:[0-9]+]] +// CHECK-SPIR-NEXT: ret void +// CHECK-SPIR-NEXT: } + +// CHECK-NVPTX: define dso_local void @_Z20__sycl_kernel_callerI26single_purpose_kernel_nameEvv +// CHECK-AMDGCN: define dso_local amdgpu_kernel void @_Z20__sycl_kernel_callerI26single_purpose_kernel_nameEvv + +// IR for compiler generated SYCL kernel caller function corresponding to +// test_kernel: + +// CHECK-SPIR: Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +// CHECK-SPIR-NEXT: define dso_local spir_kernel void @_Z20__sycl_kernel_callerIZ4mainE11test_kernelEvv +// CHECK-SPIR-SAME: (ptr noundef byval(%class.anon) align 4 %kernelFunc) #[[ATTR0]] +// CHECK-SPIR-SAME: !kernel_arg_addr_space ![[ADDRSP]] !kernel_arg_access_qual ![[ACCQUAL]] +// CHECK-SPIR-SAME: !kernel_arg_type ![[ARGTY2:[0-9]+]] !kernel_arg_base_type ![[ARGBASETY2:[0-9]+]] +// CHECK-SPIR-SAME: !kernel_arg_type_qual ![[ARGTYQUAL]] +// CHECK-SPIR-NEXT: entry: +// CHECK-SPIR-NEXT: %kernelFunc.ascast = addrspacecast ptr %kernelFunc to ptr addrspace(4) +// CHECK-SPIR-NEXT: call spir_func void @_ZZ4mainENKUlvE_clEv +// CHECK-SPIR-SAME: (ptr addrspace(4) noundef align 4 dereferenceable_or_null(4) %kernelFunc.ascast) #[[ATTR1]] +// CHECK-SPIR-NEXT: ret void +// CHECK-SPIR-NEXT: } + +// CHECK-NVPTX: define dso_local void @_Z20__sycl_kernel_callerIZ4mainE11test_kernelEvv +// CHECK-AMDGCN: define dso_local amdgpu_kernel void @_Z20__sycl_kernel_callerIZ4mainE11test_kernelEvv + +// IR for operator method of kernel object: + +// CHECK-SPIR: define internal spir_func void @_ZZ4mainENKUlvE_clEv +// CHECK-SPIR-SAME: (ptr addrspace(4) noundef align 4 dereferenceable_or_null(4) %this) #[[ATTR0]] align 2 { +// CHECK-SPIR-NEXT: entry: +// CHECK-SPIR-NEXT: %this.addr = alloca ptr addrspace(4), align 8 +// CHECK-SPIR-NEXT: %this.addr.ascast = addrspacecast ptr %this.addr to ptr addrspace(4) +// CHECK-SPIR-NEXT: store ptr addrspace(4) %this, ptr addrspace(4) %this.addr.ascast, align 8 +// CHECK-SPIR-NEXT: %this1 = load ptr addrspace(4), ptr addrspace(4) %this.addr.ascast, align 8 +// CHECK-SPIR-NEXT: %[[CAPTURE:.+]] = getelementptr inbounds nuw %class.anon, ptr addrspace(4) %this1, i32 0, i32 0 +// CHECK-SPIR-NEXT: ret void +// CHECK-SPIR-NEXT: } + +// CHECK-NVPTX: define internal void @_ZZ4mainENKUlvE_clEv +// CHECK-AMDGCN: define internal void @_ZZ4mainENKUlvE_clEv + +// CHECK-SPIR: #[[ATTR0]] = { convergent mustprogress noinline norecurse nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK-SPIR: #[[ATTR1]] = { convergent nounwind } + +// CHECK-SPIR: ![[ADDRSP]] = !{i32 0} +// CHECK-SPIR: ![[ACCQUAL]] = !{!"none"} +// CHECK-SPIR: ![[ARGTY1]] = !{!"single_purpose_kernel"} +// CHECK-SPIR: ![[ARGTYQUAL]] = !{!""} +// CHECK-SPIR: ![[ARGTY2]] = !{!"(lambda at diff --git a/clang/test/CodeGenSYCL/kernel-caller-names.cpp b/clang/test/CodeGenSYCL/kernel-caller-names.cpp new file mode 100644 index 0000000000000..efb5570e569ed --- /dev/null +++ b/clang/test/CodeGenSYCL/kernel-caller-names.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-llvm -triple spir -aux-triple x86_64-linux-gnu %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-llvm -triple spir -aux-triple x86_64-pc-windows-msvc %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-llvm -triple spir64 -aux-triple x86_64-linux-gnu %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-llvm -triple spir64 -aux-triple x86_64-pc-windows-msvc %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-llvm -triple nvptx -aux-triple x86_64-linux-gnu %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-llvm -triple nvptx -aux-triple x86_64-pc-windows-msvc %s -o - | FileCheck %s + +// use_default_kernel_name is used as a tag type to opt in to use of the +// kernel type as the kernel name. +struct use_default_kernel_name; +template +struct kernel_name { + using type = KN; +}; +template +struct kernel_name { + using type = KT; +}; +template +using kernel_name_t = typename kernel_name::type; + +template +__attribute__((sycl_kernel_entry_point(kernel_name_t))) +void skep(KT k) { + k(); +} + +auto gl1 = []{}; +auto gl2 = []{}; +struct GF1 { + void operator()() const {} +}; +struct explicit_kernel_name; + +// Validate SYCL kernel caller names generated for kernel name types +// declared at namespace scope. +void ok1() { + skep(gl1); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIUlvE_Evv{{.*}} { + skep(gl2); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIUlvE0_Evv{{.*}} { + skep(GF1{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerI3GF1Evv{{.*}} { + skep([]{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerI20explicit_kernel_nameEvv{{.*}} { +} + +// Validate SYCL kernel caller names generated for kernel name types +// declared at block scope. +void ok2() { + auto ll1 = []{}; + auto ll2 = []{}; + struct LF1 { + void operator()() const {} + }; + struct local_explicit_kernel_name {}; + + skep(ll1); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIZ3ok2vEUlvE_Evv{{.*}} { + skep(ll2); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIZ3ok2vEUlvE0_Evv{{.*}} { + skep(LF1{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIZ3ok2vE3LF1Evv{{.*}} { + skep([]{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIZ3ok2vE26local_explicit_kernel_nameEvv{{.*}} { +} + +// Validate SYCL kernel caller names generated for kernel name types +// that are cv-qualified. +void ok3() { + // The SYCL 2020 specification is not clear regarding whether the types used + // for kernel names may be cv-qualified. The following issue tracks clarifying + // the intent. + // - https://github.com/KhronosGroup/SYCL-Docs/issues/568 + struct kn {}; + skep([]{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIZ3ok3vE2knEvv{{.*}} { + skep([]{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIKZ3ok3vE2knEvv{{.*}} { + skep([]{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIVZ3ok3vE2knEvv{{.*}} { + skep([]{}); + // CHECK: define {{.*}} @_Z20__sycl_kernel_callerIVKZ3ok3vE2knEvv{{.*}} { +} diff --git a/clang/test/CodeGenSYCL/unique_stable_name.cpp b/clang/test/CodeGenSYCL/unique_stable_name.cpp index cc9dd61f435d7..ab419187e9d23 100644 --- a/clang/test/CodeGenSYCL/unique_stable_name.cpp +++ b/clang/test/CodeGenSYCL/unique_stable_name.cpp @@ -1,22 +1,23 @@ -// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -// CHECK: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00" -// CHECK: @[[INT1:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" -// CHECK: @[[STRING:[^\w]+]] = private unnamed_addr addrspace(1) constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00", -// CHECK: @[[INT2:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE]] c"_ZTSi\00" -// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00" -// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE0_\00" -// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE1_\00" -// CHECK: @{{.*}} = private unnamed_addr addrspace(1) constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE2_\00", align 1 -// CHECK: @{{.*}} = private unnamed_addr addrspace(1) constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE3_\00", align 1 -// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE4_\00" -// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE5_\00" -// CHECK: @[[INT3:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE]] c"_ZTSi\00" -// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00" -// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00", -// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_EvvEUlvE_\00", -// CHECK: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr addrspace(1) constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00", -// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00", -// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00", +// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-DEVICE +// RUN: %clang_cc1 -triple x86_64-linux-pc -fsycl-is-host -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-HOST +// CHECK-HOST: @[[LAMBDA_KERNEL3:[^\w]+]] = private unnamed_addr constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE_E_\00" +// CHECK-HOST: @[[INT1:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" +// CHECK-HOST: @[[STRING:[^\w]+]] = private unnamed_addr constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00", +// CHECK-DEVICE: @[[INT2:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" +// CHECK-DEVICE: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00" +// CHECK-DEVICE: @[[MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE0_\00" +// CHECK-DEVICE: @[[MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE1_\00" +// CHECK-DEVICE: @{{.*}} = private unnamed_addr addrspace(1) constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE2_\00", align 1 +// CHECK-DEVICE: @{{.*}} = private unnamed_addr addrspace(1) constant [32 x i8] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE3_\00", align 1 +// CHECK-DEVICE: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE4_\00" +// CHECK-DEVICE: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE5_\00" +// CHECK-DEVICE: @[[INT3:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE]] c"_ZTSi\00" +// CHECK-DEVICE: @[[LAMBDA:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE0_clEvEUlvE_\00" +// CHECK-DEVICE: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00", +// CHECK-DEVICE: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_EvvEUlvE_\00", +// CHECK-DEVICE: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr addrspace(1) constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00", +// CHECK-DEVICE: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00", +// CHECK-DEVICE: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00", extern "C" void puts(const char *) {} @@ -61,99 +62,99 @@ struct Derp { }; template -[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { +[[clang::sycl_kernel_entry_point(KernelName)]] void kernel_single_task(KernelType kernelFunc) { kernelFunc(); } int main() { kernel_single_task(func); - // CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(ptr noundef @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv) + // CHECK-HOST: call void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(ptr noundef @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv) auto l1 = []() { return 1; }; auto l2 = [](decltype(l1) *l = nullptr) { return 2; }; kernel_single_task(l2); puts(__builtin_sycl_unique_stable_name(decltype(l2))); - // CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_ - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_KERNEL3]] to ptr addrspace(4))) + // CHECK-HOST: call void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_ + // CHECK-HOST: call void @puts(ptr noundef @[[LAMBDA_KERNEL3]]) constexpr const char str[] = "lalala"; static_assert(__builtin_strcmp(__builtin_sycl_unique_stable_name(decltype(str)), "_ZTSA7_Kc\0") == 0, "unexpected mangling"); int i = 0; puts(__builtin_sycl_unique_stable_name(decltype(i++))); - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT1]] to ptr addrspace(4))) + // CHECK-HOST: call void @puts(ptr noundef @[[INT1]]) // FIXME: Ensure that j is incremented because VLAs are terrible. int j = 55; puts(__builtin_sycl_unique_stable_name(int[++j])); - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[STRING]] to ptr addrspace(4))) + // CHECK-HOST: call void @puts(ptr noundef @[[STRING]]) - // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_ - // CHECK: declare spir_func noundef ptr addrspace(4) @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv - // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_ - // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE6kernelZ4mainEUlvE0_EvT0_ + // CHECK-HOST: define internal void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_ + // CHECK-HOST: declare noundef ptr @_Z4funcI4DerpEDTu33__builtin_sycl_unique_stable_nameDtsrT_3strEEEv + // CHECK-HOST: define internal void @_Z18kernel_single_taskIZ4mainE7kernel3Z4mainEUlPZ4mainEUlvE_E_EvT0_ + // CHECK-HOST: define internal void @_Z18kernel_single_taskIZ4mainE6kernelZ4mainEUlvE0_EvT0_ kernel_single_task( []() { puts(__builtin_sycl_unique_stable_name(int)); - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT2]] to ptr addrspace(4))) + // CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT2]] to ptr addrspace(4))) auto x = []() {}; puts(__builtin_sycl_unique_stable_name(decltype(x))); - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_X]] to ptr addrspace(4))) + // CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_X]] to ptr addrspace(4))) DEF_IN_MACRO(); - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_X]] to ptr addrspace(4))) - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_Y]] to ptr addrspace(4))) + // CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_X]] to ptr addrspace(4))) + // CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_Y]] to ptr addrspace(4))) MACRO_CALLS_MACRO(); - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_MACRO_X]] to ptr addrspace(4))) - // CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_MACRO_Y]] to ptr addrspace(4))) + // CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_MACRO_X]] to ptr addrspace(4))) + // CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[MACRO_MACRO_Y]] to ptr addrspace(4))) template_param(); - // CHECK: call spir_func void @_Z14template_paramIiEvv + // CHECK-DEVICE: call spir_func void @_Z14template_paramIiEvv template_param(); - // CHECK: call spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv + // CHECK-DEVICE: call spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv lambda_in_dependent_function(); - // CHECK: call spir_func void @_Z28lambda_in_dependent_functionIiEvv + // CHECK-DEVICE: call spir_func void @_Z28lambda_in_dependent_functionIiEvv lambda_in_dependent_function(); - // CHECK: call spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv + // CHECK-DEVICE: call spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv lambda_no_dep(3, 5.5); - // CHECK: call spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 noundef 3, double noundef 5.500000e+00) + // CHECK-DEVICE: call spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 noundef 3, double noundef 5.500000e+00) int a = 5; double b = 10.7; auto y = [](int a) { return a; }; auto z = [](double b) { return b; }; lambda_two_dep(); - // CHECK: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv + // CHECK-DEVICE: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv lambda_two_dep(); - // CHECK: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv + // CHECK-DEVICE: call spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv }); } -// CHECK: define linkonce_odr spir_func void @_Z14template_paramIiEvv -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT3]] to ptr addrspace(4))) +// CHECK-DEVICE: define linkonce_odr spir_func void @_Z14template_paramIiEvv +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[INT3]] to ptr addrspace(4))) -// CHECK: define internal spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA]] to ptr addrspace(4))) +// CHECK-DEVICE: define internal spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA]] to ptr addrspace(4))) -// CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_IN_DEP_INT]] to ptr addrspace(4))) +// CHECK-DEVICE: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_IN_DEP_INT]] to ptr addrspace(4))) -// CHECK: define internal spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_IN_DEP_X]] to ptr addrspace(4))) +// CHECK-DEVICE: define internal spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_IN_DEP_X]] to ptr addrspace(4))) -// CHECK: define linkonce_odr spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 noundef %a, double noundef %b) -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_NO_DEP]] to ptr addrspace(4))) +// CHECK-DEVICE: define linkonce_odr spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 noundef %a, double noundef %b) +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_NO_DEP]] to ptr addrspace(4))) -// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_TWO_DEP]] to ptr addrspace(4))) +// CHECK-DEVICE: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_TWO_DEP]] to ptr addrspace(4))) -// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv -// CHECK: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_TWO_DEP2]] to ptr addrspace(4))) +// CHECK-DEVICE: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv +// CHECK-DEVICE: call spir_func void @puts(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @[[LAMBDA_TWO_DEP2]] to ptr addrspace(4))) diff --git a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp index 7dd08a0c89255..5bb5c2ad7ea02 100644 --- a/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp +++ b/clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp @@ -2,33 +2,11 @@ // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsycl-is-device -disable-llvm-passes -fsycl-is-device -emit-llvm %s -o - | FileCheck %s '-D$ADDRSPACE=' -template -__attribute__((sycl_kernel)) void kernel(Func F){ - F(); -} - -template -__attribute__((sycl_kernel)) void kernel2(Func F){ - F(1); -} - -template -__attribute__((sycl_kernel)) void kernel3(Func F){ - F(1.1); -} - int main() { - int i; - double d; - float f; auto lambda1 = [](){}; auto lambda2 = [](int){}; auto lambda3 = [](double){}; - kernel(lambda1); - kernel2(lambda2); - kernel3(lambda3); - // Ensure the kernels are named the same between the device and host // invocations. (void)__builtin_sycl_unique_stable_name(decltype(lambda1)); diff --git a/clang/test/SemaSYCL/builtin-sycl-kernel-name.cpp b/clang/test/SemaSYCL/builtin-sycl-kernel-name.cpp new file mode 100644 index 0000000000000..1881e4bf0bb8f --- /dev/null +++ b/clang/test/SemaSYCL/builtin-sycl-kernel-name.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s + +class kernel_name_1; +class kernel_name_2; +class kernel_name_3; +typedef kernel_name_3 kernel_name_TD; +class kernel_name_4; +struct constexpr_kernel_name; + +template +struct kernel_id_1 { + using type = KN; +}; + +struct kernel_id_2 { + using type = kernel_name_2; +}; + +struct kernel_id_3 { + using invalid_name = kernel_name_2; +}; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +void testBuiltinBeforeKernelInvocation2(); +void testBuiltinBeforeKernelInvocation1() { + const char* testBefore1 = __builtin_sycl_kernel_name(kernel_id_1()); // Valid + constexpr const char* testBefore2 = __builtin_sycl_kernel_name(kernel_id_1()); // expected-error {{constexpr variable 'testBefore2' must be initialized by a constant expression}} +} + +void testBuiltinBeforeKernelInvocation2() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + testBuiltinBeforeKernelInvocation2(); +} + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + const char* test1 = __builtin_sycl_kernel_name(kernel_id_1()); // Valid + const char* test2 = __builtin_sycl_kernel_name(kernel_id_1()); // Valid + const char* test3 = __builtin_sycl_kernel_name(kernel_id_2()); // Valid + const char* test4 = __builtin_sycl_kernel_name(kernel_id_3()); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + const char* test5 = __builtin_sycl_kernel_name("str"); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + const char* test6 = __builtin_sycl_kernel_name(kernel_id_2(), kernel_id_2()); // expected-error {{builtin takes one argument}} +} + diff --git a/clang/test/SemaSYCL/builtin-sycl-kernel-param-count.cpp b/clang/test/SemaSYCL/builtin-sycl-kernel-param-count.cpp new file mode 100644 index 0000000000000..831aed34e66e5 --- /dev/null +++ b/clang/test/SemaSYCL/builtin-sycl-kernel-param-count.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s + +class kernel_name_1; +class kernel_name_2; +class kernel_name_3; +typedef kernel_name_3 kernel_name_TD; + +template +struct kernel_id_1 { + using type = KN; +}; + +struct kernel_id_2 { + using type = kernel_name_2; +}; + +struct kernel_id_3 { + using invalid_name = kernel_name_2; +}; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_count(kernel_id_1()); // Valid + int test2 = __builtin_sycl_kernel_param_count(kernel_id_1()); // Valid + int test3 = __builtin_sycl_kernel_param_count(kernel_id_2()); // Valid + int test4 = __builtin_sycl_kernel_param_count(kernel_id_3()); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + int test5 = __builtin_sycl_kernel_param_count("str"); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + int test6 = __builtin_sycl_kernel_param_count(kernel_id_2(), kernel_id_2()); // expected-error {{builtin takes one argument}} +} + diff --git a/clang/test/SemaSYCL/builtin-sycl-kernel-param-kind.cpp b/clang/test/SemaSYCL/builtin-sycl-kernel-param-kind.cpp new file mode 100644 index 0000000000000..7b81dbbf2fe1d --- /dev/null +++ b/clang/test/SemaSYCL/builtin-sycl-kernel-param-kind.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s + +class kernel_name_1; +class kernel_name_2; +class kernel_name_3; +typedef kernel_name_3 kernel_name_TD; + +template +struct kernel_id_1 { + using type = KN; +}; + +struct kernel_id_2 { + using type = kernel_name_2; +}; + +struct kernel_id_3 { + using invalid_name = kernel_name_2; +}; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_kind(kernel_id_1(), 0); // Valid + int test2 = __builtin_sycl_kernel_param_kind(kernel_id_1(), 0); // Valid + int test3 = __builtin_sycl_kernel_param_kind(kernel_id_2(), 0); // Valid + int test4 = __builtin_sycl_kernel_param_kind(kernel_id_3(), 0); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + int test5 = __builtin_sycl_kernel_param_kind(kernel_id_2(), "str"); // expected-error {{2nd argument must be an 'int' (was 'const char[4]')}} + int test6 = __builtin_sycl_kernel_param_kind(kernel_id_2()); // expected-error {{builtin requires exactly 2 arguments}} +} + diff --git a/clang/test/SemaSYCL/builtin-sycl-kernel-param-offset.cpp b/clang/test/SemaSYCL/builtin-sycl-kernel-param-offset.cpp new file mode 100644 index 0000000000000..6de8e3ebd9775 --- /dev/null +++ b/clang/test/SemaSYCL/builtin-sycl-kernel-param-offset.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s + +class kernel_name_1; +class kernel_name_2; +class kernel_name_3; +typedef kernel_name_3 kernel_name_TD; + +template +struct kernel_id_1 { + using type = KN; +}; + +struct kernel_id_2 { + using type = kernel_name_2; +}; + +struct kernel_id_3 { + using invalid_name = kernel_name_2; +}; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_offset(kernel_id_1(), 0); // Valid + int test2 = __builtin_sycl_kernel_param_offset(kernel_id_1(), 0); // Valid + int test3 = __builtin_sycl_kernel_param_offset(kernel_id_2(), 0); // Valid + int test4 = __builtin_sycl_kernel_param_offset(kernel_id_3(), 0); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + int test5 = __builtin_sycl_kernel_param_offset(kernel_id_2(), "str"); // expected-error {{2nd argument must be an 'int' (was 'const char[4]')}} + int test6 = __builtin_sycl_kernel_param_offset(kernel_id_2()); // expected-error {{builtin requires exactly 2 arguments}} +} + diff --git a/clang/test/SemaSYCL/builtin-sycl-kernel-param-size.cpp b/clang/test/SemaSYCL/builtin-sycl-kernel-param-size.cpp new file mode 100644 index 0000000000000..d84f2333e7223 --- /dev/null +++ b/clang/test/SemaSYCL/builtin-sycl-kernel-param-size.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s + +class kernel_name_1; +class kernel_name_2; +class kernel_name_3; +typedef kernel_name_3 kernel_name_TD; + +template +struct kernel_id_1 { + using type = KN; +}; + +struct kernel_id_2 { + using type = kernel_name_2; +}; + +struct kernel_id_3 { + using invalid_name = kernel_name_2; +}; + +template +__attribute__((sycl_kernel_entry_point(name))) void kernel_single_task(const Func kernelFunc) { + kernelFunc(); +} + +struct SYCLKernel { + int m; + public: + void operator()() const {} +}; + +void test() { + SYCLKernel Obj; + kernel_single_task(Obj); + kernel_single_task(Obj); + kernel_single_task(Obj); + int test1 = __builtin_sycl_kernel_param_size(kernel_id_1(), 0); // Valid + int test2 = __builtin_sycl_kernel_param_size(kernel_id_1(), 0); // Valid + int test3 = __builtin_sycl_kernel_param_size(kernel_id_2(), 0); // Valid + int test4 = __builtin_sycl_kernel_param_size(kernel_id_3(), 0); // expected-error {{invalid argument; expected a class or structure with a member typedef or type alias alias named 'type'}} + int test5 = __builtin_sycl_kernel_param_size(kernel_id_2(), "str"); // expected-error {{2nd argument must be an 'int' (was 'const char[4]')}} + int test6 = __builtin_sycl_kernel_param_size(kernel_id_2()); // expected-error {{builtin requires exactly 2 arguments}} +} + diff --git a/clang/test/SemaSYCL/unique-stable-name-multiple-target-crash.cpp b/clang/test/SemaSYCL/unique-stable-name-multiple-target-crash.cpp index ec78feac8b7b3..c5929f36578df 100644 --- a/clang/test/SemaSYCL/unique-stable-name-multiple-target-crash.cpp +++ b/clang/test/SemaSYCL/unique-stable-name-multiple-target-crash.cpp @@ -6,7 +6,8 @@ // // expected-no-diagnostics class Empty {}; -template __attribute__((sycl_kernel)) void kernel(F) { +template +__attribute__((sycl_kernel_entry_point(N))) void kernel(F) { __builtin_sycl_unique_stable_name(F); } diff --git a/clang/test/SemaSYCL/unique_stable_name.cpp b/clang/test/SemaSYCL/unique_stable_name.cpp index fb3b0dbe9e0ee..b83f702dc221f 100644 --- a/clang/test/SemaSYCL/unique_stable_name.cpp +++ b/clang/test/SemaSYCL/unique_stable_name.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 %s -std=c++17 -triple x86_64-linux-gnu -fsycl-is-device -verify -fsyntax-only -Wno-unused template -[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { // #kernelSingleTask +[[clang::sycl_kernel_entry_point(KernelName)]] void kernel_single_task(KernelType kernelFunc) { // #kernelSingleTask kernelFunc(); }