Skip to content

[SYCL] Add has_known_identity/known_identity #2528

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

Merged
merged 12 commits into from
Feb 3, 2021

Conversation

Pennycook
Copy link
Contributor

These traits have been requested by developers who would like to
determine at compile-time whether the reduction() interface supports
their use-case, or whether they need to fall back to some other
implementation.

Exposes existing functionality of reduction implementation as part of
the public API for reductions.

Signed-off-by: John Pennycook john.pennycook@intel.com

These traits have been requested by developers who would like to
determine at compile-time whether the reduction() interface supports
their use-case, or whether they need to fall back to some other
implementation.

Signed-off-by: John Pennycook <john.pennycook@intel.com>
Exposes existing functionality of reduction implementation as part of
the public API for reductions.

Signed-off-by: John Pennycook <john.pennycook@intel.com>
@Pennycook Pennycook added enhancement New feature or request spec extension All issues/PRs related to extensions specifications labels Sep 23, 2020
Signed-off-by: John Pennycook <john.pennycook@intel.com>
@Pennycook
Copy link
Contributor Author

@Fznamznon, @AlexeySachkov: Could you please take a look at the build failures here and help identify a path forwards?

It looks to me like reduction_nd_ext_half.cpp is failing now because the calculation of negative infinity isn't constexpr for half, but I'm not sure how to fix it. Is there an alternative way to write the below that is constexpr for half, or do we need to add some new constexpr functions to the host implementation of half?

  static constexpr AccumulatorT value =
      std::numeric_limits<AccumulatorT>::has_infinity
          ? static_cast<AccumulatorT>(
                -std::numeric_limits<AccumulatorT>::infinity())
          : std::numeric_limits<AccumulatorT>::lowest();

I think unary - triggers a conversion to float which isn't constexpr. I tried making operator float() constexpr, but there's no host definition of this function that I could see.

Copy link
Contributor

@v-klochkov v-klochkov left a comment

Choose a reason for hiding this comment

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

Looks good to me, I found only 1 typo.

Comment on lines +181 to +182
typename std::enable_if<IsMinimumIdentityOp<
AccumulatorT, BinaryOperation>::value>::type> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor comment, definitely not a request to change.
This could be a little bit shorter (but same number of lines though):

