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/thinLTO 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+ // In non-LTO mode:
53+ // - The pass apply speculative devirtualization without requiring any type of
54+ // visibility.
55+ // - Skips other features like virtual constant propagation, uniform return
56+ // value
57+ // optimization, unique return value optimization, branch funnels to minimize
58+ // the drawbacks of wrong speculation.
5159// ===----------------------------------------------------------------------===//
5260
5361#include " llvm/Transforms/IPO/WholeProgramDevirt.h"
6068#include " llvm/ADT/Statistic.h"
6169#include " llvm/Analysis/AssumptionCache.h"
6270#include " llvm/Analysis/BasicAliasAnalysis.h"
71+ #include " llvm/Analysis/ModuleSummaryAnalysis.h"
6372#include " llvm/Analysis/OptimizationRemarkEmitter.h"
73+ #include " llvm/Analysis/ProfileSummaryInfo.h"
6474#include " llvm/Analysis/TypeMetadataUtils.h"
6575#include " llvm/Bitcode/BitcodeReader.h"
6676#include " llvm/Bitcode/BitcodeWriter.h"
@@ -798,6 +808,21 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
798808 return PreservedAnalyses::all ();
799809 return PreservedAnalyses::none ();
800810 }
811+ std::optional<ModuleSummaryIndex> Index;
812+ // Force Fallback mode as it's safe in case it's non-LTO mode where
813+ // we don't have hidden visibility.
814+ if (!InLTOMode) {
815+ DevirtCheckMode = WPDCheckMode::Fallback;
816+ // In non-LTO mode, we don't have an ExportSummary, so we
817+ // build the ExportSummary from the module.
818+ assert (!ExportSummary &&
819+ " ExportSummary is expected to be empty in non-LTO mode" );
820+ if (DevirtCheckMode == WPDCheckMode::Fallback && !ExportSummary) {
821+ ProfileSummaryInfo PSI (M);
822+ Index.emplace (buildModuleSummaryIndex (M, nullptr , &PSI));
823+ ExportSummary = Index.has_value () ? &Index.value () : nullptr ;
824+ }
825+ }
801826 if (!DevirtModule (M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
802827 ImportSummary)
803828 .run ())
@@ -1091,10 +1116,12 @@ bool DevirtModule::tryFindVirtualCallTargets(
10911116 if (!TM.Bits ->GV ->isConstant ())
10921117 return false ;
10931118
1094- // We cannot perform whole program devirtualization analysis on a vtable
1095- // with public LTO visibility.
1096- if (TM.Bits ->GV ->getVCallVisibility () ==
1097- GlobalObject::VCallVisibilityPublic)
1119+ // If speculative devirtualization is NOT enabled, it's not safe to perform
1120+ // whole program devirtualization
1121+ // analysis on a vtable with public LTO visibility.
1122+ if (DevirtCheckMode != WPDCheckMode::Fallback &&
1123+ TM.Bits ->GV ->getVCallVisibility () ==
1124+ GlobalObject::VCallVisibilityPublic)
10981125 return false ;
10991126
11001127 Function *Fn = nullptr ;
@@ -1112,6 +1139,11 @@ bool DevirtModule::tryFindVirtualCallTargets(
11121139 // calls to pure virtuals are UB.
11131140 if (Fn->getName () == " __cxa_pure_virtual" )
11141141 continue ;
1142+ // In Most cases empty functions will be overridden by the
1143+ // implementation of the derived class, so we can skip them.
1144+ if (DevirtCheckMode == WPDCheckMode::Fallback &&
1145+ Fn->getReturnType ()->isVoidTy () && Fn->getInstructionCount () <= 1 )
1146+ continue ;
11151147
11161148 // We can disregard unreachable functions as possible call targets, as
11171149 // unreachable functions shouldn't be called.
@@ -1333,10 +1365,11 @@ bool DevirtModule::trySingleImplDevirt(
13331365 if (!IsExported)
13341366 return false ;
13351367
1336- // If the only implementation has local linkage, we must promote to external
1337- // to make it visible to thin LTO objects. We can only get here during the
1338- // ThinLTO export phase.
1339- if (TheFn->hasLocalLinkage ()) {
1368+ // In case of non-speculative devirtualization, If the only implementation has
1369+ // local linkage, we must promote to external
1370+ // to make it visible to thin LTO objects. We can only get here during the
1371+ // ThinLTO export phase.
1372+ if (DevirtCheckMode != WPDCheckMode::Fallback && TheFn->hasLocalLinkage ()) {
13401373 std::string NewName = (TheFn->getName () + " .llvm.merged" ).str ();
13411374
13421375 // Since we are renaming the function, any comdats with the same name must
@@ -2315,6 +2348,11 @@ bool DevirtModule::run() {
23152348
23162349 Function *TypeTestFunc =
23172350 Intrinsic::getDeclarationIfExists (&M, Intrinsic::type_test);
2351+ // If we are applying speculative devirtualization, we can work on the public
2352+ // type test intrinsics.
2353+ if (!TypeTestFunc && DevirtCheckMode == WPDCheckMode::Fallback)
2354+ TypeTestFunc =
2355+ Intrinsic::getDeclarationIfExists (&M, Intrinsic::public_type_test);
23182356 Function *TypeCheckedLoadFunc =
23192357 Intrinsic::getDeclarationIfExists (&M, Intrinsic::type_checked_load);
23202358 Function *TypeCheckedLoadRelativeFunc = Intrinsic::getDeclarationIfExists (
@@ -2437,12 +2475,18 @@ bool DevirtModule::run() {
24372475 .WPDRes [S.first .ByteOffset ];
24382476 if (tryFindVirtualCallTargets (TargetsForSlot, TypeMemberInfos,
24392477 S.first .ByteOffset , ExportSummary)) {
2440-
2441- if (!trySingleImplDevirt (ExportSummary, TargetsForSlot, S.second , Res)) {
2442- DidVirtualConstProp |=
2443- tryVirtualConstProp (TargetsForSlot, S.second , Res, S.first );
2444-
2445- tryICallBranchFunnel (TargetsForSlot, S.second , Res, S.first );
2478+ trySingleImplDevirt (ExportSummary, TargetsForSlot, S.second , Res);
2479+ // In Speculative devirt mode, we skip virtual constant propagation
2480+ // and branch funneling to minimize the drawback if we got wrong
2481+ // speculation during devirtualization.
2482+ if (DevirtCheckMode != WPDCheckMode::Fallback) {
2483+ if (!trySingleImplDevirt (ExportSummary, TargetsForSlot, S.second ,
2484+ Res)) {
2485+ DidVirtualConstProp |=
2486+ tryVirtualConstProp (TargetsForSlot, S.second , Res, S.first );
2487+
2488+ tryICallBranchFunnel (TargetsForSlot, S.second , Res, S.first );
2489+ }
24462490 }
24472491
24482492 // Collect functions devirtualized at least for one call site for stats.
0 commit comments