[WPD] Allow virtual calls to be analyzed with multiple type tests
authorTeresa Johnson <tejohnson@google.com>
Fri, 1 May 2020 15:16:38 +0000 (08:16 -0700)
committerTeresa Johnson <tejohnson@google.com>
Wed, 24 Jun 2020 17:51:24 +0000 (10:51 -0700)
commitd291bd510e6a4e62594186cb8f3ddc18acf2ee1a
tree44a699ee266f0f72bd2544e5eb23ab6f5f41303c
parent8dc92142e3c5332d741aff4bc81ee6aeed7784b2
[WPD] Allow virtual calls to be analyzed with multiple type tests

Summary:
In D52514 I had fixed a bug with WPD after indirect call promotion, by
checking that a type test being analyzed dominates potential virtual
calls. With that fix I included a small effiency enhancement to avoid
processing a devirt candidate multiple times (when there are multiple
type tests). This latter change wasn't in response to any measured
efficiency issues, it was merely theoretical. Unfortuantely, it turns
out to limit optimization opportunities after inlining.

Specifically, consider code that looks like:

class A {
  virtual void foo();
};
class B : public A {
  void foo();
}
void callee(A *a) {
  a->foo(); // Call 1
}
void caller(B *b) {
  b->foo(); // Call 2
  callee(b);
}

After inlining callee into caller, because of the existing call to
b->foo() in caller there will be 2 type tests in caller for the vtable
pointer of b: the original type test against B from Call 2, and the
inlined type test against A from Call 1. If the code was compiled with
-fstrict-vtable-pointers, then after optimization WPD will see that
both type tests are associated with the inlined virtual Call 1.
With my earlier change to only process a virtual call against one type
test, we may only consider virtual Call 1 against the base class A type
test, which can't be devirtualized. With my change here to remove this
restriction, it also gets considered for the type test against the
derived class B type test, where it can be devirtualized.

Note that if caller didn't include it's own earlier virtual call
b->foo() we will not be able to devirtualize after inlining callee even
after this fix, since there would not be a type test against B in the
IR. As a future enhancement we can consider inserting type tests at call
sites that pass pointers to classes with virtual calls, to enable
context-sensitive devirtualization after inlining.

Reviewers: pcc, vitalybuka, evgeny777

Subscribers: Prazek, hiraditya, steven_wu, dexonsmith, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D79235
llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
llvm/test/ThinLTO/X86/devirt_multiple_type_test.ll [new file with mode: 0644]