Skip to content

Commit 8347ee4

Browse files
author
Erich Keane
committed
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
1 parent bd97889 commit 8347ee4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1111
-34
lines changed

clang/docs/LanguageExtensions.rst

+34
Original file line numberDiff line numberDiff line change
@@ -2404,6 +2404,40 @@ argument.
24042404
int *pb =__builtin_preserve_access_index(&v->c[3].b);
24052405
__builtin_preserve_access_index(v->j);
24062406
2407+
``__builtin_sycl_unique_stable_name``
2408+
-------------------------------------
2409+
2410+
``__builtin_sycl_unique_stable_name()`` is a builtin that takes a type and
2411+
produces a string literal containing a unique name for the type that is stable
2412+
across split compilations, mainly to support SYCL/Data Parallel C++ language.
2413+
2414+
In cases where the split compilation needs to share a unique token for a type
2415+
across the boundary (such as in an offloading situation), this name can be used
2416+
for lookup purposes, such as in the SYCL Integration Header.
2417+
2418+
The value of this builtin is computed entirely at compile time, so it can be
2419+
used in constant expressions. This value encodes lambda functions based on a
2420+
stable numbering order in which they appear in their local declaration contexts.
2421+
Once this builtin is evaluated in a constexpr context, it is erroneous to use
2422+
it in an instantiation which changes its value.
2423+
2424+
In order to produce the unique name, the current implementation of the bultin
2425+
uses Itanium mangling even if the host compilation uses a different name
2426+
mangling scheme at runtime. The mangler marks all the lambdas required to name
2427+
the SYCL kernel and emits a stable local ordering of the respective lambdas,
2428+
starting from ``10000``. The initial value of ``10000`` serves as an obvious
2429+
differentiator from ordinary lambda mangling numbers but does not serve any
2430+
other purpose and may change in the future. The resulting pattern is
2431+
demanglable. When non-lambda types are passed to the builtin, the mangler emits
2432+
their usual pattern without any special treatment.
2433+
2434+
**Syntax**:
2435+
2436+
.. code-block:: c
2437+
2438+
// Computes a unique stable name for the given type.
2439+
constexpr const char * __builtin_sycl_unique_stable_name( type-id );
2440+
24072441
Multiprecision Arithmetic Builtins
24082442
----------------------------------
24092443

clang/include/clang/AST/ASTContext.h

+23
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
23602360
/// If \p T is null pointer, assume the target in ASTContext.
23612361
MangleContext *createMangleContext(const TargetInfo *T = nullptr);
23622362

2363+
/// Creates a device mangle context to correctly mangle lambdas in a mixed
2364+
/// architecture compile by setting the lambda mangling number source to the
2365+
/// DeviceLambdaManglingNumber. Currently this asserts that the TargetInfo
2366+
/// (from the AuxTargetInfo) is a an itanium target.
2367+
MangleContext *createDeviceMangleContext(const TargetInfo &T);
2368+
23632369
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
23642370
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
23652371

@@ -3163,10 +3169,27 @@ OPT_LIST(V)
31633169

31643170
StringRef getCUIDHash() const;
31653171

3172+
void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD);
3173+
bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const;
3174+
unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD) const;
3175+
/// A SourceLocation to store whether we have evaluated a kernel name already,
3176+
/// and where it happened. If so, we need to diagnose an illegal use of the
3177+
/// builtin.
3178+
llvm::MapVector<const SYCLUniqueStableNameExpr *, std::string>
3179+
SYCLUniqueStableNameEvaluatedValues;
3180+
31663181
private:
31673182
/// All OMPTraitInfo objects live in this collection, one per
31683183
/// `pragma omp [begin] declare variant` directive.
31693184
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;
3185+
3186+
/// A list of the (right now just lambda decls) declarations required to
3187+
/// name all the SYCL kernels in the translation unit, so that we can get the
3188+
/// correct kernel name, as well as implement
3189+
/// __builtin_sycl_unique_stable_name.
3190+
llvm::DenseMap<const DeclContext *,
3191+
llvm::SmallPtrSet<const CXXRecordDecl *, 4>>
3192+
SYCLKernelNamingTypes;
31703193
};
31713194

