Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
114 changes: 106 additions & 8 deletions include/RAJA/index/IndexValue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ struct IndexValue : public IndexValueBase
RAJA_INLINE IndexValue& operator=(IndexValue const&) = default;
RAJA_INLINE IndexValue& operator=(IndexValue&&) = default;

RAJA_INLINE IndexValue& operator=(const value_type& v)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to be able to easily assign to a strongly typed index?

{
value = v;
return *this;
}

/*!
* \brief Explicit constructor.
* \param v Initial value
Expand Down Expand Up @@ -300,23 +306,107 @@ convertIndex_helper(typename FROM::IndexValueType const val)

} // namespace internal

namespace concepts
{
// Should we try to move this to either util/concepts.hpp
// or pattern/concepts.hpp?
template<typename T>
concept IndexValued = std::is_base_of_v<
RAJA::IndexValue<std::remove_cvref_t<T>,
typename std::remove_cvref_t<T>::value_type>,
Comment on lines +315 to +316

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any concern about using typename std::remove_cvref_t<T>::value_type on types that are not IndexValues and don't have value_type aliases?

std::remove_cvref_t<T>>;


} // namespace concepts

namespace type_traits
{
template<typename T>
struct is_instance_of_index_value
: std::is_base_of<RAJA::IndexValue<std::remove_cvref_t<T>>,
std::remove_cvref_t<T>>
: std::bool_constant<RAJA::concepts::IndexValued<T>>
{};

template<typename T>
constexpr bool is_instance_of_index_value_v =
inline constexpr bool is_instance_of_index_value_v =
is_instance_of_index_value<T>::value;

} // namespace type_traits

namespace concepts
template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE TYPE operator+(typename TYPE::value_type lhs,
TYPE rhs)
{
template<typename T>
concept IndexValued = type_traits::is_instance_of_index_value_v<T>;
return TYPE(lhs + *rhs);
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE TYPE operator-(typename TYPE::value_type lhs,
TYPE rhs)
{
return TYPE(lhs - *rhs);
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE TYPE operator*(typename TYPE::value_type lhs,
TYPE rhs)
{
return TYPE(lhs * *rhs);
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE TYPE operator/(typename TYPE::value_type lhs,
TYPE rhs)
{
return TYPE(lhs / *rhs);
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE TYPE operator%(typename TYPE::value_type lhs,
TYPE rhs)
{
return TYPE(lhs % *rhs);
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE bool operator<(typename TYPE::value_type lhs,
TYPE rhs)
{
return lhs < *rhs;
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE bool operator<=(typename TYPE::value_type lhs,
TYPE rhs)
{
return lhs <= *rhs;
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE bool operator>(typename TYPE::value_type lhs,
TYPE rhs)
{
return lhs > *rhs;
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE bool operator>=(typename TYPE::value_type lhs,
TYPE rhs)
{
return lhs >= *rhs;
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE bool operator==(typename TYPE::value_type lhs,
TYPE rhs)
{
return lhs == *rhs;
}

template<concepts::IndexValued TYPE>
RAJA_HOST_DEVICE RAJA_INLINE bool operator!=(typename TYPE::value_type lhs,
TYPE rhs)
{
return lhs != *rhs;
}

/*!
Expand Down Expand Up @@ -404,9 +494,12 @@ using make_signed_t =
#define RAJA_INDEX_VALUE(TYPE, NAME) \
class TYPE : public ::RAJA::IndexValue<TYPE> \
{ \
using parent = ::RAJA::IndexValue<TYPE>; \
\
public: \
using parent = ::RAJA::IndexValue<TYPE>; \
using parent::operator=; \
using parent::operator*; \
using parent::operator++; \
using parent::operator--; \
using IndexValueType = TYPE; \
RAJA_HOST_DEVICE RAJA_INLINE TYPE() : parent::IndexValue() {} \
RAJA_HOST_DEVICE RAJA_INLINE explicit TYPE(::RAJA::Index_type v) \
Expand All @@ -425,6 +518,11 @@ using make_signed_t =
class TYPE : public ::RAJA::IndexValue<TYPE, IDXT> \
{ \
public: \
using parent = RAJA::IndexValue<TYPE, IDXT>; \
using parent::operator=; \
using parent::operator*; \
using parent::operator++; \
using parent::operator--; \
RAJA_HOST_DEVICE RAJA_INLINE TYPE() \
: RAJA::IndexValue<TYPE, IDXT>::IndexValue() \
{} \
Expand Down
17 changes: 16 additions & 1 deletion include/RAJA/index/RangeSegment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ namespace RAJA
*
******************************************************************************
*/
template<typename StorageT,
template<concepts::Index StorageT,
typename DiffT = make_signed_t<strip_index_type_t<StorageT>>>
struct TypedRangeSegment
{
Expand Down Expand Up @@ -140,6 +140,21 @@ struct TypedRangeSegment
m_end(begin > end ? m_begin : iterator(end))
{}

//! This constructor exists whenever an IndexValued index is passed to a
//! RangeSegment So that the class may be constructed directly with values of
//! the underlying storage type
template<concepts::Index BeginT, concepts::Index EndT>
requires((concepts::IndexValued<BeginT> || concepts::IndexValued<EndT>) &&
std::is_convertible_v<strip_index_type_t<BeginT>, StripStorageT> &&
std::is_convertible_v<strip_index_type_t<EndT>, StripStorageT>)
RAJA_HOST_DEVICE constexpr TypedRangeSegment(BeginT begin, EndT end)
: m_begin(iterator(StripStorageT(stripIndexType(begin)))),
m_end(StripStorageT(stripIndexType(begin)) >
StripStorageT(stripIndexType(end))
? m_begin
: iterator(StripStorageT(stripIndexType(end))))
{}

//! Disable compiler generated constructor
RAJA_HOST_DEVICE TypedRangeSegment() = delete;

Expand Down
6 changes: 6 additions & 0 deletions include/RAJA/internal/Iterators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ class numeric_iterator
return val + rhs.val;
}

