1010
1111#include < cstdint> // for uint64_t
1212#include < optional>
13+ #include < utility> // for std::integer_sequence
1314
1415namespace sycl {
1516inline namespace _V1 {
@@ -1009,6 +1010,163 @@ template <bool MakeCall> class if_architecture_helper {
10091010
10101011namespace ext ::oneapi::experimental {
10111012
1013+ namespace detail {
1014+ // Call the callable object "fn" only when this code runs on a device which
1015+ // has a certain set of aspects or a particular architecture.
1016+ //
1017+ // Condition is a parameter pack of int's that define a simple expression
1018+ // language which tells the set of aspects or architectures that the device
1019+ // must have in order to enable the call. See the "Condition*" values below.
1020+ template <typename T, typename ... Condition>
1021+ #ifdef __SYCL_DEVICE_ONLY__
1022+ [[__sycl_detail__::add_ir_attributes_function(
1023+ " sycl-call-if-on-device-conditionally" , true )]]
1024+ #endif
1025+ void call_if_on_device_conditionally (T fn, Condition...) {
1026+ fn ();
1027+ }
1028+
1029+ // The "Condition" parameter pack above is a sequence of int's that define an
1030+ // expression tree. Each node represents a boolean subexpression:
1031+ //
1032+ // ConditionAspect - Next int is a value from "enum aspect". The
1033+ // subexpression is true if the device has this
1034+ // aspect.
1035+ // ConditionArchitecture - Next int is a value from "enum architecture". The
1036+ // subexpression is true if the device has this
1037+ // architecture.
1038+ // ConditionNot - Next int is the root of another subexpression S1.
1039+ // This subexpression is true if S1 is false.
1040+ // ConditionAnd - Next int is the root of another subexpression S1.
1041+ // The int following that subexpression is the root
1042+ // of another subexpression S2. This subexpression
1043+ // is true if both S1 and S2 are true.
1044+ // ConditionOr - Next int is the root of another subexpression S1.
1045+ // The int following that subexpression is the root
1046+ // of another subexpression S2. This subexpression
1047+ // is true if either S1 or S2 are true.
1048+ //
1049+ // These values are stored in the application's executable, so they are
1050+ // effectively part of the ABI. Therefore, any change to an existing value
1051+ // is an ABI break.
1052+ //
1053+ // There is no programmatic reason for the values to be negative. They are
1054+ // negative only by convention to make it easier for humans to distinguish them
1055+ // from aspect or architecture values (which are positive).
1056+ static constexpr int ConditionAspect = -1 ;
1057+ static constexpr int ConditionArchitecture = -2 ;
1058+ static constexpr int ConditionNot = -3 ;
1059+ static constexpr int ConditionAnd = -4 ;
1060+ static constexpr int ConditionOr = -5 ;
1061+
1062+ // Metaprogramming helper to construct a ConditionOr expression for a sequence
1063+ // of architectures. "ConditionAnyArchitectureBuilder<Archs...>::seq" is an
1064+ // "std::integer_sequence" representing the expression.
1065+ template <architecture... Archs> struct ConditionAnyArchitectureBuilder ;
1066+
1067+ template <architecture Arch, architecture... Archs>
1068+ struct ConditionAnyArchitectureBuilder <Arch, Archs...> {
1069+ template <int I1, int I2, int I3, int ... Is>
1070+ static auto append (std::integer_sequence<int , Is...>) {
1071+ return std::integer_sequence<int , I1, I2, I3, Is...>{};
1072+ }
1073+ using rest = typename ConditionAnyArchitectureBuilder<Archs...>::seq;
1074+ static constexpr int arch = static_cast <int >(Arch);
1075+ using seq =
1076+ decltype (append<ConditionOr, ConditionArchitecture, arch>(rest{}));
1077+ };
1078+
1079+ template <architecture Arch> struct ConditionAnyArchitectureBuilder <Arch> {
1080+ static constexpr int arch = static_cast <int >(Arch);
1081+ using seq = std::integer_sequence<int , ConditionArchitecture, arch>;
1082+ };
1083+
1084+ // Metaprogramming helper to construct a ConditionNot expression.
1085+ // ConditionNotBuilder<Exp>::seq" is an "std::integer_sequence" representing
1086+ // the expression.
1087+ template <typename Exp> struct ConditionNotBuilder {
1088+ template <int I, int ... Is>
1089+ static auto append (std::integer_sequence<int , Is...>) {
1090+ return std::integer_sequence<int , I, Is...>{};
1091+ }
1092+ using rest = typename Exp::seq;
1093+ using seq = decltype (append<ConditionNot>(rest{}));
1094+ };
1095+
1096+ // Metaprogramming helper to construct a ConditionAnd expression.
1097+ // "ConditionAndBuilder<Exp1, Exp2>::seq" is an "std::integer_sequence"
1098+ // representing the expression.
1099+ template <typename Exp1, typename Exp2> struct ConditionAndBuilder {
1100+ template <int I, int ... I1s, int ... I2s>
1101+ static auto append (std::integer_sequence<int , I1s...>,
1102+ std::integer_sequence<int , I2s...>) {
1103+ return std::integer_sequence<int , I, I1s..., I2s...>{};
1104+ }
1105+ using rest1 = typename Exp1::seq;
1106+ using rest2 = typename Exp2::seq;
1107+ using seq = decltype (append<ConditionAnd>(rest1{}, rest2{}));
1108+ };
1109+
1110+ // Metaprogramming helper to construct a ConditionOr expression.
1111+ // "ConditionOrBuilder<Exp1, Exp2>::seq" is an "std::integer_sequence"
1112+ // representing the expression.
1113+ template <typename Exp1, typename Exp2> struct ConditionOrBuilder {
1114+ template <int I, int ... I1s, int ... I2s>
1115+ static auto append (std::integer_sequence<int , I1s...>,
1116+ std::integer_sequence<int , I2s...>) {
1117+ return std::integer_sequence<int , I, I1s..., I2s...>{};
1118+ }
1119+ using rest1 = typename Exp1::seq;
1120+ using rest2 = typename Exp2::seq;
1121+ using seq = decltype (append<ConditionOr>(rest1{}, rest2{}));
1122+ };
1123+
1124+ // Helper function to call call_if_on_device_conditionally() while converting
1125+ // the "std::integer_sequence" for a condition expression into individual
1126+ // arguments of type int.
1127+ template <typename T, int ... Is>
1128+ void call_if_on_device_conditionally_helper (T fn,
1129+ std::integer_sequence<int , Is...>) {
1130+ call_if_on_device_conditionally (fn, Is...);
1131+ }
1132+
1133+ // Same sort of helper object for "else_if_architecture_is".
1134+ template <typename MakeCallIf> class if_architecture_is_helper {
1135+ public:
1136+ template <architecture... Archs, typename T,
1137+ typename = std::enable_if<std::is_invocable_v<T>>>
1138+ auto else_if_architecture_is (T fn) {
1139+ using make_call_if =
1140+ ConditionAndBuilder<MakeCallIf,
1141+ ConditionAnyArchitectureBuilder<Archs...>>;
1142+ using make_else_call_if = ConditionAndBuilder<
1143+ MakeCallIf,
1144+ ConditionNotBuilder<ConditionAnyArchitectureBuilder<Archs...>>>;
1145+
1146+ using cond = typename make_call_if::seq;
1147+ call_if_on_device_conditionally_helper (fn, cond{});
1148+ return if_architecture_is_helper<make_else_call_if>{};
1149+ }
1150+
1151+ template <typename T> void otherwise (T fn) {
1152+ using cond = typename MakeCallIf::seq;
1153+ call_if_on_device_conditionally_helper (fn, cond{});
1154+ }
1155+ };
1156+
1157+ } // namespace detail
1158+
1159+ #ifdef SYCL_EXT_ONEAPI_DEVICE_ARCHITECTURE_NEW_DESIGN_IMPL
1160+ template <architecture... Archs, typename T>
1161+ static auto if_architecture_is (T fn) {
1162+ using make_call_if = detail::ConditionAnyArchitectureBuilder<Archs...>;
1163+ using make_else_call_if = detail::ConditionNotBuilder<make_call_if>;
1164+
1165+ using cond = typename make_call_if::seq;
1166+ detail::call_if_on_device_conditionally_helper (fn, cond{});
1167+ return detail::if_architecture_is_helper<make_else_call_if>{};
1168+ }
1169+ #else
10121170// / The condition is `true` only if the device which executes the
10131171// / `if_architecture_is` function has any one of the architectures listed in the
10141172// / @tparam Archs pack.
@@ -1026,6 +1184,7 @@ constexpr static auto if_architecture_is(T fn) {
10261184 return sycl::detail::if_architecture_helper<true >{};
10271185 }
10281186}
1187+ #endif // SYCL_EXT_ONEAPI_DEVICE_ARCHITECTURE_NEW_DESIGN_IMPL
10291188
10301189// / The condition is `true` only if the device which executes the
10311190// / `if_architecture_is` function has an architecture that is in any one of the
0 commit comments