5050// - Import phase: (same as with hybrid case above).
5151//
5252// In non-LTO mode:
53- // - The pass apply speculative devirtualization without requiring any type of
53+ // - The pass applies speculative devirtualization without requiring any type of
5454// visibility.
5555// - 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.
56+ // value optimization, unique return value optimization, branch funnels as they
57+ // need LTO.
5958// ===----------------------------------------------------------------------===//
6059
6160#include " llvm/Transforms/IPO/WholeProgramDevirt.h"
@@ -629,11 +628,13 @@ struct DevirtModule {
629628 std::map<CallInst *, unsigned > NumUnsafeUsesForTypeTest;
630629 PatternList FunctionsToSkip;
631630
631+ const bool InLTOMode;
632+
632633 DevirtModule (Module &M, function_ref<AAResults &(Function &)> AARGetter,
633634 function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
634635 function_ref<DominatorTree &(Function &)> LookupDomTree,
635636 ModuleSummaryIndex *ExportSummary,
636- const ModuleSummaryIndex *ImportSummary)
637+ const ModuleSummaryIndex *ImportSummary, bool InLTOMode )
637638 : M(M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),
638639 ExportSummary (ExportSummary), ImportSummary(ImportSummary),
639640 Int8Ty(Type::getInt8Ty(M.getContext())),
@@ -642,7 +643,8 @@ struct DevirtModule {
642643 Int64Ty(Type::getInt64Ty(M.getContext())),
643644 IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)),
644645 Int8Arr0Ty(ArrayType::get(Type::getInt8Ty(M.getContext()), 0)),
645- RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
646+ RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter),
647+ InLTOMode(InLTOMode) {
646648 assert (!(ExportSummary && ImportSummary));
647649 FunctionsToSkip.init (SkipFunctionNames);
648650 }
@@ -759,7 +761,8 @@ struct DevirtModule {
759761 static bool
760762 runForTesting (Module &M, function_ref<AAResults &(Function &)> AARGetter,
761763 function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
762- function_ref<DominatorTree &(Function &)> LookupDomTree);
764+ function_ref<DominatorTree &(Function &)> LookupDomTree,
765+ bool InLTOMode);
763766};
764767
765768struct DevirtIndex {
@@ -815,7 +818,8 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
815818 if (TestNoLTOMode)
816819 // we are outside LTO mode. enable speculative devirtualization:
817820 DevirtCheckMode = WPDCheckMode::Fallback;
818- if (!DevirtModule::runForTesting (M, AARGetter, OREGetter, LookupDomTree))
821+ if (!DevirtModule::runForTesting (M, AARGetter, OREGetter, LookupDomTree,
822+ !TestNoLTOMode))
819823 return PreservedAnalyses::all ();
820824 return PreservedAnalyses::none ();
821825 }
@@ -828,14 +832,12 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
828832 // build the ExportSummary from the module.
829833 assert (!ExportSummary &&
830834 " ExportSummary is expected to be empty in non-LTO mode" );
831- if (DevirtCheckMode == WPDCheckMode::Fallback && !ExportSummary) {
832- ProfileSummaryInfo PSI (M);
833- Index.emplace (buildModuleSummaryIndex (M, nullptr , &PSI));
834- ExportSummary = Index.has_value () ? &Index.value () : nullptr ;
835- }
835+ ProfileSummaryInfo PSI (M);
836+ Index.emplace (buildModuleSummaryIndex (M, nullptr , &PSI));
837+ ExportSummary = Index.has_value () ? &Index.value () : nullptr ;
836838 }
837839 if (!DevirtModule (M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
838- ImportSummary)
840+ ImportSummary, InLTOMode )
839841 .run ())
840842 return PreservedAnalyses::all ();
841843 return PreservedAnalyses::none ();
@@ -1034,7 +1036,7 @@ static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary) {
10341036bool DevirtModule::runForTesting (
10351037 Module &M, function_ref<AAResults &(Function &)> AARGetter,
10361038 function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
1037- function_ref<DominatorTree &(Function &)> LookupDomTree) {
1039+ function_ref<DominatorTree &(Function &)> LookupDomTree, bool InLTOMode ) {
10381040 std::unique_ptr<ModuleSummaryIndex> Summary =
10391041 std::make_unique<ModuleSummaryIndex>(/* HaveGVs=*/ false );
10401042
@@ -1063,7 +1065,8 @@ bool DevirtModule::runForTesting(
10631065 ClSummaryAction == PassSummaryAction::Export ? Summary.get ()
10641066 : nullptr ,
10651067 ClSummaryAction == PassSummaryAction::Import ? Summary.get ()
1066- : nullptr )
1068+ : nullptr ,
1069+ InLTOMode)
10671070 .run ();
10681071
10691072 if (!ClWriteSummary.empty ()) {
@@ -1127,12 +1130,10 @@ bool DevirtModule::tryFindVirtualCallTargets(
11271130 if (!TM.Bits ->GV ->isConstant ())
11281131 return false ;
11291132
1130- // If speculative devirtualization is NOT enabled, it's not safe to perform
1131- // whole program devirtualization
1132- // analysis on a vtable with public LTO visibility.
1133- if (DevirtCheckMode != WPDCheckMode::Fallback &&
1134- TM.Bits ->GV ->getVCallVisibility () ==
1135- GlobalObject::VCallVisibilityPublic)
1133+ // In LTO mode, it's not safe to perform whole program devirtualization
1134+ // analysis on a vtable with public LTO visibility.
1135+ if (InLTOMode && TM.Bits ->GV ->getVCallVisibility () ==
1136+ GlobalObject::VCallVisibilityPublic)
11361137 return false ;
11371138
11381139 Function *Fn = nullptr ;
@@ -1150,10 +1151,10 @@ bool DevirtModule::tryFindVirtualCallTargets(
11501151 // calls to pure virtuals are UB.
11511152 if (Fn->getName () == " __cxa_pure_virtual" )
11521153 continue ;
1153- // In Most cases empty functions will be overridden by the
1154+ // In most cases empty functions will be overridden by the
11541155 // implementation of the derived class, so we can skip them.
1155- if (DevirtCheckMode == WPDCheckMode::Fallback &&
1156- Fn->getReturnType ()-> isVoidTy () && Fn-> getInstructionCount () <= 1 )
1156+ if (!InLTOMode && Fn-> getReturnType ()-> isVoidTy () &&
1157+ Fn->getInstructionCount () <= 1 )
11571158 continue ;
11581159
11591160 // We can disregard unreachable functions as possible call targets, as
@@ -1376,11 +1377,10 @@ bool DevirtModule::trySingleImplDevirt(
13761377 if (!IsExported)
13771378 return false ;
13781379
1379- // In case of non-speculative devirtualization, If the only implementation has
1380- // local linkage, we must promote to external
1381- // to make it visible to thin LTO objects. We can only get here during the
1382- // ThinLTO export phase.
1383- if (DevirtCheckMode != WPDCheckMode::Fallback && TheFn->hasLocalLinkage ()) {
1380+ // In LTO mode, if the only implementation has local linkage, we must promote
1381+ // to external to make it visible to thin LTO objects. We can only get here
1382+ // during the ThinLTO export phase.
1383+ if (InLTOMode && TheFn->hasLocalLinkage ()) {
13841384 std::string NewName = (TheFn->getName () + " .llvm.merged" ).str ();
13851385
13861386 // Since we are renaming the function, any comdats with the same name must
@@ -2359,9 +2359,9 @@ bool DevirtModule::run() {
23592359
23602360 Function *TypeTestFunc =
23612361 Intrinsic::getDeclarationIfExists (&M, Intrinsic::type_test);
2362- // If we are applying speculative devirtualization , we can work on the public
2362+ // If we are out of LTO mode , we can work on the public
23632363 // type test intrinsics.
2364- if (!TypeTestFunc && DevirtCheckMode == WPDCheckMode::Fallback )
2364+ if (!TypeTestFunc && !InLTOMode )
23652365 TypeTestFunc =
23662366 Intrinsic::getDeclarationIfExists (&M, Intrinsic::public_type_test);
23672367 Function *TypeCheckedLoadFunc =
@@ -2488,10 +2488,9 @@ bool DevirtModule::run() {
24882488 S.first .ByteOffset , ExportSummary)) {
24892489 bool SingleImplDevirt =
24902490 trySingleImplDevirt (ExportSummary, TargetsForSlot, S.second , Res);
2491- // In Speculative devirt mode, we skip virtual constant propagation
2492- // and branch funneling to minimize the drawback if we got wrong
2493- // speculation during devirtualization.
2494- if (!SingleImplDevirt && DevirtCheckMode != WPDCheckMode::Fallback) {
2491+ // We apply virtual constant propagation and branch funneling only in LTO
2492+ // mode.
2493+ if (!SingleImplDevirt && InLTOMode) {
24952494 DidVirtualConstProp |=
24962495 tryVirtualConstProp (TargetsForSlot, S.second , Res, S.first );
24972496
0 commit comments