Skip to content

Commit eba69b5

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 caf86d2 commit eba69b5

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

+1116
-37
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,7 +1794,7 @@ correctly in any circumstances. It can be used if:
17941794
metaprogramming algorithms to be able to specify/detect types generically.
17951795
17961796
- the generated kernel binary does not contain indirect calls because they
1797-
are eliminated using compiler optimizations e.g. devirtualization.
1797+
are eliminated using compiler optimizations e.g. devirtualization.
17981798
17991799
- the selected target supports the function pointer like functionality e.g.
18001800
most CPU targets.
@@ -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
@@ -2598,7 +2632,7 @@ Guaranteed inlined copy
25982632
``__builtin_memcpy_inline`` has been designed as a building block for efficient
25992633
``memcpy`` implementations. It is identical to ``__builtin_memcpy`` but also
26002634
guarantees not to call any external functions. See LLVM IR `llvm.memcpy.inline
2601-
<https://llvm.org/docs/LangRef.html#llvm-memcpy-inline-intrinsic>`_ intrinsic
2635+
<https://llvm.org/docs/LangRef.html#llvm-memcpy-inline-intrinsic>`_ intrinsic
26022636
for more information.
26032637
26042638
This is useful to implement a custom version of ``memcpy``, implement a

clang/include/clang/AST/ASTContext.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2355,6 +2355,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
23552355
/// If \p T is null pointer, assume the target in ASTContext.
23562356
MangleContext *createMangleContext(const TargetInfo *T = nullptr);
23572357

2358+
/// Creates a device mangle context to correctly mangle lambdas in a mixed
2359+
/// architecture compile by setting the lambda mangling number source to the
2360+
/// DeviceLambdaManglingNumber. Currently this asserts that the TargetInfo
2361+
/// (from the AuxTargetInfo) is a an itanium target.
2362+
MangleContext *createDeviceMangleContext(const TargetInfo &T);
2363+
23582364
void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass,
23592365
SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const;
23602366

@@ -3158,10 +3164,27 @@ OPT_LIST(V)
31583164

31593165
StringRef getCUIDHash() const;
31603166

3167+
void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD);
3168+
bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const;
3169+
unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD) const;
3170+
/// A SourceLocation to store whether we have evaluated a kernel name already,
3171+
/// and where it happened. If so, we need to diagnose an illegal use of the
3172+
/// builtin.
3173+
llvm::MapVector<const SYCLUniqueStableNameExpr *, std::string>
3174+
SYCLUniqueStableNameEvaluatedValues;
3175+
31613176
private:
31623177
/// All OMPTraitInfo objects live in this collection, one per
31633178
/// `pragma omp [begin] declare variant` directive.
31643179
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;
3180+
3181+
/// A list of the (right now just lambda decls) declarations required to
3182+
/// name all the SYCL kernels in the translation unit, so that we can get the
3183+
/// correct kernel name, as well as implement
3184+
/// __builtin_sycl_unique_stable_name.
3185+
llvm::DenseMap<const DeclContext *,
3186+
llvm::SmallPtrSet<const CXXRecordDecl *, 4>>
3187+
SYCLKernelNamingTypes;
31653188
};
31663189

31673190
/// Insertion operator for diagnostics.

clang/include/clang/AST/ComputeDependence.h

Lines changed: 2 additions & 0 deletions
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

Lines changed: 58 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 8 additions & 3 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6352,6 +6352,11 @@ def warn_pointer_arith_null_ptr : Warning<
63526352
def warn_gnu_null_ptr_arith : Warning<
63536353
"arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension">,
63546354
InGroup<NullPointerArithmetic>, DefaultIgnore;
6355+
def err_kernel_invalidates_sycl_unique_stable_name
6356+
: Error<"kernel instantiation changes the result of an evaluated "
6357+
"'__builtin_sycl_unique_stable_name'">;
6358+
def note_sycl_unique_stable_name_evaluated_here
6359+
: Note<"'__builtin_sycl_unique_stable_name' evaluated here">;
63556360

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

clang/include/clang/Basic/LangOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,8 @@ class LangOptions : public LangOptionsBase {
444444
bool hasWasmExceptions() const {
445445
return getExceptionHandling() == ExceptionHandlingKind::Wasm;
446446
}
447+
448+
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
447449
};
448450

449451
/// Floating point control options

clang/include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 0 deletions
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

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

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

705706
// Clang-specific keywords enabled only in testing.
706707
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
@@ -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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,10 @@ class Sema final {
911911
OpaqueParser = P;
912912
}
913913

914+
// Does the work necessary to deal with a SYCL kernel lambda. At the moment,
915+
// this just marks the list of lambdas required to name the kernel.
916+
void AddSYCLKernelLambda(const FunctionDecl *FD);
917+
914918
class DelayedDiagnostics;
915919

916920
class DelayedDiagnosticsState {
@@ -5190,6 +5194,15 @@ class Sema final {
51905194
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
51915195
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
51925196

5197+
ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
5198+
SourceLocation LParen,
5199+
SourceLocation RParen,
5200+
TypeSourceInfo *TSI);
5201+
ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
5202+
SourceLocation LParen,
5203+
SourceLocation RParen,
5204+
ParsedType ParsedTy);
5205+
51935206
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
51945207

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

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,9 @@ enum StmtCode {
19601960

19611961
// FixedPointLiteral
19621962
EXPR_FIXEDPOINT_LITERAL,
1963+
1964+
// SYCLUniqueStableNameExpr
1965+
EXPR_SYCL_UNIQUE_STABLE_NAME,
19631966
};
19641967

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

0 commit comments

Comments
 (0)