Skip to content

[SYCL][NVPTX][AMDGCN] Move devicelib cmath to header #18706

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

Draft
wants to merge 6 commits into
base: sycl
Choose a base branch
from

Conversation

npmiller
Copy link
Contributor

This patch experiments with moving standard library math built-ins from libdevice into headers.

This is based on the way clang handles this for CUDA and HIP. In these languages you can define device functions as overloads. This allows re-defining standard library functions specifically for the device in a header, so that we can provide a device specific implementations of certain built-ins while still using the regular standard library headers.

By default SYCL doesn't do overloads for device functions, so this patch introduces a new sycl_device_only attribute, this attribute will make a function device only and allow it to overload with existing functions.

This patch experiments with moving standard library math built-ins from
libdevice into headers.

This is based on the way clang handles this for CUDA and HIP. In these
languages you can define device functions as overloads. This allows
re-defining standard library functions specifically for the device in a
header, so that we can provide a device specific implementations of
certain built-ins while still using the regular standard library
headers.

By default SYCL doesn't do overloads for device functions, so this patch
introduces a new `sycl_device_only` attribute, this attribute will make
a function device only and allow it to overload with existing functions.
@npmiller
Copy link
Contributor Author

@bader this is a proof of concept for moving C++ library handling from libdevice code into headers. It allows us to remove the hack blocking LLVM intrinsic generation for standard math built-ins, since we intercept them earlier in the header for device side, which is in-line with what clang cuda does. Only for cmath and for Nvidia and AMD for now.

I've currently placed the header into the stl_wrappers directory, it might be better as a clang header, but at least on CUDA the clang header is always included whereas with the stl wrappers it will only be included when the matching standard library header is included.

This still needs a ton of work which is why it's a draft, but let me know if you have any feedback on the approach.

It would be good to know if this would be interesting for non-AOT targets as well, there's a lot of logic in the driver to conditionally link libdevice libraries, I suspect in theory most of that could be replaced with this header approach, but I haven't looked into this much so I'm not 100% sure if this is something we'd want.

Copy link
Contributor

@bader bader left a comment

Choose a reason for hiding this comment

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

@npmiller, thanks for working on this.

It allows us to remove the hack blocking LLVM intrinsic generation for standard math built-ins, since we intercept them earlier in the header for device side, which is in-line with what clang cuda does.

I discussed this approach with Johannes Doerfert a few years ago. He told me that he doesn't like "what clang cuda does" and plans to change it. I think clang still uses the header solution, but it may be worth to double check with LLVM community is doing any work in that direction.

I've currently placed the header into the stl_wrappers directory, it might be better as a clang header, but at least on CUDA the clang header is always included whereas with the stl wrappers it will only be included when the matching standard library header is included.

Interesting... I thought that clang only adds path to the clang headers at the beginning of the search paths list to make sure that clang wrapper header is included before STL one. I didn't know that CUDA compiler always includes clang wrapper headers.

It would be good to know if this would be interesting for non-AOT targets as well, there's a lot of logic in the driver to conditionally link libdevice libraries, I suspect in theory most of that could be replaced with this header approach, but I haven't looked into this much so I'm not 100% sure if this is something we'd want.

@AlexeySachkov, could you take into SPIR-V part, please?

The change looks to be aligned with the community approach. The only concern I have is compile time, but potential increase should be negligible.

cc @Naghasan just to keep in the loop.

Comment on lines 3732 to 3733
if (Context.getLangOpts().isSYCL() && hasAttr<SYCLDeviceOnlyAttr>() &&
!(BuiltinID == Builtin::BIprintf || BuiltinID == Builtin::BImalloc)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

If I get it right, we allow printf and malloc for all SYCL targets. I'm open to discuss if requiring printf support is reasonable, but I'm not sure if malloc can be supported by all SYCL targets.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a copy/paste from the CUDA code just above, malloc shouldn't be there

Copy link
Contributor

@Naghasan Naghasan left a comment

Choose a reason for hiding this comment

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

don't forget to add tests and documentation for the attribute before undrafting :)

Comment on lines 3732 to 3733
if (Context.getLangOpts().isSYCL() && hasAttr<SYCLDeviceOnlyAttr>() &&
!(BuiltinID == Builtin::BIprintf || BuiltinID == Builtin::BImalloc)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a copy/paste from the CUDA code just above, malloc shouldn't be there

@@ -1629,6 +1629,14 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
}
}

// Allow overloads with SYCLDeviceOnlyAttr
if (SemaRef.getLangOpts().isSYCL()) {
if (hasExplicitAttr<SYCLDeviceOnlyAttr>(Old) !=
Copy link
Contributor

Choose a reason for hiding this comment

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

we shouldn't limit to explicit attr

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated all the hasExplicitAttr to hasAttr

def SYCLDeviceOnly : InheritableAttr {
let Spellings = [GNU<"sycl_device_only">];
let Subjects = SubjectList<[Function]>;
let LangOpts = [SYCLIsDevice];
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
let LangOpts = [SYCLIsDevice];
let LangOpts = [SYCLIsHost, SYCLIsDevice];

otherwise this would create a warning during host compilation and the filtering is dead code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added SilentlyIgnoreSYCLIsHost instead, sycl_device had that and it sounds like it should suppress the warning you mention.

We don't support malloc in SYCL, silence warnings for host compilation
with `sycl_device_only`. Fix failing clang test with new attribute.
@npmiller
Copy link
Contributor Author

Interesting... I thought that clang only adds path to the clang headers at the beginning of the search paths list to make sure that clang wrapper header is included before STL one. I didn't know that CUDA compiler always includes clang wrapper headers.

Yeah in the driver here it does:

  CC1Args.push_back("-include");
  CC1Args.push_back("__clang_cuda_runtime_wrapper.h");

And __clang_cuda_cmath.h is included from that runtime wrapper header here, it also includes <cmath>.

Using our stl wrappers solution should allow us to be a little more conservative about when we include all of this stuff.

npmiller added 3 commits May 29, 2025 10:54
This test was relying on the hack preventing LLVM intrinsics from being
emitted so it doesn't work at all with the new approach.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants