From bd97889e1d89ab04b79d2e99ea9a0381faa00090 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Thu, 29 Apr 2021 10:48:38 -0700 Subject: [PATCH 01/19] Revert old implementation sans tests --- clang/docs/LanguageExtensions.rst | 28 +------ clang/include/clang/AST/Expr.h | 69 +--------------- clang/include/clang/AST/Mangle.h | 10 +-- clang/include/clang/Basic/TokenKinds.def | 11 ++- clang/include/clang/Parse/Parser.h | 1 - clang/include/clang/Sema/Sema.h | 9 --- clang/lib/AST/Expr.cpp | 81 +------------------ clang/lib/AST/ItaniumMangle.cpp | 52 ++---------- clang/lib/Parse/ParseExpr.cpp | 41 +--------- clang/lib/Sema/SemaExpr.cpp | 64 --------------- clang/lib/Sema/SemaSYCL.cpp | 14 ++-- clang/lib/Sema/SemaTemplateInstantiate.cpp | 41 ---------- clang/test/Analysis/eval-predefined-exprs.cpp | 11 --- .../unique-stable-name-placeholder-crash.cpp | 28 ------- clang/test/CodeGenSYCL/unique-stable-name.cpp | 77 ------------------ clang/test/ParserSYCL/unique-stable-name.cpp | 33 -------- 16 files changed, 29 insertions(+), 541 deletions(-) delete mode 100644 clang/test/CodeGenSYCL/unique-stable-name-placeholder-crash.cpp delete mode 100644 clang/test/CodeGenSYCL/unique-stable-name.cpp delete mode 100644 clang/test/ParserSYCL/unique-stable-name.cpp diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 9dd094e85d253..59ca4135b47fc 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1794,7 +1794,7 @@ correctly in any circumstances. It can be used if: metaprogramming algorithms to be able to specify/detect types generically. - the generated kernel binary does not contain indirect calls because they - are eliminated using compiler optimizations e.g. devirtualization. + are eliminated using compiler optimizations e.g. devirtualization. - the selected target supports the function pointer like functionality e.g. most CPU targets. @@ -2404,30 +2404,6 @@ argument. int *pb =__builtin_preserve_access_index(&v->c[3].b); __builtin_preserve_access_index(v->j); -``__builtin_unique_stable_name`` --------------------------------- - -``__builtin_unique_stable_name()`` is a builtin that takes a type or expression and -produces a string literal containing a unique name for the type (or type of the -expression) that is stable across split compilations. - -In cases where the split compilation needs to share a unique token for a type -across the boundary (such as in an offloading situation), this name can be used -for lookup purposes. - -This builtin is superior to RTTI for this purpose for two reasons. First, this -value is computed entirely at compile time, so it can be used in constant -expressions. Second, this value encodes lambda functions based on line-number -rather than the order in which it appears in a function. This is valuable -because it is stable in cases where an unrelated lambda is introduced -conditionally in the same function. - -The current implementation of this builtin uses a slightly modified Itanium -Mangler to produce the unique name. The lambda ordinal is replaced with one or -more line/column pairs in the format ``LINE->COL``, separated with a ``~`` -character. Typically, only one pair will be included, however in the case of -macro expansions the entire macro expansion stack is expressed. - Multiprecision Arithmetic Builtins ---------------------------------- @@ -2622,7 +2598,7 @@ Guaranteed inlined copy ``__builtin_memcpy_inline`` has been designed as a building block for efficient ``memcpy`` implementations. It is identical to ``__builtin_memcpy`` but also guarantees not to call any external functions. See LLVM IR `llvm.memcpy.inline -`_ intrinsic +`_ intrinsic for more information. This is useful to implement a custom version of ``memcpy``, implement a diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 9453b447270bb..589199dbcdcaf 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1948,17 +1948,13 @@ class StringLiteral final /// [C99 6.4.2.2] - A predefined identifier such as __func__. class PredefinedExpr final : public Expr, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; // PredefinedExpr is optionally followed by a single trailing // "Stmt *" for the predefined identifier. It is present if and only if // hasFunctionName() is true and is always a "StringLiteral *". - // It can also be followed by a Expr* in the case of a - // __builtin_unique_stable_name with an expression, or TypeSourceInfo * if - // __builtin_unique_stable_name with a type. public: enum IdentKind { @@ -1971,18 +1967,12 @@ class PredefinedExpr final PrettyFunction, /// The same as PrettyFunction, except that the /// 'virtual' keyword is omitted for virtual member functions. - PrettyFunctionNoVirtual, - UniqueStableNameType, - UniqueStableNameExpr, + PrettyFunctionNoVirtual }; private: PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL); - PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - TypeSourceInfo *Info); - PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - Expr *E); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); @@ -1995,39 +1985,10 @@ class PredefinedExpr final *getTrailingObjects() = SL; } - void setTypeSourceInfo(TypeSourceInfo *Info) { - assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType && - "TypeSourceInfo only valid for UniqueStableName of a Type"); - *getTrailingObjects() = Info; - } - - void setExpr(Expr *E) { - assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && - "TypeSourceInfo only valid for UniqueStableName of n Expression."); - *getTrailingObjects() = E; - } - - size_t numTrailingObjects(OverloadToken) const { - return hasFunctionName(); - } - - size_t numTrailingObjects(OverloadToken) const { - return getIdentKind() == UniqueStableNameType && !hasFunctionName(); - } - size_t numTrailingObjects(OverloadToken) const { - return getIdentKind() == UniqueStableNameExpr && !hasFunctionName(); - } - public: /// Create a PredefinedExpr. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL); - static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, StringLiteral *SL, - TypeSourceInfo *Info); - static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, StringLiteral *SL, - Expr *E); /// Create an empty PredefinedExpr. static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, @@ -2052,38 +2013,12 @@ class PredefinedExpr final : nullptr; } - TypeSourceInfo *getTypeSourceInfo() { - assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType && - "TypeSourceInfo only valid for UniqueStableName of a Type"); - return *getTrailingObjects(); - } - - const TypeSourceInfo *getTypeSourceInfo() const { - assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType && - "TypeSourceInfo only valid for UniqueStableName of a Type"); - return *getTrailingObjects(); - } - - Expr *getExpr() { - assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && - "TypeSourceInfo only valid for UniqueStableName of n Expression."); - return *getTrailingObjects(); - } - - const Expr *getExpr() const { - assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr && - "TypeSourceInfo only valid for UniqueStableName of n Expression."); - return *getTrailingObjects(); - } - static StringRef getIdentKindName(IdentKind IK); StringRef getIdentKindName() const { return getIdentKindName(getIdentKind()); } static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); - static std::string ComputeName(ASTContext &Context, IdentKind IK, - const QualType Ty); SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return getLocation(); } diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index be0e89730ab1f..dc620ec10ff9e 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -172,14 +172,9 @@ class MangleContext { }; class ItaniumMangleContext : public MangleContext { - bool IsUniqueNameMangler = false; public: explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D) : MangleContext(C, D, MK_Itanium) {} - explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D, - bool IsUniqueNameMangler) - : MangleContext(C, D, MK_Itanium), - IsUniqueNameMangler(IsUniqueNameMangler) {} virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0; virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0; @@ -200,15 +195,12 @@ class ItaniumMangleContext : public MangleContext { virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0; - bool isUniqueNameMangler() { return IsUniqueNameMangler; } - static bool classof(const MangleContext *C) { return C->getKind() == MK_Itanium; } static ItaniumMangleContext *create(ASTContext &Context, - DiagnosticsEngine &Diags, - bool IsUniqueNameMangler = false); + DiagnosticsEngine &Diags); }; class MicrosoftMangleContext : public MangleContext { diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 09207a9a3d6e8..176e4f6d18797 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -695,12 +695,11 @@ ALIAS("_declspec" , __declspec , KEYMS) ALIAS("_pascal" , __pascal , KEYBORLAND) // Clang Extensions. -KEYWORD(__builtin_convertvector , KEYALL) -ALIAS("__char16_t" , char16_t , KEYCXX) -ALIAS("__char32_t" , char32_t , KEYCXX) -KEYWORD(__builtin_bit_cast , KEYALL) -KEYWORD(__builtin_available , KEYALL) -KEYWORD(__builtin_unique_stable_name, KEYALL) +KEYWORD(__builtin_convertvector , KEYALL) +ALIAS("__char16_t" , char16_t , KEYCXX) +ALIAS("__char32_t" , char32_t , KEYCXX) +KEYWORD(__builtin_bit_cast , KEYALL) +KEYWORD(__builtin_available , KEYALL) // Clang-specific keywords enabled only in testing. TESTING_KEYWORD(__unknown_anytype , KEYALL) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 215e0e36509da..87075d508b32d 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1800,7 +1800,6 @@ class Parser : public CodeCompletionHandler { ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); ExprResult ParseUnaryExprOrTypeTraitExpression(); ExprResult ParseBuiltinPrimaryExpression(); - ExprResult ParseUniqueStableNameExpression(); ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 563d4a8c5a86f..99f7c791f3554 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5420,15 +5420,6 @@ class Sema final { ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); - ExprResult BuildUniqueStableName(SourceLocation Loc, TypeSourceInfo *Operand); - ExprResult BuildUniqueStableName(SourceLocation Loc, Expr *E); - ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, ParsedType Ty); - ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, Expr *E); - bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index be0f2855f2980..fe2cdc91fb27c 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -518,34 +518,6 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, setDependence(computeDependence(this)); } -PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK, - TypeSourceInfo *Info) - : Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) { - PredefinedExprBits.Kind = IK; - assert((getIdentKind() == IK) && - "IdentKind do not fit in PredefinedExprBitFields!"); - assert(IK == UniqueStableNameType && - "Constructor only valid with UniqueStableNameType"); - PredefinedExprBits.HasFunctionName = false; - PredefinedExprBits.Loc = L; - setTypeSourceInfo(Info); - setDependence(computeDependence(this)); -} - -PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK, - Expr *E) - : Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) { - PredefinedExprBits.Kind = IK; - assert((getIdentKind() == IK) && - "IdentKind do not fit in PredefinedExprBitFields!"); - assert(IK == UniqueStableNameExpr && - "Constructor only valid with UniqueStableNameExpr"); - PredefinedExprBits.HasFunctionName = false; - PredefinedExprBits.Loc = L; - setExpr(E); - setDependence(computeDependence(this)); -} - PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName) : Expr(PredefinedExprClass, Empty) { PredefinedExprBits.HasFunctionName = HasFunctionName; @@ -555,44 +527,15 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL) { bool HasFunctionName = SL != nullptr; - void *Mem = Ctx.Allocate( - totalSizeToAlloc(HasFunctionName, 0, 0), - alignof(PredefinedExpr)); - return new (Mem) PredefinedExpr(L, FNTy, IK, SL); -} - -PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, - StringLiteral *SL, - TypeSourceInfo *Info) { - assert(IK == UniqueStableNameType && "Only valid with UniqueStableNameType"); - bool HasFunctionName = SL != nullptr; - void *Mem = Ctx.Allocate(totalSizeToAlloc( - HasFunctionName, 0, !HasFunctionName), - alignof(PredefinedExpr)); - if (HasFunctionName) - return new (Mem) PredefinedExpr(L, FNTy, IK, SL); - return new (Mem) PredefinedExpr(L, FNTy, IK, Info); -} - -PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, - StringLiteral *SL, Expr *E) { - assert(IK == UniqueStableNameExpr && "Only valid with UniqueStableNameExpr"); - bool HasFunctionName = SL != nullptr; - void *Mem = Ctx.Allocate(totalSizeToAlloc( - HasFunctionName, !HasFunctionName, 0), + void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); - if (HasFunctionName) - return new (Mem) PredefinedExpr(L, FNTy, IK, SL); - return new (Mem) PredefinedExpr(L, FNTy, IK, E); + return new (Mem) PredefinedExpr(L, FNTy, IK, SL); } PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx, bool HasFunctionName) { - void *Mem = Ctx.Allocate( - totalSizeToAlloc(HasFunctionName, 0, 0), - alignof(PredefinedExpr)); + void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), + alignof(PredefinedExpr)); return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName); } @@ -612,28 +555,12 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) { return "__FUNCSIG__"; case LFuncSig: return "L__FUNCSIG__"; - case UniqueStableNameType: - case UniqueStableNameExpr: - return "__builtin_unique_stable_name"; case PrettyFunctionNoVirtual: break; } llvm_unreachable("Unknown ident kind for PredefinedExpr"); } -std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentKind IK, - QualType Ty) { - std::unique_ptr Ctx{ItaniumMangleContext::create( - Context, Context.getDiagnostics(), /*IsUniqueNameMangler*/ true)}; - - Ty = Ty.getCanonicalType(); - - SmallString<256> Buffer; - llvm::raw_svector_ostream Out(Buffer); - Ctx->mangleTypeName(Ty, Out); - return std::string(Buffer.str()); -} - // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 3ad3ad01122ba..25ccc289ca65b 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -131,9 +131,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { public: explicit ItaniumMangleContextImpl(ASTContext &Context, - DiagnosticsEngine &Diags, - bool IsUniqueNameMangler) - : ItaniumMangleContext(Context, Diags, IsUniqueNameMangler) {} + DiagnosticsEngine &Diags) + : ItaniumMangleContext(Context, Diags) {} /// @name Mangler Entry Points /// @{ @@ -1516,8 +1515,7 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, // ::= * + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast(TD)) { - if (Record->isLambda() && (Record->getLambdaManglingNumber() || - Context.isUniqueNameMangler())) { + if (Record->isLambda() && Record->getLambdaManglingNumber()) { assert(!AdditionalAbiTags && "Lambda type cannot have additional abi tags"); mangleLambda(Record); @@ -1921,37 +1919,6 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { } } -// Handles the __builtin_unique_stable_name feature for lambdas. Instead of the -// ordinal of the lambda in its mangling, this does line/column to uniquely and -// reliably identify the lambda. Additionally, macro expansions are expressed -// as well to prevent macros causing duplicates. -static void mangleUniqueNameLambda(CXXNameMangler &Mangler, SourceManager &SM, - raw_ostream &Out, - const CXXRecordDecl *Lambda) { - SourceLocation Loc = Lambda->getLocation(); - - PresumedLoc PLoc = SM.getPresumedLoc(Loc); - Mangler.mangleNumber(PLoc.getLine()); - Out << "_"; - Mangler.mangleNumber(PLoc.getColumn()); - - while(Loc.isMacroID()) { - SourceLocation SLToPrint = Loc; - if (SM.isMacroArgExpansion(Loc)) - SLToPrint = SM.getImmediateExpansionRange(Loc).getBegin(); - - PLoc = SM.getPresumedLoc(SM.getSpellingLoc(SLToPrint)); - Out << "m"; - Mangler.mangleNumber(PLoc.getLine()); - Out << "_"; - Mangler.mangleNumber(PLoc.getColumn()); - - Loc = SM.getImmediateMacroCallerLoc(Loc); - if (Loc.isFileID()) - Loc = SM.getImmediateMacroCallerLoc(SLToPrint); - } -} - void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // When trying to be ABI-compatibility with clang 12 and before, mangle a // now, with no substitutions. @@ -1975,12 +1942,6 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { mangleLambdaSig(Lambda); Out << "E"; - if (Context.isUniqueNameMangler()) { - mangleUniqueNameLambda( - *this, Context.getASTContext().getSourceManager(), Out, Lambda); - return; - } - // The number is omitted for the first closure type with a given // in a given context; it is n-2 for the nth closure type // (in lexical order) with that same and context. @@ -6425,8 +6386,7 @@ void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl *Lambda, Mangler.mangleLambdaSig(Lambda); } -ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context, - DiagnosticsEngine &Diags, - bool IsUniqueNameMangler) { - return new ItaniumMangleContextImpl(Context, Diags, IsUniqueNameMangler); +ItaniumMangleContext * +ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { + return new ItaniumMangleContextImpl(Context, Diags); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 8be38faee923d..c2b47f6375b84 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1469,9 +1469,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_this: Res = ParseCXXThis(); break; - case tok::kw___builtin_unique_stable_name: - Res = ParseUniqueStableNameExpression(); - break; + case tok::annot_typename: if (isStartOfObjCClassMessageMissingOpenBracket()) { TypeResult Type = getTypeAnnotation(Tok); @@ -2327,43 +2325,6 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, } -ExprResult Parser::ParseUniqueStableNameExpression() { - assert(Tok.is(tok::kw___builtin_unique_stable_name) && - "Not __bulitin_unique_stable_name"); - - SourceLocation OpLoc = ConsumeToken(); - BalancedDelimiterTracker T(*this, tok::l_paren); - - // typeid expressions are always parenthesized. - if (T.expectAndConsume(diag::err_expected_lparen_after, - "__builtin_unique_stable_name")) - return ExprError(); - - if (isTypeIdInParens()) { - TypeResult Ty = ParseTypeName(); - T.consumeClose(); - - if (Ty.isInvalid()) - return ExprError(); - - return Actions.ActOnUniqueStableNameExpr(OpLoc, T.getOpenLocation(), - T.getCloseLocation(), Ty.get()); - } - - EnterExpressionEvaluationContext Unevaluated( - Actions, Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult Result = ParseExpression(); - - if (Result.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return Result; - } - - T.consumeClose(); - return Actions.ActOnUniqueStableNameExpr(OpLoc, T.getOpenLocation(), - T.getCloseLocation(), Result.get()); -} - /// Parse a sizeof or alignof expression. /// /// \verbatim diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 02042b05c724e..f6f0c12db4ad9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3549,70 +3549,6 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } -static std::pair -GetUniqueStableNameInfo(ASTContext &Context, QualType OpType, - SourceLocation OpLoc, PredefinedExpr::IdentKind K) { - std::pair Result{{}, nullptr}; - - if (OpType->isDependentType()) { - Result.first = Context.DependentTy; - return Result; - } - - std::string Str = PredefinedExpr::ComputeName(Context, K, OpType); - llvm::APInt Length(32, Str.length() + 1); - Result.first = - Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); - Result.first = Context.getConstantArrayType( - Result.first, Length, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0); - Result.second = StringLiteral::Create(Context, Str, StringLiteral::Ascii, - /*Pascal*/ false, Result.first, OpLoc); - return Result; -} - -ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, - TypeSourceInfo *Operand) { - QualType ResultTy; - StringLiteral *SL; - std::tie(ResultTy, SL) = GetUniqueStableNameInfo( - Context, Operand->getType(), OpLoc, PredefinedExpr::UniqueStableNameType); - - return PredefinedExpr::Create(Context, OpLoc, ResultTy, - PredefinedExpr::UniqueStableNameType, SL, - Operand); -} - -ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, - Expr *E) { - QualType ResultTy; - StringLiteral *SL; - std::tie(ResultTy, SL) = GetUniqueStableNameInfo( - Context, E->getType(), OpLoc, PredefinedExpr::UniqueStableNameExpr); - - return PredefinedExpr::Create(Context, OpLoc, ResultTy, - PredefinedExpr::UniqueStableNameExpr, SL, E); -} - -ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation L, SourceLocation R, - ParsedType Ty) { - TypeSourceInfo *TInfo = nullptr; - QualType T = GetTypeFromParser(Ty, &TInfo); - - if (T.isNull()) - return ExprError(); - if (!TInfo) - TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); - - return BuildUniqueStableName(OpLoc, TInfo); -} - -ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation L, SourceLocation R, - Expr *E) { - return BuildUniqueStableName(OpLoc, E); -} - ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentKind IK; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index c2c11765a8bc2..95e7343892afd 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -888,10 +888,11 @@ constructKernelName(Sema &S, FunctionDecl *KernelCallerFunc, MC.mangleTypeName(KernelNameType, Out); - return {std::string(Out.str()), - PredefinedExpr::ComputeName(S.getASTContext(), - PredefinedExpr::UniqueStableNameType, - KernelNameType)}; + // TODO: ERICH: insert this in correctly. + return {std::string(Out.str()), ""}; + //PredefinedExpr::ComputeName(S.getASTContext(), + // PredefinedExpr::UniqueStableNameType, + // KernelNameType)}; } static bool isDefaultSPIRArch(ASTContext &Context) { @@ -3271,9 +3272,10 @@ class SyclKernelIntHeaderCreator : public SyclKernelFieldHandler { // Get specialization constant ID type, which is the second template // argument. QualType SpecConstIDTy = TemplateArgs.get(1).getAsType().getCanonicalType(); - const std::string SpecConstName = PredefinedExpr::ComputeName( + // TODO: ERICH: Update with actual implementation. + const std::string SpecConstName = "";/*PredefinedExpr::ComputeName( SemaRef.getASTContext(), PredefinedExpr::UniqueStableNameType, - SpecConstIDTy); + SpecConstIDTy);*/ Header.addSpecConstant(SpecConstName, SpecConstIDTy); return true; } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 37684b68cb43e..5ba50747d84ca 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1440,52 +1440,11 @@ TemplateName TemplateInstantiator::TransformTemplateName( AllowInjectedClassName); } -static ExprResult TransformUniqueStableName(TemplateInstantiator &TI, - PredefinedExpr *E) { - if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) { - TypeSourceInfo *Info = - TI.getDerived().TransformType(E->getTypeSourceInfo()); - - if (!Info) - return ExprError(); - - if (!TI.getDerived().AlwaysRebuild() && Info == E->getTypeSourceInfo()) - return E; - - return TI.getSema().BuildUniqueStableName(E->getLocation(), Info); - } - - if (E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) { - EnterExpressionEvaluationContext Unevaluated( - TI.getSema(), Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult SubExpr = TI.getDerived().TransformExpr(E->getExpr()); - - if (SubExpr.isInvalid()) - return ExprError(); - - SubExpr = TI.getSema().CheckPlaceholderExpr(SubExpr.get()); - - if (SubExpr.isInvalid()) - return ExprError(); - - if (!TI.getDerived().AlwaysRebuild() && SubExpr.get() == E->getExpr()) - return E; - - return TI.getSema().BuildUniqueStableName(E->getLocation(), SubExpr.get()); - } - - llvm_unreachable("Only valid for UniqueStableNameType/Expr"); -} - ExprResult TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return E; - if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType || - E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) - return TransformUniqueStableName(*this, E); - return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentKind()); } diff --git a/clang/test/Analysis/eval-predefined-exprs.cpp b/clang/test/Analysis/eval-predefined-exprs.cpp index 947ef148eeef0..1eec4476a065f 100644 --- a/clang/test/Analysis/eval-predefined-exprs.cpp +++ b/clang/test/Analysis/eval-predefined-exprs.cpp @@ -7,12 +7,6 @@ template void clang_analyzer_dump(const T *); void clang_analyzer_warnIfReached(); -void builtin_unique_stable_name_of_lambda() { - auto y = [] {}; - clang_analyzer_dump(__builtin_unique_stable_name(y)); - // expected-warning@-1 {{&Element{"_ZTSZ36builtin_unique_stable_name_of_lambdavEUlvE11_12",0 S64b,char}}} -} - template void func(U param) { clang_analyzer_dump(__func__); @@ -56,11 +50,6 @@ void foo() { func('b'); // instantiate template } -void test_builtin_unique_stable_name(int a) { - clang_analyzer_dump(__builtin_unique_stable_name(a)); - // expected-warning@-1 {{&Element{"_ZTSi",0 S64b,char}}} -} - struct A { A() { clang_analyzer_dump(__func__); diff --git a/clang/test/CodeGenSYCL/unique-stable-name-placeholder-crash.cpp b/clang/test/CodeGenSYCL/unique-stable-name-placeholder-crash.cpp deleted file mode 100644 index b6da2c9a9d070..0000000000000 --- a/clang/test/CodeGenSYCL/unique-stable-name-placeholder-crash.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -internal-isystem %S/Inputs -std=c++17 -sycl-std=2020 -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s - -#include - -using namespace cl::sycl; - -struct A { - int a = 0; - A() = default; -}; -constexpr A THE_NAME; - -template void temp() {} -template void foo(const char *out) { - out = __builtin_unique_stable_name(temp); -} - -int main() { - kernel_single_task( - []() { - const char *c; - foo(c); - }); -} - -// Note: the mangling here is actually the 'typeinfo name for void ()'. That is -// because the type of temp is actually the function type (which is void()). -// CHECK: @__builtin_unique_stable_name._Z3fooIL_ZL8THE_NAMEEEvPKc = private unnamed_addr addrspace(1) constant [9 x i8] c"_ZTSFvvE\00", align 1 diff --git a/clang/test/CodeGenSYCL/unique-stable-name.cpp b/clang/test/CodeGenSYCL/unique-stable-name.cpp deleted file mode 100644 index 2259548c1a29e..0000000000000 --- a/clang/test/CodeGenSYCL/unique-stable-name.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s -// CHECK: @[[INT:[^\w]+]] = private unnamed_addr addrspace(1) constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" -// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE42_5clEvEUlvE46_16\00" -// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE42_5clEvEUlvE52_7m28_18\00" -// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE42_5clEvEUlvE52_7m28_41\00" -// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE42_5clEvEUlvE55_7m28_18m33_4\00" -// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr addrspace(1) constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE42_5clEvEUlvE55_7m28_41m33_4\00" -// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE23_12\00", -// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr addrspace(1) constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE42_5clEvEUlvE46_16EvvEUlvE23_12\00", - -extern "C" void printf(const char *) {} - -template -void template_param() { - printf(__builtin_unique_stable_name(T)); -} - -template -T getT() { return T{}; } - -template -void lambda_in_dependent_function() { - auto y = [] {}; - printf(__builtin_unique_stable_name(y)); -} - -#define DEF_IN_MACRO() \ - auto MACRO_X = []() {};auto MACRO_Y = []() {}; \ - printf(__builtin_unique_stable_name(MACRO_X)); \ - printf(__builtin_unique_stable_name(MACRO_Y)); - -#define MACRO_CALLS_MACRO() \ - {DEF_IN_MACRO();}{DEF_IN_MACRO();} - -template -[[clang::sycl_kernel]] void kernel_single_task(const KernelType &kernelFunc) { - kernelFunc(); -} - -int main() { - kernel_single_task( - []() { - printf(__builtin_unique_stable_name(int)); - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]] addrspace(4)* addrspacecast ([[INT_SIZE]] addrspace(1)* @[[INT]] to [[INT_SIZE]] addrspace(4)* - - auto x = [](){}; - printf(__builtin_unique_stable_name(x)); - printf(__builtin_unique_stable_name(decltype(x))); - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]] addrspace(4)* addrspacecast ([[LAMBDA_X_SIZE]] addrspace(1)* @[[LAMBDA_X]] to [[LAMBDA_X_SIZE]] addrspace(4)* - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]] addrspace(4)* addrspacecast ([[LAMBDA_X_SIZE]] addrspace(1)* @[[LAMBDA_X]] to [[LAMBDA_X_SIZE]] addrspace(4)* - - DEF_IN_MACRO(); - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]] addrspace(4)* addrspacecast ([[MACRO_SIZE]] addrspace(1)* @[[MACRO_X]] to [[MACRO_SIZE]] addrspace(4)* - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]] addrspace(4)* addrspacecast ([[MACRO_SIZE]] addrspace(1)* @[[MACRO_Y]] to [[MACRO_SIZE]] addrspace(4)* - MACRO_CALLS_MACRO(); - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]] addrspace(4)* addrspacecast ([[MACRO_MACRO_SIZE]] addrspace(1)* @[[MACRO_MACRO_X]] to [[MACRO_MACRO_SIZE]] addrspace(4)* - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]] addrspace(4)* addrspacecast ([[MACRO_MACRO_SIZE]] addrspace(1)* @[[MACRO_MACRO_Y]] to [[MACRO_MACRO_SIZE]] addrspace(4)* - - template_param(); - // CHECK: define linkonce_odr spir_func void @_Z14template_paramIiEvv - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]] addrspace(4)* addrspacecast ([[INT_SIZE]] addrspace(1)* @[[INT]] to [[INT_SIZE]] addrspace(4)* - - template_param(); - // CHECK: define internal spir_func void @"_Z14template_paramIZZ4mainENK3 - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]] addrspace(4)* addrspacecast ([[LAMBDA_X_SIZE]] addrspace(1)* @[[LAMBDA_X]] to [[LAMBDA_X_SIZE]] addrspace(4)* - - lambda_in_dependent_function(); - // CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[DEP_INT_SIZE]], [[DEP_INT_SIZE]] addrspace(4)* addrspacecast ([[DEP_INT_SIZE]] addrspace(1)* @[[LAMBDA_IN_DEP_INT]] to [[DEP_INT_SIZE]] addrspace(4)* - - lambda_in_dependent_function(); - // CHECK: define internal spir_func void @"_Z28lambda_in_dependent_functionIZZ4mainENK3$_0clEvEUlvE_Evv - // CHECK: call spir_func void @printf(i8 addrspace(4)* getelementptr inbounds ([[DEP_LAMBDA_SIZE]], [[DEP_LAMBDA_SIZE]] addrspace(4)* addrspacecast ([[DEP_LAMBDA_SIZE]] addrspace(1)* @[[LAMBDA_IN_DEP_X]] to [[DEP_LAMBDA_SIZE]] addrspace(4)* - - }); -} - diff --git a/clang/test/ParserSYCL/unique-stable-name.cpp b/clang/test/ParserSYCL/unique-stable-name.cpp deleted file mode 100644 index d1f1304cf8b45..0000000000000 --- a/clang/test/ParserSYCL/unique-stable-name.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused %s - -namespace NS{}; - -void f(int var) { - // expected-error@+1{{expected '(' after '__builtin_unique_stable_name'}} - __builtin_unique_stable_name int; - // expected-error@+1{{expected '(' after '__builtin_unique_stable_name'}} - __builtin_unique_stable_name {int}; - - __builtin_unique_stable_name(var); - // expected-error@+1{{use of undeclared identifier 'bad_var'}} - __builtin_unique_stable_name(bad_var); - // expected-error@+1{{use of undeclared identifier 'bad'}} - __builtin_unique_stable_name(bad::type); - // expected-error@+1{{no member named 'still_bad' in namespace 'NS'}} - __builtin_unique_stable_name(NS::still_bad); -} - -template -void f2() { - // expected-error@+1{{no member named 'bad_val' in 'S'}} - __builtin_unique_stable_name(T::bad_val); - // expected-error@+1{{no type named 'bad_type' in 'S'}} - __builtin_unique_stable_name(typename T::bad_type); -} - -struct S{}; - -void use() { - // expected-note@+1{{in instantiation of}} - f2(); -} From 8347ee428cf16512d5722d99111bd8d051668d28 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 23 Apr 2021 08:22:35 -0700 Subject: [PATCH 02/19] Reimplement __builtin_unique_stable_name- The original version of this was reverted, and @rjmcall provided some advice to architect a new solution. This is that solution. This implements a builtin to provide a unique name that is stable across compilations of this TU for the purposes of implementing the library component of the unnamed kernel feature of SYCL. It does this by running the Itanium mangler with a few modifications. Because it is somewhat common to wrap non-kernel-related lambdas in macros that aren't present on the device (such as for logging), this uniquely generates an ID for all lambdas involved in the naming of a kernel. It uses the lambda-mangling number to do this, except replaces this with its own number (starting at 10000 for readabililty reasons) for lambdas used to name a kernel. Additionally, this implements itself as constexpr with a slight catch: if a name would be invalidated by the use of this lambda in a later kernel invocation, it is diagnosed as an error (see the Sema tests). Differential Revision: https://reviews.llvm.org/D103112 --- clang/docs/LanguageExtensions.rst | 34 +++ clang/include/clang/AST/ASTContext.h | 23 ++ clang/include/clang/AST/ComputeDependence.h | 2 + clang/include/clang/AST/Expr.h | 58 +++++ clang/include/clang/AST/JSONNodeDumper.h | 1 + clang/include/clang/AST/Mangle.h | 11 +- clang/include/clang/AST/RecursiveASTVisitor.h | 3 + clang/include/clang/AST/TextNodeDumper.h | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 5 + clang/include/clang/Basic/LangOptions.h | 2 + clang/include/clang/Basic/StmtNodes.td | 1 + clang/include/clang/Basic/TokenKinds.def | 11 +- clang/include/clang/Parse/Parser.h | 1 + clang/include/clang/Sema/Sema.h | 13 ++ .../include/clang/Serialization/ASTBitCodes.h | 3 + clang/lib/AST/ASTContext.cpp | 115 +++++++++- clang/lib/AST/ComputeDependence.cpp | 4 + clang/lib/AST/Expr.cpp | 65 ++++++ clang/lib/AST/ExprClassification.cpp | 3 + clang/lib/AST/ExprConstant.cpp | 24 +- clang/lib/AST/ItaniumMangle.cpp | 53 +++-- clang/lib/AST/JSONNodeDumper.cpp | 6 + clang/lib/AST/StmtPrinter.cpp | 7 + clang/lib/AST/StmtProfile.cpp | 6 + clang/lib/AST/TextNodeDumper.cpp | 5 + clang/lib/Basic/IdentifierTable.cpp | 2 + clang/lib/CodeGen/CGCUDANV.cpp | 27 ++- clang/lib/CodeGen/CGExprScalar.cpp | 21 ++ clang/lib/Parse/ParseExpr.cpp | 30 +++ clang/lib/Sema/SemaExceptionSpec.cpp | 2 + clang/lib/Sema/SemaExpr.cpp | 22 ++ clang/lib/Sema/SemaLambda.cpp | 6 +- clang/lib/Sema/SemaSYCL.cpp | 32 +++ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 34 +++ clang/lib/Sema/TreeTransform.h | 31 +++ clang/lib/Serialization/ASTReaderStmt.cpp | 14 ++ clang/lib/Serialization/ASTWriterStmt.cpp | 11 + clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + .../AST/ast-print-sycl-unique-stable-name.cpp | 28 +++ clang/test/CodeGenSYCL/unique_stable_name.cpp | 159 +++++++++++++ clang/test/ParserSYCL/unique_stable_name.cpp | 43 ++++ .../unique_stable_name_sycl_only.cpp | 9 + clang/test/SemaSYCL/unique_stable_name.cpp | 215 ++++++++++++++++++ clang/tools/libclang/CXCursor.cpp | 1 + 44 files changed, 1111 insertions(+), 34 deletions(-) create mode 100644 clang/test/AST/ast-print-sycl-unique-stable-name.cpp create mode 100644 clang/test/CodeGenSYCL/unique_stable_name.cpp create mode 100644 clang/test/ParserSYCL/unique_stable_name.cpp create mode 100644 clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp create mode 100644 clang/test/SemaSYCL/unique_stable_name.cpp diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 59ca4135b47fc..129e73345b2a2 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2404,6 +2404,40 @@ argument. int *pb =__builtin_preserve_access_index(&v->c[3].b); __builtin_preserve_access_index(v->j); +``__builtin_sycl_unique_stable_name`` +------------------------------------- + +``__builtin_sycl_unique_stable_name()`` is a builtin that takes a type and +produces a string literal containing a unique name for the type that is stable +across split compilations, mainly to support SYCL/Data Parallel C++ language. + +In cases where the split compilation needs to share a unique token for a type +across the boundary (such as in an offloading situation), this name can be used +for lookup purposes, such as in the SYCL Integration Header. + +The value of this builtin is computed entirely at compile time, so it can be +used in constant expressions. This value encodes lambda functions based on a +stable numbering order in which they appear in their local declaration contexts. +Once this builtin is evaluated in a constexpr context, it is erroneous to use +it in an instantiation which changes its value. + +In order to produce the unique name, the current implementation of the bultin +uses Itanium mangling even if the host compilation uses a different name +mangling scheme at runtime. The mangler marks all the lambdas required to name +the SYCL kernel and emits a stable local ordering of the respective lambdas, +starting from ``10000``. The initial value of ``10000`` serves as an obvious +differentiator from ordinary lambda mangling numbers but does not serve any +other purpose and may change in the future. The resulting pattern is +demanglable. When non-lambda types are passed to the builtin, the mangler emits +their usual pattern without any special treatment. + +**Syntax**: + +.. code-block:: c + + // Computes a unique stable name for the given type. + constexpr const char * __builtin_sycl_unique_stable_name( type-id ); + Multiprecision Arithmetic Builtins ---------------------------------- diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 55f15003acab8..593258c398c19 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2360,6 +2360,12 @@ class ASTContext : public RefCountedBase { /// If \p T is null pointer, assume the target in ASTContext. MangleContext *createMangleContext(const TargetInfo *T = nullptr); + /// Creates a device mangle context to correctly mangle lambdas in a mixed + /// architecture compile by setting the lambda mangling number source to the + /// DeviceLambdaManglingNumber. Currently this asserts that the TargetInfo + /// (from the AuxTargetInfo) is a an itanium target. + MangleContext *createDeviceMangleContext(const TargetInfo &T); + void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, SmallVectorImpl &Ivars) const; @@ -3163,10 +3169,27 @@ OPT_LIST(V) StringRef getCUIDHash() const; + void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD); + bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const; + unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD) const; + /// A SourceLocation to store whether we have evaluated a kernel name already, + /// and where it happened. If so, we need to diagnose an illegal use of the + /// builtin. + llvm::MapVector + SYCLUniqueStableNameEvaluatedValues; + private: /// All OMPTraitInfo objects live in this collection, one per /// `pragma omp [begin] declare variant` directive. SmallVector, 4> OMPTraitInfoVector; + + /// A list of the (right now just lambda decls) declarations required to + /// name all the SYCL kernels in the translation unit, so that we can get the + /// correct kernel name, as well as implement + /// __builtin_sycl_unique_stable_name. + llvm::DenseMap> + SYCLKernelNamingTypes; }; /// Insertion operator for diagnostics. diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 04e8e2c7d2ccb..7dde42ee71ba0 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -78,6 +78,7 @@ class MaterializeTemporaryExpr; class CXXFoldExpr; class TypeTraitExpr; class ConceptSpecializationExpr; +class SYCLUniqueStableNameExpr; class PredefinedExpr; class CallExpr; class OffsetOfExpr; @@ -165,6 +166,7 @@ ExprDependence computeDependence(TypeTraitExpr *E); ExprDependence computeDependence(ConceptSpecializationExpr *E, bool ValueDependent); +ExprDependence computeDependence(SYCLUniqueStableNameExpr *E); ExprDependence computeDependence(PredefinedExpr *E); ExprDependence computeDependence(CallExpr *E, llvm::ArrayRef PreArgs); ExprDependence computeDependence(OffsetOfExpr *E); diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 589199dbcdcaf..55ee96feae98c 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2039,6 +2039,64 @@ class PredefinedExpr final } }; +// This represents a use of the __builtin_sycl_unique_stable_name, which takes a +// type-id, and at CodeGen time emits a unique string representation of the +// type in a way that permits us to properly encode information about the SYCL +// kernels. +class SYCLUniqueStableNameExpr final : public Expr { + friend class ASTStmtReader; + SourceLocation OpLoc, LParen, RParen; + TypeSourceInfo *TypeInfo; + + SYCLUniqueStableNameExpr(EmptyShell Empty, QualType ResultTy); + SYCLUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, + SourceLocation RParen, QualType ResultTy, + TypeSourceInfo *TSI); + + void setTypeSourceInfo(TypeSourceInfo *Ty) { TypeInfo = Ty; } + + void setLocation(SourceLocation L) { OpLoc = L; } + void setLParenLocation(SourceLocation L) { LParen = L; } + void setRParenLocation(SourceLocation L) { RParen = L; } + +public: + TypeSourceInfo *getTypeSourceInfo() { return TypeInfo; } + + const TypeSourceInfo *getTypeSourceInfo() const { return TypeInfo; } + + static SYCLUniqueStableNameExpr * + Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen, + SourceLocation RParen, TypeSourceInfo *TSI); + + static SYCLUniqueStableNameExpr *CreateEmpty(const ASTContext &Ctx); + + SourceLocation getBeginLoc() const { return getLocation(); } + SourceLocation getEndLoc() const { return RParen; } + SourceLocation getLocation() const { return OpLoc; } + SourceLocation getLParenLocation() const { return LParen; } + SourceLocation getRParenLocation() const { return RParen; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SYCLUniqueStableNameExprClass; + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + // Convenience function to generate the name of the currently stored type. + std::string ComputeName(ASTContext &Context) const; + + // Get the generated name of the type. Note that this only works after all + // kernels have been instantiated. + static std::string ComputeName(ASTContext &Context, QualType Ty); +}; + /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index 4e7162992418a..a8b731a7cd31d 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -263,6 +263,7 @@ class JSONNodeDumper void VisitBlockDecl(const BlockDecl *D); void VisitDeclRefExpr(const DeclRefExpr *DRE); + void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E); void VisitPredefinedExpr(const PredefinedExpr *PE); void VisitUnaryOperator(const UnaryOperator *UO); void VisitBinaryOperator(const BinaryOperator *BO); diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index dc620ec10ff9e..7d02f08e0120c 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -107,9 +107,6 @@ class MangleContext { virtual bool shouldMangleCXXName(const NamedDecl *D) = 0; virtual bool shouldMangleStringLiteral(const StringLiteral *SL) = 0; - virtual bool isDeviceMangleContext() const { return false; } - virtual void setDeviceMangleContext(bool) {} - virtual bool isUniqueInternalLinkageDecl(const NamedDecl *ND) { return false; } @@ -173,6 +170,8 @@ class MangleContext { class ItaniumMangleContext : public MangleContext { public: + using DiscriminatorOverrideTy = + llvm::Optional (*)(ASTContext &, const NamedDecl *); explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D) : MangleContext(C, D, MK_Itanium) {} @@ -195,12 +194,18 @@ class ItaniumMangleContext : public MangleContext { virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0; + // This has to live here, otherwise the CXXNameMangler won't have access to + // it. + virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0; static bool classof(const MangleContext *C) { return C->getKind() == MK_Itanium; } static ItaniumMangleContext *create(ASTContext &Context, DiagnosticsEngine &Diags); + static ItaniumMangleContext *create(ASTContext &Context, + DiagnosticsEngine &Diags, + DiscriminatorOverrideTy Discriminator); }; class MicrosoftMangleContext : public MangleContext { diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 4770a2fd42a2a..b3ea6f7817ef9 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2651,6 +2651,9 @@ DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, { DEF_TRAVERSE_STMT(ObjCAvailabilityCheckExpr, {}) DEF_TRAVERSE_STMT(ParenExpr, {}) DEF_TRAVERSE_STMT(ParenListExpr, {}) +DEF_TRAVERSE_STMT(SYCLUniqueStableNameExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); +}) DEF_TRAVERSE_STMT(PredefinedExpr, {}) DEF_TRAVERSE_STMT(ShuffleVectorExpr, {}) DEF_TRAVERSE_STMT(ConvertVectorExpr, {}) diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 0955c494a74ad..e3aa94d5a1e83 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -249,6 +249,7 @@ class TextNodeDumper void VisitCastExpr(const CastExpr *Node); void VisitImplicitCastExpr(const ImplicitCastExpr *Node); void VisitDeclRefExpr(const DeclRefExpr *Node); + void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *Node); void VisitPredefinedExpr(const PredefinedExpr *Node); void VisitCharacterLiteral(const CharacterLiteral *Node); void VisitIntegerLiteral(const IntegerLiteral *Node); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 02786427801e4..ee9d90ccb5e8d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6394,6 +6394,11 @@ def warn_pointer_arith_null_ptr : Warning< def warn_gnu_null_ptr_arith : Warning< "arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">, InGroup, DefaultIgnore; +def err_kernel_invalidates_sycl_unique_stable_name + : Error<"kernel instantiation changes the result of an evaluated " + "'__builtin_sycl_unique_stable_name'">; +def note_sycl_unique_stable_name_evaluated_here + : Note<"'__builtin_sycl_unique_stable_name' evaluated here">; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 21003b6838574..cb8b02eeadac7 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -462,6 +462,8 @@ class LangOptions : public LangOptionsBase { bool hasWasmExceptions() const { return getExceptionHandling() == ExceptionHandlingKind::Wasm; } + + bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; } }; /// Floating point control options diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index ecaf7b027e778..6134e60f35414 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -57,6 +57,7 @@ def CoreturnStmt : StmtNode; // Expressions def Expr : StmtNode; def PredefinedExpr : StmtNode; +def SYCLUniqueStableNameExpr : StmtNode; def DeclRefExpr : StmtNode; def IntegerLiteral : StmtNode; def FixedPointLiteral : StmtNode; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 176e4f6d18797..9113f0c9c8651 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -695,11 +695,12 @@ ALIAS("_declspec" , __declspec , KEYMS) ALIAS("_pascal" , __pascal , KEYBORLAND) // Clang Extensions. -KEYWORD(__builtin_convertvector , KEYALL) -ALIAS("__char16_t" , char16_t , KEYCXX) -ALIAS("__char32_t" , char32_t , KEYCXX) -KEYWORD(__builtin_bit_cast , KEYALL) -KEYWORD(__builtin_available , KEYALL) +KEYWORD(__builtin_convertvector , KEYALL) +ALIAS("__char16_t" , char16_t , KEYCXX) +ALIAS("__char32_t" , char32_t , KEYCXX) +KEYWORD(__builtin_bit_cast , KEYALL) +KEYWORD(__builtin_available , KEYALL) +KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL) // Clang-specific keywords enabled only in testing. TESTING_KEYWORD(__unknown_anytype , KEYALL) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 87075d508b32d..bfc2016df645e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1800,6 +1800,7 @@ class Parser : public CodeCompletionHandler { ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); ExprResult ParseUnaryExprOrTypeTraitExpression(); ExprResult ParseBuiltinPrimaryExpression(); + ExprResult ParseSYCLUniqueStableNameExpression(); ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 99f7c791f3554..b787a152a11c3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1068,6 +1068,10 @@ class Sema final { OpaqueParser = P; } + // Does the work necessary to deal with a SYCL kernel lambda. At the moment, + // this just marks the list of lambdas required to name the kernel. + void AddSYCLKernelLambda(const FunctionDecl *FD); + class DelayedDiagnostics; class DelayedDiagnosticsState { @@ -5420,6 +5424,15 @@ class Sema final { ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); + ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI); + ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy); + bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 6d0fde4418841..eb1fff1cca6ad 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1965,6 +1965,9 @@ enum StmtCode { // FixedPointLiteral EXPR_FIXEDPOINT_LITERAL, + + // SYCLUniqueStableNameExpr + EXPR_SYCL_UNIQUE_STABLE_NAME, }; /// The kinds of designators that can occur in a diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4f07c5a180800..3ed8ce6bab3b8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2470,7 +2470,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { // The preferred alignment of member pointers is that of a pointer. if (T->isMemberPointerType()) return getPreferredTypeAlign(getPointerDiffType().getTypePtr()); - + if (!Target->allowsLargerPreferedTypeAlignment()) return ABIAlign; @@ -11116,6 +11116,33 @@ MangleContext *ASTContext::createMangleContext(const TargetInfo *T) { llvm_unreachable("Unsupported ABI"); } +MangleContext *ASTContext::createDeviceMangleContext(const TargetInfo &T) { + assert(T.getCXXABI().getKind() != TargetCXXABI::Microsoft && + "Device mangle context does not support Microsoft mangling."); + switch (T.getCXXABI().getKind()) { + case TargetCXXABI::AppleARM64: + case TargetCXXABI::Fuchsia: + case TargetCXXABI::GenericAArch64: + case TargetCXXABI::GenericItanium: + case TargetCXXABI::GenericARM: + case TargetCXXABI::GenericMIPS: + case TargetCXXABI::iOS: + case TargetCXXABI::WebAssembly: + case TargetCXXABI::WatchOS: + case TargetCXXABI::XL: + return ItaniumMangleContext::create( + *this, getDiagnostics(), + [](ASTContext &, const NamedDecl *ND) -> llvm::Optional { + if (const auto *RD = dyn_cast(ND)) + return RD->getDeviceLambdaManglingNumber(); + return llvm::None; + }); + case TargetCXXABI::Microsoft: + return MicrosoftMangleContext::create(*this, getDiagnostics()); + } + llvm_unreachable("Unsupported ABI"); +} + CXXABI::~CXXABI() = default; size_t ASTContext::getSideTableAllocatedMemory() const { @@ -11689,3 +11716,89 @@ StringRef ASTContext::getCUIDHash() const { CUIDHash = llvm::utohexstr(llvm::MD5Hash(LangOpts.CUID), /*LowerCase=*/true); return CUIDHash; } + +// Get the closest named parent, so we can order the sycl naming decls somewhere +// that mangling is meaningful. +static const DeclContext *GetNamedParent(const CXXRecordDecl *RD) { + const DeclContext *DC = RD->getDeclContext(); + + while (!isa(DC)) + DC = DC->getParent(); + return DC; +} + +void ASTContext::AddSYCLKernelNamingDecl(const CXXRecordDecl *RD) { + assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); + RD = RD->getCanonicalDecl(); + const DeclContext *DC = GetNamedParent(RD); + + assert(RD->getLocation().isValid() && + "Invalid location on kernel naming decl"); + + (void)SYCLKernelNamingTypes[DC].insert(RD); +} + +bool ASTContext::IsSYCLKernelNamingDecl(const NamedDecl *ND) const { + assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); + const auto *RD = dyn_cast(ND); + if (!RD) + return false; + RD = RD->getCanonicalDecl(); + const DeclContext *DC = GetNamedParent(RD); + + auto Itr = SYCLKernelNamingTypes.find(DC); + + if (Itr == SYCLKernelNamingTypes.end()) + return false; + + return Itr->getSecond().count(RD); +} + +// Filters the Decls list to those that share the lambda mangling with the +// passed RD. +static void FilterSYCLKernelNamingDecls( + ASTContext &Ctx, const CXXRecordDecl *RD, + llvm::SmallVectorImpl &Decls) { + static std::unique_ptr Mangler{ + ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())}; + + llvm::SmallString<128> LambdaSig; + llvm::raw_svector_ostream Out(LambdaSig); + Mangler->mangleLambdaSig(RD, Out); + + llvm::erase_if(Decls, [&LambdaSig](const CXXRecordDecl *LocalRD) { + llvm::SmallString<128> LocalLambdaSig; + llvm::raw_svector_ostream LocalOut(LocalLambdaSig); + Mangler->mangleLambdaSig(LocalRD, LocalOut); + return LambdaSig != LocalLambdaSig; + }); +} + +unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) const { + assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); + assert(IsSYCLKernelNamingDecl(ND) && + "Lambda not involved in mangling asked for a naming index?"); + + const CXXRecordDecl *RD = cast(ND)->getCanonicalDecl(); + const DeclContext *DC = GetNamedParent(RD); + + auto Itr = SYCLKernelNamingTypes.find(DC); + assert(Itr != SYCLKernelNamingTypes.end() && "Not a valid DeclContext?"); + + const llvm::SmallPtrSet &Set = Itr->getSecond(); + + llvm::SmallVector Decls{Set.begin(), Set.end()}; + + // If we are in an itanium situation, the mangling-numbers for a lambda depend + // on the mangled signature, so sort by that. Only TargetCXXABI::Microsoft + // doesn't use the itanium mangler, and just sets the lambda mangling number + // incrementally, with no consideration to the signature. + if (Target->getCXXABI().getKind() != TargetCXXABI::Microsoft) + FilterSYCLKernelNamingDecls(const_cast(*this), RD, Decls); + + llvm::sort(Decls, [](const CXXRecordDecl *LHS, const CXXRecordDecl *RHS) { + return LHS->getLambdaManglingNumber() < RHS->getLambdaManglingNumber(); + }); + + return llvm::find(Decls, RD) - Decls.begin(); +} diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 4026fdc76fd6f..1a5d2f7075fb5 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -556,6 +556,10 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) { return D; } +ExprDependence clang::computeDependence(SYCLUniqueStableNameExpr *E) { + return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence()); +} + ExprDependence clang::computeDependence(PredefinedExpr *E) { return toExprDependence(E->getType()->getDependence()) & ~ExprDependence::UnexpandedPack; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index fe2cdc91fb27c..49e1305beea97 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -504,6 +504,70 @@ SourceLocation DeclRefExpr::getEndLoc() const { return getNameInfo().getEndLoc(); } +SYCLUniqueStableNameExpr::SYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + QualType ResultTy, + TypeSourceInfo *TSI) + : Expr(SYCLUniqueStableNameExprClass, ResultTy, VK_RValue, OK_Ordinary), + OpLoc(OpLoc), LParen(LParen), RParen(RParen) { + setTypeSourceInfo(TSI); + setDependence(computeDependence(this)); +} + +SYCLUniqueStableNameExpr::SYCLUniqueStableNameExpr(EmptyShell Empty, + QualType ResultTy) + : Expr(SYCLUniqueStableNameExprClass, ResultTy, VK_RValue, OK_Ordinary) {} + +SYCLUniqueStableNameExpr * +SYCLUniqueStableNameExpr::Create(const ASTContext &Ctx, SourceLocation OpLoc, + SourceLocation LParen, SourceLocation RParen, + TypeSourceInfo *TSI) { + QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst()); + return new (Ctx) + SYCLUniqueStableNameExpr(OpLoc, LParen, RParen, ResultTy, TSI); +} + +SYCLUniqueStableNameExpr * +SYCLUniqueStableNameExpr::CreateEmpty(const ASTContext &Ctx) { + QualType ResultTy = Ctx.getPointerType(Ctx.CharTy.withConst()); + return new (Ctx) SYCLUniqueStableNameExpr(EmptyShell(), ResultTy); +} + +std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context) const { + return SYCLUniqueStableNameExpr::ComputeName(Context, + getTypeSourceInfo()->getType()); +} + +std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context, + QualType Ty) { + auto MangleCallback = [](ASTContext &Ctx, + const NamedDecl *ND) -> llvm::Optional { + // This replaces the 'lambda number' in the mangling with a unique number + // based on its order in the declaration. To provide some level of visual + // notability (actual uniqueness from normal lambdas isn't necessary, as + // these are used differently), we add 10,000 to the number. + // For example: + // _ZTSZ3foovEUlvE10005_ + // Demangles to: typeinfo name for foo()::'lambda10005'() + // Note that the mangler subtracts 2, since with normal lambdas the lambda + // mangling number '0' is an anonymous struct mangle, and '1' is omitted. + // So 10,002 results in the first number being 10,000. + if (Ctx.IsSYCLKernelNamingDecl(ND)) + return 10'002 + Ctx.GetSYCLKernelNamingIndex(ND); + return llvm::None; + }; + std::unique_ptr Ctx{ItaniumMangleContext::create( + Context, Context.getDiagnostics(), MangleCallback)}; + + std::string Buffer; + Buffer.reserve(128); + llvm::raw_string_ostream Out(Buffer); + Ctx->mangleTypeName(Ty, Out); + + return Out.str(); +} + PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL) : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary) { @@ -3381,6 +3445,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case SourceLocExprClass: case ConceptSpecializationExprClass: case RequiresExprClass: + case SYCLUniqueStableNameExprClass: // These never have a side-effect. return false; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 0286c730ce4e3..dd7c4a4cbe00b 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -433,6 +433,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CoawaitExprClass: case Expr::CoyieldExprClass: return ClassifyInternal(Ctx, cast(E)->getResumeExpr()); + case Expr::SYCLUniqueStableNameExprClass: + return Cl::CL_PRValue; + break; } llvm_unreachable("unhandled expression kind in classification"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5508a71508604..22cb01f946c4f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8669,6 +8669,26 @@ class PointerExprEvaluator return true; } + bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E) { + std::string ResultStr = E->ComputeName(Info.Ctx); + + Info.Ctx.SYCLUniqueStableNameEvaluatedValues[E] = ResultStr; + + QualType CharTy = Info.Ctx.CharTy.withConst(); + APInt Size(Info.Ctx.getTypeSize(Info.Ctx.getSizeType()), + ResultStr.size() + 1); + QualType ArrayTy = Info.Ctx.getConstantArrayType(CharTy, Size, nullptr, + ArrayType::Normal, 0); + + StringLiteral *SL = + StringLiteral::Create(Info.Ctx, ResultStr, StringLiteral::Ascii, + /*Pascal*/ false, ArrayTy, E->getLocation()); + + evaluateLValue(SL, Result); + Result.addArray(Info, E, cast(ArrayTy)); + return true; + } + // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace @@ -10367,7 +10387,8 @@ namespace { Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); - if (!Result.hasArrayFiller()) return true; + if (!Result.hasArrayFiller()) + return true; // Zero-initialize all elements. LValue Subobject = This; @@ -15159,6 +15180,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::CoawaitExprClass: case Expr::DependentCoawaitExprClass: case Expr::CoyieldExprClass: + case Expr::SYCLUniqueStableNameExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); case Expr::InitListExprClass: { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 25ccc289ca65b..6369d23630314 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -125,14 +125,16 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { typedef std::pair DiscriminatorKeyTy; llvm::DenseMap Discriminator; llvm::DenseMap Uniquifier; + const DiscriminatorOverrideTy DiscriminatorOverride = nullptr; - bool IsDevCtx = false; bool NeedsUniqueInternalLinkageNames = false; public: - explicit ItaniumMangleContextImpl(ASTContext &Context, - DiagnosticsEngine &Diags) - : ItaniumMangleContext(Context, Diags) {} + explicit ItaniumMangleContextImpl( + ASTContext &Context, DiagnosticsEngine &Diags, + DiscriminatorOverrideTy DiscriminatorOverride) + : ItaniumMangleContext(Context, Diags), + DiscriminatorOverride(DiscriminatorOverride) {} /// @name Mangler Entry Points /// @{ @@ -147,9 +149,6 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { NeedsUniqueInternalLinkageNames = true; } - bool isDeviceMangleContext() const override { return IsDevCtx; } - void setDeviceMangleContext(bool IsDev) override { IsDevCtx = IsDev; } - void mangleCXXName(GlobalDecl GD, raw_ostream &) override; void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &) override; @@ -246,6 +245,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { return Name; } + DiscriminatorOverrideTy getDiscriminatorOverride() const override { + return DiscriminatorOverride; + } + /// @} }; @@ -1515,7 +1518,9 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, // ::= * + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast(TD)) { - if (Record->isLambda() && Record->getLambdaManglingNumber()) { + if (Record->isLambda() && (Record->getLambdaManglingNumber() || + Context.getDiscriminatorOverride()( + Context.getASTContext(), Record))) { assert(!AdditionalAbiTags && "Lambda type cannot have additional abi tags"); mangleLambda(Record); @@ -1953,9 +1958,11 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // if the host-side CXX ABI has different numbering for lambda. In such case, // if the mangle context is that device-side one, use the device-side lambda // mangling number for this lambda. - unsigned Number = Context.isDeviceMangleContext() - ? Lambda->getDeviceLambdaManglingNumber() - : Lambda->getLambdaManglingNumber(); + llvm::Optional DeviceNumber = + Context.getDiscriminatorOverride()(Context.getASTContext(), Lambda); + unsigned Number = DeviceNumber.hasValue() ? *DeviceNumber + : Lambda->getLambdaManglingNumber(); + assert(Number > 0 && "Lambda should be mangled as an unnamed class"); if (Number > 1) mangleNumber(Number - 2); @@ -5034,6 +5041,16 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, Out << "v18co_yield"; mangleExpression(cast(E)->getOperand()); break; + case Expr::SYCLUniqueStableNameExprClass: { + const auto *USN = cast(E); + NotPrimaryExpr(); + + Out << "u33__builtin_sycl_unique_stable_name"; + mangleType(USN->getTypeSourceInfo()->getType()); + + Out << "E"; + break; + } } if (AsTemplateArg && !IsPrimaryExpr) @@ -6386,7 +6403,17 @@ void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl *Lambda, Mangler.mangleLambdaSig(Lambda); } +ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context, + DiagnosticsEngine &Diags) { + return new ItaniumMangleContextImpl( + Context, Diags, + [](ASTContext &, const NamedDecl *) -> llvm::Optional { + return llvm::None; + }); +} + ItaniumMangleContext * -ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { - return new ItaniumMangleContextImpl(Context, Diags); +ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags, + DiscriminatorOverrideTy DiscriminatorOverride) { + return new ItaniumMangleContextImpl(Context, Diags, DiscriminatorOverride); } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 95e60f8b19a6a..5d5388880e675 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1164,6 +1164,12 @@ void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) { } } +void JSONNodeDumper::VisitSYCLUniqueStableNameExpr( + const SYCLUniqueStableNameExpr *E) { + JOS.attribute("typeSourceInfo", + createQualType(E->getTypeSourceInfo()->getType())); +} + void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) { JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind())); } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 58afc020f457e..3e275744931a5 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1081,6 +1081,13 @@ void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) { OS << "]"; } +void StmtPrinter::VisitSYCLUniqueStableNameExpr( + SYCLUniqueStableNameExpr *Node) { + OS << "__builtin_sycl_unique_stable_name("; + Node->getTypeSourceInfo()->getType().print(OS, Policy); + OS << ")"; +} + void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { OS << PredefinedExpr::getIdentKindName(Node->getIdentKind()); } diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index fc1f8a5327244..dc91043b44a67 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1190,6 +1190,12 @@ void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) { } } +void StmtProfiler::VisitSYCLUniqueStableNameExpr( + const SYCLUniqueStableNameExpr *S) { + VisitExpr(S); + VisitType(S->getTypeSourceInfo()->getType()); +} + void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) { VisitExpr(S); ID.AddInteger(S->getIdentKind()); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index ce5089ff5ecee..cb5b4230a5ab9 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1018,6 +1018,11 @@ void TextNodeDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) { OS << " isFreeIvar"; } +void TextNodeDumper::VisitSYCLUniqueStableNameExpr( + const SYCLUniqueStableNameExpr *Node) { + dumpType(Node->getTypeSourceInfo()->getType()); +} + void TextNodeDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { OS << " " << PredefinedExpr::getIdentKindName(Node->getIdentKind()); } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 0d68a2b86c387..5bee625b6b5a8 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -157,6 +157,8 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future; if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus20 && (Flags & CHAR8SUPPORT)) return KS_Future; + if (LangOpts.isSYCL() && (Flags & KEYSYCL)) + return KS_Enabled; return KS_Disabled; } diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 995b6a0b5fec6..bfd2c16c12827 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -191,12 +191,27 @@ CGNVCUDARuntime::addUnderscoredPrefixToName(StringRef FuncName) const { return ((Twine("__cuda") + Twine(FuncName)).str()); } +static std::unique_ptr InitDeviceMC(CodeGenModule &CGM) { + // If the host and device have different C++ ABIs, mark it as the device + // mangle context so that the mangling needs to retrieve the additional + // device lambda mangling number instead of the regular host one. + if (CGM.getContext().getAuxTargetInfo() && + CGM.getContext().getTargetInfo().getCXXABI().isMicrosoft() && + CGM.getContext().getAuxTargetInfo()->getCXXABI().isItaniumFamily()) { + return std::unique_ptr( + CGM.getContext().createDeviceMangleContext( + *CGM.getContext().getAuxTargetInfo())); + } + + return std::unique_ptr(CGM.getContext().createMangleContext( + CGM.getContext().getAuxTargetInfo())); +} + CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) : CGCUDARuntime(CGM), Context(CGM.getLLVMContext()), TheModule(CGM.getModule()), RelocatableDeviceCode(CGM.getLangOpts().GPURelocatableDeviceCode), - DeviceMC(CGM.getContext().createMangleContext( - CGM.getContext().getAuxTargetInfo())) { + DeviceMC(InitDeviceMC(CGM)) { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -207,14 +222,6 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy)); VoidPtrTy = cast(Types.ConvertType(Ctx.VoidPtrTy)); VoidPtrPtrTy = VoidPtrTy->getPointerTo(); - if (CGM.getContext().getAuxTargetInfo()) { - // If the host and device have different C++ ABIs, mark it as the device - // mangle context so that the mangling needs to retrieve the additonal - // device lambda mangling number instead of the regular host one. - DeviceMC->setDeviceMangleContext( - CGM.getContext().getTargetInfo().getCXXABI().isMicrosoft() && - CGM.getContext().getAuxTargetInfo()->getCXXABI().isItaniumFamily()); - } } llvm::FunctionCallee CGNVCUDARuntime::getSetupArgumentFn() const { diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 89ab9abc7dadb..d67d6abe93c99 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -486,6 +486,8 @@ class ScalarExprEmitter return CGF.EmitPseudoObjectRValue(E).getScalarVal(); } + Value *VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E); + Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) { if (E->isGLValue()) return EmitLoadOfLValue(CGF.getOrCreateOpaqueLValueMapping(E), @@ -1581,6 +1583,25 @@ Value *ScalarExprEmitter::VisitExpr(Expr *E) { return llvm::UndefValue::get(CGF.ConvertType(E->getType())); } +Value * +ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) { + ASTContext &Context = CGF.getContext(); + llvm::Optional GlobalAS = + Context.getTargetInfo().getConstantAddressSpace(); + llvm::Constant *GlobalConstStr = Builder.CreateGlobalStringPtr( + E->ComputeName(Context), "__usn_str", + static_cast(GlobalAS.getValueOr(LangAS::Default))); + + unsigned ExprAS = Context.getTargetAddressSpace(E->getType()); + + if (GlobalConstStr->getType()->getPointerAddressSpace() == ExprAS) + return GlobalConstStr; + + llvm::Type *EltTy = GlobalConstStr->getType()->getPointerElementType(); + llvm::PointerType *NewPtrTy = llvm::PointerType::get(EltTy, ExprAS); + return Builder.CreateAddrSpaceCast(GlobalConstStr, NewPtrTy, "usn_addr_cast"); +} + Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { // Vector Mask Case if (E->getNumSubExprs() == 2) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index c2b47f6375b84..22f3b7624c45b 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1469,6 +1469,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw_this: Res = ParseCXXThis(); break; + case tok::kw___builtin_sycl_unique_stable_name: + Res = ParseSYCLUniqueStableNameExpression(); + break; case tok::annot_typename: if (isStartOfObjCClassMessageMissingOpenBracket()) { @@ -2324,6 +2327,33 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return Operand; } +/// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id as +/// a parameter. +ExprResult Parser::ParseSYCLUniqueStableNameExpression() { + assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) && + "Not __bulitin_sycl_unique_stable_name"); + + SourceLocation OpLoc = ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + + // __builtin_sycl_unique_stable_name expressions are always parenthesized. + if (T.expectAndConsume(diag::err_expected_lparen_after, + "__builtin_sycl_unique_stable_name")) + return ExprError(); + + TypeResult Ty = ParseTypeName(); + + if (Ty.isInvalid()) { + T.skipToEnd(); + return ExprError(); + } + + if (T.consumeClose()) + return ExprError(); + + return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(), + T.getCloseLocation(), Ty.get()); +} /// Parse a sizeof or alignof expression. /// diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index f0b9e6a5bc3ba..fd6a4940c174f 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1575,6 +1575,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { return mergeCanThrow(CT, canThrow(TS->getTryBody())); } + case Stmt::SYCLUniqueStableNameExprClass: + return CT_Cannot; case Stmt::NoStmtClass: llvm_unreachable("Invalid class for statement"); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f6f0c12db4ad9..03da561f2061a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3549,6 +3549,28 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } +ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI); +} + +ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy) { + TypeSourceInfo *TSI = nullptr; + QualType Ty = GetTypeFromParser(ParsedTy, &TSI); + + if (Ty.isNull()) + return ExprError(); + if (!TSI) + TSI = Context.getTrivialTypeSourceInfo(Ty, LParen); + + return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); +} + ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentKind IK; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 1c07732fe8aa4..cf5e20f7b6c1e 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -461,11 +461,15 @@ void Sema::handleLambdaNumbering( std::tie(MCtx, ManglingContextDecl) = getCurrentMangleNumberContext(Class->getDeclContext()); bool HasKnownInternalLinkage = false; - if (!MCtx && getLangOpts().CUDA) { + if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice || + getLangOpts().SYCLIsHost)) { // Force lambda numbering in CUDA/HIP as we need to name lambdas following // ODR. Both device- and host-compilation need to have a consistent naming // on kernel functions. As lambdas are potential part of these `__global__` // function names, they needs numbering following ODR. + // Also force for SYCL, since we need this for the + // __builtin_sycl_unique_stable_name implementation, which depends on lambda + // mangling. MCtx = getMangleNumberingContext(Class, ManglingContextDecl); assert(MCtx && "Retrieving mangle numbering context failed!"); HasKnownInternalLinkage = true; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 95e7343892afd..f093b3b96fa1d 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -5075,3 +5075,35 @@ bool Util::matchQualifiedTypeName(QualType Ty, const auto *Ctx = cast(RecTy); return Util::matchContext(Ctx, Scopes); } + +// The SYCL kernel's 'object type' used for diagnostics and naming/mangling is +// the first parameter to a sycl_kernel labeled function template. In SYCL1.2.1, +// this was passed by value, and in SYCL2020, it is passed by reference. +static QualType GetSYCLKernelObjectType(const FunctionDecl *KernelCaller) { + assert(KernelCaller->getNumParams() > 0 && "Insufficient kernel parameters"); + QualType KernelParamTy = KernelCaller->getParamDecl(0)->getType(); + + // SYCL 2020 kernels are passed by reference. + if (KernelParamTy->isReferenceType()) + return KernelParamTy->getPointeeType(); + + // SYCL 1.2.1 + return KernelParamTy; +} + +void Sema::AddSYCLKernelLambda(const FunctionDecl *FD) { + auto MangleCallback = [](ASTContext &Ctx, + const NamedDecl *ND) -> llvm::Optional { + if (const auto *RD = dyn_cast(ND)) + Ctx.AddSYCLKernelNamingDecl(RD); + // We always want to go into the lambda mangling (skipping the unnamed + // struct version), so make sure we return a value here. + return 1; + }; + + QualType Ty = GetSYCLKernelObjectType(FD); + std::unique_ptr Ctx{ItaniumMangleContext::create( + Context, Context.getDiagnostics(), MangleCallback)}; + llvm::raw_null_ostream Out; + Ctx->mangleTypeName(Ty, Out); +} diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1d19f81c50bcd..fdbdfaff2aa65 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -761,6 +761,35 @@ static void instantiateWorkGroupSizeHintAttr( ZResult.get()); } +// This doesn't take any template parameters, but we have a custom action that +// needs to happen when the kernel itself is instantiated. We need to run the +// ItaniumMangler to mark the names required to name this kernel. +static void instantiateDependentSYCLKernelAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const SYCLKernelAttr &Attr, Decl *New) { + // Functions cannot be partially specialized, so if we are being instantiated, + // we are obviously a complete specialization. Since this attribute is only + // valid on function template declarations, we know that this is a full + // instantiation of a kernel. + S.AddSYCLKernelLambda(cast(New)); + + // Evaluate whether this would change any of the already evaluated + // __builtin_sycl_unique_stable_name values. + for (auto &Itr : S.Context.SYCLUniqueStableNameEvaluatedValues) { + const std::string &CurName = Itr.first->ComputeName(S.Context); + if (Itr.second != CurName) { + S.Diag(New->getLocation(), + diag::err_kernel_invalidates_sycl_unique_stable_name); + S.Diag(Itr.first->getLocation(), + diag::note_sycl_unique_stable_name_evaluated_here); + // Update this so future diagnostics work correctly. + Itr.second = CurName; + } + } + + New->addAttr(Attr.clone(S.getASTContext())); +} + /// Determine whether the attribute A might be relevent to the declaration D. /// If not, we can skip instantiating it. The attribute may or may not have /// been instantiated yet. @@ -1040,6 +1069,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (auto *A = dyn_cast(TmplAttr)) { + instantiateDependentSYCLKernelAttr(*this, TemplateArgs, *A, New); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0ae76326717b8..60f1eb3716def 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2403,6 +2403,19 @@ class TreeTransform { return SEHFinallyStmt::Create(getSema().getASTContext(), Loc, Block); } + ExprResult RebuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, Expr *E) { + return getSema().BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, E); + } + + ExprResult RebuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + return getSema().BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); + } + /// Build a new predefined expression. /// /// By default, performs semantic analysis to build the new expression. @@ -10179,6 +10192,24 @@ TreeTransform::TransformConstantExpr(ConstantExpr *E) { return TransformExpr(E->getSubExpr()); } +template +ExprResult TreeTransform::TransformSYCLUniqueStableNameExpr( + SYCLUniqueStableNameExpr *E) { + if (!E->isTypeDependent()) + return E; + + TypeSourceInfo *NewT = getDerived().TransformType(E->getTypeSourceInfo()); + + if (!NewT) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && E->getTypeSourceInfo() == NewT) + return E; + + return getDerived().RebuildSYCLUniqueStableNameExpr( + E->getLocation(), E->getLParenLocation(), E->getRParenLocation(), NewT); +} + template ExprResult TreeTransform::TransformPredefinedExpr(PredefinedExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 04adbabc9b89b..c1f66709c8515 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -581,6 +581,16 @@ void ASTStmtReader::VisitConstantExpr(ConstantExpr *E) { E->setSubExpr(Record.readSubExpr()); } +void ASTStmtReader::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) { + VisitExpr(E); + + E->setLocation(readSourceLocation()); + E->setLParenLocation(readSourceLocation()); + E->setRParenLocation(readSourceLocation()); + + E->setTypeSourceInfo(Record.readTypeSourceInfo()); +} + void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); bool HasFunctionName = Record.readInt(); @@ -2802,6 +2812,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { /*StorageKind=*/Record[ASTStmtReader::NumExprFields])); break; + case EXPR_SYCL_UNIQUE_STABLE_NAME: + S = SYCLUniqueStableNameExpr::CreateEmpty(Context); + break; + case EXPR_PREDEFINED: S = PredefinedExpr::CreateEmpty( Context, diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 017de0db357b5..10be9b894c277 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -580,6 +580,17 @@ void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) { Code = serialization::EXPR_CONSTANT; } +void ASTStmtWriter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) { + VisitExpr(E); + + Record.AddSourceLocation(E->getLocation()); + Record.AddSourceLocation(E->getLParenLocation()); + Record.AddSourceLocation(E->getRParenLocation()); + Record.AddTypeSourceInfo(E->getTypeSourceInfo()); + + Code = serialization::EXPR_SYCL_UNIQUE_STABLE_NAME; +} + void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { VisitExpr(E); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ccfc84bd7a58a..d40161f289f88 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1419,6 +1419,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPArraySectionExprClass: case Stmt::OMPArrayShapingExprClass: case Stmt::OMPIteratorExprClass: + case Stmt::SYCLUniqueStableNameExprClass: case Stmt::TypeTraitExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; diff --git a/clang/test/AST/ast-print-sycl-unique-stable-name.cpp b/clang/test/AST/ast-print-sycl-unique-stable-name.cpp new file mode 100644 index 0000000000000..3f49ea9ee733c --- /dev/null +++ b/clang/test/AST/ast-print-sycl-unique-stable-name.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -ast-print -fsycl-is-device %s -o - -triple spir64-sycldevice | FileCheck %s + +template +void WrappedInTemplate(T t) { + (void)__builtin_sycl_unique_stable_name(T); + (void)__builtin_sycl_unique_stable_name(typename T::type); + (void)__builtin_sycl_unique_stable_name(decltype(t.foo())); +} + +struct Type { + using type = int; + + double foo(); +}; + +void use() { + WrappedInTemplate(Type{}); +} + +// CHECK: template void WrappedInTemplate(T t) +// CHECK: __builtin_sycl_unique_stable_name(T); +// CHECK: __builtin_sycl_unique_stable_name(typename T::type); +// CHECK: __builtin_sycl_unique_stable_name(decltype(t.foo())); + +// CHECK: template<> void WrappedInTemplate(Type t) +// CHECK: __builtin_sycl_unique_stable_name(Type); +// CHECK: __builtin_sycl_unique_stable_name(typename Type::type); +// CHECK: __builtin_sycl_unique_stable_name(decltype(t.foo())); diff --git a/clang/test/CodeGenSYCL/unique_stable_name.cpp b/clang/test/CodeGenSYCL/unique_stable_name.cpp new file mode 100644 index 0000000000000..380ddaeadc69c --- /dev/null +++ b/clang/test/CodeGenSYCL/unique_stable_name.cpp @@ -0,0 +1,159 @@ +// 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 constant [[LAMBDA_K3_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ4mainEUlPZ4mainEUlvE10000_E10000_\00" +// CHECK: @[[INT1:[^\w]+]] = private unnamed_addr constant [[INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSi\00" +// CHECK: @[[STRING:[^\w]+]] = private unnamed_addr constant [[STRING_SIZE:\[[0-9]+ x i8\]]] c"_ZTSAppL_ZZ4mainE1jE_i\00", +// CHECK: @[[INT2:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00" +// CHECK: @[[LAMBDA_X:[^\w]+]] = private unnamed_addr constant [[LAMBDA_X_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE_\00" +// CHECK: @[[MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE0_\00" +// CHECK: @[[MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE1_\00" +// CHECK: @{{.*}} = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE2_\00", align 1 +// CHECK: @{{.*}} = private unnamed_addr constant [36 x i8] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE3_\00", align 1 +// CHECK: @[[MACRO_MACRO_X:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE4_\00" +// CHECK: @[[MACRO_MACRO_Y:[^\w]+]] = private unnamed_addr constant [[MACRO_MACRO_SIZE]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE5_\00" +// CHECK: @[[INT3:[^\w]+]] = private unnamed_addr constant [[INT_SIZE]] c"_ZTSi\00" +// CHECK: @[[LAMBDA:[^\w]+]] = private unnamed_addr constant [[LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZZ4mainENKUlvE10001_clEvEUlvE_\00" +// CHECK: @[[LAMBDA_IN_DEP_INT:[^\w]+]] = private unnamed_addr constant [[DEP_INT_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIiEvvEUlvE_\00", +// CHECK: @[[LAMBDA_IN_DEP_X:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ28lambda_in_dependent_functionIZZ4mainENKUlvE10001_clEvEUlvE_EvvEUlvE_\00", +// CHECK: @[[LAMBDA_NO_DEP:[^\w]+]] = private unnamed_addr constant [[NO_DEP_LAMBDA_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ13lambda_no_depIidEvT_T0_EUlidE_\00", +// CHECK: @[[LAMBDA_TWO_DEP:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA1_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE10001_clEvEUliE_ZZ4mainENKS0_clEvEUldE_EvvEUlvE_\00", +// CHECK: @[[LAMBDA_TWO_DEP2:[^\w]+]] = private unnamed_addr constant [[DEP_LAMBDA2_SIZE:\[[0-9]+ x i8\]]] c"_ZTSZ14lambda_two_depIZZ4mainENKUlvE10001_clEvEUldE_ZZ4mainENKS0_clEvEUliE_EvvEUlvE_\00", + +extern "C" void puts(const char *) {} + +template +void template_param() { + puts(__builtin_sycl_unique_stable_name(T)); +} + +template +void lambda_in_dependent_function() { + auto y = [] {}; + puts(__builtin_sycl_unique_stable_name(decltype(y))); +} + +template +void lambda_two_dep() { + auto z = [] {}; + puts(__builtin_sycl_unique_stable_name(decltype(z))); +} + +template +void lambda_no_dep(Tw a, Tz b) { + auto p = [](Tw a, Tz b) { return ((Tz)a + b); }; + puts(__builtin_sycl_unique_stable_name(decltype(p))); +} + +#define DEF_IN_MACRO() \ + auto MACRO_X = []() {}; \ + auto MACRO_Y = []() {}; \ + puts(__builtin_sycl_unique_stable_name(decltype(MACRO_X))); \ + puts(__builtin_sycl_unique_stable_name(decltype(MACRO_Y))); + +#define MACRO_CALLS_MACRO() \ + { DEF_IN_MACRO(); } \ + { DEF_IN_MACRO(); } + +template +auto func() -> decltype(__builtin_sycl_unique_stable_name(decltype(Ty::str))); + +struct Derp { + static constexpr const char str[] = "derp derp derp"; +}; + +template +[[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { + kernelFunc(); +} + +int main() { + kernel_single_task(func); + // CHECK: call spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_(i8 addrspace(4)* ()* @_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(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_K3_SIZE]], [[LAMBDA_K3_SIZE]]* @[[LAMBDA_KERNEL3]], i32 0, i32 0) to i8 addrspace(4)*)) + + 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(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT1]], i32 0, i32 0) to i8 addrspace(4)*)) + + // 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(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[STRING_SIZE]], [[STRING_SIZE]]* @[[STRING]], i32 0, i32 0) to i8 addrspace(4)*)) + + // CHECK: define internal spir_func void @_Z18kernel_single_taskIZ4mainE7kernel2PFPKcvEEvT0_ + // CHECK: declare spir_func i8 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_ + + kernel_single_task( + []() { + puts(__builtin_sycl_unique_stable_name(int)); + // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT2]], i32 0, i32 0) to i8 addrspace(4)*)) + + auto x = []() {}; + puts(__builtin_sycl_unique_stable_name(decltype(x))); + // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_X_SIZE]], [[LAMBDA_X_SIZE]]* @[[LAMBDA_X]], i32 0, i32 0) to i8 addrspace(4)*)) + + DEF_IN_MACRO(); + // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_X]], i32 0, i32 0) to i8 addrspace(4)*)) + // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_SIZE]], [[MACRO_SIZE]]* @[[MACRO_Y]], i32 0, i32 0) to i8 addrspace(4)*)) + + MACRO_CALLS_MACRO(); + // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_X]], i32 0, i32 0) to i8 addrspace(4)*)) + // CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[MACRO_MACRO_SIZE]], [[MACRO_MACRO_SIZE]]* @[[MACRO_MACRO_Y]], i32 0, i32 0) to i8 addrspace(4)*)) + + template_param(); + // CHECK: call spir_func void @_Z14template_paramIiEvv + + template_param(); + // CHECK: call spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv + + lambda_in_dependent_function(); + // CHECK: call spir_func void @_Z28lambda_in_dependent_functionIiEvv + + lambda_in_dependent_function(); + // CHECK: 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 3, double 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 + + lambda_two_dep(); + // CHECK: 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(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[INT_SIZE]], [[INT_SIZE]]* @[[INT3]], i32 0, i32 0) to i8 addrspace(4)*)) + +// CHECK: define internal spir_func void @_Z14template_paramIZZ4mainENKUlvE0_clEvEUlvE_Evv +// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[LAMBDA_SIZE]], [[LAMBDA_SIZE]]* @[[LAMBDA]], i32 0, i32 0) to i8 addrspace(4)*)) + +// CHECK: define linkonce_odr spir_func void @_Z28lambda_in_dependent_functionIiEvv +// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_INT_SIZE]], [[DEP_INT_SIZE]]* @[[LAMBDA_IN_DEP_INT]], i32 0, i32 0) to i8 addrspace(4)*)) + +// CHECK: define internal spir_func void @_Z28lambda_in_dependent_functionIZZ4mainENKUlvE0_clEvEUlvE_Evv +// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_LAMBDA_SIZE]], [[DEP_LAMBDA_SIZE]]* @[[LAMBDA_IN_DEP_X]], i32 0, i32 0) to i8 addrspace(4)*)) + +// CHECK: define linkonce_odr spir_func void @_Z13lambda_no_depIidEvT_T0_(i32 %a, double %b) +// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[NO_DEP_LAMBDA_SIZE]], [[NO_DEP_LAMBDA_SIZE]]* @[[LAMBDA_NO_DEP]], i32 0, i32 0) to i8 addrspace(4)*)) + +// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUliE_ZZ4mainENKS0_clEvEUldE_Evv +// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_LAMBDA1_SIZE]], [[DEP_LAMBDA1_SIZE]]* @[[LAMBDA_TWO_DEP]], i32 0, i32 0) to i8 addrspace(4)*)) + +// CHECK: define internal spir_func void @_Z14lambda_two_depIZZ4mainENKUlvE0_clEvEUldE_ZZ4mainENKS0_clEvEUliE_Evv +// CHECK: call spir_func void @puts(i8 addrspace(4)* addrspacecast (i8* getelementptr inbounds ([[DEP_LAMBDA2_SIZE]], [[DEP_LAMBDA2_SIZE]]* @[[LAMBDA_TWO_DEP2]], i32 0, i32 0) to i8 addrspace(4)*)) diff --git a/clang/test/ParserSYCL/unique_stable_name.cpp b/clang/test/ParserSYCL/unique_stable_name.cpp new file mode 100644 index 0000000000000..aa50f54ab2137 --- /dev/null +++ b/clang/test/ParserSYCL/unique_stable_name.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify -Wno-unused %s + +namespace NS { +using good = double; +} + +void f(int var) { + // expected-error@+1{{expected '(' after '__builtin_sycl_unique_stable_name'}} + __builtin_sycl_unique_stable_name int; // Correct usage is __builtin_sycl_unique_stable_name(int); + + // expected-error@+1{{expected '(' after '__builtin_sycl_unique_stable_name'}} + __builtin_sycl_unique_stable_name{int}; // Correct usage is __builtin_sycl_unique_stable_name(int); + + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} + __builtin_sycl_unique_stable_name(int; // Missing paren before semicolon + + // expected-error@+2{{expected ')'}} + // expected-note@+1{{to match this '('}} + __builtin_sycl_unique_stable_name(int, float); // Missing paren before comma + + // expected-error@+1{{unknown type name 'var'}} + __builtin_sycl_unique_stable_name(var); + __builtin_sycl_unique_stable_name(NS::good); + + // expected-error@+1{{expected a type}} + __builtin_sycl_unique_stable_name(for (int i = 0; i < 10; ++i) {}) + __builtin_sycl_unique_stable_name({ + (for (int i = 0; i < 10; ++i){})}) +} + +template +void f2() { + __builtin_sycl_unique_stable_name(typename T::good_type); +} + +struct S { + class good_type {}; +}; + +void use() { + f2(); +} diff --git a/clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp b/clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp new file mode 100644 index 0000000000000..5f2a2e3313df5 --- /dev/null +++ b/clang/test/ParserSYCL/unique_stable_name_sycl_only.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=notsycl -Wno-unused %s +// RUN: %clang_cc1 -fsyntax-only -fsycl-is-host -verify=sycl -Wno-unused %s +// RUN: %clang_cc1 -fsyntax-only -fsycl-is-device -verify=sycl -Wno-unused %s + +// sycl-no-diagnostics +void foo() { + // notsycl-error@+1{{expected '(' for function-style cast or type construction}} + __builtin_sycl_unique_stable_name(int); +} diff --git a/clang/test/SemaSYCL/unique_stable_name.cpp b/clang/test/SemaSYCL/unique_stable_name.cpp new file mode 100644 index 0000000000000..f86000fca4e23 --- /dev/null +++ b/clang/test/SemaSYCL/unique_stable_name.cpp @@ -0,0 +1,215 @@ +// RUN: %clang_cc1 %s -std=c++17 -triple x86_64-pc-windows-msvc -fsycl-is-device -verify -fsyntax-only -Wno-unused +// 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 + kernelFunc(); +} + +// kernel1 - expect error +// The current function is named with a lambda (i.e., takes a lambda as a +// template parameter. Call the builtin on the current function then it is +// passed to a kernel. Test that passing the given function to the unique +// stable name builtin and then to the kernel throws an error because the +// latter causes its name mangling to change. +template +void kernel1func(const Func &F1) { + constexpr const char *F1_output = __builtin_sycl_unique_stable_name(Func); // #USN_F1 + // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} + // expected-note@#kernel1func_call{{in instantiation of function template specialization}} + // expected-note@#USN_F1{{'__builtin_sycl_unique_stable_name' evaluated here}} + // expected-note@+1{{in instantiation of function template specialization}} + kernel_single_task(F1); // #kernel1_call +} + +void callkernel1() { + kernel1func([]() {}); // #kernel1func_call +} + +// kernel2 - expect error +// The current function is named with a lambda (i.e., takes a lambda as a +// template parameter). Call the builtin on the given function, +// then an empty lambda is passed to kernel. +// Test that passing the given function to the unique stable name builtin and +// then passing a different lambda to the kernel still throws an error because +// the calling context is part of naming the kernel. Even though the given +// function (F2) is not passed to the kernel, its mangling changes due to +// kernel call with the unrelated lambda. +template +void kernel2func(const Func &F2) { + constexpr const char *F2_output = __builtin_sycl_unique_stable_name(Func); // #USN_F2 + // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}} + // expected-note@#kernel2func_call{{in instantiation of function template specialization}} + // expected-note@#USN_F2{{'__builtin_sycl_unique_stable_name' evaluated here}} + // expected-note@+1{{in instantiation of function template specialization}} + kernel_single_task([]() {}); +} + +void callkernel2() { + kernel2func([]() {}); // #kernel2func_call +} + +template