[PATCH 0/3] c++: Devirtualization of constant pointer to member function call
Chi Wang <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
GCC has barely any devirtualization support for pointer to member function (PMF) call. The only possible devirtualization is by constant propagation of virtual table to a known object that is taken address of: T t; ((&t)->*member) (); However, PMFs are useful to simplify repetitive call patterns or use as callbacks in functions or templates. In these usages, the PMFs are clearly constants but do not benefit from trivial devirtualization. Even for a simple call: T* t; (t->*&T::func) (); // or std::invoke (&T::func, t); cannot be devirtualized if func is a virtual function and marked final, while in practice it should be the same as calling t->func (). This patch series tries to address this gap. We use an internal function IFN_PTRMEMFUNC_OBJ to mark the calling object in the virtual branch of PMF decoding. The motivation behind this is that both IFN_PTRMEMFUNC_OBJ can preserve more C++ FE type information and guard folding pointer type cast and pointer plus expressions, which can obfuscate the offsets in PMF object adjustments and vtable lookup. In a PMF call, two pointer adjustments happen: one is when front end adjusts the object pointer to the base type of the PMF, and the other is at runtime, the PMF *this object adjustment. The design is that IFN_PTRMEMFUNC_OBJ will hold the casted object, the type of PMF, the original type of the object, the front end cast offset, and whether the front end cast is through any virtual base lookup (which makes the previous offset not reliable for derived classes). This marker drives a tree pass that tries to convert to direct call to final polymorphic target, similar to how C++ FE does for plain polymorphic call, and also lets IPA and WPA discover inlining and cloning opportunities. These are simply extending the existing code path for simple indirect call and simple polymorphic call to also recognize the PMF call patterns. The main result is that most simple PMF constant calls are now possible to be a direct call or even inlined. Testing results: * x86_64 native: bootstrapped and regression tested on all languages * x86_64 -m32: bootstrapped and regression tested on all languages except golang (cannot build because of 32 bit system call issues) * aarch64: bootstrapped and regression tested on C and C++ * ia64: tested non-LTO devirtualization tests, on a cross-compiler build that disables all libraries, shared libraries linking, and threading support. I ran this because it was still in the codebase and is the only target using function descriptors, although it is marked obsolete now. Ok for trunk? Chi Wang (3): Add a pass to devirtualize polymorphic PMF calls ipa: New indirect info kind and optimization for PMF lto: Keep vtable definition for PMF calls gcc/Makefile.in | 1 + gcc/cgraph.cc | 73 ++- gcc/cgraph.h | 81 ++- gcc/cgraphclones.cc | 5 + gcc/cgraphunit.cc | 24 + gcc/cp/constexpr.cc | 2 + gcc/cp/method.cc | 1 + gcc/cp/typeck.cc | 32 +- gcc/doc/ifn.texi | 5 + gcc/gimple-ptrmemfunc.cc | 656 ++++++++++++++++++++++++ gcc/gimple-ptrmemfunc.h | 29 ++ gcc/internal-fn.cc | 11 + gcc/internal-fn.def | 3 + gcc/ipa-cp.cc | 26 +- gcc/ipa-devirt.cc | 55 ++ gcc/ipa-fnsummary.cc | 2 +- gcc/ipa-prop.cc | 279 ++++++++-- gcc/ipa-prop.h | 3 +- gcc/ipa-utils.h | 2 + gcc/ipa.cc | 49 +- gcc/lto-cgraph.cc | 86 +++- gcc/passes.def | 2 + gcc/testsuite/g++.dg/lto/devirtpmf1_0.C | 13 + gcc/testsuite/g++.dg/lto/devirtpmf1_1.C | 16 + gcc/testsuite/g++.dg/lto/devirtpmf2_0.C | 13 + gcc/testsuite/g++.dg/lto/devirtpmf2_1.C | 11 + gcc/testsuite/g++.dg/lto/devirtpmf2_2.C | 7 + gcc/testsuite/g++.dg/lto/devirtpmf3_0.C | 13 + gcc/testsuite/g++.dg/lto/devirtpmf3_1.C | 24 + gcc/testsuite/g++.dg/opt/devirtpmf1.C | 128 +++++ gcc/testsuite/g++.dg/opt/devirtpmf2.C | 63 +++ gcc/testsuite/g++.dg/opt/devirtpmf3.C | 57 ++ gcc/testsuite/g++.dg/opt/devirtpmf4.C | 45 ++ gcc/testsuite/g++.dg/opt/devirtpmf5.C | 72 +++ gcc/testsuite/g++.dg/opt/devirtpmf6.C | 62 +++ gcc/testsuite/g++.dg/opt/devirtpmf7.C | 23 + gcc/testsuite/g++.dg/opt/devirtpmf8.C | 28 + gcc/timevar.def | 1 + gcc/tree-pass.h | 1 + gcc/varpool.cc | 2 + 40 files changed, 1920 insertions(+), 86 deletions(-) create mode 100644 gcc/gimple-ptrmemfunc.cc create mode 100644 gcc/gimple-ptrmemfunc.h create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf2_1.C create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf2_2.C create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf3_0.C create mode 100644 gcc/testsuite/g++.dg/lto/devirtpmf3_1.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf1.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf2.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf3.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf4.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf5.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf6.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf7.C create mode 100644 gcc/testsuite/g++.dg/opt/devirtpmf8.C -- 2.43.0