Skip to content

Commit 525d253

Browse files
authored
[SYCL] Add __builtin_num_fields and __builtin_field_type (#3658)
This is an experimental branch to see whether we can implement the device copyability checking functionality within the SYCL library by using some builtins to provide super rudimentary introspection of structures and lambdas. These builtins will tell you how many fields are in the structure or how many captures are in the lambda, and tell you what types those fields are. __builtin_num_fields() accepts a type id and returns the number of fields in the given type as an integer constant expression. __builtin_field_type() accepts a type id and an integer constant expression and returns a "value" of the field at the given offset from the given type. The call should always be wrapped in a decltype (or similar) expression to get the actual type of the field. The value returned is meaningless and it is UB to inspect it. Note: if we wish to upstream any of this functionality, this builtin should be replaced by a new type in the type system, akin to how decltype and typeof work. More work is still needed for the SYCL library to fully support the checking in that there is a need to get the number of base classes and the base class type information.
1 parent d6a28a7 commit 525d253

25 files changed

+1028
-1
lines changed

clang/include/clang/AST/ComputeDependence.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ class ObjCSubscriptRefExpr;
102102
class ObjCIsaExpr;
103103
class ObjCIndirectCopyRestoreExpr;
104104
class ObjCMessageExpr;
105+
class SYCLBuiltinNumFieldsExpr;
106+
class SYCLBuiltinNumBasesExpr;
107+
class SYCLBuiltinFieldTypeExpr;
108+
class SYCLBuiltinBaseTypeExpr;
105109

106110
// The following functions are called from constructors of `Expr`, so they
107111
// should not access anything beyond basic
@@ -194,5 +198,10 @@ ExprDependence computeDependence(ObjCIsaExpr *E);
194198
ExprDependence computeDependence(ObjCIndirectCopyRestoreExpr *E);
195199
ExprDependence computeDependence(ObjCMessageExpr *E);
196200

201+
ExprDependence computeDependence(SYCLBuiltinNumFieldsExpr *E);
202+
ExprDependence computeDependence(SYCLBuiltinNumBasesExpr *E);
203+
ExprDependence computeDependence(SYCLBuiltinFieldTypeExpr *E);
204+
ExprDependence computeDependence(SYCLBuiltinBaseTypeExpr *E);
205+
197206
} // namespace clang
198207
#endif

clang/include/clang/AST/ExprCXX.h

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4902,6 +4902,186 @@ class BuiltinBitCastExpr final
49024902
}
49034903
};
49044904

4905+
/// Represents a __builtin_num_fields expression.
4906+
class SYCLBuiltinNumFieldsExpr : public Expr {
4907+
friend class ASTStmtReader;
4908+
4909+
SourceLocation Loc;
4910+
QualType SourceTy;
4911+
4912+
public:
4913+
SYCLBuiltinNumFieldsExpr(SourceLocation Loc, QualType SourceTy,
4914+
QualType RetTy)
4915+
: Expr(SYCLBuiltinNumFieldsExprClass, RetTy, VK_RValue, OK_Ordinary),
4916+
Loc(Loc), SourceTy(SourceTy) {
4917+
setDependence(computeDependence(this));
4918+
}
4919+
4920+
explicit SYCLBuiltinNumFieldsExpr(EmptyShell Empty)
4921+
: Expr(SYCLBuiltinNumFieldsExprClass, Empty) {}
4922+
4923+
QualType getSourceType() const { return SourceTy; }
4924+
unsigned getNumFields() const {
4925+
assert(!SourceTy->isDependentType());
4926+
assert(SourceTy->isRecordType());
4927+
const auto *RD = SourceTy->getAsRecordDecl();
4928+
assert(RD);
4929+
return static_cast<unsigned>(
4930+
std::distance(RD->field_begin(), RD->field_end()));
4931+
}
4932+
4933+
SourceLocation getBeginLoc() const { return Loc; }
4934+
SourceLocation getEndLoc() const { return Loc; }
4935+
4936+
SourceLocation getLocation() const { return Loc; }
4937+
void setLocation(SourceLocation L) { Loc = L; }
4938+
4939+
child_range children() {
4940+
return child_range(child_iterator(), child_iterator());
4941+
}
4942+
4943+
const_child_range children() const {
4944+
return const_child_range(const_child_iterator(), const_child_iterator());
4945+
}
4946+
4947+
static bool classof(const Stmt *T) {
4948+
return T->getStmtClass() == SYCLBuiltinNumFieldsExprClass;
4949+
}
4950+
};
4951+
4952+
/// Represents a __builtin_field_type expression. This does not actually return
4953+
/// the type itself (it would need to be a new type in the type system rather
4954+
/// than an expression to do that), but instead is a valueless expression of
4955+
/// the field's type. The expected usage is to use decltype to extract the
4956+
/// actual type information. This expression can only be used in an unevaluated
4957+
/// context.
4958+
class SYCLBuiltinFieldTypeExpr : public Expr {
4959+
friend class ASTStmtReader;
4960+
4961+
SourceLocation Loc;
4962+
QualType SourceTy;
4963+
Stmt *Index;
4964+
4965+
public:
4966+
SYCLBuiltinFieldTypeExpr(SourceLocation Loc, QualType SourceTy, Expr *Index,
4967+
QualType FieldTy, ExprValueKind ValueKind)
4968+
: Expr(SYCLBuiltinFieldTypeExprClass, FieldTy, ValueKind, OK_Ordinary),
4969+
Loc(Loc), SourceTy(SourceTy), Index(Index) {
4970+
setDependence(computeDependence(this));
4971+
}
4972+
4973+
explicit SYCLBuiltinFieldTypeExpr(EmptyShell Empty)
4974+
: Expr(SYCLBuiltinFieldTypeExprClass, Empty) {}
4975+
4976+
QualType getSourceType() const { return SourceTy; }
4977+
4978+
const Expr *getIndex() const { return static_cast<const Expr *>(Index); }
4979+
Expr *getIndex() { return static_cast<Expr *>(Index); }
4980+
4981+
SourceLocation getBeginLoc() const { return Loc; }
4982+
SourceLocation getEndLoc() const { return Loc; }
4983+
4984+
SourceLocation getLocation() const { return Loc; }
4985+
void setLocation(SourceLocation L) { Loc = L; }
4986+
4987+
static bool classof(const Stmt *T) {
4988+
return T->getStmtClass() == SYCLBuiltinFieldTypeExprClass;
4989+
}
4990+
4991+
child_range children() { return child_range(&Index, &Index + 1); }
4992+
4993+
const_child_range children() const {
4994+
return const_child_range(&Index, &Index + 1);
4995+
}
4996+
};
4997+
4998+
/// Represents a __builtin_num_bases expression.
4999+
class SYCLBuiltinNumBasesExpr : public Expr {
5000+
friend class ASTStmtReader;
5001+
5002+
SourceLocation Loc;
5003+
QualType SourceTy;
5004+
5005+
public:
5006+
SYCLBuiltinNumBasesExpr(SourceLocation Loc, QualType SourceTy, QualType RetTy)
5007+
: Expr(SYCLBuiltinNumBasesExprClass, RetTy, VK_RValue, OK_Ordinary),
5008+
Loc(Loc), SourceTy(SourceTy) {
5009+
setDependence(computeDependence(this));
5010+
}
5011+
5012+
explicit SYCLBuiltinNumBasesExpr(EmptyShell Empty)
5013+
: Expr(SYCLBuiltinNumBasesExprClass, Empty) {}
5014+
5015+
QualType getSourceType() const { return SourceTy; }
5016+
unsigned getNumBases() const {
5017+
assert(!SourceTy->isDependentType());
5018+
assert(SourceTy->isRecordType());
5019+
const auto *RD = SourceTy->getAsCXXRecordDecl();
5020+
assert(RD);
5021+
return RD->getNumBases();
5022+
}
5023+
5024+
SourceLocation getBeginLoc() const { return Loc; }
5025+
SourceLocation getEndLoc() const { return Loc; }
5026+
5027+
SourceLocation getLocation() const { return Loc; }
5028+
void setLocation(SourceLocation L) { Loc = L; }
5029+
5030+
child_range children() {
5031+
return child_range(child_iterator(), child_iterator());
5032+
}
5033+
5034+
const_child_range children() const {
5035+
return const_child_range(const_child_iterator(), const_child_iterator());
5036+
}
5037+
5038+
static bool classof(const Stmt *T) {
5039+
return T->getStmtClass() == SYCLBuiltinNumBasesExprClass;
5040+
}
5041+
};
5042+
5043+
/// Represents a __builtin_base_type expression. This has the same behavior and
5044+
/// constraints as __builtin_field_type.
5045+
class SYCLBuiltinBaseTypeExpr : public Expr {
5046+
friend class ASTStmtReader;
5047+
5048+
SourceLocation Loc;
5049+
QualType SourceTy;
5050+
Stmt *Index;
5051+
5052+
public:
5053+
SYCLBuiltinBaseTypeExpr(SourceLocation Loc, QualType SourceTy, Expr *Index,
5054+
QualType BaseTy)
5055+
: Expr(SYCLBuiltinBaseTypeExprClass, BaseTy, VK_RValue, OK_Ordinary),
5056+
Loc(Loc), SourceTy(SourceTy), Index(Index) {
5057+
setDependence(computeDependence(this));
5058+
}
5059+
5060+
explicit SYCLBuiltinBaseTypeExpr(EmptyShell Empty)
5061+
: Expr(SYCLBuiltinBaseTypeExprClass, Empty) {}
5062+
5063+
QualType getSourceType() const { return SourceTy; }
5064+
5065+
const Expr *getIndex() const { return static_cast<const Expr *>(Index); }
5066+
Expr *getIndex() { return static_cast<Expr *>(Index); }
5067+
5068+
SourceLocation getBeginLoc() const { return Loc; }
5069+
SourceLocation getEndLoc() const { return Loc; }
5070+
5071+
SourceLocation getLocation() const { return Loc; }
5072+
void setLocation(SourceLocation L) { Loc = L; }
5073+
5074+
static bool classof(const Stmt *T) {
5075+
return T->getStmtClass() == SYCLBuiltinBaseTypeExprClass;
5076+
}
5077+
5078+
child_range children() { return child_range(&Index, &Index + 1); }
5079+
5080+
const_child_range children() const {
5081+
return const_child_range(&Index, &Index + 1);
5082+
}
5083+
};
5084+
49055085
} // namespace clang
49065086

49075087
#endif // LLVM_CLANG_AST_EXPRCXX_H

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,20 @@ DEF_TRAVERSE_STMT(BuiltinBitCastExpr, {
23592359
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
23602360
})
23612361

2362+
DEF_TRAVERSE_STMT(SYCLBuiltinFieldTypeExpr, {
2363+
TRY_TO(TraverseType(S->getSourceType()));
2364+
})
2365+
DEF_TRAVERSE_STMT(SYCLBuiltinBaseTypeExpr, {
2366+
TRY_TO(TraverseType(S->getSourceType()));
2367+
})
2368+
2369+
DEF_TRAVERSE_STMT(SYCLBuiltinNumFieldsExpr, {
2370+
TRY_TO(TraverseType(S->getSourceType()));
2371+
})
2372+
DEF_TRAVERSE_STMT(SYCLBuiltinNumBasesExpr, {
2373+
TRY_TO(TraverseType(S->getSourceType()));
2374+
})
2375+
23622376
template <typename Derived>
23632377
bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
23642378
InitListExpr *S, DataRecursionQueue *Queue) {

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11351,6 +11351,21 @@ def warn_sycl_kernel_too_big_args : Warning<
1135111351
def err_sycl_virtual_types : Error<
1135211352
"no class with a vtable can be used in a SYCL kernel or any code included in the kernel">;
1135311353
def note_sycl_recursive_function_declared_here: Note<"function implemented using recursion declared here">;
11354+
def err_sycl_type_trait_requires_complete_type : Error<
11355+
"'%select{__builtin_num_fields|__builtin_field_type|__builtin_num_bases|"
11356+
"__builtin_base_type}0' requires a complete type">;
11357+
def err_sycl_type_trait_requires_record_type : Error<
11358+
"'%select{__builtin_num_fields|__builtin_field_type|__builtin_num_bases|"
11359+
"__builtin_base_type}0' requires a structure "
11360+
"or lambda type">;
11361+
def err_sycl_builtin_type_trait_index_out_of_range : Error<
11362+
"index %0 is greater than the number of %select{fields|bases}2 in type %1">;
11363+
def err_sycl_type_trait_requires_nonnegative_index : Error<
11364+
"'%select{__builtin_field_type|__builtin_base_type}0' requires a "
11365+
"non-negative index">;
11366+
def err_sycl_builtin_type_trait_evaluated : Error<
11367+
"'%select{__builtin_field_type|__builtin_base_type}0' cannot be used in an "
11368+
"evaluated context">;
1135411369
def err_sycl_non_trivially_copy_ctor_dtor_type
1135511370
: Error<"kernel parameter has non-trivially %select{copy "
1135611371
"constructible|destructible}0 class/struct type %1">;

clang/include/clang/Basic/StmtNodes.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ def ObjCBridgedCastExpr : StmtNode<ExplicitCastExpr>;
194194
// CUDA Expressions.
195195
def CUDAKernelCallExpr : StmtNode<CallExpr>;
196196

197+
// SYCL Extensions.
198+
def SYCLBuiltinNumFieldsExpr : StmtNode<Expr>;
199+
def SYCLBuiltinFieldTypeExpr : StmtNode<Expr>;
200+
def SYCLBuiltinNumBasesExpr : StmtNode<Expr>;
201+
def SYCLBuiltinBaseTypeExpr : StmtNode<Expr>;
202+
197203
// Clang Extensions.
198204
def ShuffleVectorExpr : StmtNode<Expr>;
199205
def ConvertVectorExpr : StmtNode<Expr>;

clang/include/clang/Basic/TokenKinds.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,12 @@ TYPE_TRAIT_1(__has_unique_object_representations,
508508
HasUniqueObjectRepresentations, KEYCXX)
509509
KEYWORD(__underlying_type , KEYCXX)
510510

511+
// SYCL Type Traits
512+
KEYWORD(__builtin_num_fields, KEYSYCL)
513+
KEYWORD(__builtin_field_type, KEYSYCL)
514+
KEYWORD(__builtin_num_bases, KEYSYCL)
515+
KEYWORD(__builtin_base_type, KEYSYCL)
516+
511517
// Clang-only C++ Type Traits
512518
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
513519

clang/include/clang/Parse/Parser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3460,6 +3460,12 @@ class Parser : public CodeCompletionHandler {
34603460
ExprResult ParseArrayTypeTrait();
34613461
ExprResult ParseExpressionTrait();
34623462

3463+
/// SYCL Type Traits
3464+
// __builtin_num_fields, __builtin_num_bases
3465+
ExprResult ParseSYCLBuiltinNum();
3466+
// __builtin_field_type, __builtin_base_type
3467+
ExprResult ParseSYCLBuiltinType();
3468+
34633469
//===--------------------------------------------------------------------===//
34643470
// Preprocessor code-completion pass-through
34653471
void CodeCompleteDirective(bool InConditional) override;

clang/include/clang/Sema/Sema.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13250,6 +13250,28 @@ class Sema final {
1325013250
void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC);
1325113251
void MarkDevices();
1325213252

13253+
/// Get the number of fields or captures within the parsed type.
13254+
ExprResult ActOnSYCLBuiltinNumFieldsExpr(ParsedType PT);
13255+
ExprResult BuildSYCLBuiltinNumFieldsExpr(SourceLocation Loc,
13256+
QualType SourceTy);
13257+
13258+
/// Get a value based on the type of the given field number so that callers
13259+
/// can wrap it in a decltype() to get the actual type of the field.
13260+
ExprResult ActOnSYCLBuiltinFieldTypeExpr(ParsedType PT, Expr *Idx);
13261+
ExprResult BuildSYCLBuiltinFieldTypeExpr(SourceLocation Loc,
13262+
QualType SourceTy, Expr *Idx);
13263+
13264+
/// Get the number of base classes within the parsed type.
13265+
ExprResult ActOnSYCLBuiltinNumBasesExpr(ParsedType PT);
13266+
ExprResult BuildSYCLBuiltinNumBasesExpr(SourceLocation Loc,
13267+
QualType SourceTy);
13268+
13269+
/// Get a value based on the type of the given base number so that callers
13270+
/// can wrap it in a decltype() to get the actual type of the base class.
13271+
ExprResult ActOnSYCLBuiltinBaseTypeExpr(ParsedType PT, Expr *Idx);
13272+
ExprResult BuildSYCLBuiltinBaseTypeExpr(SourceLocation Loc, QualType SourceTy,
13273+
Expr *Idx);
13274+
1325313275
/// Emit a diagnostic about the given attribute having a deprecated name, and
1325413276
/// also emit a fixit hint to generate the new attribute name.
1325513277
void DiagnoseDeprecatedAttribute(const ParsedAttr &A, StringRef NewScope,

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1966,7 +1966,11 @@ enum StmtCode {
19661966
// FixedPointLiteral
19671967
EXPR_FIXEDPOINT_LITERAL,
19681968

1969-
// SYCLUniqueStableNameExpr
1969+
// SYCL
1970+
EXPR_SYCL_BUILTIN_NUM_FIELDS,
1971+
EXPR_SYCL_BUILTIN_FIELD_TYPE,
1972+
EXPR_SYCL_BUILTIN_NUM_BASES,
1973+
EXPR_SYCL_BUILTIN_BASE_TYPE,
19701974
EXPR_SYCL_UNIQUE_STABLE_NAME,
19711975
};
19721976

clang/lib/AST/ComputeDependence.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,3 +846,27 @@ ExprDependence clang::computeDependence(ObjCMessageExpr *E) {
846846
D |= A->getDependence();
847847
return D;
848848
}
849+
850+
ExprDependence clang::computeDependence(SYCLBuiltinNumFieldsExpr *E) {
851+
return toExprDependence(E->getSourceType()->getDependence()) &
852+
~ExprDependence::Type;
853+
}
854+
855+
ExprDependence clang::computeDependence(SYCLBuiltinNumBasesExpr *E) {
856+
return toExprDependence(E->getSourceType()->getDependence()) &
857+
~ExprDependence::Type;
858+
}
859+
860+
ExprDependence clang::computeDependence(SYCLBuiltinFieldTypeExpr *E) {
861+
auto D = toExprDependence(E->getSourceType()->getDependence()) &
862+
~ExprDependence::Type;
863+
D |= E->getIndex()->getDependence();
864+
return D;
865+
}
866+
867+
ExprDependence clang::computeDependence(SYCLBuiltinBaseTypeExpr *E) {
868+
auto D = toExprDependence(E->getSourceType()->getDependence()) &
869+
~ExprDependence::Type;
870+
D |= E->getIndex()->getDependence();
871+
return D;
872+
}

clang/lib/AST/Expr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3445,6 +3445,10 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
34453445
case SourceLocExprClass:
34463446
case ConceptSpecializationExprClass:
34473447
case RequiresExprClass:
3448+
case SYCLBuiltinNumFieldsExprClass:
3449+
case SYCLBuiltinFieldTypeExprClass:
3450+
case SYCLBuiltinNumBasesExprClass:
3451+
case SYCLBuiltinBaseTypeExprClass:
34483452
case SYCLUniqueStableNameExprClass:
34493453
// These never have a side-effect.
34503454
return false;

clang/lib/AST/ExprClassification.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
197197
case Expr::SourceLocExprClass:
198198
case Expr::ConceptSpecializationExprClass:
199199
case Expr::RequiresExprClass:
200+
case Expr::SYCLBuiltinNumFieldsExprClass:
201+
case Expr::SYCLBuiltinFieldTypeExprClass:
202+
case Expr::SYCLBuiltinNumBasesExprClass:
203+
case Expr::SYCLBuiltinBaseTypeExprClass:
200204
return Cl::CL_PRValue;
201205

202206
case Expr::ConstantExprClass:

0 commit comments

Comments
 (0)