2424// returns 0, or a single vtable's function returns 1, replace each virtual
2525// call with a comparison of the vptr against that vtable's address.
2626//
27- // This pass is intended to be used during the regular and thin LTO pipelines:
27+ // This pass is intended to be used during the regular/thin and non-LTO
28+ // pipelines:
2829//
2930// During regular LTO, the pass determines the best optimization for each
3031// virtual call and applies the resolutions directly to virtual calls that are
4849// is supported.
4950// - Import phase: (same as with hybrid case above).
5051//
52+ // During Speculative devirtualization mode -not restricted to LTO-:
53+ // - The pass applies speculative devirtualization without requiring any type of
54+ // visibility.
55+ // - Skips other features like virtual constant propagation, uniform return
56+ // value optimization, unique return value optimization and branch funnels as
57+ // they need LTO.
58+ // - This mode is enabled via 'devirtualize-speculatively' flag.
59+ //
5160// ===----------------------------------------------------------------------===//
5261
5362#include " llvm/Transforms/IPO/WholeProgramDevirt.h"
6170#include " llvm/Analysis/AssumptionCache.h"
6271#include " llvm/Analysis/BasicAliasAnalysis.h"
6372#include " llvm/Analysis/BlockFrequencyInfo.h"
73+ #include " llvm/Analysis/ModuleSummaryAnalysis.h"
6474#include " llvm/Analysis/OptimizationRemarkEmitter.h"
75+ #include " llvm/Analysis/ProfileSummaryInfo.h"
6576#include " llvm/Analysis/TypeMetadataUtils.h"
6677#include " llvm/Bitcode/BitcodeReader.h"
6778#include " llvm/Bitcode/BitcodeWriter.h"
@@ -145,6 +156,13 @@ static cl::opt<std::string> ClWriteSummary(
145156 " bitcode, otherwise YAML" ),
146157 cl::Hidden);
147158
159+ // TODO: This option eventually should support any public visibility vtables
160+ // with/out LTO.
161+ static cl::opt<bool > ClDevirtualizeSpeculatively (
162+ " devirtualize-speculatively" ,
163+ cl::desc (" Enable speculative devirtualization optimization" ),
164+ cl::init(false ));
165+
148166static cl::opt<unsigned >
149167 ClThreshold (" wholeprogramdevirt-branch-funnel-threshold" , cl::Hidden,
150168 cl::init (10 ),
@@ -892,6 +910,8 @@ void llvm::updatePublicTypeTestCalls(Module &M,
892910 CI->eraseFromParent ();
893911 }
894912 } else {
913+ // TODO: Don't replace public type tests when speculative devirtualization
914+ // gets enabled in LTO mode.
895915 auto *True = ConstantInt::getTrue (M.getContext ());
896916 for (Use &U : make_early_inc_range (PublicTypeTestFunc->uses ())) {
897917 auto *CI = cast<CallInst>(U.getUser ());
@@ -1083,10 +1103,10 @@ bool DevirtModule::tryFindVirtualCallTargets(
10831103 if (!TM.Bits ->GV ->isConstant ())
10841104 return false ;
10851105
1086- // We cannot perform whole program devirtualization analysis on a vtable
1087- // with public LTO visibility.
1088- if (TM.Bits ->GV ->getVCallVisibility () ==
1089- GlobalObject::VCallVisibilityPublic)
1106+ // Without ClDevirtualizeSpeculatively, we cannot perform whole program
1107+ // devirtualization analysis on a vtable with public LTO visibility.
1108+ if (!ClDevirtualizeSpeculatively && TM.Bits ->GV ->getVCallVisibility () ==
1109+ GlobalObject::VCallVisibilityPublic)
10901110 return false ;
10911111
10921112 Function *Fn = nullptr ;
@@ -1105,6 +1125,12 @@ bool DevirtModule::tryFindVirtualCallTargets(
11051125 if (Fn->getName () == " __cxa_pure_virtual" )
11061126 continue ;
11071127
1128+ // In most cases empty functions will be overridden by the
1129+ // implementation of the derived class, so we can skip them.
1130+ if (ClDevirtualizeSpeculatively && Fn->getReturnType ()->isVoidTy () &&
1131+ Fn->getInstructionCount () <= 1 )
1132+ continue ;
1133+
11081134 // We can disregard unreachable functions as possible call targets, as
11091135 // unreachable functions shouldn't be called.
11101136 if (mustBeUnreachableFunction (Fn, ExportSummary))
@@ -1223,10 +1249,12 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
12231249 CallTrap->setDebugLoc (CB.getDebugLoc ());
12241250 }
12251251
1226- // If fallback checking is enabled, add support to compare the virtual
1227- // function pointer to the devirtualized target. In case of a mismatch,
1228- // fall back to indirect call.
1229- if (DevirtCheckMode == WPDCheckMode::Fallback) {
1252+ // If fallback checking or speculative devirtualization are enabled,
1253+ // add support to compare the virtual function pointer to the
1254+ // devirtualized target. In case of a mismatch, fall back to indirect
1255+ // call.
1256+ if (DevirtCheckMode == WPDCheckMode::Fallback ||
1257+ ClDevirtualizeSpeculatively) {
12301258 MDNode *Weights = MDBuilder (M.getContext ()).createLikelyBranchWeights ();
12311259 // Version the indirect call site. If the called value is equal to the
12321260 // given callee, 'NewInst' will be executed, otherwise the original call
@@ -2057,15 +2085,15 @@ void DevirtModule::scanTypeTestUsers(
20572085 Function *TypeTestFunc,
20582086 DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
20592087 // Find all virtual calls via a virtual table pointer %p under an assumption
2060- // of the form llvm.assume(llvm.type.test(%p, %md)). This indicates that %p
2061- // points to a member of the type identifier %md. Group calls by (type ID,
2062- // offset) pair (effectively the identity of the virtual function) and store
2063- // to CallSlots.
2088+ // of the form llvm.assume(llvm.type.test(%p, %md)) or
2089+ // llvm.assume(llvm.public.type.test(%p, %md)).
2090+ // This indicates that %p points to a member of the type identifier %md.
2091+ // Group calls by (type ID, offset) pair (effectively the identity of the
2092+ // virtual function) and store to CallSlots.
20642093 for (Use &U : llvm::make_early_inc_range (TypeTestFunc->uses ())) {
20652094 auto *CI = dyn_cast<CallInst>(U.getUser ());
20662095 if (!CI)
20672096 continue ;
2068-
20692097 // Search for virtual calls based on %p and add them to DevirtCalls.
20702098 SmallVector<DevirtCallSite, 1 > DevirtCalls;
20712099 SmallVector<CallInst *, 1 > Assumes;
@@ -2348,6 +2376,12 @@ bool DevirtModule::run() {
23482376 (ImportSummary && ImportSummary->partiallySplitLTOUnits ()))
23492377 return false ;
23502378
2379+ Function *PublicTypeTestFunc = nullptr ;
2380+ // If we are in speculative devirtualization mode, we can work on the public
2381+ // type test intrinsics.
2382+ if (ClDevirtualizeSpeculatively)
2383+ PublicTypeTestFunc =
2384+ Intrinsic::getDeclarationIfExists (&M, Intrinsic::public_type_test);
23512385 Function *TypeTestFunc =
23522386 Intrinsic::getDeclarationIfExists (&M, Intrinsic::type_test);
23532387 Function *TypeCheckedLoadFunc =
@@ -2361,8 +2395,9 @@ bool DevirtModule::run() {
23612395 // module, this pass has nothing to do. But if we are exporting, we also need
23622396 // to handle any users that appear only in the function summaries.
23632397 if (!ExportSummary &&
2364- (!TypeTestFunc || TypeTestFunc->use_empty () || !AssumeFunc ||
2365- AssumeFunc->use_empty ()) &&
2398+ (((!PublicTypeTestFunc || PublicTypeTestFunc->use_empty ()) &&
2399+ (!TypeTestFunc || TypeTestFunc->use_empty ())) ||
2400+ !AssumeFunc || AssumeFunc->use_empty ()) &&
23662401 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty ()) &&
23672402 (!TypeCheckedLoadRelativeFunc ||
23682403 TypeCheckedLoadRelativeFunc->use_empty ()))
@@ -2373,6 +2408,9 @@ bool DevirtModule::run() {
23732408 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
23742409 buildTypeIdentifierMap (Bits, TypeIdMap);
23752410
2411+ if (PublicTypeTestFunc && AssumeFunc)
2412+ scanTypeTestUsers (PublicTypeTestFunc, TypeIdMap);
2413+
23762414 if (TypeTestFunc && AssumeFunc)
23772415 scanTypeTestUsers (TypeTestFunc, TypeIdMap);
23782416
@@ -2472,8 +2510,12 @@ bool DevirtModule::run() {
24722510 .WPDRes [S.first .ByteOffset ];
24732511 if (tryFindVirtualCallTargets (TargetsForSlot, TypeMemberInfos,
24742512 S.first .ByteOffset , ExportSummary)) {
2475-
2476- if (!trySingleImplDevirt (ExportSummary, TargetsForSlot, S.second , Res)) {
2513+ bool SingleImplDevirt =
2514+ trySingleImplDevirt (ExportSummary, TargetsForSlot, S.second , Res);
2515+ // Out of speculative devirtualization mode, Try to apply virtual constant
2516+ // propagation or branch funneling.
2517+ // TODO: This should eventually be enabled for non-public type tests.
2518+ if (!SingleImplDevirt && !ClDevirtualizeSpeculatively) {
24772519 DidVirtualConstProp |=
24782520 tryVirtualConstProp (TargetsForSlot, S.second , Res, S.first );
24792521
0 commit comments