31723195
/// Insertion operator for diagnostics.

clang/include/clang/AST/ComputeDependence.h

+2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class MaterializeTemporaryExpr;
7878
class CXXFoldExpr;
7979
class TypeTraitExpr;
8080
class ConceptSpecializationExpr;
81+
class SYCLUniqueStableNameExpr;
8182
class PredefinedExpr;
8283
class CallExpr;
8384
class OffsetOfExpr;
@@ -165,6 +166,7 @@ ExprDependence computeDependence(TypeTraitExpr *E);
165166
ExprDependence computeDependence(ConceptSpecializationExpr *E,
166167
bool ValueDependent);
167168

169+
ExprDependence computeDependence(SYCLUniqueStableNameExpr *E);
168170
ExprDependence computeDependence(PredefinedExpr *E);
169171
ExprDependence computeDependence(CallExpr *E, llvm::ArrayRef<Expr *> PreArgs);
170172
ExprDependence computeDependence(OffsetOfExpr *E);

clang/include/clang/AST/Expr.h

+58
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,64 @@ class PredefinedExpr final
20392039
}
20402040
};
20412041

2042+
// This represents a use of the __builtin_sycl_unique_stable_name, which takes a
2043+
// type-id, and at CodeGen time emits a unique string representation of the
2044+
// type in a way that permits us to properly encode information about the SYCL
2045+
// kernels.
2046+
class SYCLUniqueStableNameExpr final : public Expr {
2047+
friend class ASTStmtReader;
2048+
SourceLocation OpLoc, LParen, RParen;
2049+
TypeSourceInfo *TypeInfo;
2050+
2051+
SYCLUniqueStableNameExpr(EmptyShell Empty, QualType ResultTy);
2052+
SYCLUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen,
2053+
SourceLocation RParen, QualType ResultTy,
2054+
TypeSourceInfo *TSI);
2055+
2056+
void setTypeSourceInfo(TypeSourceInfo *Ty) { TypeInfo = Ty; }
2057+
2058+
void setLocation(SourceLocation L) { OpLoc = L; }
2059+
void setLParenLocation(SourceLocation L) { LParen = L; }
2060+
void setRParenLocation(SourceLocation L) { RParen = L; }
2061+
2062+
public:
2063+
TypeSourceInfo *getTypeSourceInfo() { return TypeInfo; }
2064+
2065+
const TypeSourceInfo *getTypeSourceInfo() const { return TypeInfo; }
2066+
2067+
static SYCLUniqueStableNameExpr *
2068+
Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen,
2069+
SourceLocation RParen, TypeSourceInfo *TSI);
2070+
2071+
static SYCLUniqueStableNameExpr *CreateEmpty(const ASTContext &Ctx);
2072+
2073+
SourceLocation getBeginLoc() const { return getLocation(); }
2074+
SourceLocation getEndLoc() const { return RParen; }
2075+
SourceLocation getLocation() const { return OpLoc; }
2076+
SourceLocation getLParenLocation() const { return LParen; }
2077+
SourceLocation getRParenLocation() const { return RParen; }
2078+
2079+
static bool classof(const Stmt *T) {
2080+
return T->getStmtClass() == SYCLUniqueStableNameExprClass;
2081+
}
2082+
2083+
// Iterators
2084+
child_range children() {
2085+
return child_range(child_iterator(), child_iterator());
2086+
}
2087+
2088+
const_child_range children() const {
2089+
return const_child_range(const_child_iterator(), const_child_iterator());
2090+
}
2091+
2092+
// Convenience function to generate the name of the currently stored type.
2093+
std::string ComputeName(ASTContext &Context) const;
2094+
2095+
// Get the generated name of the type. Note that this only works after all
2096+
// kernels have been instantiated.
2097+
static std::string ComputeName(ASTContext &Context, QualType Ty);
2098+
};
2099+
20422100
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
20432101
/// AST node is only formed if full location information is requested.
20442102
class ParenExpr : public Expr {

clang/include/clang/AST/JSONNodeDumper.h

+1
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ class JSONNodeDumper
263263
void VisitBlockDecl(const BlockDecl *D);
264264

265265
void VisitDeclRefExpr(const DeclRefExpr *DRE);
266+
void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);
266267
void VisitPredefinedExpr(const PredefinedExpr *PE);
267268
void VisitUnaryOperator(const UnaryOperator *UO);
268269
void VisitBinaryOperator(const BinaryOperator *BO);

