Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ This extension also depends on the following other SYCL extensions:

== Status

This is a proposed extension specification, intended to gather community
feedback. Interfaces defined in this specification may not be implemented yet
or may be in a preliminary state. The specification itself may also change in
incompatible ways before it is finalized. *Shipping software products should
not rely on APIs defined in this specification.*

This is an experimental extension specification, intended to provide early
access to features and gather community feedback. Interfaces defined in this
specification are implemented in {dpcpp}, but they are not finalized and may
change incompatibly in future versions of {dpcpp} without prior notice.
*Shipping software products should not rely on APIs defined in this
specification.*

== Overview

Expand Down Expand Up @@ -87,7 +87,8 @@ implementation supports.
|Description

|1
|Initial version of this extension.
|The APIs of this experimental extension are not versioned, so the
feature-test macro always has this value.
|===

=== `reduction` overload
Expand All @@ -111,7 +112,7 @@ template <typename T, typename BinaryOperation, typename PropertyList>
__unspecified__ reduction(T* var, BinaryOperation combiner,
PropertyList properties);

template <typename T, typename Extent, typename BinaryOperation, typename PropertyList>
template <typename T, size_t Extent, typename BinaryOperation, typename PropertyList>
__unspecified__ reduction(span<T, Extent> vars, BinaryOperation combiner,
PropertyList properties);

Expand All @@ -124,14 +125,17 @@ template <typename T, typename BinaryOperation, typename PropertyList>
__unspecified__ reduction(T* var, const T& identity, BinaryOperation combiner,
PropertyList properties);

template <typename T, typename Extent, typename BinaryOperation, typename PropertyList>
template <typename T, size_t Extent, typename BinaryOperation, typename PropertyList>
__unspecified__ reduction(span<T, Extent> vars, const T& identity,
BinaryOperation combiner,
PropertyList properties);

}
----

_Mandates_: The specified `properties` are compatible with the reduction,
according to the description of each individual property.

=== Reduction properties

New `reduction` properties are introduced to allow developers to constrain
Expand All @@ -145,7 +149,7 @@ request for specific reduction behavior(s), the implementation must throw an

[source,c++]
----
namespace sycl::ext::oneapi {
namespace sycl::ext::oneapi::experimental {

struct deterministic_key {
using value_t = property_value<deterministic_key>;
Expand Down Expand Up @@ -185,14 +189,18 @@ use of atomic operations, etc. _{endnote}_]
|Adds the same requirement as
`sycl::property::reduction::initialize_to_identity`.

For `reduction` overloads without an `identity` parameter, the identity of the
combination operation must be identifiable via the `known_identity` trait
class.

|===


=== Usage example

[source,c++]
----
using syclex = sycl::ext::oneapi::experimental;
namespace syclex = sycl::ext::oneapi::experimental;

float sum(sycl::queue q, float* input, size_t N) {

Expand All @@ -205,10 +213,10 @@ float sum(sycl::queue q, float* input, size_t N) {
h.parallel_for(N, reduction, [=](size_t i, auto& reducer) {
reducer += input[i];
});
}
});
}
return result;

}

...
Expand Down
143 changes: 143 additions & 0 deletions sycl/include/sycl/ext/oneapi/experimental/reduction_properties.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
//==------- properties.hpp - SYCL properties associated with reductions ----==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#pragma once
#define SYCL_EXT_ONEAPI_REDUCTION_PROPERTIES

#include <sycl/ext/oneapi/properties/property.hpp>
#include <sycl/ext/oneapi/properties/property_value.hpp>
#include <sycl/reduction.hpp>

