nickitat wrote:
Thanks for your comments. AFAIK, the general problem that prevents a lot of
devirtualization currently is that we should assume that code like this exists
in the program:
``` cpp
#include <new>
#include <cstdio>
struct Base {
virtual void hello() { printf("Base\n"); }
virtual ~Base() = default;
};
struct Derived : Base {
virtual void hello() override { printf("Derived\n"); }
};
static_assert(sizeof(Base) == sizeof(Derived)); // same layout
void clobber(Base* p) {
p->~Base(); // explicitly destroy the Base object
::new (p) Derived(); // construct a Derived in the same storage
// vptr now points to Derived's vtable
}
int main() {
alignas(Derived) unsigned char buf[sizeof(Derived)];
Base* p = ::new (buf) Base();
p->hello(); // "Base"
clobber(p);
p->hello(); // "Derived"
p->~Base(); // calls ~Derived() via vtable — correct
}
```
I.e., a simple fact that we have a `T*` and that `T` is final or whatever does
not guarantee anything by itself. This is why the current implementation is
able to devirtualize when it can find the relevant store of vptr:
https://github.com/llvm/llvm-project/blob/8e702735090388a3231a863e343f880d0f96fecb/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp#L709-L712
And a case like this works in the current clang:
``` cpp
void h() {
Impl impl; // here is the traceable vptr store
impl.foo();
}
```
But not the case from the description. So, I don't aim for a really generic
solution here. Rather, I'd like to extend the current logic tracking vptr
stores to include `static_cast` as another source of a guarantee on the dynamic
type.
How to properly propagate this knowledge from the `static_cast` to all
subsequent calls is another good question. Probably with alias analysis or some
clever invariant groups that were described
[here](https://youtu.be/Dt4UehzzcsE?si=t-OPPNrz8ogCYUBN). For now I've added a
simple AA-based solution.
https://github.com/llvm/llvm-project/pull/185087
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits