I believe that this solves most (if not all) blocking optimizations problems. I even checked how many Clang's tests will fail with -fstrict-vtable-pointers set by default,
and all passed (there were around 15 failing before that), so I am really happy about this.
2. Hoisting invariant.group loads from Loops:
I wanted to hoist vtable loads from loops, but there is a big problem with LICM: it always drops invariant.group metadata.
For loads that are guaranteed to happen it is probably safe to not discard metadata, and for speculative loads we need a new concept of metadata that holds globally (unconditionally) - like the one proposed here https://reviews.llvm.org/D18738