Skip to content

Commit 5a6c69b

Browse files
committed
[WPD]: Add devirtualization pass to the pass pipeline.
- Build ExportSummary locally when they are not given.
1 parent 03e66ae commit 5a6c69b

File tree

4 files changed

+59
-17
lines changed

4 files changed

+59
-17
lines changed

llvm/include/llvm/Passes/PassBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class PipelineTuningOptions {
9999
// analyses after various module->function or cgscc->function adaptors in the
100100
// default pipelines.
101101
bool EagerlyInvalidateAnalyses;
102+
103+
// Tuning option to enable/disable speculative devirtualization.
104+
// Its default value is false.
105+
bool DevirtualizeSpeculatively;
102106
};
103107

104108
/// This class provides access to building LLVM's passes.

llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,14 @@ struct WholeProgramDevirtPass : public PassInfoMixin<WholeProgramDevirtPass> {
226226
ModuleSummaryIndex *ExportSummary;
227227
const ModuleSummaryIndex *ImportSummary;
228228
bool UseCommandLine = false;
229+
bool DevirtSpeculatively = false;
229230
WholeProgramDevirtPass()
230231
: ExportSummary(nullptr), ImportSummary(nullptr), UseCommandLine(true) {}
231232
WholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary,
232-
const ModuleSummaryIndex *ImportSummary)
233-
: ExportSummary(ExportSummary), ImportSummary(ImportSummary) {
233+
const ModuleSummaryIndex *ImportSummary,
234+
bool DevirtSpeculatively = false)
235+
: ExportSummary(ExportSummary), ImportSummary(ImportSummary),
236+
DevirtSpeculatively(DevirtSpeculatively) {
234237
assert(!(ExportSummary && ImportSummary));
235238
}
236239
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &);

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ PipelineTuningOptions::PipelineTuningOptions() {
325325
MergeFunctions = EnableMergeFunctions;
326326
InlinerThreshold = -1;
327327
EagerlyInvalidateAnalyses = EnableEagerlyInvalidateAnalyses;
328+
DevirtualizeSpeculatively = false;
328329
}
329330

330331
namespace llvm {
@@ -1641,6 +1642,24 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
16411642
if (!LTOPreLink)
16421643
MPM.addPass(RelLookupTableConverterPass());
16431644

1645+
if (PTO.DevirtualizeSpeculatively && LTOPhase == ThinOrFullLTOPhase::None) {
1646+
MPM.addPass(WholeProgramDevirtPass(
1647+
/*ExportSummary*/ nullptr,
1648+
/*ImportSummary*/ nullptr,
1649+
/*DevirtSpeculatively*/ PTO.DevirtualizeSpeculatively));
1650+
MPM.addPass(LowerTypeTestsPass(nullptr, nullptr,
1651+
lowertypetests::DropTestKind::Assume));
1652+
if (EnableModuleInliner) {
1653+
MPM.addPass(ModuleInlinerPass(getInlineParamsFromOptLevel(Level),
1654+
UseInlineAdvisor,
1655+
ThinOrFullLTOPhase::None));
1656+
} else {
1657+
MPM.addPass(ModuleInlinerWrapperPass(
1658+
getInlineParamsFromOptLevel(Level),
1659+
/* MandatoryFirst */ true,
1660+
InlineContext{ThinOrFullLTOPhase::None, InlinePass::CGSCCInliner}));
1661+
}
1662+
}
16441663
return MPM;
16451664
}
16461665

llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -636,9 +636,11 @@ struct DevirtModule {
636636
std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
637637
PatternList FunctionsToSkip;
638638

639+
const bool DevirtSpeculatively;
639640
DevirtModule(Module &M, ModuleAnalysisManager &MAM,
640641
ModuleSummaryIndex *ExportSummary,
641-
const ModuleSummaryIndex *ImportSummary)
642+
const ModuleSummaryIndex *ImportSummary,
643+
bool DevirtSpeculatively)
642644
: M(M), MAM(MAM),
643645
FAM(MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager()),
644646
ExportSummary(ExportSummary), ImportSummary(ImportSummary),
@@ -651,7 +653,8 @@ struct DevirtModule {
651653
RemarksEnabled(areRemarksEnabled()),
652654
OREGetter([&](Function &F) -> OptimizationRemarkEmitter & {
653655
return FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
654-
}) {
656+
}),
657+
DevirtSpeculatively(DevirtSpeculatively) {
655658
assert(!(ExportSummary && ImportSummary));
656659
FunctionsToSkip.init(SkipFunctionNames);
657660
}
@@ -765,7 +768,8 @@ struct DevirtModule {
765768

766769
// Lower the module using the action and summary passed as command line
767770
// arguments. For testing purposes only.
768-
static bool runForTesting(Module &M, ModuleAnalysisManager &MAM);
771+
static bool runForTesting(Module &M, ModuleAnalysisManager &MAM,
772+
bool DevirtSpeculatively);
769773
};
770774

771775
struct DevirtIndex {
@@ -808,11 +812,22 @@ struct DevirtIndex {
808812
PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
809813
ModuleAnalysisManager &MAM) {
810814
if (UseCommandLine) {
811-
if (!DevirtModule::runForTesting(M, MAM))
815+
if (!DevirtModule::runForTesting(M, MAM, ClDevirtualizeSpeculatively))
812816
return PreservedAnalyses::all();
813817
return PreservedAnalyses::none();
814818
}
815-
if (!DevirtModule(M, MAM, ExportSummary, ImportSummary).run())
819+
820+
std::optional<ModuleSummaryIndex> Index;
821+
if (!ExportSummary && !ImportSummary && DevirtSpeculatively) {
822+
// Build the ExportSummary from the module.
823+
assert(!ExportSummary &&
824+
"ExportSummary is expected to be empty in non-LTO mode");
825+
ProfileSummaryInfo PSI(M);
826+
Index.emplace(buildModuleSummaryIndex(M, nullptr, &PSI));
827+
ExportSummary = Index.has_value() ? &Index.value() : nullptr;
828+
}
829+
if (!DevirtModule(M, MAM, ExportSummary, ImportSummary, DevirtSpeculatively)
830+
.run())
816831
return PreservedAnalyses::all();
817832
return PreservedAnalyses::none();
818833
}
@@ -1010,7 +1025,8 @@ static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary) {
10101025
return ErrorSuccess();
10111026
}
10121027

1013-
bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM) {
1028+
bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM,
1029+
bool DevirtSpeculatively) {
10141030
std::unique_ptr<ModuleSummaryIndex> Summary =
10151031
std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false);
10161032

@@ -1039,7 +1055,8 @@ bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM) {
10391055
ClSummaryAction == PassSummaryAction::Export ? Summary.get()
10401056
: nullptr,
10411057
ClSummaryAction == PassSummaryAction::Import ? Summary.get()
1042-
: nullptr)
1058+
: nullptr,
1059+
DevirtSpeculatively)
10431060
.run();
10441061

10451062
if (!ClWriteSummary.empty()) {
@@ -1103,10 +1120,10 @@ bool DevirtModule::tryFindVirtualCallTargets(
11031120
if (!TM.Bits->GV->isConstant())
11041121
return false;
11051122

1106-
// Without ClDevirtualizeSpeculatively, we cannot perform whole program
1123+
// Without DevirtSpeculatively, we cannot perform whole program
11071124
// devirtualization analysis on a vtable with public LTO visibility.
1108-
if (!ClDevirtualizeSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1109-
GlobalObject::VCallVisibilityPublic)
1125+
if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1126+
GlobalObject::VCallVisibilityPublic)
11101127
return false;
11111128

11121129
Function *Fn = nullptr;
@@ -1127,7 +1144,7 @@ bool DevirtModule::tryFindVirtualCallTargets(
11271144

11281145
// In most cases empty functions will be overridden by the
11291146
// implementation of the derived class, so we can skip them.
1130-
if (ClDevirtualizeSpeculatively && Fn->getReturnType()->isVoidTy() &&
1147+
if (DevirtSpeculatively && Fn->getReturnType()->isVoidTy() &&
11311148
Fn->getInstructionCount() <= 1)
11321149
continue;
11331150

@@ -1250,8 +1267,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
12501267
// add support to compare the virtual function pointer to the
12511268
// devirtualized target. In case of a mismatch, fall back to indirect
12521269
// call.
1253-
if (DevirtCheckMode == WPDCheckMode::Fallback ||
1254-
ClDevirtualizeSpeculatively) {
1270+
if (DevirtCheckMode == WPDCheckMode::Fallback || DevirtSpeculatively) {
12551271
MDNode *Weights = MDBuilder(M.getContext()).createLikelyBranchWeights();
12561272
// Version the indirect call site. If the called value is equal to the
12571273
// given callee, 'NewInst' will be executed, otherwise the original call
@@ -2375,7 +2391,7 @@ bool DevirtModule::run() {
23752391
Function *PublicTypeTestFunc = nullptr;
23762392
// If we are in speculative devirtualization mode, we can work on the public
23772393
// type test intrinsics.
2378-
if (ClDevirtualizeSpeculatively)
2394+
if (DevirtSpeculatively)
23792395
PublicTypeTestFunc =
23802396
Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test);
23812397
Function *TypeTestFunc =
@@ -2511,7 +2527,7 @@ bool DevirtModule::run() {
25112527
// Out of speculative devirtualization mode, Try to apply virtual constant
25122528
// propagation or branch funneling.
25132529
// TODO: This should eventually be enabled for non-public type tests.
2514-
if (!SingleImplDevirt && !ClDevirtualizeSpeculatively) {
2530+
if (!SingleImplDevirt && !DevirtSpeculatively) {
25152531
DidVirtualConstProp |=
25162532
tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
25172533

0 commit comments

Comments
 (0)