Skip to content

Enable WPD without lto #141777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
83 changes: 50 additions & 33 deletions llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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())
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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())
Expand Down
Loading