namespace sycl {
inline namespace _V1 {
namespace ext {
namespace oneapi {
namespace experimental {

struct deterministic_key
: detail::compile_time_property_key<detail::PropKind::Deterministic> {
using value_t = property_value<deterministic_key>;
};
inline constexpr deterministic_key::value_t deterministic;

struct initialize_to_identity_key
: detail::compile_time_property_key<
detail::PropKind::InitializeToIdentity> {
using value_t = property_value<initialize_to_identity_key>;
};
inline constexpr initialize_to_identity_key::value_t initialize_to_identity;

} // namespace experimental
} // namespace oneapi
} // namespace ext

namespace detail {

template <typename BinaryOperation, typename PropertyList>
auto WrapOp(BinaryOperation combiner, PropertyList properties) {
if constexpr (properties.template has_property<
ext::oneapi::experimental::deterministic_key>()) {
return DeterministicOperatorWrapper(combiner);
} else {
return combiner;
}
}

template <typename T, typename BinaryOperation, typename PropertyList>
void CheckReductionIdentity(PropertyList properties) {
if constexpr (properties.template has_property<
ext::oneapi::experimental::initialize_to_identity_key>()) {
static_assert(has_known_identity_v<BinaryOperation, T>,
"initialize_to_identity requires an identity value.");
}
}

template <typename PropertyList>
property_list GetReductionPropertyList(PropertyList properties) {
if constexpr (properties.template has_property<
ext::oneapi::experimental::initialize_to_identity_key>()) {
return sycl::property::reduction::initialize_to_identity{};
}
return {};
}

template <typename BinaryOperation> struct DeterministicOperatorWrapper {

DeterministicOperatorWrapper(BinaryOperation BinOp = BinaryOperation())
: BinOp(BinOp) {}

template <typename... Args>
std::invoke_result_t<BinaryOperation, Args...> operator()(Args... args) {
return BinOp(std::forward<Args>(args)...);
}

BinaryOperation BinOp;
};

template <typename BinaryOperation>
struct IsDeterministicOperator<DeterministicOperatorWrapper<BinaryOperation>>
: std::true_type {};

} // namespace detail

template <typename BufferT, typename BinaryOperation, typename PropertyList>
auto reduction(BufferT vars, handler &cgh, BinaryOperation combiner,
PropertyList properties) {
detail::CheckReductionIdentity<typename BufferT::value_type, BinaryOperation>(
properties);
auto WrappedOp = detail::WrapOp(combiner, properties);
auto RuntimeProps = detail::GetReductionPropertyList(properties);
return reduction(vars, cgh, WrappedOp, RuntimeProps);
}

template <typename T, typename BinaryOperation, typename PropertyList>
auto reduction(T *var, BinaryOperation combiner, PropertyList properties) {
detail::CheckReductionIdentity<T, BinaryOperation>(properties);
auto WrappedOp = detail::WrapOp(combiner, properties);
auto RuntimeProps = detail::GetReductionPropertyList(properties);
return reduction(var, WrappedOp, RuntimeProps);
}

template <typename T, size_t Extent, typename BinaryOperation,
typename PropertyList>
auto reduction(span<T, Extent> vars, BinaryOperation combiner,
PropertyList properties) {
detail::CheckReductionIdentity<T, BinaryOperation>(properties);
auto WrappedOp = detail::WrapOp(combiner, properties);
auto RuntimeProps = detail::GetReductionPropertyList(properties);
return reduction(vars, WrappedOp, RuntimeProps);
}

template <typename BufferT, typename BinaryOperation, typename PropertyList>
auto reduction(BufferT vars, handler &cgh,
const typename BufferT::value_type &identity,
BinaryOperation combiner, PropertyList properties) {
auto WrappedOp = detail::WrapOp(combiner, properties);
auto RuntimeProps = detail::GetReductionPropertyList(properties);
return reduction(vars, cgh, identity, WrappedOp, RuntimeProps);
}

template <typename T, typename BinaryOperation, typename PropertyList>
auto reduction(T *var, const T &identity, BinaryOperation combiner,
PropertyList properties) {
auto WrappedOp = detail::WrapOp(combiner, properties);
auto RuntimeProps = detail::GetReductionPropertyList(properties);
return reduction(var, identity, WrappedOp, RuntimeProps);
}

template <typename T, size_t Extent, typename BinaryOperation,
typename PropertyList>
auto reduction(span<T, Extent> vars, const T &identity,
BinaryOperation combiner, PropertyList properties) {
auto WrappedOp = detail::WrapOp(combiner, properties);
auto RuntimeProps = detail::GetReductionPropertyList(properties);
return reduction(vars, identity, WrappedOp, RuntimeProps);
}

} // namespace _V1
} // namespace sycl
4 changes: 3 additions & 1 deletion sycl/include/sycl/ext/oneapi/properties/property.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,10 @@ enum PropKind : uint32_t {
ResponseCapacity = 73,
MaxWorkGroupSize = 74,
MaxLinearWorkGroupSize = 75,
Deterministic = 76,
InitializeToIdentity = 77,
// PropKindSize must always be the last value.
PropKindSize = 76,
PropKindSize = 78,
};