Suggested change
typename std::enable_if<IsMinimumIdentityOp<
AccumulatorT, BinaryOperation>::value>::type> {
enable_if_t<IsMinimumIdentityOp<
AccumulatorT, BinaryOperation>::value>> {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried this during development and couldn't get it to work. I chalked it up to me not understanding enough about how our implementation of enable_if_t differs from std::enable_if. Can you compile locally if you make this change? Maybe I'm doing something wrong.

Copy link
Contributor

Choose a reason for hiding this comment

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

I checked our enable_if_t implementation. It is the same as in C++ standard. So, there should not be any problem. If you need help we may have a call or IM

Signed-off-by: John Pennycook <john.pennycook@intel.com>
Signed-off-by: John Pennycook <john.pennycook@intel.com>
If an implementation can identify the identity value for a given combination of accumulator type `AccumulatorT` and function object type `BinaryOperation`, the value is defined as a member of the `known_identity` trait class:
```c++
template <typename BinaryOperation, typename AccumulatorT>
struct known_identity {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure we should telling that known_identity is a struct on the spec level. It may be implemented as the using to something. I would also try to align the API with integral_constant. I understand that this is not possible for 100% but traits with values usually have some run-time API as well. The comment is applicable to other traits

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of the traits in C++ are defined as a struct, aren't they? Is there a good reason that known_identity should be different?

I'm not sure what you're imagining when aligning with integral_constant. In the general case, I don't think we can guarantee that the identity value is something that can be passed as a template parameter (e.g. it may be a floating-point type).

typename std::enable_if<IsMaximumIdentityOp<
AccumulatorT, BinaryOperation>::value>::type> {
static constexpr AccumulatorT value =
std::numeric_limits<AccumulatorT>::has_infinity
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like AccumulatorT is the the fundamental C++ type only (because it's used in std::numeric_limits).

Two questions basing on that:

  • What about custom types?
  • If only fundamental types should be supported, can we introduce the integral_constant semantics for known_identity API as I suggested for has_known_identity?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a short-term fix. Our reduction implementation currently only detects identity values automatically for fundamental C++ types (and half), so that's all we've decided to cover with the traits for now.

Eventually we want developers to be able to declare the identity value for their own types and function object types. The current thinking is that for combinations of fundamental types and known function object types (e.g. std::plus<>) the traits will continue to work as implemented here, but for anything else they'll check the function object for something like an identity member.

There are still some open questions about exactly what this should look like for transparent functors and what additional checks are needed (e.g. if we can determine an identity for T1 and T1 is convertible to T2, is it safe to assume that the identity for T1 can be used?). These are important questions, but I don't think the first implementation of the traits should be blocked by them.

Comment on lines +181 to +182
typename std::enable_if<IsMinimumIdentityOp<
AccumulatorT, BinaryOperation>::value>::type> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I checked our enable_if_t implementation. It is the same as in C++ standard. So, there should not be any problem. If you need help we may have a call or IM

Pennycook and others added 2 commits September 30, 2020 10:24
Signed-off-by: John Pennycook <john.pennycook@intel.com>
uint16_t Buf;
friend std::numeric_limits<class cl::sycl::detail::half_impl::half>;
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't realize all is fwd-declared and therefore

Suggested change
friend std::numeric_limits<class cl::sycl::detail::half_impl::half>;
friend std::numeric_limits<half_impl::half>;

or

Suggested change
friend std::numeric_limits<class cl::sycl::detail::half_impl::half>;
friend std::numeric_limits<sycl::half>;

works too. Do we prefer one of these shorter options?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have no preference.

@Pennycook
Copy link
Contributor Author

@rolandschulz: Are you still working on fixing the broken cases here?

@bader
Copy link
Contributor

bader commented Oct 14, 2020

We also need resolve conflicts with #2624.

@@ -26,6 +26,11 @@
#else
#define __SYCL_CONSTEXPR_ON_DEVICE
#endif
#if __cplusplus >= 201402L
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is there the sycl-include-gnu11.cpp test which checks it compiles with C++11? I thought we only support compiling as >=C++14.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the RT library is C++14, but the headers are C++11.

Copy link
Contributor

Choose a reason for hiding this comment

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

@bader , @romanovvlad - Can't we assume C++14 or newer in SYCL header files?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't have a simple "yes/no" answer, but I'm aware of a couple of factors restricting usage of C++ features:

  • SYCL specification: SYCL-1.2.1 relies on C++11 and SYCL-2020 relies on C++17 features. It seems to me that DPC++ is not going to support "strict SYCL-1.2.1" mode where C++14 (or later) features are not supported.
  • Runtime library ABI compatibility (see the note in our contribution guide). It's hard to say if using C++14 features in SYCL headers breaks runtime ABI, but it possible and should be prevented by regression tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

We have C++ version documented at:
https://github.com/intel/llvm/blob/sycl/sycl/doc/GetStartedGuide.md#c-standard
but it doesn't answer whether C++11 mode will be functional or broken.

I think it would be good to know and catch the case when we really want to break C++11 compatibility and have some discussion on that. Maybe that's what sycl-include-gnu11.cpp test is doing?

Copy link
Contributor

Choose a reason for hiding this comment

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

The test only checks that the header can be included. But not that any template in the header can be instantiated in C++11 mode. The current version of this PR passes all tests . But trying to instantiate known_identity for half in C++11 will give a compiler error (not tested).

It shouldn't have any ABI issues to use any C++14 features in the header. The problematic release for ABI issues is C++11 (e.g. string). There weren't any such things in C++14.

Copy link
Contributor

Choose a reason for hiding this comment

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

C++14 is required now. The doc changes have been merged 10 days ago: #3053

@Pennycook Pennycook marked this pull request as ready for review January 12, 2021 15:03
@Pennycook Pennycook requested review from AlexeySachkov and a team as code owners January 12, 2021 15:03
@Pennycook
Copy link
Contributor Author

Thanks for the fixes, @rolandschulz. Opening up to review now.

pvchupin pushed a commit to pvchupin/llvm that referenced this pull request Jan 18, 2021
* Add note that SYCL 2020 implementation is in progress (see issue intel#2971)
* Add note that DPC++ runtime and headers require C++14 (see PR intel#2528)

Signed-off-by: Pavel V Chupin <pavel.v.chupin@intel.com>
pvchupin added a commit that referenced this pull request Jan 19, 2021
* Add note that SYCL 2020 implementation is in progress (see issue #2971)
* Add note that DPC++ runtime and headers require C++14 (see PR #2528)

Signed-off-by: Pavel V Chupin <pavel.v.chupin@intel.com>
Copy link
Contributor

@v-klochkov v-klochkov left a comment

Choose a reason for hiding this comment

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

Looks good to me. I suggest merging this patch as is now.

A bit later I'll fix the c++11 LIT test (the fix in that LIT test is included into #3123) and also will remove the macro _CPP14_CONSTEXPR .

@Pennycook please approve the fix if you agree with the changes and the idea to merge the fix in the current state.

Copy link
Contributor

@AlexeySachkov AlexeySachkov left a comment

Choose a reason for hiding this comment

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

half_type.hpp changes look good to me, one minor code style comment

@Pennycook
Copy link
Contributor Author

Looks good to me. I suggest merging this patch as is now.

A bit later I'll fix the c++11 LIT test (the fix in that LIT test is included into #3123) and also will remove the macro _CPP14_CONSTEXPR .

@Pennycook please approve the fix if you agree with the changes and the idea to merge the fix in the current state.

Apparently GitHub doesn't let people approve their own PRs, but I agree with your proposal. Thanks for picking up the required LIT test and macro changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request spec extension All issues/PRs related to extensions specifications
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants