Skip to content

Commit c709986

Browse files
author
Erich Keane
authored
[NFC][SYCL] Simplify the error checking of arrays by only visiting 1x. (#2344)
The current visitor requires that we go through our diagnostics checkers once per element. This is expensive, so this patch makes it an opt-out as to whether we should visit each element, or only the 1st.
1 parent 82e5323 commit c709986

File tree

1 file changed

+51
-18
lines changed

1 file changed

+51
-18
lines changed

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -832,8 +832,8 @@ class KernelObjVisitor {
832832

833833
// Implements the 'for-each-visitor' pattern.
834834
template <typename... Handlers>
835-
void VisitElement(CXXRecordDecl *Owner, FieldDecl *ArrayField,
836-
QualType ElementTy, Handlers &... handlers) {
835+
void VisitElementImpl(CXXRecordDecl *Owner, FieldDecl *ArrayField,
836+
QualType ElementTy, Handlers &... handlers) {
837837
if (Util::isSyclAccessorType(ElementTy))
838838
KF_FOR_EACH(handleSyclAccessorType, ArrayField, ElementTy);
839839
else if (Util::isSyclStreamType(ElementTy))
@@ -854,6 +854,16 @@ class KernelObjVisitor {
854854
KF_FOR_EACH(handleScalarType, ArrayField, ElementTy);
855855
}
856856

857+
template <typename... Handlers>
858+
void VisitFirstElement(CXXRecordDecl *Owner, FieldDecl *ArrayField,
859+
QualType ElementTy, Handlers &... handlers) {
860+
VisitElementImpl(Owner, ArrayField, ElementTy, handlers...);
861+
}
862+
863+
template <typename... Handlers>
864+
void VisitNthElement(CXXRecordDecl *Owner, FieldDecl *ArrayField,
865+
QualType ElementTy, Handlers &... handlers);
866+
857867
template <typename... Handlers>
858868
void VisitArrayElements(FieldDecl *FD, QualType FieldTy,
859869
Handlers &... handlers) {
@@ -863,17 +873,35 @@ class KernelObjVisitor {
863873
QualType ET = CAT->getElementType();
864874
int64_t ElemCount = CAT->getSize().getSExtValue();
865875
std::initializer_list<int>{(handlers.enterArray(), 0)...};
866-
for (int64_t Count = 0; Count < ElemCount; Count++) {
867-
VisitElement(nullptr, FD, ET, handlers...);
876+
877+
assert(ElemCount > 0 && "SYCL prohibits 0 sized arrays");
878+
VisitFirstElement(nullptr, FD, ET, handlers...);
879+
(void)std::initializer_list<int>{(handlers.nextElement(ET), 0)...};
880+
881+
for (int64_t Count = 1; Count < ElemCount; Count++) {
882+
VisitNthElement(nullptr, FD, ET, handlers...);
868883
(void)std::initializer_list<int>{(handlers.nextElement(ET), 0)...};
869884
}
885+
870886
(void)std::initializer_list<int>{
871887
(handlers.leaveArray(FD, ET, ElemCount), 0)...};
872888
}
873889

890+
// Parent contains the FieldDecl or CXXBaseSpecifier that was used to enter
891+
// the Wrapper structure that we're currently visiting. Owner is the parent
892+
// type (which doesn't exist in cases where it is a FieldDecl in the
893+
// 'root'), and Wrapper is the current struct being unwrapped.
874894
template <typename ParentTy, typename... Handlers>
875895
void VisitRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
876-
const CXXRecordDecl *Wrapper, Handlers &... handlers);
896+
const CXXRecordDecl *Wrapper, Handlers &... handlers) {
897+
(void)std::initializer_list<int>{
898+
(handlers.enterStruct(Owner, Parent), 0)...};
899+
VisitRecordHelper(Wrapper, Wrapper->bases(), handlers...);
900+
VisitRecordHelper(Wrapper, Wrapper->fields(), handlers...);
901+
(void)std::initializer_list<int>{
902+
(handlers.leaveStruct(Owner, Parent), 0)...};
903+
}
904+
877905
template <typename ParentTy, typename... Handlers>
878906
void VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent,
879907
const CXXRecordDecl *Wrapper, Handlers &... handlers);
@@ -988,25 +1016,13 @@ class KernelObjVisitor {
9881016
}
9891017
#undef KF_FOR_EACH
9901018
};
991-
// Parent contains the FieldDecl or CXXBaseSpecifier that was used to enter
992-
// the Wrapper structure that we're currently visiting. Owner is the parent
993-
// type (which doesn't exist in cases where it is a FieldDecl in the
994-
// 'root'), and Wrapper is the current struct being unwrapped.
995-
template <typename ParentTy, typename... Handlers>
996-
void KernelObjVisitor::VisitRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
997-
const CXXRecordDecl *Wrapper,
998-
Handlers &... handlers) {
999-
(void)std::initializer_list<int>{(handlers.enterStruct(Owner, Parent), 0)...};
1000-
VisitRecordHelper(Wrapper, Wrapper->bases(), handlers...);
1001-
VisitRecordHelper(Wrapper, Wrapper->fields(), handlers...);
1002-
(void)std::initializer_list<int>{(handlers.leaveStruct(Owner, Parent), 0)...};
1003-
}
10041019

10051020
// A base type that the SYCL OpenCL Kernel construction task uses to implement
10061021
// individual tasks.
10071022
class SyclKernelFieldHandlerBase {
10081023
public:
10091024
static constexpr const bool VisitUnionBody = false;
1025+
static constexpr const bool VisitNthElement = true;
10101026
// Mark these virtual so that we can use override in the implementer classes,
10111027
// despite virtual dispatch never being used.
10121028

@@ -1115,6 +1131,21 @@ void KernelObjVisitor::VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent,
11151131
HandlerFilter<Handlers::VisitUnionBody, Handlers>(handlers).Handler...);
11161132
}
11171133

1134+
template <typename... Handlers>
1135+
void KernelObjVisitor::VisitNthElement(CXXRecordDecl *Owner,
1136+
FieldDecl *ArrayField,
1137+
QualType ElementTy,
1138+
Handlers &... handlers) {
1139+
// Don't continue descending if none of the handlers 'care'. This could be 'if
1140+
// constexpr' starting in C++17. Until then, we have to count on the
1141+
// optimizer to realize "if (false)" is a dead branch.
1142+
if (AnyTrue<Handlers::VisitNthElement...>::Value)
1143+
VisitElementImpl(
1144+
Owner, ArrayField, ElementTy,
1145+
HandlerFilter<Handlers::VisitNthElement, Handlers>(handlers)
1146+
.Handler...);
1147+
}
1148+
11181149
// A type to check the validity of all of the argument types.
11191150
class SyclKernelFieldChecker : public SyclKernelFieldHandler {
11201151
bool IsInvalid = false;
@@ -1237,6 +1268,7 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
12371268
public:
12381269
SyclKernelFieldChecker(Sema &S)
12391270
: SyclKernelFieldHandler(S), Diag(S.getASTContext().getDiagnostics()) {}
1271+
static constexpr const bool VisitNthElement = false;
12401272
bool isValid() { return !IsInvalid; }
12411273

12421274
bool handleReferenceType(FieldDecl *FD, QualType FieldTy) final {
@@ -1285,6 +1317,7 @@ class SyclKernelUnionChecker : public SyclKernelFieldHandler {
12851317
: SyclKernelFieldHandler(S), Diag(S.getASTContext().getDiagnostics()) {}
12861318
bool isValid() { return !IsInvalid; }
12871319
static constexpr const bool VisitUnionBody = true;
1320+
static constexpr const bool VisitNthElement = false;
12881321

12891322
bool checkType(SourceLocation Loc, QualType Ty) {
12901323
if (UnionCount) {

0 commit comments

Comments
 (0)