[clang] [llvm] Enable WPD without lto (PR #141777)
Hassnaa Hamdi via cfe-commits
cfe-commits at lists.llvm.org
Wed May 28 07:34:37 PDT 2025
https://github.com/hassnaaHamdi created https://github.com/llvm/llvm-project/pull/141777
None
>From 702f64a84914d2fe467a12babd99338f2215d425 Mon Sep 17 00:00:00 2001
From: Hassnaa Hamdi <hassnaa.hamdi at arm.com>
Date: Wed, 28 May 2025 14:27:34 +0000
Subject: [PATCH] Enable WPD without lto
---
clang/lib/CodeGen/CGVTables.cpp | 3 +-
clang/lib/Driver/ToolChains/Clang.cpp | 8 +-
llvm/lib/Passes/PassBuilderPipelines.cpp | 3 +
.../lib/Transforms/IPO/WholeProgramDevirt.cpp | 83 +++++++++++--------
4 files changed, 61 insertions(+), 36 deletions(-)
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index c7447273a42fa..48036df7b7b6f 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -1359,7 +1359,8 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
// Emit type metadata on vtables with LTO or IR instrumentation.
// In IR instrumentation, the type metadata is used to find out vtable
// definitions (for type profiling) among all global variables.
- if (!getCodeGenOpts().LTOUnit && !getCodeGenOpts().hasProfileIRInstr())
+ if (!getCodeGenOpts().LTOUnit && !getCodeGenOpts().hasProfileIRInstr() &&
+ !getCodeGenOpts().WholeProgramVTables)
return;
CharUnits ComponentWidth = GetTargetTypeStoreSize(getVTableComponentType());
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 13842b8cc2870..bdb7fc9b778d6 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7970,8 +7970,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
IsDeviceOffloadAction ? D.getLTOMode() : D.getOffloadLTOMode();
auto OtherIsUsingLTO = OtherLTOMode != LTOK_None;
- if ((!IsUsingLTO && !OtherIsUsingLTO) ||
- (IsPS4 && !UnifiedLTO && (D.getLTOMode() != LTOK_Full)))
+ if (!IsUsingLTO && !OtherIsUsingLTO && !UnifiedLTO) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ if (!A->getOption().matches(options::OPT_O0))
+ CmdArgs.push_back("-fwhole-program-vtables");
+ } else if ((!IsUsingLTO && !OtherIsUsingLTO) ||
+ (IsPS4 && !UnifiedLTO && (D.getLTOMode() != LTOK_Full)))
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-fwhole-program-vtables"
<< ((IsPS4 && !UnifiedLTO) ? "-flto=full" : "-flto");
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index f3654600c5abb..0d021cb7c47c3 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -1295,6 +1295,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
MPM.addPass(GlobalOptPass());
MPM.addPass(GlobalDCEPass());
+ if (Phase == ThinOrFullLTOPhase::None && Level != OptimizationLevel::O0)
+ MPM.addPass(WholeProgramDevirtPass(nullptr, nullptr));
+
return MPM;
}
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index 3a25255d0a4c8..44c2b58f3b735 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -60,7 +60,9 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/ModuleSummaryAnalysis.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TypeMetadataUtils.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Bitcode/BitcodeWriter.h"
@@ -209,7 +211,8 @@ static cl::opt<WPDCheckMode> DevirtCheckMode(
cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"),
clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"),
clEnumValN(WPDCheckMode::Fallback, "fallback",
- "Fallback to indirect when incorrect")));
+ "Fallback to indirect when incorrect")),
+ cl::init(WPDCheckMode::Fallback));
namespace {
struct PatternList {
@@ -804,6 +807,12 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
+ if (!ExportSummary) {
+ ProfileSummaryInfo PSI(M);
+ std::optional<ModuleSummaryIndex> Index;
+ Index.emplace(buildModuleSummaryIndex(M, nullptr, &PSI));
+ ExportSummary = Index.has_value() ? &Index.value() : nullptr;
+ }
if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
ImportSummary)
.run())
@@ -814,8 +823,10 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
// Enable whole program visibility if enabled by client (e.g. linker) or
// internal option, and not force disabled.
bool llvm::hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO) {
- return (WholeProgramVisibilityEnabledInLTO || WholeProgramVisibility) &&
- !DisableWholeProgramVisibility;
+ if (WholeProgramVisibilityEnabledInLTO)
+ return (WholeProgramVisibilityEnabledInLTO || WholeProgramVisibility) &&
+ !DisableWholeProgramVisibility;
+ return true;
}
static bool
@@ -1099,9 +1110,9 @@ bool DevirtModule::tryFindVirtualCallTargets(
// We cannot perform whole program devirtualization analysis on a vtable
// with public LTO visibility.
- if (TM.Bits->GV->getVCallVisibility() ==
- GlobalObject::VCallVisibilityPublic)
- return false;
+ // if (TM.Bits->GV->getVCallVisibility() ==
+ // GlobalObject::VCallVisibilityPublic)
+ // return false;
Function *Fn = nullptr;
Constant *C = nullptr;
@@ -1342,26 +1353,28 @@ bool DevirtModule::trySingleImplDevirt(
// If the only implementation has local linkage, we must promote to external
// to make it visible to thin LTO objects. We can only get here during the
// ThinLTO export phase.
- if (TheFn->hasLocalLinkage()) {
- std::string NewName = (TheFn->getName() + ".llvm.merged").str();
-
- // Since we are renaming the function, any comdats with the same name must
- // also be renamed. This is required when targeting COFF, as the comdat name
- // must match one of the names of the symbols in the comdat.
- if (Comdat *C = TheFn->getComdat()) {
- if (C->getName() == TheFn->getName()) {
- Comdat *NewC = M.getOrInsertComdat(NewName);
- NewC->setSelectionKind(C->getSelectionKind());
- for (GlobalObject &GO : M.global_objects())
- if (GO.getComdat() == C)
- GO.setComdat(NewC);
- }
- }
-
- TheFn->setLinkage(GlobalValue::ExternalLinkage);
- TheFn->setVisibility(GlobalValue::HiddenVisibility);
- TheFn->setName(NewName);
- }
+ // if (TheFn->hasLocalLinkage()) {
+ // std::string NewName = (TheFn->getName() + ".llvm.merged").str();
+
+ // // Since we are renaming the function, any comdats with the same name
+ // must
+ // // also be renamed. This is required when targeting COFF, as the comdat
+ // name
+ // // must match one of the names of the symbols in the comdat.
+ // if (Comdat *C = TheFn->getComdat()) {
+ // if (C->getName() == TheFn->getName()) {
+ // Comdat *NewC = M.getOrInsertComdat(NewName);
+ // NewC->setSelectionKind(C->getSelectionKind());
+ // for (GlobalObject &GO : M.global_objects())
+ // if (GO.getComdat() == C)
+ // GO.setComdat(NewC);
+ // }
+ // }
+
+ // TheFn->setLinkage(GlobalValue::ExternalLinkage);
+ // TheFn->setVisibility(GlobalValue::HiddenVisibility);
+ // TheFn->setName(NewName);
+ // }
if (ValueInfo TheFnVI = ExportSummary->getValueInfo(TheFn->getGUID()))
// Any needed promotion of 'TheFn' has already been done during
// LTO unit split, so we can ignore return value of AddCalls.
@@ -2321,6 +2334,9 @@ bool DevirtModule::run() {
Function *TypeTestFunc =
Intrinsic::getDeclarationIfExists(&M, Intrinsic::type_test);
+ if (!TypeTestFunc)
+ TypeTestFunc =
+ Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test);
Function *TypeCheckedLoadFunc =
Intrinsic::getDeclarationIfExists(&M, Intrinsic::type_checked_load);
Function *TypeCheckedLoadRelativeFunc = Intrinsic::getDeclarationIfExists(
@@ -2443,13 +2459,14 @@ bool DevirtModule::run() {
.WPDRes[S.first.ByteOffset];
if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
S.first.ByteOffset, ExportSummary)) {
-
- if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res)) {
- DidVirtualConstProp |=
- tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
-
- tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
- }
+ trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
+ // Following features are not needed for the case of enabling WPD without
+ // lto. if (!trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second,
+ // Res)) { DidVirtualConstProp |=
+ // tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
+
+ // tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
+ // }
// Collect functions devirtualized at least for one call site for stats.
if (RemarksEnabled || AreStatisticsEnabled())
More information about the cfe-commits
mailing list