Skip to content

Commit

Permalink
Cpp14 support (#314)
Browse files Browse the repository at this point in the history
* ci: test with C++14 and treat compile warnings as errors

* replace fold expressions in `extents.hpp` with macro

Use the `_MDSPAN_FOLD_AND` macro to avoid using fold expressions
when building for C++14.

* use empty message with static assert

Add an empty message to static assert in `layout_padded_fwd.hpp` to
avoid use of C++17 extensions when building for C++14.

* replace constexpr if in p0009 bits

Replace use of constexpr if in headers used to implement p0009 in
order to allow compilation for C++14 without C++17 extensions.

* define precondition macro and violation handler

* Make new precondition macros IMPL only

* Make test for dims C++14 compatible

* replace `std::is_signed_v` for C++14 compatibility

* isolate precondition tests

Move test cases that test preconditions with `ASSERT_DEATH` to separate
test files. This allows other (non-precondition) tests to be compiled
with or without preconditions. CMake test targets will enable
preconditions during compilation if passed the option
`ENABLE_PRECONDITIONS`.

This only requires moving a single test case from `test_layout_ctors` -
`test_alternate_precondition_violation_handler`
and `test_macros` are test files have been written primary to test
preconditions.

* use MDSPAN_IMPL_PRECONDITION in layout_padded_fwd

* test that precondition checks can be disabled

* handle precondition error printing for multiple archs

* Fix CUDA (and hopefully HIP/SYCL) compilation

* Fix CUDA build and run issues

* More fixes for cpp14 and warnings

* Guard inclusion of layout_padded_fwd

---------

Co-authored-by: Christian Trott <crtrott@sandia.gov>
  • Loading branch information
oliverlee and crtrott authored May 23, 2024
1 parent 4409e8c commit 2f5ae3d
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 121 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
fail-fast: false
matrix:
compiler_driver: [g++-9, g++-10, clang++, icpx]
stdcxx: [17, 20, 23]
stdcxx: [14, 17, 20, 23]
include:
- compiler_driver: g++-9
compiler_prefix: /usr/bin
Expand All @@ -27,6 +27,8 @@ jobs:
# https://www.intel.com/content/www/us/en/developer/articles/tool/oneapi-standalone-components.html#inpage-nav-6-undefined
compiler_url: https://registrationcenter-download.intel.com/akdlm/IRC_NAS/ebf5d9aa-17a7-46a4-b5df-ace004227c0e/l_dpcpp-cpp-compiler_p_2023.2.1.8_offline.sh
- enable_benchmark: ON
- stdcxx: 14
enable_benchmark: OFF
- stdcxx: 23
enable_benchmark: OFF
exclude:
Expand Down
32 changes: 17 additions & 15 deletions include/experimental/__p0009_bits/extents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@

#pragma once
#include "dynamic_extent.hpp"
#include "utility.hpp"

#ifdef __cpp_lib_span
#include <span>
#endif
#include <array>
#include <type_traits>

#include <cassert>
#include <cinttypes>
Expand Down Expand Up @@ -60,8 +62,8 @@ template<class IndexType, class ... Arguments>
MDSPAN_INLINE_FUNCTION
static constexpr bool are_valid_indices() {
return
(std::is_convertible<Arguments, IndexType>::value && ... && true) &&
(std::is_nothrow_constructible<IndexType, Arguments>::value && ... && true);
_MDSPAN_FOLD_AND(std::is_convertible<Arguments, IndexType>::value) &&
_MDSPAN_FOLD_AND(std::is_nothrow_constructible<IndexType, Arguments>::value);
}

// ------------------------------------------------------------------
Expand Down Expand Up @@ -539,14 +541,9 @@ template <class IndexType, size_t... Extents> class extents {
MDSPAN_INLINE_FUNCTION friend constexpr bool
operator==(const extents &lhs,
const extents<OtherIndexType, OtherExtents...> &rhs) noexcept {
if constexpr (rank() != extents<OtherIndexType, OtherExtents...>::rank()) {
return false;
} else {
using common_t = std::common_type_t<index_type, OtherIndexType>;
for (size_type r = 0; r < m_rank; r++)
if(static_cast<common_t>(rhs.extent(r)) != static_cast<common_t>(lhs.extent(r))) return false;
}
return true;
return
rank() == extents<OtherIndexType, OtherExtents...>::rank() &&
detail::rankwise_equal(detail::with_rank<rank()>{}, rhs, lhs, detail::extent);
}

#if !(MDSPAN_HAS_CXX_20)
Expand Down Expand Up @@ -649,17 +646,21 @@ check_upper_bound(InputIndexType user_index,
#endif
}

// Returning true to use AND fold instead of comma
// CPP14 mode doesn't like the use of void expressions
// with the way the _MDSPAN_FOLD_AND is set up
template<class InputIndex, class ExtentsIndexType>
MDSPAN_INLINE_FUNCTION
constexpr void
constexpr bool
check_one_index(InputIndex user_index,
ExtentsIndexType current_extent)
{
check_lower_bound(user_index, current_extent,
std::integral_constant<bool, std::is_signed_v<ExtentsIndexType>>{});
std::integral_constant<bool, std::is_signed<ExtentsIndexType>::value>{});
check_upper_bound(user_index, current_extent);
return true;
}

template<size_t ... RankIndices,
class ExtentsIndexType, size_t ... Exts,
class ... Indices>
Expand All @@ -669,7 +670,8 @@ check_all_indices_helper(std::index_sequence<RankIndices...>,
const extents<ExtentsIndexType, Exts...>& exts,
Indices... indices)
{
_MDSPAN_FOLD_COMMA(
// Suppress warning about statement has no effect
(void) _MDSPAN_FOLD_AND(
(check_one_index(indices, exts.extent(RankIndices)))
);
}
Expand All @@ -684,6 +686,6 @@ check_all_indices(const extents<ExtentsIndexType, Exts...>& exts,
check_all_indices_helper(std::make_index_sequence<sizeof...(Indices)>(),
exts, indices...);
}

} // namespace detail
} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE
23 changes: 8 additions & 15 deletions include/experimental/__p0009_bits/layout_left.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
#include "macros.hpp"
#include "trait_backports.hpp"
#include "extents.hpp"
#include "layout_stride.hpp"
#include "utility.hpp"
#if MDSPAN_HAS_CXX_17
#include "../__p2642_bits/layout_padded_fwd.hpp"
#include <cassert>
#endif
#include <type_traits>

