-
Notifications
You must be signed in to change notification settings - Fork 787
[SYCL] Allow SYCL_EXTERNAL for class member functions #1295
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
Conversation
@@ -2098,7 +2098,7 @@ This attribute can only be applied to functions and indicates that the | |||
function must be treated as a device function and must be emitted even if it has | |||
no direct uses from other SYCL device functions. However, it cannot be applied | |||
to functions marked as 'static', functions declared within an anonymous | |||
namespace or class member functions. | |||
namespace or virtual/pure virtual class member functions. |
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 not sure the virtual/pure virtual is worth the differentiation. I'd say simply 'virtual' is sufficient. Same in the error message.
clang/lib/Sema/SemaDeclAttr.cpp
Outdated
@@ -4429,9 +4429,9 @@ static void handleSYCLDeviceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { | |||
<< AL << 0 /* static function or anonymous namespace */; | |||
return; | |||
} | |||
if (isa<CXXMethodDecl>(FD)) { | |||
if (FD->isVirtualAsWritten() || FD->isPure()) { |
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.
Do you have a case where the 'isPure' check is required? I don't know of any case where you can mark a function as pure but not as virtual. Additionally, I'd suggest just using this function: https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html#a1f488b7521f08ced46dce05c44cab5c5
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 agree that using isVirtual
function seems more elegant. I also can't recall cases when pure function is not virtual.
But then, I'm just curious, why isVirtual
function also checks both isVirtualAsWritten
and isPure
internally. (see https://clang.llvm.org/doxygen/DeclCXX_8h_source.html#l01948 )
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, because Microsoft. __interface is a markup in MSVC (https://docs.microsoft.com/en-us/cpp/cpp/interface?view=vs-2019) that makes every function in it pure, but not marked virtual as written :)
For standards compliant C++, only the 'isvirtualaswritten' and size_overridden_methods checks actually are necessary.
clang/test/SemaSYCL/sycl-device.cpp
Outdated
virtual int foo() {} | ||
|
||
__attribute__((sycl_device)) // expected-error {{'sycl_device' attribute cannot be applied to a virtual or pure virtual class member function}} | ||
virtual int bar() = 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.
Add a test for override/final as well! Additionally, cases where the class itself is 'final'.
I also wonder if we should ALLOW final versions of the function (or when the class is marked final).
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, technically we could allow any stuff which do not bring virtual table usage into resulting LLVM IR module.
I had some interesting observation:
First, any call of virtual function doesn't bring vtable usage to IR if it was done without using of pointer to the base class, i.e.
struct Bar {
virtual void bar1() {}
};
__attribute__((sycl_device)) void FOO() {
Bar b;
b.bar1();
}
But, such calls will be diagnosed by our diagnostic in SemaSYCL here
llvm/clang/lib/Sema/SemaSYCL.cpp
Line 226 in 092367b
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict) |
Second, the diagnostic in SemaSYCL always triggered by the functions marked as override
and final
if they were marked as virtual in base class.
BTW if you are using function marked as final but through pointer to the base class, vtable usage will appear in resulting device code module anyway.
Another funny thing that the diagnostic implemented in place where attribute handling happens i.e. inside handleSYCLDeviceAttr
function triggers only if function is explicitly marked as virtual, so, if you, for example, just override some virtual function and do not leave virtual
keyword near it's declaration/definition, it will be possible to add sycl_kernel
attribute to it, but calling of this function will be prohibited by the SemaSYCL diagnostic. I guess this happens because SemaSYCL diagnostic happens much more later when more information is presented.
The point to disallow sycl_kernel
attribute for virtual function was to improve user experience, I guess, because virtual functions cannot be called on device, which makes marking them with sycl_device
useless.
But I suppose if this diagnostic is not so efficient and it's behavior can't be aligned with the diagnostic which validates actual virtual function calls, we can do not implement it to do not confuse users. Because now it looks like this:
struct Bar {
virtual void bar1() {}
};
struct Bar1 : Bar {
__attribute__((sycl_device)) void bar1() final {} // no diagnostic
};
__attribute__((sycl_device)) void FOO() {
Bar1 b;
b.bar1(); // sycl-device.cpp:65:5: error: SYCL kernel cannot call a virtual function
// b.bar1();
}
As a conclusion, I'm asking. @AlexeySachkov , @erichkeane is it ok if we won't implement diagnostic which disallow usage of sycl_kernel
/indirectly_callable
attirubute for virtual functions.
Please NOTE: my observation about that diagnostic for virtual function calls triggers even for cases which do not bring vtable usage to device code is not in scope of 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.
Hmm... yeah, I had forgotten about the parts where we already know the type.
Bar &b =...;
b.bar1();
Should definitely diagnose. However, any non-ref/pointer types already know their type. Anything marked 'override' should still obviously diagnose, BUT, this should not:
Bar1 &b=...;
b.bar1();
Because bar1 is final in Bar1, I would expect us to KNOW the call and not need to use the vtable ( though I am not sure we CAN do this, I'm not sure if this sitll uses the vtable).
Another example:
struct Bar2 : Bar {
__attribute___((sycl_device)) void bar1() override {} /// should still diagnose.
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.
As I said, problems with diagnosing of virtual function calls is not in scope of this PR. I just captured my observations while adding new test cases and exploring behavior.
This PR is about SYCL_EXTERNAL
and therefore about __attribute___((sycl_device))
Such case can't be diagnosed in a way I use now:
struct Bar2 : Bar {
__attribute___((sycl_device)) void bar1() override {}
Because inside handleSYCLDeviceAttr
function we don't have enough information yet, so here diagnostic happens only if function explicitly marked with virtual
keyword. But once this function is called, the call will be diagnosed by our old diagnostic from SemaSYCL because it happens later with more information.
So, I propose do not diagnose sycl_device
usage on virtual functions, because such diagnostic is not sufficient.
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.
Right, I'm exploring the problem space here... I don't think skipping this diagnostic is a bad idea if we can properly count on diagnosing calls.
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.
Generally OK, I would just like a few additional codegen tests, otherwise LGTM.
}; | ||
|
||
class B { | ||
public: |
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 add tests for what the behavior (I think from a CodeGen perspective) of what happens to:
override functions marked with these attributes (where the 'base' does NOT have them)
override functions marked with these attributes (where hte base DOES have them)
unmarked override functions (where the base DOES have them)
marked/unmarked 'final' functions in the above.
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, added for both attributes.
This patch allows to apply `SYCL_EXTERNAL` to class member functions, but only if they weren't declared as virtual or as pure virtual. The same logic was applied to `[[intel::device_indireclty_callable]]`. Signed-off-by: Alexey Sachkov <[email protected]>
Signed-off-by: Mariya Podchishchaeva <[email protected]>
Signed-off-by: Mariya Podchishchaeva <[email protected]>
Signed-off-by: Mariya Podchishchaeva <[email protected]>
Signed-off-by: Mariya Podchishchaeva <[email protected]>
Moved device code outlining to CodeGen because the old scheme in combination with SYCL_EXTERNAL implementation for methods triggered assertions Signed-off-by: Mariya Podchishchaeva <[email protected]>
@romanovvlad idk what that means. I reviewed the patch and am waiting on the committer to update the patch. |
We use assignee field to indicate one person who is responsible |
Signed-off-by: Mariya Podchishchaeva <[email protected]>
Signed-off-by: Mariya Podchishchaeva <[email protected]>
Signed-off-by: Mariya Podchishchaeva <[email protected]>
407a845
to
2225ffd
Compare
BTW, applying |
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, looks like @bader might have some opens, so once he's ok so am I.
This patch allows to apply sycl_device attribute and therefore SYCL_EXTERNAL macro to class member functions.
The same logic was applied to [[intel::device_indireclty_callable]].