Skip to content

Commit b5a034e

Browse files
author
Erich Keane
committed
[SYCL] Implement __builtin_unique_stable_name.
In order to support non-user-named kernels, SYCL needs some way in the integration headers to name the kernel object themselves. Initially, the design considered just RTTI naming of the lambdas, this results in a quite unstable situation in light of some device/host macros. Additionally, this ends up needing to use RTTI, which is a burden on the implementation and typically unsupported. Instead, we've introduced a builtin, __builtin_unique_stable_name, which takes a type or expression, and results in a constexpr constant character array that uniquely represents the type (or type of the expression) being passed to it. The implementation accomplishes that simply by using a slightly modified version of the Itanium Mangling. The one exception is when mangling lambdas, instead of appending the index of the lambda in the function, it appends the macro-expansion back-trace of the lambda itself in the form LINE->COL[~LINE->COL...]. Differential Revision: https://reviews.llvm.org/D76620
1 parent 7754b65 commit b5a034e

File tree

14 files changed

+489
-19
lines changed

14 files changed

+489
-19
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,6 +2187,30 @@ argument.
21872187
int *pb =__builtin_preserve_access_index(&v->c[3].b);
21882188
__builtin_preserve_access_index(v->j);
21892189
2190+
``__builtin_unique_stable_name``
2191+
------------------------
2192+
2193+
``__builtin_unique_stable_name()`` is a builtin that takes a type or expression and
2194+
produces a string literal containing a unique name for the type (or type of the
2195+
expression) that is stable across split compilations.
2196+
2197+
In cases where the split compilation needs to share a unique token for a type
2198+
across the boundary (such as in an offloading situation), this name can be used
2199+
for lookup purposes.
2200+
2201+
This builtin is superior to RTTI for this purpose for two reasons. First, this
2202+
value is computed entirely at compile time, so it can be used in constant
2203+
expressions. Second, this value encodes lambda functions based on line-number
2204+
rather than the order in which it appears in a function. This is valuable
2205+
because it is stable in cases where an unrelated lambda is introduced
2206+
conditionally in the same function.
2207+
2208+
The current implementation of this builtin uses a slightly modified Itanium
2209+
Mangler to produce the unique name. The lambda ordinal is replaced with one or
2210+
more line/column pairs in the format ``LINE->COL``, separated with a ``~``
2211+
character. Typically, only one pair will be included, however in the case of
2212+
macro expansions the entire macro expansion stack is expressed.
2213+
21902214
Multiprecision Arithmetic Builtins
21912215
----------------------------------
21922216

clang/include/clang/AST/Expr.h

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,13 +1896,17 @@ class StringLiteral final
18961896
/// [C99 6.4.2.2] - A predefined identifier such as __func__.
18971897
class PredefinedExpr final
18981898
: public Expr,
1899-
private llvm::TrailingObjects<PredefinedExpr, Stmt *> {
1899+
private llvm::TrailingObjects<PredefinedExpr, Stmt *, Expr *,
1900+
TypeSourceInfo *> {
19001901
friend class ASTStmtReader;
19011902
friend TrailingObjects;
19021903

19031904
// PredefinedExpr is optionally followed by a single trailing
19041905
// "Stmt *" for the predefined identifier. It is present if and only if
19051906
// hasFunctionName() is true and is always a "StringLiteral *".
1907+
// It can also be followed by a Expr* in the case of a
1908+
// __builtin_unique_stable_name with an expression, or TypeSourceInfo * if
1909+
// __builtin_unique_stable_name with a type.
19061910

19071911
public:
19081912
enum IdentKind {
@@ -1915,12 +1919,18 @@ class PredefinedExpr final
19151919
PrettyFunction,
19161920
/// The same as PrettyFunction, except that the
19171921
/// 'virtual' keyword is omitted for virtual member functions.
1918-
PrettyFunctionNoVirtual
1922+
PrettyFunctionNoVirtual,
1923+
UniqueStableNameType,
1924+
UniqueStableNameExpr,
19191925
};
19201926

19211927
private:
19221928
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
19231929
StringLiteral *SL);
1930+
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
1931+
TypeSourceInfo *Info);
1932+
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
1933+
Expr *E);
19241934

19251935
explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName);
19261936

@@ -1933,10 +1943,39 @@ class PredefinedExpr final
19331943
*getTrailingObjects<Stmt *>() = SL;
19341944
}
19351945

1946+
void setTypeSourceInfo(TypeSourceInfo *Info) {
1947+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
1948+
"TypeSourceInfo only valid for UniqueStableName of a Type");
1949+
*getTrailingObjects<TypeSourceInfo *>() = Info;
1950+
}
1951+
1952+
void setExpr(Expr *E) {
1953+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
1954+
"TypeSourceInfo only valid for UniqueStableName of n Expression.");
1955+
*getTrailingObjects<Expr *>() = E;
1956+
}
1957+
1958+
size_t numTrailingObjects(OverloadToken<Stmt *>) const {
1959+
return hasFunctionName();
1960+
}
1961+
1962+
size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const {
1963+
return getIdentKind() == UniqueStableNameType && !hasFunctionName();
1964+
}
1965+
size_t numTrailingObjects(OverloadToken<Expr *>) const {
1966+
return getIdentKind() == UniqueStableNameExpr && !hasFunctionName();
1967+
}
1968+
19361969
public:
19371970
/// Create a PredefinedExpr.
19381971
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
19391972
QualType FNTy, IdentKind IK, StringLiteral *SL);
1973+
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
1974+
QualType FNTy, IdentKind IK, StringLiteral *SL,
1975+
TypeSourceInfo *Info);
1976+
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
1977+
QualType FNTy, IdentKind IK, StringLiteral *SL,
1978+
Expr *E);
19401979

19411980
/// Create an empty PredefinedExpr.
19421981
static PredefinedExpr *CreateEmpty(const ASTContext &Ctx,
@@ -1961,8 +2000,33 @@ class PredefinedExpr final
19612000
: nullptr;
19622001
}
19632002

2003+
TypeSourceInfo *getTypeSourceInfo() {
2004+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
2005+
"TypeSourceInfo only valid for UniqueStableName of a Type");
2006+
return *getTrailingObjects<TypeSourceInfo *>();
2007+
}
2008+
2009+
const TypeSourceInfo *getTypeSourceInfo() const {
2010+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameType &&
2011+
"TypeSourceInfo only valid for UniqueStableName of a Type");
2012+
return *getTrailingObjects<TypeSourceInfo *>();
2013+
}
2014+
2015+
Expr *getExpr() {
2016+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
2017+
"TypeSourceInfo only valid for UniqueStableName of n Expression.");
2018+
return *getTrailingObjects<Expr *>();
2019+
}
2020+
2021+
const Expr *getExpr() const {
2022+
assert(!hasFunctionName() && getIdentKind() == UniqueStableNameExpr &&
2023+
"TypeSourceInfo only valid for UniqueStableName of n Expression.");
2024+
return *getTrailingObjects<Expr *>();
2025+
}
2026+
19642027
static StringRef getIdentKindName(IdentKind IK);
19652028
static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl);
2029+
static std::string ComputeName(ASTContext &Ctx, IdentKind IK, const QualType Ty);
19662030

19672031
SourceLocation getBeginLoc() const { return getLocation(); }
19682032
SourceLocation getEndLoc() const { return getLocation(); }

clang/include/clang/AST/Mangle.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,14 @@ class MangleContext {
148148
};
149149

150150
class ItaniumMangleContext : public MangleContext {
151+
bool IsUniqueNameMangler = false;
151152
public:
152153
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
153154
: MangleContext(C, D, MK_Itanium) {}
155+
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D,
156+
bool IsUniqueNameMangler)
157+
: MangleContext(C, D, MK_Itanium),
158+
IsUniqueNameMangler(IsUniqueNameMangler) {}
154159

155160
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
156161
virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
@@ -169,12 +174,15 @@ class ItaniumMangleContext : public MangleContext {
169174

170175
virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;
171176

177+
bool isUniqueNameMangler() { return IsUniqueNameMangler; }
178+
172179
static bool classof(const MangleContext *C) {
173180
return C->getKind() == MK_Itanium;
174181
}
175182

176183
static ItaniumMangleContext *create(ASTContext &Context,
177-
DiagnosticsEngine &Diags);
184+
DiagnosticsEngine &Diags,
185+
bool IsUniqueNameMangler = false);
178186
};
179187

180188
class MicrosoftMangleContext : public MangleContext {

clang/include/clang/Basic/TokenKinds.def

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -674,11 +674,12 @@ ALIAS("_declspec" , __declspec , KEYMS)
674674
ALIAS("_pascal" , __pascal , KEYBORLAND)
675675

676676
// Clang Extensions.
677-
KEYWORD(__builtin_convertvector , KEYALL)
678-
ALIAS("__char16_t" , char16_t , KEYCXX)
679-
ALIAS("__char32_t" , char32_t , KEYCXX)
680-
KEYWORD(__builtin_bit_cast , KEYALL)
681-
KEYWORD(__builtin_available , KEYALL)
677+
KEYWORD(__builtin_convertvector , KEYALL)
678+
ALIAS("__char16_t" , char16_t , KEYCXX)
679+
ALIAS("__char32_t" , char32_t , KEYCXX)
680+
KEYWORD(__builtin_bit_cast , KEYALL)
681+
KEYWORD(__builtin_available , KEYALL)
682+
KEYWORD(__builtin_unique_stable_name, KEYALL)
682683

683684
// Clang-specific keywords enabled only in testing.
684685
TESTING_KEYWORD(__unknown_anytype , KEYALL)

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,7 @@ class Parser : public CodeCompletionHandler {
17541754
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
17551755
ExprResult ParseUnaryExprOrTypeTraitExpression();
17561756
ExprResult ParseBuiltinPrimaryExpression();
1757+
ExprResult ParseUniqueStableNameExpression();
17571758

17581759
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
17591760
bool &isCastExpr,

clang/include/clang/Sema/Sema.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4817,6 +4817,15 @@ class Sema final {
48174817
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
48184818
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
48194819

4820+
ExprResult BuildUniqueStableName(SourceLocation Loc, TypeSourceInfo *Operand);
4821+
ExprResult BuildUniqueStableName(SourceLocation Loc, Expr *E);
4822+
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
4823+
SourceLocation LParen,
4824+
SourceLocation RParen, ParsedType Ty);
4825+
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
4826+
SourceLocation LParen,
4827+
SourceLocation RParen, Expr *Operand);
4828+
48204829
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
48214830

48224831
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);

clang/lib/AST/Expr.cpp

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,34 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
507507
setDependence(computeDependence(this));
508508
}
509509

510+
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK,
511+
TypeSourceInfo *Info)
512+
: Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) {
513+
PredefinedExprBits.Kind = IK;
514+
assert((getIdentKind() == IK) &&
515+
"IdentKind do not fit in PredefinedExprBitFields!");
516+
assert(IK == UniqueStableNameType &&
517+
"Constructor only valid with UniqueStableNameType");
518+
PredefinedExprBits.HasFunctionName = false;
519+
PredefinedExprBits.Loc = L;
520+
setTypeSourceInfo(Info);
521+
setDependence(computeDependence(this));
522+
}
523+
524+
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK,
525+
Expr *Info)
526+
: Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) {
527+
PredefinedExprBits.Kind = IK;
528+
assert((getIdentKind() == IK) &&
529+
"IdentKind do not fit in PredefinedExprBitFields!");
530+
assert(IK == UniqueStableNameExpr &&
531+
"Constructor only valid with UniqueStableNameExpr");
532+
PredefinedExprBits.HasFunctionName = false;
533+
PredefinedExprBits.Loc = L;
534+
setExpr(Info);
535+
setDependence(computeDependence(this));
536+
}
537+
510538
PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName)
511539
: Expr(PredefinedExprClass, Empty) {
512540
PredefinedExprBits.HasFunctionName = HasFunctionName;
@@ -516,15 +544,44 @@ PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
516544
QualType FNTy, IdentKind IK,
517545
StringLiteral *SL) {
518546
bool HasFunctionName = SL != nullptr;
519-
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
520-
alignof(PredefinedExpr));
547+
void *Mem = Ctx.Allocate(
548+
totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(HasFunctionName, 0, 0),
549+
alignof(PredefinedExpr));
521550
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
522551
}
523552

553+
PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
554+
QualType FNTy, IdentKind IK,
555+
StringLiteral *SL,
556+
TypeSourceInfo *Info) {
557+
assert(IK == UniqueStableNameType && "Only valid with UniqueStableNameType");
558+
bool HasFunctionName = SL != nullptr;
559+
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(
560+
HasFunctionName, 0, !HasFunctionName),
561+
alignof(PredefinedExpr));
562+
if (HasFunctionName)
563+
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
564+
return new (Mem) PredefinedExpr(L, FNTy, IK, Info);
565+
}
566+
567+
PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L,
568+
QualType FNTy, IdentKind IK,
569+
StringLiteral *SL, Expr *E) {
570+
assert(IK == UniqueStableNameExpr && "Only valid with UniqueStableNameExpr");
571+
bool HasFunctionName = SL != nullptr;
572+
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(
573+
HasFunctionName, !HasFunctionName, 0),
574+
alignof(PredefinedExpr));
575+
if (HasFunctionName)
576+
return new (Mem) PredefinedExpr(L, FNTy, IK, SL);
577+
return new (Mem) PredefinedExpr(L, FNTy, IK, E);
578+
}
579+
524580
PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx,
525581
bool HasFunctionName) {
526-
void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(HasFunctionName),
527-
alignof(PredefinedExpr));
582+
void *Mem = Ctx.Allocate(
583+
totalSizeToAlloc<Stmt *, Expr *, TypeSourceInfo *>(HasFunctionName, 0, 0),
584+
alignof(PredefinedExpr));
528585
return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName);
529586
}
530587

@@ -544,12 +601,28 @@ StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) {
544601
return "__FUNCSIG__";
545602
case LFuncSig:
546603
return "L__FUNCSIG__";
604+
case UniqueStableNameType:
605+
case UniqueStableNameExpr:
606+
return "__builtin_unique_stable_name";
547607
case PrettyFunctionNoVirtual:
548608
break;
549609
}
550610
llvm_unreachable("Unknown ident kind for PredefinedExpr");
551611
}
552612

613+
std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentKind IK,
614+
QualType Ty) {
615+
std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
616+
Context, Context.getDiagnostics(), /*IsUniqueNameMangler*/ true)};
617+
618+
Ty = Ty.getCanonicalType();
619+
620+
SmallString<256> Buffer;
621+
llvm::raw_svector_ostream Out(Buffer);
622+
Ctx->mangleTypeName(Ty, Out);
623+
return std::string(Buffer.str());
624+
}
625+
553626
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
554627
// expr" policy instead.
555628
std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) {

0 commit comments

Comments
 (0)