namespace MDSPAN_IMPL_STANDARD_NAMESPACE {
Expand Down Expand Up @@ -133,11 +136,11 @@ class layout_left::mapping {
: __extents(__other.extents())
{
MDSPAN_IMPL_PROPOSED_NAMESPACE::detail::
check_padded_layout_converting_constructor_mandates<extents_type,
_Mapping>();
check_padded_layout_converting_constructor_mandates<
extents_type, _Mapping>(detail::with_rank<extents_type::rank()>{});
MDSPAN_IMPL_PROPOSED_NAMESPACE::detail::
check_padded_layout_converting_constructor_preconditions<
extents_type>(__other);
extents_type>(detail::with_rank<extents_type::rank()>{}, __other);
}
#endif

Expand All @@ -156,17 +159,7 @@ class layout_left::mapping {
* TODO: check precondition
* other.required_span_size() is a representable value of type index_type
*/
#if !defined(_MDSPAN_HAS_CUDA) && !defined(_MDSPAN_HAS_HIP) && !defined(NDEBUG)
if constexpr (extents_type::rank() > 0) {
index_type stride = 1;
using common_t = std::common_type_t<index_type, typename OtherExtents::index_type>;
for(rank_type r=0; r<__extents.rank(); r++) {
if(static_cast<common_t>(stride) != static_cast<common_t>(other.stride(r)))
std::abort(); // ("Assigning layout_stride to layout_left with invalid strides.");
stride *= __extents.extent(r);
}
}
#endif
detail::validate_strides(detail::with_rank<extents_type::rank()>{}, layout_left{}, __extents, other);
}

MDSPAN_INLINE_FUNCTION_DEFAULTED _MDSPAN_CONSTEXPR_14_DEFAULTED mapping& operator=(mapping const&) noexcept = default;
Expand Down
22 changes: 7 additions & 15 deletions include/experimental/__p0009_bits/layout_right.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
#include "macros.hpp"
#include "trait_backports.hpp"
#include "extents.hpp"
#include <stdexcept>
#include "layout_stride.hpp"
#include "utility.hpp"
#if MDSPAN_HAS_CXX_17
#include "../__p2642_bits/layout_padded_fwd.hpp"
#endif

namespace MDSPAN_IMPL_STANDARD_NAMESPACE {

Expand Down Expand Up @@ -134,11 +136,11 @@ class layout_right::mapping {
: __extents(__other.extents())
{
MDSPAN_IMPL_PROPOSED_NAMESPACE::detail::
check_padded_layout_converting_constructor_mandates<extents_type,
_Mapping>();
check_padded_layout_converting_constructor_mandates<
extents_type, _Mapping>(detail::with_rank<extents_type::rank()>{});
MDSPAN_IMPL_PROPOSED_NAMESPACE::detail::
check_padded_layout_converting_constructor_preconditions<
extents_type>(__other);
extents_type>(detail::with_rank<extents_type::rank()>{}, __other);
}
#endif

Expand All @@ -157,17 +159,7 @@ class layout_right::mapping {
* TODO: check precondition
* other.required_span_size() is a representable value of type index_type
*/
#if !defined(_MDSPAN_HAS_CUDA) && !defined(_MDSPAN_HAS_HIP) && !defined(NDEBUG)
if constexpr (extents_type::rank() > 0) {
index_type stride = 1;
using common_t = std::common_type_t<index_type, typename OtherExtents::index_type>;
for(rank_type r=__extents.rank(); r>0; r--) {
if(static_cast<common_t>(stride) != static_cast<common_t>(other.stride(r-1)))
std::abort(); // ("Assigning layout_stride to layout_right with invalid strides.");
stride *= __extents.extent(r-1);
}
}
#endif
detail::validate_strides(detail::with_rank<extents_type::rank()>{}, layout_right{}, __extents, other);
}

MDSPAN_INLINE_FUNCTION_DEFAULTED _MDSPAN_CONSTEXPR_14_DEFAULTED mapping& operator=(mapping const&) noexcept = default;
Expand Down
124 changes: 84 additions & 40 deletions include/experimental/__p0009_bits/layout_stride.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
#include "extents.hpp"
#include "trait_backports.hpp"
#include "compressed_pair.hpp"
#include "utility.hpp"

#if !defined(_MDSPAN_USE_ATTRIBUTE_NO_UNIQUE_ADDRESS)
# include "no_unique_address.hpp"
#endif

#include <algorithm>
#include <numeric>
#include <array>
#include <type_traits>
#include <utility>

#ifdef __cpp_lib_span
#include <span>
#endif
Expand All @@ -38,11 +40,11 @@ namespace MDSPAN_IMPL_STANDARD_NAMESPACE {

struct layout_left {
template<class Extents>
class mapping;
class mapping;
};
struct layout_right {
template<class Extents>
class mapping;
class mapping;
};

namespace detail {
Expand Down Expand Up @@ -79,6 +81,7 @@ namespace detail {
std::bool_constant<M::is_always_unique()>::value;
};
#endif

} // namespace detail

struct layout_stride {
Expand Down Expand Up @@ -225,7 +228,11 @@ struct layout_stride {
// Can't use defaulted parameter in the __deduction_workaround template because of a bug in MSVC warning C4348.
using __impl = __deduction_workaround<std::make_index_sequence<Extents::rank()>>;

static constexpr __strides_storage_t strides_storage(std::true_type) {
static constexpr __strides_storage_t strides_storage(detail::with_rank<0>) {
return {};
}
template <std::size_t N>
static constexpr __strides_storage_t strides_storage(detail::with_rank<N>) {
__strides_storage_t s{};

extents_type e;
Expand All @@ -237,9 +244,6 @@ struct layout_stride {

return s;
}
static constexpr __strides_storage_t strides_storage(std::false_type) {
return {};
}

//----------------------------------------------------------------------------

Expand All @@ -262,7 +266,7 @@ struct layout_stride {
: __base_t(__base_t{__member_pair_t(
#endif
extents_type(),
__strides_storage_t(strides_storage(std::integral_constant<bool, (extents_type::rank() > 0)>{}))
__strides_storage_t(strides_storage(detail::with_rank<extents_type::rank()>{}))
#if defined(_MDSPAN_USE_ATTRIBUTE_NO_UNIQUE_ADDRESS)
}
#else
Expand Down Expand Up @@ -447,32 +451,48 @@ struct layout_stride {
MDSPAN_INLINE_FUNCTION static constexpr bool is_always_strided() noexcept { return true; }

MDSPAN_INLINE_FUNCTION static constexpr bool is_unique() noexcept { return true; }
MDSPAN_INLINE_FUNCTION _MDSPAN_CONSTEXPR_14 bool is_exhaustive() const noexcept {
if constexpr (extents_type::rank() == 0)
return true;
else {
index_type span_size = required_span_size();
if (span_size == static_cast<index_type>(0)) {
if constexpr (extents_type::rank() == 1) {
return stride(0) == 1;
} else {
rank_type r_largest = 0;
for (rank_type r = 1; r < extents_type::rank(); r++) {
if (stride(r) > stride(r_largest)) {
r_largest = r;
}
}
for (rank_type r = 0; r < extents_type::rank(); r++) {
if (extents().extent(r) == 0 && r != r_largest) {
return false;
}
}
return true;
}
} else {
return required_span_size() == __get_size(extents(), std::make_index_sequence<extents_type::rank()>());

private:
constexpr bool exhaustive_for_nonzero_span_size() const
{
return required_span_size() == __get_size(extents(), std::make_index_sequence<extents_type::rank()>());
}

constexpr bool is_exhaustive_impl(detail::with_rank<0>) const
{
return true;
}
constexpr bool is_exhaustive_impl(detail::with_rank<1>) const
{
if (required_span_size() != static_cast<index_type>(0)) {
return exhaustive_for_nonzero_span_size();
}
return stride(0) == 1;
}
template <std::size_t N>
constexpr bool is_exhaustive_impl(detail::with_rank<N>) const
{
if (required_span_size() != static_cast<index_type>(0)) {
return exhaustive_for_nonzero_span_size();
}

rank_type r_largest = 0;
for (rank_type r = 1; r < extents_type::rank(); r++) {
if (stride(r) > stride(r_largest)) {
r_largest = r;
}
}
for (rank_type r = 0; r < extents_type::rank(); r++) {
if (extents().extent(r) == 0 && r != r_largest) {
return false;
}
}
return true;
}

public:
MDSPAN_INLINE_FUNCTION _MDSPAN_CONSTEXPR_14 bool is_exhaustive() const noexcept {
return is_exhaustive_impl(detail::with_rank<extents_type::rank()>{});
}
MDSPAN_INLINE_FUNCTION static constexpr bool is_strided() noexcept { return true; }

Expand Down Expand Up @@ -501,15 +521,9 @@ struct layout_stride {
#endif
MDSPAN_INLINE_FUNCTION
friend constexpr bool operator==(const mapping& x, const StridedLayoutMapping& y) noexcept {
bool strides_match = true;
if constexpr (extents_type::rank() > 0) {
using common_t = std::common_type_t<index_type, typename StridedLayoutMapping::index_type>;
for(rank_type r = 0; r < extents_type::rank(); r++)
strides_match = strides_match && (static_cast<common_t>(x.stride(r)) == static_cast<common_t>(y.stride(r)));
}
return (x.extents() == y.extents()) &&
(__impl::__OFFSET(y) == static_cast<typename StridedLayoutMapping::index_type>(0)) &&
strides_match;
detail::rankwise_equal(detail::with_rank<extents_type::rank()>{}, x, y, detail::stride);
}

// This one is not technically part of the proposal. Just here to make implementation a bit more optimal hopefully
Expand Down Expand Up @@ -564,4 +578,34 @@ struct layout_stride {
};
};

namespace detail {

template <class Layout, class Extents, class Mapping>
constexpr void validate_strides(with_rank<0>, Layout, const Extents&, const Mapping&)
{}

template <std::size_t N, class Layout, class Extents, class Mapping>
constexpr void validate_strides(with_rank<N>, Layout, const Extents& ext, const Mapping& other)
{
static_assert(std::is_same<typename Mapping::layout_type, layout_stride>::value and
(std::is_same<Layout, layout_left>::value or
std::is_same<Layout, layout_right>::value)
, "This function is only intended to validate construction of "
"a layout_left or layout_right mapping from a layout_stride mapping.");

constexpr auto is_left = std::is_same<Layout, layout_left>::value;

typename Extents::index_type stride = 1;

for (std::size_t r = 0; r < N; r++) {
const std::size_t s = is_left ? r : N - 1 - r;

MDSPAN_IMPL_PRECONDITION(common_integral_compare(stride, other.stride(s))
and "invalid strides for layout_{left,right}");

stride *= ext.extent(s);
}
}

} // namespace detail
} // end namespace MDSPAN_IMPL_STANDARD_NAMESPACE
Loading

0 comments on commit 2f5ae3d

Please sign in to comment.