struct property_key_base_tag {};
Expand Down
54 changes: 24 additions & 30 deletions sycl/include/sycl/known_identity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,54 +25,48 @@ namespace sycl {
inline namespace _V1 {
namespace detail {

// Forward declaration for deterministic reductions.
template <typename BinaryOperation> struct DeterministicOperatorWrapper;

template <typename T, class BinaryOperation,
template <typename> class... KnownOperation>
using IsKnownOp = std::bool_constant<(
(std::is_same_v<BinaryOperation, KnownOperation<T>> ||
std::is_same_v<BinaryOperation, KnownOperation<void>> ||
std::is_same_v<BinaryOperation,
DeterministicOperatorWrapper<KnownOperation<T>>> ||
std::is_same_v<BinaryOperation,
DeterministicOperatorWrapper<KnownOperation<void>>>) ||
...)>;

template <typename T, class BinaryOperation>
using IsPlus =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::plus<T>> ||
std::is_same_v<BinaryOperation, sycl::plus<void>>>;
using IsPlus = IsKnownOp<T, BinaryOperation, sycl::plus>;

template <typename T, class BinaryOperation>
using IsMultiplies =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::multiplies<T>> ||
std::is_same_v<BinaryOperation, sycl::multiplies<void>>>;
using IsMultiplies = IsKnownOp<T, BinaryOperation, sycl::multiplies>;

template <typename T, class BinaryOperation>
using IsMinimum =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::minimum<T>> ||
std::is_same_v<BinaryOperation, sycl::minimum<void>>>;
using IsMinimum = IsKnownOp<T, BinaryOperation, sycl::minimum>;

template <typename T, class BinaryOperation>
using IsMaximum =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::maximum<T>> ||
std::is_same_v<BinaryOperation, sycl::maximum<void>>>;
using IsMaximum = IsKnownOp<T, BinaryOperation, sycl::maximum>;

template <typename T, class BinaryOperation>
using IsBitAND =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::bit_and<T>> ||
std::is_same_v<BinaryOperation, sycl::bit_and<void>>>;
using IsBitAND = IsKnownOp<T, BinaryOperation, sycl::bit_and>;

template <typename T, class BinaryOperation>
using IsBitOR =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::bit_or<T>> ||
std::is_same_v<BinaryOperation, sycl::bit_or<void>>>;
using IsBitOR = IsKnownOp<T, BinaryOperation, sycl::bit_or>;

template <typename T, class BinaryOperation>
using IsBitXOR =
std::bool_constant<std::is_same_v<BinaryOperation, sycl::bit_xor<T>> ||
std::is_same_v<BinaryOperation, sycl::bit_xor<void>>>;
using IsBitXOR = IsKnownOp<T, BinaryOperation, sycl::bit_xor>;

template <typename T, class BinaryOperation>
using IsLogicalAND = std::bool_constant<
std::is_same_v<BinaryOperation, std::logical_and<T>> ||
std::is_same_v<BinaryOperation, std::logical_and<void>> ||
std::is_same_v<BinaryOperation, sycl::logical_and<T>> ||
std::is_same_v<BinaryOperation, sycl::logical_and<void>>>;
using IsLogicalAND =
IsKnownOp<T, BinaryOperation, std::logical_and, sycl::logical_and>;

template <typename T, class BinaryOperation>
using IsLogicalOR =
std::bool_constant<std::is_same_v<BinaryOperation, std::logical_or<T>> ||
std::is_same_v<BinaryOperation, std::logical_or<void>> ||
std::is_same_v<BinaryOperation, sycl::logical_or<T>> ||
std::is_same_v<BinaryOperation, sycl::logical_or<void>>>;
IsKnownOp<T, BinaryOperation, std::logical_or, sycl::logical_or>;

// Use SFINAE so that the "true" branch could be implemented in
// include/sycl/stl_wrappers/complex that would only be available if STL's
Expand Down
Loading
Loading