clang/include/clang/AST/Mangle.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ class MangleContext {
107107
virtual bool shouldMangleCXXName(const NamedDecl *D) = 0;
108108
virtual bool shouldMangleStringLiteral(const StringLiteral *SL) = 0;
109109

110-
virtual bool isDeviceMangleContext() const { return false; }
111-
virtual void setDeviceMangleContext(bool) {}
112-
113110
virtual bool isUniqueInternalLinkageDecl(const NamedDecl *ND) {
114111
return false;
115112
}
@@ -173,6 +170,8 @@ class MangleContext {
173170

174171
class ItaniumMangleContext : public MangleContext {
175172
public:
173+
using DiscriminatorOverrideTy =
174+
llvm::Optional<unsigned> (*)(ASTContext &, const NamedDecl *);
176175
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
177176
: MangleContext(C, D, MK_Itanium) {}
178177

@@ -195,12 +194,18 @@ class ItaniumMangleContext : public MangleContext {
195194

196195
virtual void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &) = 0;
197196

197+
// This has to live here, otherwise the CXXNameMangler won't have access to
198+
// it.
199+
virtual DiscriminatorOverrideTy getDiscriminatorOverride() const = 0;
198200
static bool classof(const MangleContext *C) {
199201
return C->getKind() == MK_Itanium;
200202
}
201203

202204
static ItaniumMangleContext *create(ASTContext &Context,
203205
DiagnosticsEngine &Diags);
206+
static ItaniumMangleContext *create(ASTContext &Context,
207+
DiagnosticsEngine &Diags,
208+
DiscriminatorOverrideTy Discriminator);
204209
};
205210

206211
class MicrosoftMangleContext : public MangleContext {

clang/include/clang/AST/RecursiveASTVisitor.h

+3
Original file line numberDiff line numberDiff line change
@@ -2651,6 +2651,9 @@ DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
26512651
DEF_TRAVERSE_STMT(ObjCAvailabilityCheckExpr, {})
26522652
DEF_TRAVERSE_STMT(ParenExpr, {})
26532653
DEF_TRAVERSE_STMT(ParenListExpr, {})
2654+
DEF_TRAVERSE_STMT(SYCLUniqueStableNameExpr, {
2655+
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
2656+
})
26542657
DEF_TRAVERSE_STMT(PredefinedExpr, {})
26552658
DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
26562659
DEF_TRAVERSE_STMT(ConvertVectorExpr, {})

clang/include/clang/AST/TextNodeDumper.h

+1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ class TextNodeDumper
249249
void VisitCastExpr(const CastExpr *Node);
250250
void VisitImplicitCastExpr(const ImplicitCastExpr *Node);
251251
void VisitDeclRefExpr(const DeclRefExpr *Node);
252+
void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *Node);
252253
void VisitPredefinedExpr(const PredefinedExpr *Node);
253254
void VisitCharacterLiteral(const CharacterLiteral *Node);
254255
void VisitIntegerLiteral(const IntegerLiteral *Node);

clang/include/clang/Basic/DiagnosticSemaKinds.td

+5
Original file line numberDiff line numberDiff line change
@@ -6394,6 +6394,11 @@ def warn_pointer_arith_null_ptr : Warning<
63946394
def warn_gnu_null_ptr_arith : Warning<
63956395
"arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">,
63966396
InGroup<NullPointerArithmetic>, DefaultIgnore;
6397+
def err_kernel_invalidates_sycl_unique_stable_name
6398+
: Error<"kernel instantiation changes the result of an evaluated "
6399+
"'__builtin_sycl_unique_stable_name'">;
6400+
def note_sycl_unique_stable_name_evaluated_here
6401+
: Note<"'__builtin_sycl_unique_stable_name' evaluated here">;
63976402

63986403
def warn_floatingpoint_eq : Warning<
63996404
"comparing floating point with == or != is unsafe">,

clang/include/clang/Basic/LangOptions.h

+2
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ class LangOptions : public LangOptionsBase {
462462
bool hasWasmExceptions() const {
463463
return getExceptionHandling() == ExceptionHandlingKind::Wasm;
464464
}
465+
466+
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
465467
};
466468

467469
/// Floating point control options

clang/include/clang/Basic/StmtNodes.td

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def CoreturnStmt : StmtNode<Stmt>;
5757
// Expressions
5858
def Expr : StmtNode<ValueStmt, 1>;
5959
def PredefinedExpr : StmtNode<Expr>;
60+
def SYCLUniqueStableNameExpr : StmtNode<Expr>;
6061
def DeclRefExpr : StmtNode<Expr>;
6162
def IntegerLiteral : StmtNode<Expr>;
6263
def FixedPointLiteral : StmtNode<Expr>;

clang/include/clang/Basic/TokenKinds.def

+6-5
Original file line numberDiff line numberDiff line change
@@ -695,11 +695,12 @@ ALIAS("_declspec" , __declspec , KEYMS)
695695
ALIAS("_pascal" , __pascal , KEYBORLAND)
696696

697697
// Clang Extensions.
698-
KEYWORD(__builtin_convertvector , KEYALL)
699-
ALIAS("__char16_t" , char16_t , KEYCXX)
700-
ALIAS("__char32_t" , char32_t , KEYCXX)
701-
KEYWORD(__builtin_bit_cast , KEYALL)
702-
KEYWORD(__builtin_available , KEYALL)
698+
KEYWORD(__builtin_convertvector , KEYALL)
699+
ALIAS("__char16_t" , char16_t , KEYCXX)
700+
ALIAS("__char32_t" , char32_t , KEYCXX)
701+
KEYWORD(__builtin_bit_cast , KEYALL)
702+
KEYWORD(__builtin_available , KEYALL)
703+
KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL)
703704

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

clang/include/clang/Parse/Parser.h

+1
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ class Parser : public CodeCompletionHandler {
18001800
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
18011801
ExprResult ParseUnaryExprOrTypeTraitExpression();
18021802
ExprResult ParseBuiltinPrimaryExpression();
1803+
ExprResult ParseSYCLUniqueStableNameExpression();
18031804

18041805
ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
18051806
bool &isCastExpr,

clang/include/clang/Sema/Sema.h

+13
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,10 @@ class Sema final {
10681068
OpaqueParser = P;
10691069
}
10701070

1071+
// Does the work necessary to deal with a SYCL kernel lambda. At the moment,
1072+
// this just marks the list of lambdas required to name the kernel.
1073+
void AddSYCLKernelLambda(const FunctionDecl *FD);
1074+
10711075
class DelayedDiagnostics;
10721076

10731077
class DelayedDiagnosticsState {
@@ -5420,6 +5424,15 @@ class Sema final {
54205424
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
54215425
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
54225426

5427+
ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
5428+
SourceLocation LParen,
5429+
SourceLocation RParen,
5430+
TypeSourceInfo *TSI);
5431+
ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
5432+
SourceLocation LParen,
5433+
SourceLocation RParen,
5434+
ParsedType ParsedTy);
5435+
54235436
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
54245437

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

clang/include/clang/Serialization/ASTBitCodes.h

+3
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,9 @@ enum StmtCode {
19651965

19661966
// FixedPointLiteral
19671967
EXPR_FIXEDPOINT_LITERAL,
1968+
1969+
// SYCLUniqueStableNameExpr
1970+
EXPR_SYCL_UNIQUE_STABLE_NAME,
19681971
};
19691972

19701973
/// The kinds of designators that can occur in a

0 commit comments

Comments
 (0)