[cfe-dev] RFC: Emitting empty invariant group for vtable loads

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Mon Jan 30 09:38:05 PST 2017


On 20 Jan 2017 8:07 am, "Piotr Padlewski" <piotr.padlewski at gmail.com> wrote:

Hi all,

I would like to propose a new way clang would decorate vtable loads in
order to handle devirtualization better.

I've added *llvm-dev* also, because this can start a discussion about
changing invariant.group to just invariant.

PDF version of this RFC can be found here:

https://drive.google.com/file/d/0B72TmzNsY6Z8ZmpOUnB5dDZfSFU/
view?usp=sharing


Background:

Initial old design:

http://lists.llvm.org/pipermail/cfe-dev/2015-July/044227.html

My talk from LLVM Dev Meeting

http://llvm.org/devmtg/2016-11/#talk6

The problem

Clang with -fstrict-vtable-pointers decorates vtable loads with metadata
corresponding to mangled pointer type name like:

void g(A& a){
   a.foo();
}


define void @_Z1gR1A(%struct.A* dereferenceable(8) %a) local_unnamed_addr #0
{
entry:
 %0 = bitcast %struct.A* %a to void (%struct.A*)***
 %vtable = load void (%struct.A*)**, void (%struct.A*)*** %0,
!invariant.group !7
 %1 = load void (%struct.A*)*, void (%struct.A*)** %vtable
 tail call void %1(%struct.A* nonnull %a)
 ret void
}

!7 = !{!"_ZTS1A"}



This works well if the pointer type doesn’t change, but when it does,
devirtualization might not happen like here:

struct A {
   A();
   virtual void foo();
};
struct B : A{
   B();
   virtual void foo();
};
void g(A& a){
   a.foo();
   a.foo();
}
void clobber(A&);
void f() {
     B b;
     clobber(b);
     g(b);
}

The other problem is that when we combine 2 instructions with different
invariant.group metadata, then we pick one of them, because for now we can
have only single !invariant.group metadata.

The solution

I had some initial ideas how it can be solved, like

   1.

   introducing multi invariant groups
   2.

   having sub invariant groups - like inheritance, so we could figure out
   that one group is subgroup of another
   3.

   decorating all loads with base pointer MD (doesn’t work with multiple
   inheritance)


The original idea was that the metadata would indicate the class that
introduced the vptr; that seems like it should work ok with multiple
inheritance. Is there a problem with that approach? (We may still be able
to remove it entirely, which could still be preferable.)

I consulted my ideas with Krzysztof Pszeniczny, and he proposed something
much simpler: we can decorate every invariant.group md with empty metadata.

This should work because the lifetime of the object is strictly defined by
invariant.group.barrier.


If this holds, we can start discussion about if it makes sense to keep
invariant groups, and instead have just “invariant”, that would be
equivalent to having invariant.group with the same metadata.

Do you have some thoughts about this approach? I don’t have a mathematical
proof, but I am confident that it should be valid.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170130/25b92c10/attachment.html>


More information about the cfe-dev mailing list