I'm not sure whether this is the exact problem at hand in your example,
but one of the major hurdles llvm suffers when trying to devirtualize
is the second point you made: it doesn't see the invariance of the
table pointer post construction. In your specific example the
constructors are trivial and inlinable so it I'm not sure why llvm
would be having trouble proving the value of the vptr &
devirtualizing. , perhaps due to them being static so the
initialization is contingent on it being the first call (& llvm doesn't
know that the vptr is constant after construction until destruction
begins) & doesn't see the connection across all calls.
So there are a few issues that need to be addressed to help this.
One is some kind of constant range where the front end can promise not
to modify certain values for a range (this might not be correct though
- I remember some argument as to whether it was valid to destroy and
then placement new the same type into that memory before the object
goes out of scope - if so, then it's not obvious if the vptr is
constant in any range) & secondly (at least for the case of non inline
constructors) the ability to provide some kind of assert that, post
construction, the vptr is equal to some known constant. (this assertion
is currently possible with a branch to unreachable, except llvm throws
out the unreachable code in SimplyCFG before any optimizations run - so
we need to see if we can keep them around longer - there are some PRs
filed for this but I haven't made much progress on it