This is an archive of the discontinued LLVM Phabricator instance.

Remove readnone from invariant.group.barrier
AbandonedPublic

Authored by Prazek on Mar 28 2017, 2:54 PM.

Details

Summary

Readnone attribute would cause CSE of two barriers with
the same argument, which is invalid by example:

struct Base {
      virtual int foo() { return 42; }
};

struct Derived1 : Base {
      int foo() override { return 50; }
};

struct Derived2 : Base {
      int foo() override { return 100; }
};

void foo() {
    Base *x = new Base{};
    new (x) Derived1{};
    int a = std::launder(x)->foo();
    new (x) Derived2{};
    int b = std::launder(x)->foo();
}

Here 2 calls of std::launder will produce @llvm.invariant.group.barrier,
which would be merged into one call, causing devirtualization
to devirtualize second call into Derived1::foo() instead of
Derived2::foo()

Event Timeline

Prazek created this revision.Mar 28 2017, 2:54 PM
Prazek added inline comments.Mar 28 2017, 2:59 PM
test/Transforms/EarlyCSE/invariant.group.barrier.ll
2

any ideas?

hfinkel added inline comments.Mar 28 2017, 3:09 PM
include/llvm/IR/Intrinsics.td
620

I think that this makes sense. The placement new (or whatever else is installing something with a new type in the memory) will write to the memory, so marking this as reading will keep things separated. Can you add a comment here explaining why.

Prazek added inline comments.Mar 28 2017, 3:14 PM
include/llvm/IR/Intrinsics.td
620

So it doesn't write to any memory, because the barrier doesn't set anything, but you can think of it as if barrier would read the vptr in order to decide what kind of pointer it should return - (Chandlers idea) like if the phisical address of returned pointer would be the same, but some bits of the pointer would be set according to it's dynamic type.

Prazek abandoned this revision.Mar 31 2017, 5:56 AM

reposting because of forgotten llvm-commits