Skip to content

Commit b97ca3b

Browse files
author
Erich Keane
authored
[NFC][SYCL] Simplify the VisitUnion functionality to be more reusable. (#2336)
The VisitUnion implmentation that I gave Soumi to do this ended up becoming way too complicated. This patch takes a slightly different implementation tack in order to be significantly less code. This patch uses a 'no-op' handler, one that just does nothing in order to just replace the handlers that no longer need to visit, rather than removing them from the list. This is slightly less efficient than the old way, since there are now more function calls, but I don't think this is a problem for 2 reasons: 1- The noop handler is marked 'final', AND is trivially inlinable, AND does nothing, a moderately smart optimizer can just remove the calls. 2- Since we've broken up the diagnostic visitors into a separate step (during call-expr creation, instead of all at once), my suspicion is that it will be an 'all or nothing' sort of thing.
1 parent 1dbc358 commit b97ca3b

File tree

1 file changed

+58
-64
lines changed

1 file changed

+58
-64
lines changed

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 58 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,16 @@ template <typename T> using bind_param_t = typename bind_param<T>::type;
791791
class KernelObjVisitor {
792792
Sema &SemaRef;
793793

794+
template <typename ParentTy, typename... Handlers>
795+
void VisitUnionImpl(const CXXRecordDecl *Owner, ParentTy &Parent,
796+
const CXXRecordDecl *Wrapper, Handlers &... handlers) {
797+
(void)std::initializer_list<int>{
798+
(handlers.enterUnion(Owner, Parent), 0)...};
799+
VisitRecordHelper(Wrapper, Wrapper->fields(), handlers...);
800+
(void)std::initializer_list<int>{
801+
(handlers.leaveUnion(Owner, Parent), 0)...};
802+
}
803+
794804
public:
795805
KernelObjVisitor(Sema &S) : SemaRef(S) {}
796806

@@ -867,65 +877,9 @@ class KernelObjVisitor {
867877
template <typename ParentTy, typename... Handlers>
868878
void VisitRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
869879
const CXXRecordDecl *Wrapper, Handlers &... handlers);
870-
871-
// Base case, only calls these when filtered.
872-
template <typename... FilteredHandlers, typename ParentTy>
873-
std::enable_if_t<(sizeof...(FilteredHandlers) > 0)>
874-
VisitUnion(FilteredHandlers &... handlers, const CXXRecordDecl *Owner,
875-
ParentTy &Parent, const CXXRecordDecl *Wrapper) {
876-
(void)std::initializer_list<int>{
877-
(handlers.enterUnion(Owner, Parent), 0)...};
878-
VisitRecordHelper(Wrapper, Wrapper->fields(), handlers...);
879-
(void)std::initializer_list<int>{
880-
(handlers.leaveUnion(Owner, Parent), 0)...};
881-
}
882-
883-
// Handle empty base case.
884-
template <typename ParentTy>
880+
template <typename ParentTy, typename... Handlers>
885881
void VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent,
886-
const CXXRecordDecl *Wrapper) {}
887-
888-
template <typename... FilteredHandlers, typename ParentTy,
889-
typename CurHandler, typename... Handlers>
890-
std::enable_if_t<!CurHandler::VisitUnionBody &&
891-
(sizeof...(FilteredHandlers) > 0)>
892-
VisitUnion(FilteredHandlers &... filtered_handlers,
893-
const CXXRecordDecl *Owner, ParentTy &Parent,
894-
const CXXRecordDecl *Wrapper, CurHandler &cur_handler,
895-
Handlers &... handlers) {
896-
VisitUnion<FilteredHandlers...>(filtered_handlers..., Owner, Parent,
897-
Wrapper, handlers...);
898-
}
899-
900-
template <typename... FilteredHandlers, typename ParentTy,
901-
typename CurHandler, typename... Handlers>
902-
std::enable_if_t<CurHandler::VisitUnionBody &&
903-
(sizeof...(FilteredHandlers) > 0)>
904-
VisitUnion(FilteredHandlers &... filtered_handlers,
905-
const CXXRecordDecl *Owner, ParentTy &Parent,
906-
const CXXRecordDecl *Wrapper, CurHandler &cur_handler,
907-
Handlers &... handlers) {
908-
VisitUnion<FilteredHandlers..., CurHandler>(
909-
filtered_handlers..., cur_handler, Owner, Parent, Wrapper, handlers...);
910-
}
911-
912-
// Add overloads without having filtered-handlers
913-
// to handle leading-empty argument packs.
914-
template <typename ParentTy, typename CurHandler, typename... Handlers>
915-
std::enable_if_t<!CurHandler::VisitUnionBody>
916-
VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent,
917-
const CXXRecordDecl *Wrapper, CurHandler &cur_handler,
918-
Handlers &... handlers) {
919-
VisitUnion(Owner, Parent, Wrapper, handlers...);
920-
}
921-
922-
template <typename ParentTy, typename CurHandler, typename... Handlers>
923-
std::enable_if_t<CurHandler::VisitUnionBody>
924-
VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent,
925-
const CXXRecordDecl *Wrapper, CurHandler &cur_handler,
926-
Handlers &... handlers) {
927-
VisitUnion<CurHandler>(cur_handler, Owner, Parent, Wrapper, handlers...);
928-
}
882+
const CXXRecordDecl *Wrapper, Handlers &... handlers);
929883

930884
template <typename... Handlers>
931885
void VisitRecordHelper(const CXXRecordDecl *Owner,
@@ -1050,11 +1004,7 @@ void KernelObjVisitor::VisitRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
10501004

10511005
// A base type that the SYCL OpenCL Kernel construction task uses to implement
10521006
// individual tasks.
1053-
class SyclKernelFieldHandler {
1054-
protected:
1055-
Sema &SemaRef;
1056-
SyclKernelFieldHandler(Sema &S) : SemaRef(S) {}
1057-
1007+
class SyclKernelFieldHandlerBase {
10581008
public:
10591009
static constexpr const bool VisitUnionBody = false;
10601010
// Mark these virtual so that we can use override in the implementer classes,
@@ -1118,9 +1068,53 @@ class SyclKernelFieldHandler {
11181068
virtual bool nextElement(QualType) { return true; }
11191069
virtual bool leaveArray(FieldDecl *, QualType, int64_t) { return true; }
11201070

1121-
virtual ~SyclKernelFieldHandler() = default;
1071+
virtual ~SyclKernelFieldHandlerBase() = default;
1072+
};
1073+
1074+
// A class to act as the direct base for all the SYCL OpenCL Kernel construction
1075+
// tasks that contains a reference to Sema (and potentially any other
1076+
// universally required data).
1077+
class SyclKernelFieldHandler : public SyclKernelFieldHandlerBase {
1078+
protected:
1079+
Sema &SemaRef;
1080+
SyclKernelFieldHandler(Sema &S) : SemaRef(S) {}
11221081
};
11231082

1083+
// A class to represent the 'do nothing' case for filtering purposes.
1084+
class SyclEmptyHandler final : public SyclKernelFieldHandlerBase {};
1085+
SyclEmptyHandler GlobalEmptyHandler;
1086+
1087+
template <bool Keep, typename H> struct HandlerFilter;
1088+
template <typename H> struct HandlerFilter<true, H> {
1089+
H &Handler;
1090+
HandlerFilter(H &Handler) : Handler(Handler) {}
1091+
};
1092+
template <typename H> struct HandlerFilter<false, H> {
1093+
SyclEmptyHandler &Handler = GlobalEmptyHandler;
1094+
HandlerFilter(H &Handler) {}
1095+
};
1096+
1097+
template <bool B, bool... Rest> struct AnyTrue;
1098+
1099+
template <bool B> struct AnyTrue<B> { static constexpr bool Value = B; };
1100+
1101+
template <bool B, bool... Rest> struct AnyTrue {
1102+
static constexpr bool Value = B || AnyTrue<Rest...>::Value;
1103+
};
1104+
1105+
template <typename ParentTy, typename... Handlers>
1106+
void KernelObjVisitor::VisitUnion(const CXXRecordDecl *Owner, ParentTy &Parent,
1107+
const CXXRecordDecl *Wrapper,
1108+
Handlers &... handlers) {
1109+
// Don't continue descending if none of the handlers 'care'. This could be 'if
1110+
// constexpr' starting in C++17. Until then, we have to count on the
1111+
// optimizer to realize "if (false)" is a dead branch.
1112+
if (AnyTrue<Handlers::VisitUnionBody...>::Value)
1113+
VisitUnionImpl(
1114+
Owner, Parent, Wrapper,
1115+
HandlerFilter<Handlers::VisitUnionBody, Handlers>(handlers).Handler...);
1116+
}
1117+
11241118
// A type to check the validity of all of the argument types.
11251119
class SyclKernelFieldChecker : public SyclKernelFieldHandler {
11261120
bool IsInvalid = false;

0 commit comments

Comments
 (0)