RAJA_HOST_DEVICE inline stripped_value_type operator*(
const numeric_iterator& rhs) const
{
return val * rhs.val;
}

RAJA_HOST_DEVICE inline stripped_value_type operator-(
const numeric_iterator& rhs) const
{
Expand Down
3 changes: 3 additions & 0 deletions include/RAJA/pattern/concepts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ concept ExecutionPolicy =
/// specializations of camp::num<bool=false/true>. Because of this, their
/// value type is actually const long, not bool. Therefore, static_cast to
/// bool is used below to define these.
template<typename T>
concept Index = concepts::Integral<T> || concepts::IndexValued<T>;

template<typename T>
concept IndexSetType =
static_cast<bool>(type_traits::is_index_set<std::decay_t<T>>::value);
Expand Down
71 changes: 48 additions & 23 deletions include/RAJA/pattern/kernel/Tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "camp/concepts.hpp"
#include "camp/tuple.hpp"

#include "RAJA/index/IndexValue.hpp"
#include "RAJA/pattern/kernel/internal.hpp"
#include "RAJA/util/macros.hpp"
#include "RAJA/util/types.hpp"
Expand Down Expand Up @@ -81,6 +82,12 @@ struct tile_dynamic

namespace internal
{
// template<typename T>
// struct is_instance_of_tile_size : std::false_type {};

// template<typename SizeT>
// struct is_instance_of_tile_size<TileSize<SizeT>> : std::true_type {};


/*!
* A generic RAJA::kernel forall_impl tile wrapper for statement::For
Expand Down Expand Up @@ -109,22 +116,24 @@ struct TileWrapper : public GenericWrapper<Data, Types, EnclosedStmts...>
}
};

template<typename Iterable>
template<typename Iterable, typename BlockSizeT>
struct IterableTiler
{
using value_type = camp::decay<Iterable>;
using slice_type = typename value_type::size_type;
using block_type = RAJA::strip_index_type_t<slice_type>;

struct iterate
{
value_type s;
Index_type i;
block_type i;
};

class iterator
{
// NOTE: this must be held by value for NVCC support, *even on the host*
const IterableTiler itiler;
const Index_type block_id;
const block_type block_id;

public:
using value_type = iterate;
Expand All @@ -136,7 +145,7 @@ struct IterableTiler
RAJA_HOST_DEVICE

RAJA_INLINE
constexpr iterator(IterableTiler const& itiler_, Index_type block_id_)
constexpr iterator(IterableTiler const& itiler_, block_type block_id_)
: itiler {itiler_},
block_id {block_id_}
{}
Expand All @@ -146,7 +155,9 @@ struct IterableTiler
RAJA_INLINE
value_type operator*()
{
auto start = block_id * itiler.block_size;
auto start =
slice_type {block_id * static_cast<block_type>(
RAJA::stripIndexType(itiler.block_size))};
return iterate {itiler.it.slice(start, itiler.block_size), block_id};
}

Expand All @@ -160,15 +171,19 @@ struct IterableTiler
RAJA_HOST_DEVICE
RAJA_INLINE iterator operator-(const difference_type& rhs) const
{
return iterator(itiler, block_id - rhs);
return iterator(itiler,
static_cast<block_type>(
static_cast<difference_type>(block_id) - rhs));
}

RAJA_HOST_DEVICE
RAJA_INLINE iterator operator+(const difference_type& rhs) const
{
return iterator(itiler, block_id + rhs >= itiler.num_blocks
? itiler.num_blocks
: block_id + rhs);
const difference_type next = static_cast<difference_type>(block_id) + rhs;
return iterator(itiler,
next >= static_cast<difference_type>(itiler.num_blocks)
? itiler.num_blocks
: static_cast<block_type>(next));
}

RAJA_HOST_DEVICE
Expand All @@ -190,20 +205,20 @@ struct IterableTiler
}
};

RAJA_HOST_DEVICE

RAJA_INLINE
IterableTiler(const Iterable& it_, camp::idx_t block_size_)
RAJA_HOST_DEVICE RAJA_INLINE IterableTiler(const Iterable& it_,
BlockSizeT block_size_)
: it {it_},
block_size {block_size_}
{
using std::begin;
using std::distance;
using std::end;
dist = it.end() - it.begin(); // distance(begin(it), end(it));
num_blocks = dist / block_size;
const block_type stripped_block_size =
static_cast<block_type>(RAJA::stripIndexType(block_size));
dist = static_cast<block_type>(it.end() - it.begin());
num_blocks = dist / stripped_block_size;
// if (dist % block_size) num_blocks += 1;
if (dist - num_blocks * block_size > 0)
if (dist - num_blocks * stripped_block_size > block_type {0})
{
num_blocks += 1;
}
Expand All @@ -212,17 +227,17 @@ struct IterableTiler
RAJA_HOST_DEVICE

RAJA_INLINE
iterator begin() const { return iterator(*this, 0); }
iterator begin() const { return iterator(*this, block_type {0}); }

RAJA_HOST_DEVICE

RAJA_INLINE
iterator end() const { return iterator(*this, num_blocks); }

value_type it;
camp::idx_t block_size;
camp::idx_t num_blocks;
camp::idx_t dist;
BlockSizeT block_size;
block_type num_blocks;
block_type dist;
};

/*!
Expand All @@ -247,11 +262,15 @@ struct StatementExecutor<
auto const& segment = camp::get<ArgumentId>(data.segment_tuple);

// Get the tiling policies chunk size
auto chunk_size = tile_fixed<ChunkSize>::chunk_size;
constexpr auto chunk_size = tile_fixed<ChunkSize>::chunk_size;
using segment_t = decltype(segment);
using slice_t = typename std::decay_t<segment_t>::size_type;
using slice_value_t = RAJA::strip_index_type_t<slice_t>;

// Create a tile iterator, needs to survive until the forall is
// done executing.
IterableTiler<decltype(segment)> tiled_iterable(segment, chunk_size);
IterableTiler<segment_t, slice_t> tiled_iterable(
segment, slice_t {static_cast<slice_value_t>(chunk_size)});

// Wrap in case forall_impl needs to thread_privatize
TileWrapper<ArgumentId, Data, Types, EnclosedStmts...> tile_wrapper(data);
Expand Down Expand Up @@ -282,14 +301,20 @@ struct StatementExecutor<
// Get the segment we are going to tile
auto const& segment = camp::get<ArgumentId>(data.segment_tuple);

using segment_t = decltype(segment);
using slice_t = typename std::decay_t<segment_t>::size_type;
using slice_value_t = RAJA::strip_index_type_t<slice_t>;
// Get the tiling policies chunk size
auto chunk_size = camp::get<ArgumentId>(data.param_tuple);
static_assert(
camp::concepts::metalib::is_same<TileSize, decltype(chunk_size)>::value,
// is_instance_of_tile_size<decltype(chunk_size)>::value,
"Extracted parameter must be of type TileSize.");

// Create a tile iterator
IterableTiler<decltype(segment)> tiled_iterable(segment, chunk_size.size);
IterableTiler<segment_t, slice_t> tiled_iterable(
segment, slice_t {static_cast<slice_value_t>(
RAJA::stripIndexType(chunk_size.size))});

// Wrap in case forall_impl needs to thread_privatize
TileWrapper<ArgumentId, Data, Types, EnclosedStmts...> tile_wrapper(data);
Expand Down
Loading
Loading