-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[clang][SYCL] Add sycl_external attribute and restrict emitting device code #140282
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
base: main
Are you sure you want to change the base?
Conversation
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.
Thanks for working on this @schittir! I completed an initial pass of all of the code, but still need to look more closely at the documentation updates.
Thank you for the initial pass review, Tom! |
✅ With the latest revision this PR passed the C/C++ code formatter. |
Support for functions is sufficient for SYCL 2020 spec conformance.
Co-authored-by: Mariya Podchishchaeva <mariya.podchishchaeva@intel.com>
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.
Thanks @schittir, here are my initial review comments. I expect to review the newly added tests more closely once these comments are all addressed.
Oops new tests are failing. |
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 is looking good @schittir! I added some comments for minor issues. I still need to review the tests more closely.
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.
A few more comments. I still haven't finished my review of sycl-external-attr.cpp
, but will try to later today or over the weekend.
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 finished an initial pass through all of the tests. I'll do another round once you've had a chance to catch up on the comments so far.
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 is looking great @schittir! I just realized that, since we made the change to allow the attribute to be present during host compilation that we should no longer restrict diagnostics to device compilation and that tests should exercise host compilation as well.
I suggested a few FIXME comments, but other than that, I think this is good to go!
Thank you for the review, Tom! |
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 love it @schittir, this looks great!
@erichkeane, @bader, please review and lend your approval. Note that some of the changes to the tests are to synchronize them with continued evolution that happened in DPC++ but was not previously upstreamed.
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.
LGTM in general. I have a few minor comments related to the code style and one related to CodeGen testing.
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.
Ah shoot, apparently I forgot to click 'submit' when I reviewed this last week. Sorry about that. Here are my pending comments.
clang/include/clang/Basic/Attr.td
Outdated
@@ -1641,6 +1641,13 @@ def DeviceKernel : DeclOrTypeAttr { | |||
}]; | |||
} | |||
|
|||
def SYCLExternal : InheritableAttr { | |||
let Spellings = [Clang<"sycl_external">]; |
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.
let Spellings = [Clang<"sycl_external">]; | |
let Spellings = [CXX11<"sycl_external">]; |
Alternatively:
let Spellings = [Clang<"sycl_external">]; | |
let Spellings = [CXX11<"sycl_external">, C23<"sycl_external">]; |
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.
We use the Clang
spelling for sycl_kernel_entry_point
, what would be the reason for doing differently here? The attribute is an implementation detail used to provide the SYCL_EXTERNAL
functionality, so shouldn't be directly written by SYCL programmers. Are you suggesting excluding the GNU
spelling?
SYCL is only relevant for C++, so the C23
spelling wouldn't be desired.
If we switch to (only) the CXX11
spelling, I think the clang
namespace should be retained.
let Spellings = [Clang<"sycl_external">]; | |
let Spellings = [CXX11<"clang", "sycl_external">]; |
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.
We use the
Clang
spelling forsycl_kernel_entry_point
, what would be the reason for doing differently here? The attribute is an implementation detail used to provide theSYCL_EXTERNAL
functionality, so shouldn't be directly written by SYCL programmers. Are you suggesting excluding theGNU
spelling?SYCL is only relevant for C++, so the
C23
spelling wouldn't be desired.If we switch to (only) the
CXX11
spelling, I think theclang
namespace should be retained.
Ah! Yes, I was suggesting to dump the GNU spelling. Keeping the clang namespace is also the right thing to do, so your suggestion is the right one.
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.
Ok, I'm fine with dropping the GNU spelling. But in that case, we should also change the sycl_kernel_entry_point
attribute to match (either in this PR or in a separate one).
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.
Ok, I'm fine with dropping the GNU spelling. But in that case, we should also change the
sycl_kernel_entry_point
attribute to match (either in this PR or in a separate one).
Agreed. SLIGHT preference for separate PR (as I feel like we're almost done with this one, so for the sake of expedience).
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.
Separate PR it is!
I'll follow this spelling: let Spellings = [CXX11<"clang", "sycl_external">];
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 fails two tests; will fix.
Clang :: CodeGenSPIRV/Builtins/generic_cast_to_ptr_explicit.c
Clang :: CodeGenSPIRV/Builtins/ids_and_ranges.c
// Redeclarations of the function in the same translation unit may | ||
// optionally use SYCL_EXTERNAL, but this is not required. | ||
const SYCLExternalAttr *SEA = New->getAttr<SYCLExternalAttr>(); | ||
if (SEA && !Old->hasAttr<SYCLExternalAttr>()) { |
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.
To be consistent with the rest of our attributes, I'd probably suggest we support adding it up until definition. We can then do a conformance warning instead of error, but still let it work.
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.
That might be reasonable. I think we might still have to make it an error if there was an ODR-use before the definition though. I'd have to think about that 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.
@tahonermann - do you have any additional thoughts here?
Thank you!
@@ -12251,6 +12264,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, | |||
if (NewFD->hasAttr<SYCLKernelEntryPointAttr>()) | |||
SYCL().CheckSYCLEntryPointFunctionDecl(NewFD); | |||
|
|||
if (NewFD->hasAttr<SYCLExternalAttr>()) | |||
SYCL().CheckSYCLExternalFunctionDecl(NewFD); |
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.
Hmm... this seems like it should be handled when doing the attribute 'visiting', why is it here instead of there?
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.
The checks include checking for linkage which I don't think is necessarily computed at the time the attribute is visited.
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.
Can you confirm that linkage isn't computed at that point? I would expect us to (since the entire declaration is read before we handle attributes) have it there, so it is a little surprising.
Also, I didn't see instantiation of this attribute, do we prevent it on function templates?
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.
Linkage, or rather, external visibility, which is what we actually check, can depend on other attributes like VisibilityAttr
. Checking here ensures that all attributes have been processed and therefore avoids visitation ordering issues.
The attribute is allowed on function templates and is automatically inherited by (implicit and explicit) instantiations (and explicit specializations which is incorrect according to the C++ standard). I don't think there is anything to do to handle instantiation.
We do have a testing gap to address yet though. We have good tests for diagnostics, but are missing a test to validate which symbols are actually emitted. We'll ensure that test exercises function templates.
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.
Linkage, or rather, external visibility, which is what we actually check, can depend on other attributes like
VisibilityAttr
. Checking here ensures that all attributes have been processed and therefore avoids visitation ordering issues.The attribute is allowed on function templates and is automatically inherited by (implicit and explicit) instantiations (and explicit specializations which is incorrect according to the C++ standard). I don't think there is anything to do to handle instantiation.
We do have a testing gap to address yet though. We have good tests for diagnostics, but are missing a test to validate which symbols are actually emitted. We'll ensure that test exercises function templates.
Ah, I see, the visibility attribute makes sense here, thank you for looking into that.
I don't think there is anything to do to handle instantiation.
We've had to do some work in the past for attribute instantiation, though simple ones might be automatic. Can you make sure that specializations/partial specializations are properly tested? And diagnose if linkage isn't right?
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.
We'll add tests to make sure the attribute has the proper affect with regard to actually emitting symbols. Tests for diagnostics are already in place in clang/test/SemaSYCL/sycl-external-attr.cpp
.
Though, hmm, I think we're missing a test for implicit instantiation; I don't think we should diagnose cases like this:
namespace { struct S9 {}; }
struct T9 {
using type = S9;
};
template<typename>
[[clang::sycl_external]] void func9() {}
template<typename T>
[[clang::sycl_external]] void test_func9() {
func9<typename T::type>();
}
template void test_func9<T9>(); // Ok; don't diagnose implicit instantiation of func9<S9>().
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.
namespace { struct S9 {}; }
struct T9 {
using type = S9;
};
template<typename>
[[clang::sycl_external]] void func9() {} // error here : {{'sycl_external' can only be applied to functions with external linkage}}
template<typename T>
[[clang::sycl_external]] void test_func9() {
func9<typename T::type>(); // note here: {{in instantiation of function template specialization 'func9<(anonymous namespace)::S9>' requested here}}
}
template void test_func9<T9>(); // note here: {{in instantiation of function template specialization 'test_func9<T9>' requested here}}
This case is being diagnosed at present. Will fix it.
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.
To test for implicit instantiation, call FunctionDecl::getTemplateSpecializationInfo()
. If it returns non-null, call getSpecializationKind()
via the returned pointer. If that returns TSK_ImplicitInstantiation
, then skip the diagnostic.
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.
The suggested change to avoid diagnosing the abovementioned case affects cases even with explicit template specializations, such as the two preceding it in the test file. Using the canonical decls doesn't solve the problem. Further investigation is needed. I will leave the FIXME as it is for this case for follow up in a subsequent 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.
Thanks for the updates, @schittir. A few minor requests.
[[clang::sycl_external]] virtual void BFunc1WithAttr() { int i = 1; } | ||
// CHECK: define linkonce_odr spir_func void @_ZN1B14BFunc1WithAttrEv |
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 might not be the result we want. Virtual function definitions have particular rules for when they are emitted and those rules are different for the Itanium and MSVC ABIs. In this case, the virtual function is defined as an inline function and emitting it is ok, but I think is also unnecessary. I think we should do the following:
- Skip requiring a symbol for an unused inline function declared with sycl_external.
- Add a test for a virtual function that is defined outside the class (a symbol should be emitted).
- Add a test for an unused virtual function that is defined as inline outside the class (a symbol should not be emitted).
This patch is part of the upstreaming effort for supporting SYCL language front end.
It makes the following changes:
This patch is missing diagnostics for the following diagnostics listed in the SYCL 2020 specification's section 5.10.1, which will be addressed in a subsequent PR:
Functions that are declared using SYCL_EXTERNAL have the following additional restrictions beyond those imposed on other device functions: