Skip to content

[WIP]Unique stable name #310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8c2e149
Add infrastructure for where to run the 'mark' stage of the mangler
Apr 23, 2021
e6b6534
Add lang extension documentation
Apr 23, 2021
f3dffdd
Add builtin as keyword + add parsing code... won't link until we
Apr 23, 2021
5a2780b
Started by trying to implement the 'Build' functions, which requried an
Apr 23, 2021
8f637d8
Add ItaniumMangleContext infrastructure, still need to have it modify…
Apr 23, 2021
355ecc4
Revert unwanted changes from LangExtensions, fix issues aaron mentioned
Apr 26, 2021
acd6f9d
ACTUALLY fix the things aaron suggested
Apr 26, 2021
ba8491a
Implement Codegen for this, not including the modified mangled name
Apr 26, 2021
7358177
Move codegen time name computation into the type so that is accessibl…
Apr 26, 2021
2975b68
TemplateInstantiator doesn't need special handling, remove it so that…
Apr 26, 2021
17339c1
Require a complete type
Apr 26, 2021
0affc56
Add kernel naming structure and at least the beginning of where the C…
Apr 26, 2021
7bc6b92
Remove a pair of TODOs, I couldn't get to the mangling attempt, and t…
Apr 27, 2021
c55e53e
A little work trying to get mangling right, apparently our 'kernel la…
Apr 27, 2021
e74bc41
Add some level of mangling to the lambdas
Apr 28, 2021
bcd0493
Change the callback behavior to include 2 callbacks.
Apr 28, 2021
5c5f66e
Fix things aaron noticed
Apr 29, 2021
7e7552d
Remove some TODOs, implement a numbering mechanism that provides uniq…
Apr 29, 2021
55bb855
Move this expression to CXCursor_UnexposedExpr
Apr 29, 2021
4ad8f83
Move calc name function to a static function so it can be used in the…
Apr 29, 2021
43e51b7
Fix spelling issue, plus fix out of line decl
Apr 29, 2021
ef6ba73
Stop assuming that kernel callees are lambdas/functors, function poin…
Apr 30, 2021
3bb78fe
Change the way we do our codegen-
Apr 30, 2021
f934e00
Re-apply the placeholder-expr crash fix.
Apr 30, 2021
099df82
Correct the codegen behavior ot correctly generate a global of the co…
Apr 30, 2021
1df6b08
clang-format fixes
Apr 30, 2021
0668219
Add tests
schittir May 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2311,6 +2311,30 @@ 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 unevaluated
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
----------------------------------

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -3152,10 +3152,20 @@ OPT_LIST(V)

StringRef getCUIDHash() const;

void AddSYCLKernelNamingDecl(const TagDecl *TD);
bool IsSYCLKernelNamingDecl(const TagDecl *TD) const;
unsigned GetSYCLKernelNamingIndex(const TagDecl *TD) const;

private:
/// All OMPTraitInfo objects live in this collection, one per
/// `pragma omp [begin] declare variant` directive.
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;

/// A list of the (right now just lambda decls) tag 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_unique_stable_name.
llvm::DenseMap<const DeclContext *, llvm::SmallPtrSet<const TagDecl *, 4>>
SYCLKernelNamingTypes;
};

/// Insertion operator for diagnostics.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/ComputeDependence.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class MaterializeTemporaryExpr;
class CXXFoldExpr;
class TypeTraitExpr;
class ConceptSpecializationExpr;
class UniqueStableNameExpr;
class PredefinedExpr;
class CallExpr;
class OffsetOfExpr;
Expand Down Expand Up @@ -165,6 +166,7 @@ ExprDependence computeDependence(TypeTraitExpr *E);
ExprDependence computeDependence(ConceptSpecializationExpr *E,
bool ValueDependent);

ExprDependence computeDependence(UniqueStableNameExpr *E);
ExprDependence computeDependence(PredefinedExpr *E);
ExprDependence computeDependence(CallExpr *E, llvm::ArrayRef<Expr *> PreArgs);
ExprDependence computeDependence(OffsetOfExpr *E);
Expand Down
113 changes: 113 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,119 @@ class PredefinedExpr final
}
};

// This represents a use of the __builtin_unique_stable_name, which takes either
// a type-id or an expression, and at CodeGen time emits a unique string
// representation of the type (or type of the expression) in a way that permits
// us to properly encode information about the SYCL kernels.
class UniqueStableNameExpr final
: public Expr,
private llvm::TrailingObjects<UniqueStableNameExpr, Stmt *,
TypeSourceInfo *> {
friend class ASTStmtReader;
friend TrailingObjects;
SourceLocation OpLoc, LParen, RParen;
// Note: We store a Stmt* instead of the Expr* so that we can implement
// 'children'.
enum class ParamKind { Type, Expr };
ParamKind Kind;

UniqueStableNameExpr(EmptyShell Empty, QualType ResultTy, bool IsExpr);
UniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen,
SourceLocation RParen, QualType ResultTy,
TypeSourceInfo *TSI);
UniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen,
SourceLocation RParen, QualType ResultTy, Expr *E);

size_t numTrailingObjects(OverloadToken<TypeSourceInfo *>) const {
return Kind == ParamKind::Type ? 1 : 0;
}
size_t numTrailingObjects(OverloadToken<Stmt *>) const {
return Kind == ParamKind::Expr ? 1 : 0;
}
void setTypeSourceInfo(TypeSourceInfo *Ty) {
assert(Kind == ParamKind::Type &&
"TypeSourceInfo only valid for UniqueStableName of a Type");
*getTrailingObjects<TypeSourceInfo *>() = Ty;
}
void setExpr(Expr *E) {
assert(Kind == ParamKind::Expr &&
"Expr only valid for UniqueStableName of an Expr");
assert(E->isInstantiationDependent() &&
"Expr type only valid if the expr is dependent");
*getTrailingObjects<Stmt *>() = E;
}

void setLocation(SourceLocation L) { OpLoc = L; }
void setLParenLocation(SourceLocation L) { LParen = L; }
void setRParenLocation(SourceLocation L) { RParen = L; }

public:
TypeSourceInfo *getTypeSourceInfo() {
assert(Kind == ParamKind::Type &&
"TypeSourceInfo only valid for UniqueStableName of a Type");
return *getTrailingObjects<TypeSourceInfo *>();
}

const TypeSourceInfo *getTypeSourceInfo() const {
assert(Kind == ParamKind::Type &&
"TypeSourceInfo only valid for UniqueStableName of a Type");
return *getTrailingObjects<TypeSourceInfo *>();
}

Expr *getExpr() {
assert(Kind == ParamKind::Expr &&
"Expr only valid for UniqueStableName of an Expr");
return cast<Expr>(*getTrailingObjects<Stmt *>());
}

const Expr *getExpr() const {
assert(Kind == ParamKind::Expr &&
"Expr only valid for UniqueStableName of an Expr");
return cast<Expr>(*getTrailingObjects<Stmt *>());
}

bool isExpr() const { return Kind == ParamKind::Expr; }

bool isTypeSourceInfo() const { return Kind == ParamKind::Type; }

static UniqueStableNameExpr *
Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen,
SourceLocation RParen, TypeSourceInfo *TSI);

static UniqueStableNameExpr *Create(const ASTContext &Ctx,
SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen, Expr *E);
static UniqueStableNameExpr *CreateEmpty(const ASTContext &Ctx, bool IsExpr);

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() == UniqueStableNameExprClass;
}

// Iterators
child_range children() {
return child_range(getTrailingObjects<Stmt *>(),
getTrailingObjects<Stmt *>() + isExpr());
}
const_child_range children() const {
return const_child_range(getTrailingObjects<Stmt *>(),
getTrailingObjects<Stmt *>() + isExpr());
}

// Convenience function to generate the name of the currently stored type.
std::string ComputeName(ASTContext &Context);

// 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 {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/JSONNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class JSONNodeDumper
void VisitBlockDecl(const BlockDecl *D);

void VisitDeclRefExpr(const DeclRefExpr *DRE);
void VisitUniqueStableNameExpr(const UniqueStableNameExpr *E);
void VisitPredefinedExpr(const PredefinedExpr *PE);
void VisitUnaryOperator(const UnaryOperator *UO);
void VisitBinaryOperator(const BinaryOperator *BO);
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ class MangleContext {

class ItaniumMangleContext : public MangleContext {
public:
using ShouldCallKernelCallbackTy = bool (*)(ASTContext &, const TagDecl *);
using KernelMangleCallbackTy = void (*)(ASTContext &, const TagDecl *,
raw_ostream &);
explicit ItaniumMangleContext(ASTContext &C, DiagnosticsEngine &D)
: MangleContext(C, D, MK_Itanium) {}

Expand All @@ -195,12 +198,21 @@ class ItaniumMangleContext : public MangleContext {

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

// These have to live here, otherwise the CXXNameMangler won't have access to
// them.
virtual ShouldCallKernelCallbackTy getShouldCallKernelCallback() const = 0;
virtual KernelMangleCallbackTy getKernelMangleCallback() 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,
ShouldCallKernelCallbackTy ShouldKernelMangleCB,
KernelMangleCallbackTy KernelMangleCB);
};

class MicrosoftMangleContext : public MangleContext {
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2636,6 +2636,10 @@ DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
DEF_TRAVERSE_STMT(ObjCAvailabilityCheckExpr, {})
DEF_TRAVERSE_STMT(ParenExpr, {})
DEF_TRAVERSE_STMT(ParenListExpr, {})
DEF_TRAVERSE_STMT(UniqueStableNameExpr, {
if (S->isTypeSourceInfo())
TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc()));
})
DEF_TRAVERSE_STMT(PredefinedExpr, {})
DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ class TextNodeDumper
void VisitCastExpr(const CastExpr *Node);
void VisitImplicitCastExpr(const ImplicitCastExpr *Node);
void VisitDeclRefExpr(const DeclRefExpr *Node);
void VisitUniqueStableNameExpr(const UniqueStableNameExpr *Node);
void VisitPredefinedExpr(const PredefinedExpr *Node);
void VisitCharacterLiteral(const CharacterLiteral *Node);
void VisitIntegerLiteral(const IntegerLiteral *Node);
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def CoreturnStmt : StmtNode<Stmt>;
// Expressions
def Expr : StmtNode<ValueStmt, 1>;
def PredefinedExpr : StmtNode<Expr>;
def UniqueStableNameExpr : StmtNode<Expr>;
def DeclRefExpr : StmtNode<Expr>;
def IntegerLiteral : StmtNode<Expr>;
def FixedPointLiteral : StmtNode<Expr>;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ 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)

// Clang-specific keywords enabled only in testing.
TESTING_KEYWORD(__unknown_anytype , KEYALL)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1797,6 +1797,7 @@ class Parser : public CodeCompletionHandler {
ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
ExprResult ParseUnaryExprOrTypeTraitExpression();
ExprResult ParseBuiltinPrimaryExpression();
ExprResult ParseUniqueStableNameExpression();

ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
bool &isCastExpr,
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,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 {
Expand Down Expand Up @@ -5176,6 +5180,21 @@ class Sema final {
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);

ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
TypeSourceInfo *TSI);
ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen, Expr *E);
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
ParsedType ParsedTy);
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen, Expr *Operand);

bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);

ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1960,6 +1960,9 @@ enum StmtCode {

// FixedPointLiteral
EXPR_FIXEDPOINT_LITERAL,

// UniqueStableNameExpr
EXPR_UNIQUESTABLENAME,
};

/// The kinds of designators that can occur in a
Expand Down
54 changes: 53 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2448,7 +2448,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;

Expand Down Expand Up @@ -11638,3 +11638,55 @@ 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 TagDecl *TD) {
const DeclContext *DC = TD->getDeclContext();

while (!isa<NamedDecl, TranslationUnitDecl>(DC))
DC = DC->getParent();
return DC;
}

void ASTContext::AddSYCLKernelNamingDecl(const TagDecl *TD) {
TD = TD->getCanonicalDecl();
const DeclContext *DC = GetNamedParent(TD);

assert(TD->getLocation().isValid() &&
"Invalid location on kernel naming decl");

(void)SYCLKernelNamingTypes[DC].insert(TD);
}

bool ASTContext::IsSYCLKernelNamingDecl(const TagDecl *TD) const {
TD = TD->getCanonicalDecl();
const DeclContext *DC = GetNamedParent(TD);

auto Itr = SYCLKernelNamingTypes.find(DC);

if (Itr == SYCLKernelNamingTypes.end())
return false;

return Itr->getSecond().count(TD);
}

unsigned ASTContext::GetSYCLKernelNamingIndex(const TagDecl *TD) const {
assert(IsSYCLKernelNamingDecl(TD) &&
"Lambda not involved in mangling asked for a naming index?");

TD = TD->getCanonicalDecl();
const DeclContext *DC = GetNamedParent(TD);

auto Itr = SYCLKernelNamingTypes.find(DC);
assert(Itr != SYCLKernelNamingTypes.end() && "Not a valid DeclContext?");

const llvm::SmallPtrSet<const TagDecl *, 4> &Set = Itr->getSecond();

llvm::SmallVector<const TagDecl *> TagDecls{Set.begin(), Set.end()};
llvm::sort(TagDecls, [](const TagDecl *LHS, const TagDecl *RHS) {
return LHS->getLocation() < RHS->getLocation();
});

return llvm::find(TagDecls, TD) - TagDecls.begin();
}
6 changes: 6 additions & 0 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,12 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) {
return D;
}

ExprDependence clang::computeDependence(UniqueStableNameExpr *E) {
if (E->isExpr())
return E->getExpr()->getDependence();
return toExprDependence(E->getTypeSourceInfo()->getType()->getDependence());
}

ExprDependence clang::computeDependence(PredefinedExpr *E) {
return toExprDependence(E->getType()->getDependence()) &
~ExprDependence::UnexpandedPack;
Expand Down
Loading