[clang] [llvm] [WPD] Enable speculative devirtualization with LTO (PR #233380)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 19 02:20:44 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-llvm-transforms
Author: KRM7
<details>
<summary>Changes</summary>
Enable speculative single-target devirtualization with LTO (disabled by default, can be enabled using -fdevirtualize-speculatively).
The DevirtSpeculatively member variable is also removed from WPD, so that the optimization is controlled entirely by the -devirtualize-speculatively flag. The -enable-devirtualize-speculatively flag is now only used to add the WPD pass to the non-LTO pipeline.
---
Patch is 47.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/233380.diff
20 Files Affected:
- (modified) clang/docs/UsersManual.md (-2)
- (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+8)
- (modified) clang/test/Driver/lto.c (+8)
- (modified) llvm/include/llvm/AsmParser/LLToken.h (+1)
- (modified) llvm/include/llvm/IR/ModuleSummaryIndex.h (+1)
- (modified) llvm/include/llvm/IR/ModuleSummaryIndexYAML.h (+2)
- (modified) llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h (+2-5)
- (modified) llvm/lib/AsmParser/LLLexer.cpp (+1)
- (modified) llvm/lib/AsmParser/LLParser.cpp (+3)
- (modified) llvm/lib/IR/AsmWriter.cpp (+4-1)
- (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+1-2)
- (modified) llvm/lib/Passes/PassesOptions.td (+1-1)
- (modified) llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp (+74-69)
- (modified) llvm/test/Assembler/thinlto-summary.ll (+2-2)
- (added) llvm/test/ThinLTO/X86/devirt_speculative.ll (+71)
- (added) llvm/test/ThinLTO/X86/devirt_speculative_mixed_vis.ll (+105)
- (added) llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl-check-cfi.ll (+68)
- (added) llvm/test/Transforms/WholeProgramDevirt/speculative-devirt-cfi.ll (+68)
- (added) llvm/test/Transforms/WholeProgramDevirt/speculative-devirt-mixed-vis.ll (+77)
- (modified) llvm/test/Transforms/WholeProgramDevirt/speculative-devirt-single-impl.ll (+8-6)
``````````diff
diff --git a/clang/docs/UsersManual.md b/clang/docs/UsersManual.md
index 96d1c4e009c71a..2c2c131b656e03 100644
--- a/clang/docs/UsersManual.md
+++ b/clang/docs/UsersManual.md
@@ -2589,8 +2589,6 @@ if.end.icp: ; preds = %if.false.orig_indir
ret void
```
-This feature is temporarily ignored at the LLVM side when LTO is enabled.
-TODO: Update the comment when the LLVM side supports this feature for LTO.
This feature is turned off by default.
:::
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 7c832ef405fa51..329f5317ea47a9 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1222,6 +1222,14 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
(A->getOption().matches(options::OPT_fglobal_isel) ? "1" : "0")));
}
+ if (Arg *A = Args.getLastArg(options::OPT_fdevirtualize_speculatively,
+ options::OPT_fno_devirtualize_speculatively))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "-devirtualize-speculatively=" +
+ (A->getOption().matches(options::OPT_fdevirtualize_speculatively)
+ ? "1"
+ : "0")));
+
// If an explicit debugger tuning argument appeared, pass it along.
if (Arg *A =
Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
diff --git a/clang/test/Driver/lto.c b/clang/test/Driver/lto.c
index 838eb740863752..be18231f5d335c 100644
--- a/clang/test/Driver/lto.c
+++ b/clang/test/Driver/lto.c
@@ -127,6 +127,14 @@
// CHECK-NO-SLP: "-plugin-opt=-vectorize-slp=0"
// CHECK-SLP: "-plugin-opt=-vectorize-slp=1"
+// RUN: %clang --target=x86_64-unknown-linux -### %s -flto -fno-devirtualize-speculatively 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-DEVIRTUALIZE-SPECULATIVELY < %t %s
+// RUN: %clang --target=x86_64-unknown-linux -### %s -flto -fdevirtualize-speculatively 2> %t
+// RUN: FileCheck --check-prefix=CHECK-DEVIRTUALIZE-SPECULATIVELY < %t %s
+//
+// CHECK-NO-DEVIRTUALIZE-SPECULATIVELY: "-plugin-opt=-devirtualize-speculatively=0"
+// CHECK-DEVIRTUALIZE-SPECULATIVELY: "-plugin-opt=-devirtualize-speculatively=1"
+
// -flto passes -time-passes when -ftime-report is passed
// RUN: %clang --target=x86_64-unknown-linux-gnu -### %s -flto -ftime-report 2> %t
// RUN: FileCheck --check-prefix=CHECK-TIME-REPORT < %t %s
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 2679a630c2dd95..e5816ca301527e 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -467,6 +467,7 @@ enum Kind {
kw_indir,
kw_singleImpl,
kw_branchFunnel,
+ kw_speculative,
kw_singleImplName,
kw_resByArg,
kw_byArg,
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h
index 4f68582b65c4eb..f9d6640f50852a 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndex.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h
@@ -1349,6 +1349,7 @@ struct WholeProgramDevirtResolution {
BranchFunnel, ///< When retpoline mitigation is enabled, use a branch funnel
///< that is defined in the merged module. Otherwise same as
///< Indir.
+ Speculative, ///< Speculative devirtualization
} TheKind = Indir;
std::string SingleImplName;
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h b/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h
index 158c03e77306c9..441433eb381adc 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h
@@ -102,6 +102,8 @@ template <> struct ScalarEnumerationTraits<WholeProgramDevirtResolution::Kind> {
io.enumCase(value, "SingleImpl", WholeProgramDevirtResolution::SingleImpl);
io.enumCase(value, "BranchFunnel",
WholeProgramDevirtResolution::BranchFunnel);
+ io.enumCase(value, "Speculative",
+ WholeProgramDevirtResolution::Speculative);
}
};
diff --git a/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h b/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
index c3a394ab4fb720..0dd61bbd41a4ab 100644
--- a/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
+++ b/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
@@ -227,14 +227,11 @@ struct WholeProgramDevirtPass
ModuleSummaryIndex *ExportSummary;
const ModuleSummaryIndex *ImportSummary;
bool UseCommandLine = false;
- bool DevirtSpeculatively = false;
WholeProgramDevirtPass()
: ExportSummary(nullptr), ImportSummary(nullptr), UseCommandLine(true) {}
WholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary,
- const ModuleSummaryIndex *ImportSummary,
- bool DevirtSpeculatively = false)
- : ExportSummary(ExportSummary), ImportSummary(ImportSummary),
- DevirtSpeculatively(DevirtSpeculatively) {
+ const ModuleSummaryIndex *ImportSummary)
+ : ExportSummary(ExportSummary), ImportSummary(ImportSummary) {
assert(!(ExportSummary && ImportSummary));
}
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 5e52dc8dcb2478..20212fc26451aa 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -884,6 +884,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(indir);
KEYWORD(singleImpl);
KEYWORD(branchFunnel);
+ KEYWORD(speculative);
KEYWORD(singleImplName);
KEYWORD(resByArg);
KEYWORD(byArg);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 60b7824342aa38..03a266931632cf 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -10047,6 +10047,9 @@ bool LLParser::parseWpdRes(WholeProgramDevirtResolution &WPDRes) {
case lltok::kw_branchFunnel:
WPDRes.TheKind = WholeProgramDevirtResolution::BranchFunnel;
break;
+ case lltok::kw_speculative:
+ WPDRes.TheKind = WholeProgramDevirtResolution::Speculative;
+ break;
default:
return error(Lex.getLoc(), "unexpected WholeProgramDevirtResolution kind");
}
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 1cbcfb195764b3..a30ff85e33160b 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -3402,6 +3402,8 @@ getWholeProgDevirtResKindName(WholeProgramDevirtResolution::Kind K) {
return "singleImpl";
case WholeProgramDevirtResolution::BranchFunnel:
return "branchFunnel";
+ case WholeProgramDevirtResolution::Speculative:
+ return "speculative";
}
llvm_unreachable("invalid WholeProgramDevirtResolution kind");
}
@@ -3496,7 +3498,8 @@ void AssemblyWriter::printWPDRes(const WholeProgramDevirtResolution &WPDRes) {
Out << "wpdRes: (kind: ";
Out << getWholeProgDevirtResKindName(WPDRes.TheKind);
- if (WPDRes.TheKind == WholeProgramDevirtResolution::SingleImpl)
+ if (WPDRes.TheKind == WholeProgramDevirtResolution::SingleImpl ||
+ WPDRes.TheKind == WholeProgramDevirtResolution::Speculative)
Out << ", singleImplName: \"" << WPDRes.SingleImplName << "\"";
if (!WPDRes.ResByArg.empty()) {
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 125c8e442f27b6..b4ce758e314e94 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -1620,8 +1620,7 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
MPM.addPass(AssignGUIDPass());
MPM.addPass(WholeProgramDevirtPass(
/*ExportSummary*/ nullptr,
- /*ImportSummary*/ nullptr,
- /*DevirtSpeculatively*/ PTO.DevirtualizeSpeculatively));
+ /*ImportSummary*/ nullptr));
MPM.addPass(DropTypeTestsPass());
// Given that the devirtualization creates more opportunities for inlining,
// we run the Inliner again here to maximize the optimization gain we
diff --git a/llvm/lib/Passes/PassesOptions.td b/llvm/lib/Passes/PassesOptions.td
index 4398d5c06bff2b..d37930c7ca39d8 100644
--- a/llvm/lib/Passes/PassesOptions.td
+++ b/llvm/lib/Passes/PassesOptions.td
@@ -38,7 +38,7 @@ defm : BoolField<"enable-constraint-elimination", "true",
// TODO: There is a similar flag in WPD pass, we should consolidate them by
// parsing the option only once in PassBuilder and share it across both places.
defm : BoolField<"enable-devirtualize-speculatively", "false",
- "Enable speculative devirtualization optimization">;
+ "Enable speculative devirtualization without LTO">;
defm : BoolField<"enable-dfa-jump-thread", "true",
"Enable DFA jump threading">;
defm : BoolField<"enable-global-analyses", "true",
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index 88c57d2195bbda..ba0718882d77e0 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -160,8 +160,6 @@ static cl::opt<std::string> ClWriteSummary(
"bitcode, otherwise YAML"),
cl::Hidden);
-// TODO: This option eventually should support any public visibility vtables
-// with/out LTO.
static cl::opt<bool> ClDevirtualizeSpeculatively(
"devirtualize-speculatively",
cl::desc("Enable speculative devirtualization optimization"),
@@ -611,11 +609,9 @@ struct DevirtModule {
std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
PatternList FunctionsToSkip;
- const bool DevirtSpeculatively;
DevirtModule(Module &M, ModuleAnalysisManager &MAM,
ModuleSummaryIndex *ExportSummary,
- const ModuleSummaryIndex *ImportSummary,
- bool DevirtSpeculatively)
+ const ModuleSummaryIndex *ImportSummary)
: M(M), MAM(MAM),
FAM(MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager()),
ExportSummary(ExportSummary), ImportSummary(ImportSummary),
@@ -628,8 +624,7 @@ struct DevirtModule {
RemarksEnabled(areRemarksEnabled()),
OREGetter([&](Function &F) -> OptimizationRemarkEmitter & {
return FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
- }),
- DevirtSpeculatively(DevirtSpeculatively) {
+ }) {
assert(!(ExportSummary && ImportSummary));
FunctionsToSkip.init(SkipFunctionNames);
}
@@ -645,18 +640,18 @@ struct DevirtModule {
std::vector<VTableBits> &Bits,
DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
- bool
- tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
- const std::set<TypeMemberInfo> &TypeMemberInfos,
- uint64_t ByteOffset,
- ModuleSummaryIndex *ExportSummary);
+ bool tryFindVirtualCallTargets(
+ std::vector<VirtualCallTarget> &TargetsForSlot,
+ const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
+ ModuleSummaryIndex *ExportSummary, bool &HasPublicTarget);
void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
- bool &IsExported);
+ bool HasPublicTarget, bool &IsExported);
bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
MutableArrayRef<VirtualCallTarget> TargetsForSlot,
VTableSlotInfo &SlotInfo,
- WholeProgramDevirtResolution *Res);
+ WholeProgramDevirtResolution *Res,
+ bool HasPublicTarget);
void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
bool &IsExported);
@@ -743,8 +738,7 @@ struct DevirtModule {
// Lower the module using the action and summary passed as command line
// arguments. For testing purposes only.
- static bool runForTesting(Module &M, ModuleAnalysisManager &MAM,
- bool DevirtSpeculatively);
+ static bool runForTesting(Module &M, ModuleAnalysisManager &MAM);
};
struct DevirtIndex {
@@ -779,13 +773,14 @@ struct DevirtIndex {
bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
const TypeIdCompatibleVtableInfo TIdInfo,
- uint64_t ByteOffset);
+ uint64_t ByteOffset, bool &HasPublicTarget);
bool trySingleImplDevirt(MutableArrayRef<ValueInfo> TargetsForSlot,
VTableSlotSummary &SlotSummary,
VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res,
- std::set<ValueInfo> &DevirtTargets);
+ std::set<ValueInfo> &DevirtTargets,
+ bool HasPublicTarget);
void run();
};
@@ -794,22 +789,17 @@ struct DevirtIndex {
PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
ModuleAnalysisManager &MAM) {
if (UseCommandLine) {
- if (!DevirtModule::runForTesting(M, MAM, ClDevirtualizeSpeculatively))
+ if (!DevirtModule::runForTesting(M, MAM))
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
std::optional<ModuleSummaryIndex> Index;
- if (!ExportSummary && !ImportSummary && DevirtSpeculatively) {
- // Build the ExportSummary from the module.
- assert(!ExportSummary &&
- "ExportSummary is expected to be empty in non-LTO mode");
+ if (!ExportSummary && !ImportSummary && ClDevirtualizeSpeculatively) {
ProfileSummaryInfo PSI(M);
- Index.emplace(buildModuleSummaryIndex(M, nullptr, &PSI));
- ExportSummary = Index.has_value() ? &Index.value() : nullptr;
+ ExportSummary = &Index.emplace(buildModuleSummaryIndex(M, nullptr, &PSI));
}
- if (!DevirtModule(M, MAM, ExportSummary, ImportSummary, DevirtSpeculatively)
- .run())
+ if (!DevirtModule(M, MAM, ExportSummary, ImportSummary).run())
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
@@ -907,9 +897,7 @@ void llvm::updatePublicTypeTestCalls(Module &M,
CI->replaceAllUsesWith(NewCI);
CI->eraseFromParent();
}
- } else {
- // TODO: Don't replace public type tests when speculative devirtualization
- // gets enabled in LTO mode.
+ } else if (!ClDevirtualizeSpeculatively) {
auto *True = ConstantInt::getTrue(M.getContext());
for (Use &U : make_early_inc_range(PublicTypeTestFunc->uses())) {
auto *CI = cast<CallInst>(U.getUser());
@@ -1014,8 +1002,7 @@ static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary) {
return ErrorSuccess();
}
-bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM,
- bool DevirtSpeculatively) {
+bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM) {
std::unique_ptr<ModuleSummaryIndex> Summary =
std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false);
@@ -1044,8 +1031,7 @@ bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM,
ClSummaryAction == PassSummaryAction::Export ? Summary.get()
: nullptr,
ClSummaryAction == PassSummaryAction::Import ? Summary.get()
- : nullptr,
- DevirtSpeculatively)
+ : nullptr)
.run();
if (!ClWriteSummary.empty()) {
@@ -1104,16 +1090,19 @@ void DevirtModule::buildTypeIdentifierMap(
bool DevirtModule::tryFindVirtualCallTargets(
std::vector<VirtualCallTarget> &TargetsForSlot,
const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
- ModuleSummaryIndex *ExportSummary) {
+ ModuleSummaryIndex *ExportSummary, bool &HasPublicTarget) {
+ HasPublicTarget = false;
+
for (const TypeMemberInfo &TM : TypeMemberInfos) {
if (!TM.Bits->GV->isConstant())
return false;
- // Without DevirtSpeculatively, we cannot perform whole program
- // devirtualization analysis on a vtable with public LTO visibility.
- if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
- GlobalObject::VCallVisibilityPublic)
- return false;
+ if (TM.Bits->GV->getVCallVisibility() ==
+ GlobalObject::VCallVisibilityPublic) {
+ HasPublicTarget = true;
+ if (!ClDevirtualizeSpeculatively)
+ return false;
+ }
Function *Fn = nullptr;
Constant *C = nullptr;
@@ -1131,12 +1120,6 @@ bool DevirtModule::tryFindVirtualCallTargets(
if (Fn->getName() == "__cxa_pure_virtual")
continue;
- // In most cases empty functions will be overridden by the
- // implementation of the derived class, so we can skip them.
- if (DevirtSpeculatively && Fn->getReturnType()->isVoidTy() &&
- Fn->getInstructionCount() <= 1)
- continue;
-
// We can disregard unreachable functions as possible call targets, as
// unreachable functions shouldn't be called.
if (mustBeUnreachableFunction(Fn, ExportSummary))
@@ -1158,7 +1141,10 @@ bool DevirtModule::tryFindVirtualCallTargets(
bool DevirtIndex::tryFindVirtualCallTargets(
std::vector<ValueInfo> &TargetsForSlot,
- const TypeIdCompatibleVtableInfo TIdInfo, uint64_t ByteOffset) {
+ const TypeIdCompatibleVtableInfo TIdInfo, uint64_t ByteOffset,
+ bool &HasPublicTarget) {
+ HasPublicTarget = false;
+
for (const TypeIdOffsetVtableInfo &P : TIdInfo) {
// Find a representative copy of the vtable initializer.
// We can have multiple available_externally, linkonce_odr and weak_odr
@@ -1187,8 +1173,11 @@ bool DevirtIndex::tryFindVirtualCallTargets(
VS = CurVS;
// We cannot perform whole program devirtualization analysis on a vtable
// with public LTO visibility.
- if (VS->getVCallVisibility() == GlobalObject::VCallVisibilityPublic)
- return false;
+ if (VS->getVCallVisibility() == GlobalObject::VCallVisibilityPublic) {
+ HasPublicTarget = true;
+ if (!ClDevirtualizeSpeculatively)
+ return false;
+ }
break;
}
}
@@ -1214,7 +1203,8 @@ bool DevirtIndex::tryFindVirtualCallTargets(
}
void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
- Constant *TheFn, bool &IsExported) {
+ Constant *TheFn, bool HasPublicTarget,
+ bool &IsExported) {
// Don't devirtualize function if we're told to skip it
// in -wholeprogramdevirt-skip.
if (FunctionsToSkip.match(TheFn->stripPointerCasts()->getName()))
@@ -1257,7 +1247,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
// add support to compare the virtual function pointer to the
// devirtualized target. In case of a mismatch, fall back to indirect
// call.
- if (DevirtCheckMode == WPDCheckMode::Fallback || DevirtSpeculatively) {
+ if (DevirtCheckMode == WPDCheckMode::Fallback || HasPublicTarget) {
MDNode *Weights = MDBuilder(M.getContext()).createLikelyBranchWeights();
// Version the indirect call site. If the called value is equal to the
// given callee, 'NewInst' will be executed, otherwise the original call
@@ -1278,6 +1268,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
// In either trapping or non-checking mode, devirtualize original call.
else {
// Devirtualize unconditionally.
+ assert(!HasPublicTarget);
CB.setCalledOperand(Callee);
// Since the call site is now direct, we must clear metadata that
// is only appropriate for indirect calls. This includes !prof and
@@ -1295,7 +1286,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
}
// This use is no longer unsafe.
- if (VCallSite.NumUnsafeUses)
+ if (!HasPublicTarget && VCallSite.NumUnsafeUses)
--*VCallSite.NumUnsafeUses;
}
if (CSInfo.isExported())
@@ -1338,7 +1329,7 @@ static bool addCalls(VTable...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/233380
More information about the cfe-commits
mailing list