Skip to content
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

Is restriction on calling virtual member functions from device functions too strict? #565

Open
AlexeySachkov opened this issue Jun 12, 2024 · 1 comment

Comments

@AlexeySachkov
Copy link
Contributor

5.4. Language restrictions for device functions lists the following restriction (emphasis mine):

The odr-use of polymorphic classes and classes with virtual inheritance is allowed. However, no virtual member functions are allowed to be called in a device function.

As I read this, no call to a virtual member function is allowed, even if the call is in fact direct, i.e. it does not involve virtual call mechanism. There are a few situations where the latter could occur:

From class.virtual.16:

Explicit qualification with the scope operator ([expr.prim.id.qual]) suppresses the virtual call mechanism.
[Example 10: 

class B { public: virtual void f(); };
class D : public B { public: void f(); };
void D::f() { /* ... */ B::f(); }

Here, the function call in D​::​f really does call B​::​f and not D​::​f. — end example]

Also, expr.call.2 (emphasis mine) suggests that there are cases when a call to a virtual member function is not considered to be a virtual call:

If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.
[Note 2: The dynamic type is the type of the object referred to by the current value of the object expression. [class.cdtor] describes the behavior of virtual function calls when the object expression refers to an object under construction or destruction. — end note]

I.e. even if a selected function is virtual, but the class member access expression is in a certain form, the call is not considered to be a virtual call, but instead it is just a direct call to the said function. I'm properly lost in all those id-expression, qualified-id and other terms from the C++ draft spec, but my understanding is that there is no virtual call mechanism involved in an example below:

struct Base {
  virtual void foo();
};

void bar() {
  Base b;
  b.foo();
}

If my reading of both specs is correct, then we should update the restriction in the SYCL spec to say something like this (emphasis to highlight the diff):

The odr-use of polymorphic classes and classes with virtual inheritance is allowed. However, no virtual functions calls are allowed to be performed in a device function.

I.e. we only disallow cases where virtual call mechanism is involved, but we allow direct (i.e. non-virtual) calls to functions that are defined as virtual.

@gmlueck
Copy link
Contributor

gmlueck commented Jun 12, 2024

I.e. even if a selected function is virtual, but the class member access expression is in a certain form, the call is not considered to be a virtual call, but instead it is just a direct call to the said function. I'm properly lost in all those id-expression, qualified-id and other terms from the C++ draft spec, but my understanding is that there is no virtual call mechanism involved in an example below:

I think this is the case that expr.call.2 refers to:

struct Base {
  virtual void foo();
};

struct Derive : public Base {
  virtual void foo();
};

int main() {
  Derive d;
  Base *b = &d;
  b->Base::foo();  // Non-virtual function call to Base::foo
}

I.e. we only disallow cases where virtual call mechanism is involved, but we allow direct (i.e. non-virtual) calls to functions that are defined as virtual.

Yes, I agree. I think this proposed change makes sense. We will need to update the error checking in DPC++, though, because we currently diagnose both cases as an error.

AlexeySachkov added a commit to intel/llvm that referenced this issue Jul 12, 2024
This commit is a part of virtual functions extension implementation that
is proposed in #10540.

As part of the feature, we would like to achieve both:
- allow virtual function calls from SYCL kernels that are submitted with
the right properties as described in the language extension
specification
- disallow virtual function calls from SYCL kernels that do not use any
(or the right) properties to conform with the core SYCL 2020
specification

Implementing such diagnostics will require call graph traversal to
understand the origin of the call and that is not what's easy to do in
FE. Therefore, the implementation design for virtual functions proposes
that such diagnostic is offloaded to a pass. The draft of the analysis
pass implementation can be seen in #14141

This commit is a preparations for it: it introduces an attribute to all
virtual function calls in device code so they can be easily detected and
not confused with plain function pointer calls (for which we don't have
a language specification and therefore well-defined behavior yet).

Note that the new approach will relax virtual function call diagnostics,
because it will allow non-virtual calls to virtual functions to be
performed from kernels. This is in line with discussion in
KhronosGroup/SYCL-Docs#565 about relaxing current SYCL 2020 restrictions
about virtual functions.
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

No branches or pull requests

2 participants