Skip to content

Commit 87f60f6

Browse files
[SYCL] Adds compile-time properties (#4976)
Implements the [compile-time property list extension](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/PropertyList/SYCL_EXT_ONEAPI_property_list.asciidoc) adding the `sycl::ext::oneapi::properties` and `sycl::ext::oneapi::property_value` classes. These allow for compile-time inspection of properties passed to SYCL objects. These changes do not add support for the new property lists to any existing SYCL classes however.
1 parent 1c6bfa8 commit 87f60f6

15 files changed

+1368
-0
lines changed

sycl/include/CL/sycl.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
#include <sycl/ext/oneapi/filter_selector.hpp>
6565
#include <sycl/ext/oneapi/group_algorithm.hpp>
6666
#include <sycl/ext/oneapi/matrix/matrix.hpp>
67+
#include <sycl/ext/oneapi/properties/properties.hpp>
68+
#include <sycl/ext/oneapi/properties/property_value.hpp>
6769
#include <sycl/ext/oneapi/reduction.hpp>
6870
#include <sycl/ext/oneapi/sub_group.hpp>
6971
#include <sycl/ext/oneapi/sub_group_mask.hpp>
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
//==---------- properties.hpp --- SYCL extended property list --------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#pragma once
10+
11+
#include <CL/sycl/detail/property_helper.hpp>
12+
#include <CL/sycl/types.hpp>
13+
#include <sycl/ext/oneapi/properties/property.hpp>
14+
#include <sycl/ext/oneapi/properties/property_utils.hpp>
15+
#include <sycl/ext/oneapi/properties/property_value.hpp>
16+
17+
#include <tuple>
18+
#include <type_traits>
19+
20+
__SYCL_INLINE_NAMESPACE(cl) {
21+
namespace sycl {
22+
namespace ext {
23+
namespace oneapi {
24+
namespace experimental {
25+
26+
namespace detail {
27+
28+
// Checks if a tuple of properties contains a property.
29+
template <typename PropT, typename PropertiesT>
30+
struct ContainsProperty : std::false_type {};
31+
template <typename PropT, typename T, typename... Ts>
32+
struct ContainsProperty<PropT, std::tuple<T, Ts...>>
33+
: ContainsProperty<PropT, std::tuple<Ts...>> {};
34+
template <typename PropT, typename... Rest>
35+
struct ContainsProperty<PropT, std::tuple<PropT, Rest...>> : std::true_type {};
36+
template <typename PropT, typename... PropValuesTs, typename... Rest>
37+
struct ContainsProperty<
38+
PropT, std::tuple<property_value<PropT, PropValuesTs...>, Rest...>>
39+
: std::true_type {};
40+
41+
// Finds the full property_value type of a property in a tuple of properties.
42+
// type is void if the type was not found in the tuple of properties.
43+
template <typename CTPropertyT, typename PropertiesT = void>
44+
struct FindCompileTimePropertyValueType {
45+
using type = void;
46+
};
47+
template <typename CTPropertyT, typename OtherProperty, typename... Rest>
48+
struct FindCompileTimePropertyValueType<CTPropertyT,
49+
std::tuple<OtherProperty, Rest...>> {
50+
using type =
51+
typename FindCompileTimePropertyValueType<CTPropertyT,
52+
std::tuple<Rest...>>::type;
53+
};
54+
template <typename CTPropertyT, typename... CTPropertyValueTs, typename... Rest>
55+
struct FindCompileTimePropertyValueType<
56+
CTPropertyT,
57+
std::tuple<property_value<CTPropertyT, CTPropertyValueTs...>, Rest...>> {
58+
using type = property_value<CTPropertyT, CTPropertyValueTs...>;
59+
};
60+
61+
template <typename CTPropertyT, bool HasProperty, typename PropertiesT = void>
62+
static constexpr std::enable_if_t<
63+
HasProperty,
64+
typename FindCompileTimePropertyValueType<CTPropertyT, PropertiesT>::type>
65+
get_property() {
66+
return {};
67+
}
68+
69+
template <typename CTPropertyT, bool HasProperty, typename PropertiesT = void>
70+
static constexpr std::enable_if_t<!HasProperty, void> get_property() {
71+
return;
72+
}
73+
74+
// Filters for all runtime properties with data in a tuple of properties.
75+
// NOTE: We only need storage for runtime properties with data.
76+
template <typename T> struct RuntimePropertyStorage {};
77+
template <typename... Ts> struct RuntimePropertyStorage<std::tuple<Ts...>> {
78+
using type = std::tuple<>;
79+
};
80+
template <typename T, typename... Ts>
81+
struct RuntimePropertyStorage<std::tuple<T, Ts...>>
82+
: sycl::detail::conditional_t<
83+
IsRuntimeProperty<T>::value,
84+
PrependTuple<
85+
T, typename RuntimePropertyStorage<std::tuple<Ts...>>::type>,
86+
RuntimePropertyStorage<std::tuple<Ts...>>> {};
87+
88+
// Helper class to extract a subset of elements from a tuple.
89+
// NOTES: This assumes no duplicate properties and that all properties in the
90+
// struct template argument appear in the tuple passed to Extract.
91+
template <typename PropertiesT> struct ExtractProperties {};
92+
template <typename... PropertiesTs>
93+
struct ExtractProperties<std::tuple<PropertiesTs...>> {
94+
template <typename... PropertyValueTs>
95+
using ExtractedPropertiesT = std::tuple<>;
96+
97+
template <typename... PropertyValueTs>
98+
static ExtractedPropertiesT<PropertyValueTs...>
99+
Extract(std::tuple<PropertyValueTs...> PropertyValues) {
100+
return {};
101+
}
102+
};
103+
template <typename PropertyT, typename... PropertiesTs>
104+
struct ExtractProperties<std::tuple<PropertyT, PropertiesTs...>> {
105+
template <typename... PropertyValueTs>
106+
using NextExtractedPropertiesT =
107+
typename ExtractProperties<std::tuple<PropertiesTs...>>::
108+
template ExtractedPropertiesT<PropertyValueTs...>;
109+
template <typename... PropertyValueTs>
110+
using ExtractedPropertiesT =
111+
typename PrependTuple<PropertyT,
112+
NextExtractedPropertiesT<PropertyValueTs...>>::type;
113+
114+
template <typename... PropertyValueTs>
115+
static ExtractedPropertiesT<PropertyValueTs...>
116+
Extract(std::tuple<PropertyValueTs...> PropertyValues) {
117+
PropertyT ThisExtractedProperty = std::get<PropertyT>(PropertyValues);
118+
NextExtractedPropertiesT<PropertyValueTs...> NextExtractedProperties =
119+
ExtractProperties<std::tuple<PropertiesTs...>>::template Extract<
120+
PropertyValueTs...>(PropertyValues);
121+
return std::tuple_cat(std::tuple<PropertyT>{ThisExtractedProperty},
122+
NextExtractedProperties);
123+
}
124+
};
125+
126+
} // namespace detail
127+
128+
template <typename PropertiesT> class properties {
129+
static_assert(detail::IsTuple<PropertiesT>::value,
130+
"Properties must be in a tuple.");
131+
static_assert(detail::AllPropertyValues<PropertiesT>::value,
132+
"Unrecognized property in property list.");
133+
static_assert(detail::IsSorted<PropertiesT>::value,
134+
"Properties in property list are not sorted.");
135+
static_assert(detail::SortedAllUnique<PropertiesT>::value,
136+
"Duplicate properties in property list.");
137+
138+
public:
139+
template <typename... PropertyValueTs>
140+
properties(PropertyValueTs... props)
141+
: Storage(detail::ExtractProperties<StorageT>::Extract(
142+
std::tuple<PropertyValueTs...>{props...})) {}
143+
144+
template <typename PropertyT>
145+
static constexpr std::enable_if_t<detail::IsProperty<PropertyT>::value, bool>
146+
has_property() {
147+
return detail::ContainsProperty<PropertyT, PropertiesT>::value;
148+
}
149+
150+
template <typename PropertyT>
151+
typename std::enable_if_t<detail::IsRuntimeProperty<PropertyT>::value &&
152+
has_property<PropertyT>(),
153+
PropertyT>
154+
get_property() const {
155+
return std::get<PropertyT>(Storage);
156+
}
157+
158+
template <typename PropertyT>
159+
typename std::enable_if_t<detail::IsRuntimeProperty<PropertyT>::value &&
160+
!has_property<PropertyT>(),
161+
void>
162+
get_property() const {
163+
static_assert(has_property<PropertyT>(),
164+
"Property list does not contain the requested property.");
165+
return;
166+
}
167+
168+
template <typename PropertyT>
169+
static constexpr auto get_property(
170+
typename std::enable_if_t<detail::IsCompileTimeProperty<PropertyT>::value>
171+
* = 0) {
172+
static_assert(has_property<PropertyT>(),
173+
"Property list does not contain the requested property.");
174+
return detail::get_property<PropertyT, has_property<PropertyT>(),
175+
PropertiesT>();
176+
}
177+
178+
private:
179+
using StorageT = typename detail::RuntimePropertyStorage<PropertiesT>::type;
180+
181+
StorageT Storage;
182+
};
183+
184+
#ifdef __cpp_deduction_guides
185+
// Deduction guides
186+
template <typename... PropertyValueTs>
187+
properties(PropertyValueTs... props)
188+
-> properties<typename detail::Sorted<PropertyValueTs...>::type>;
189+
#endif
190+
191+
// Property list traits
192+
template <typename propertiesT> struct is_property_list : std::false_type {};
193+
template <typename... PropertyValueTs>
194+
struct is_property_list<properties<std::tuple<PropertyValueTs...>>>
195+
: std::is_same<
196+
properties<std::tuple<PropertyValueTs...>>,
197+
properties<typename detail::Sorted<PropertyValueTs...>::type>> {};
198+
199+
#if __cplusplus > 201402L
200+
template <typename propertiesT>
201+
inline constexpr bool is_property_list_v = is_property_list<propertiesT>::value;
202+
#endif
203+
204+
} // namespace experimental
205+
} // namespace oneapi
206+
} // namespace ext
207+
208+
// If property_list is not trivially copyable, allow properties to propagate
209+
// is_device_copyable
210+
template <typename PropertiesT>
211+
struct is_device_copyable<
212+
ext::oneapi::experimental::properties<PropertiesT>,
213+
std::enable_if_t<!std::is_trivially_copyable<
214+
ext::oneapi::experimental::properties<PropertiesT>>::value>>
215+
: is_device_copyable<PropertiesT> {};
216+
template <typename PropertiesT>
217+
struct is_device_copyable<
218+
const ext::oneapi::experimental::properties<PropertiesT>,
219+
std::enable_if_t<!std::is_trivially_copyable<
220+
const ext::oneapi::experimental::properties<PropertiesT>>::value>>
221+
: is_device_copyable<PropertiesT> {};
222+
223+
} // namespace sycl
224+
} // __SYCL_INLINE_NAMESPACE(cl)

0 commit comments

Comments
 (0)