-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cpp14 support #314
Cpp14 support #314
Conversation
ece2592
to
e2f47b2
Compare
|
||
#ifdef __cpp_lib_span | ||
#include <span> | ||
#endif | ||
#include <array> | ||
#include <type_traits> | ||
#include <stdexcept> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing in this header threw an std::exception
subclass before. Furthermore, the only reason this code now throws an exception is to trigger a call to terminate
in a noexcept
function.
Would you consider just calling std::abort
as before? Alternately, would you consider adding a configurable precondition violation handler (e.g., a macro that takes a message and just calls std::abort
by default)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you consider just calling std::abort as before? Alternately, would you consider adding a configurable precondition violation handler (e.g., a macro that takes a message and just calls std::abort by default)?
Sure that sounds like a better approach. I'm also wondering if extents.hpp
is the right location for the terminate_if_invalid_strides
function. Maybe layout_stride.hpp
is a better place?
static_assert(std::is_same<Layout, layout_left>::value or | ||
std::is_same<Layout, layout_right>::value | ||
, ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you consider adding a nonempty message here?
template <std::size_t N> | ||
struct with_rank {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you consider making this an alias of std::integral_constant
, so as to avoid more instantiations of types?
Thanks for the contribution! There are some nice refactorings in there as well. @crtrott et al. will likely want to comment.
|
I've only tested with the tests defined in CMake along with C++14 so far. All tests pass before and after this PR - however after this PR now builds without warnings.
Sure. |
5c44070
to
22258de
Compare
Thanks for making the changes! Building with C++14 results in the following CMake error message.
I think you could just change line 200 of CMakeLists.txt ( Line 200 in 0e6a69d
to something like
|
22258de
to
38d3f2f
Compare
I disabled benchmarking for C++14 using the same approach for C++23 (i.e. via matrix settings in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good. Finally found sufficient time to review it. The new macros are not a bad idea, but I think they should all be IMPL macros.
I will rebase this and merge my suggestions. |
@oliverlee FYI: I rebased and force pushed. I'd like to get this in before I work on more of the features for C++26. |
Not sure why the death tests are failing now - they were fine a few months back. I'll probably have time to look into it tomorrow. |
They passed now. We might have changed Debug to Release build at some point and so the rebase made them fail. |
It should be possible to enable precondition checks in release mode with a preprocessor macro - I imagine this is enabled only for tests and disabled for benchmarks. It shouldn't be too much trouble to do in a separate PR if you want to merge this PR and use it as a base for c++26 stuff. |
@crtrott It looks like the macro in I've created two commits - please squash or do whatever is normal for this repo. |
Thanks! I had overlooked that. That said I am not sure it's the best way to go about this. Now the tests never take the code path where the preconditions are skipped. Maybe instead we should have a mix of debug and non-debug test configs. |
Also I am waiting for a second review to finish (should happen latest by Monday I pinged appropriate people in my team). |
Same - whatever makes the most sense to you in terms of maintenance. I've seen precondition tests defined in a separate test file. That could remove the need to conditionally define test cases with |
It could make sense to separate them out. We had some platforms where the death tests never fully worked ... |
There are only a few It makes sense to do it earlier rather than later if this is approach you want to pursue. |
Yeah let's do it. Do you have time to tackle that? If not I might get around to it some point this weekend. |
Maybe this afternoon? If not, also this weekend. |
Sounds good. Also I send you an invite to our slack channel in case you are interested. |
Yeah this is great. Thanks so much! |
namespace detail { | ||
|
||
template <bool check = MDSPAN_IMPL_CHECK_PRECONDITION> | ||
constexpr void precondition(const char* cond, const char* file, unsigned line) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be decorated with MDSPAN_FUNCTION
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider tag dispatching instead ,having two non templated overloads
MDSPAN_FUNCTION constexpr void precondition(std::false_type /*checked*/, const char* /*cond*/, const char* /*file*/, unsigned /*line*/) { /* do nothing */ }
MDSPAN_FUNCTION constexpr void precondition(std::true_type /*checked*/, const char* cond, const char* file, unsigned line) { MDSPAN_IMPL_PRECONDITION_VIOLATION_HANDLER(cond, file, line); }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might have a while back? Not sure.
But I tested it out just now, and this approach produces warnings with Clang and GCC:
Clang-18:
.../mdspan/include/mdspan/../experimental/__p0009_bits/macros.hpp:142:16: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
142 | constexpr void precondition(std::true_type, const char* cond, const char* file, unsigned line)
GCC-11:
.../mdspan/include/mdspan/../experimental/__p0009_bits/macros.hpp:120:81: error: call to non-‘constexpr’ function ‘void Kokkos::detail::default_precondition_violation_handler(const char*, const char*, unsigned int)’
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expect the issue is the constexpr
specifier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose you needed it to be call it in other functions that themselves are callable in a constant expression...
namespace MDSPAN_IMPL_STANDARD_NAMESPACE { | ||
namespace detail { | ||
|
||
inline void default_precondition_violation_handler(const char* cond, const char* file, unsigned line) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine by me but just noting that the default handler would not work with CUDA/HIP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please feel free to make any changes if CUDA/HIP compatibility is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
printf
works just fine with CUDA; it's HIP that's broken lol ; - )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is a fprintf
and it is qualified so there is no way it works on CUDA. As far as I know HIP behaves just the same as CUDA here.
layout_padded_constants<typename _OtherMapping::layout_type, | ||
_ExtentsType>::padded_stride_idx; | ||
constexpr auto extent_to_pad_idx = layout_padded_constants<typename _OtherMapping::layout_type, _ExtentsType>::extent_to_pad_idx; | ||
assert(other_mapping.stride(padded_stride_idx) == other_mapping.extents().extent(extent_to_pad_idx)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not be using MDSPAN_IMPL_PRECONDITION
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure let's do that.
if(MDSPAN_TEST_LANGUAGE) | ||
set_source_files_properties(${name} PROPERTIES LANGUAGE ${MDSPAN_TEST_LANGUAGE}) | ||
endif() | ||
add_executable(${name} ${name}.cpp) | ||
target_link_libraries(${name} mdspan gtest_main) | ||
add_test(${name} ${name}) | ||
endmacro() | ||
set_property(TARGET ${name} PROPERTY COMPILE_WARNING_AS_ERROR ON) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not necessarily opposed to this but IMO it does not belong to this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is related to C++14 support to some degree - otherwise C++17 language features are still usable with some compilers when building for C++14. But I also see that the impact of this change has wider consequences.
What do you think about breaking out this change into a separate PR and rebasing this PR on top of that? I can do that later this evening - or feel free to change this PR as you see fit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Christian did you mean to keep this?
{ | ||
(void)std::fprintf(::stderr, "%s:%u: precondition failure: `%s`\n", file, line, cond); | ||
std::abort(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how HIP or SYCL work, but the following should be fine for CUDA. Note that in device code, printf
may have a performance cost even if it is never called at run time. (For example, the compiler may need to reserve registers for it.)
{ | |
(void)std::fprintf(::stderr, "%s:%u: precondition failure: `%s`\n", file, line, cond); | |
std::abort(); | |
} | |
{ | |
#if defined(__CUDA_ARCH__) | |
# if ! defined(NDEBUG) | |
printf("%s:%u: precondition failure: `%s`\n", file, line, cond); | |
assert(false); | |
# endif | |
#else | |
fprintf(stderr, "%s:%u: precondition failure: `%s`\n", file, line, cond); | |
assert(false); | |
#endif | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HIP
works the same as Cuda
. For SYCL (oneAPI), you would need to use sycl::ext::oneapi::experimental::printf
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with almost everything, just lets keep the padded layout stuff isolated (since it requires C++17 anyway)
I just noticed that this requires CXX Extensions for GCC. I.e. -std=gnu++14 - it doesn't work with -std=c++14. Do you consider that acceptable? |
Use the `_MDSPAN_FOLD_AND` macro to avoid using fold expressions when building for C++14.
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 use of constexpr if in headers used to implement p0009 in order to allow compilation for C++14 without C++17 extensions.
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.
Do you know what requires extensions? I didn't intend for that and I believe I am only using -std=c++14 in projects using mdspan (however, those don't use CMake). |
Its now fixed. |
MDSPAN_FUNCTION inline void default_precondition_violation_handler(const char* cond, const char* file, unsigned line) | ||
{ | ||
printf("%s:%u: precondition failure: `%s`\n", file, line, cond); | ||
assert(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please confirm that you did not see issue with Clang as the CUDA compiler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I couldn't find a variant which fails and we will use in Kokkos Kokkos::abort anyway.
if(MDSPAN_TEST_LANGUAGE) | ||
set_source_files_properties(${name} PROPERTIES LANGUAGE ${MDSPAN_TEST_LANGUAGE}) | ||
endif() | ||
add_executable(${name} ${name}.cpp) | ||
target_link_libraries(${name} mdspan gtest_main) | ||
add_test(${name} ${name}) | ||
endmacro() | ||
set_property(TARGET ${name} PROPERTY COMPILE_WARNING_AS_ERROR ON) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Christian did you mean to keep this?
@@ -55,6 +55,7 @@ void test_mdspan_size(std::vector<char>& storage, Extents&& e) | |||
|
|||
TEST(TestMdspan, MdspanSizeReturnTypeAndPrecondition) | |||
{ | |||
(void) test_info_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yuk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good enough.
Thank you Oliver.
I've updated the P0009 headers to compile without C++17 extensions.
For the last commit, I've dumped a few common utilities in the extents header. Please feel free to edit as desired.