summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/IPO
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/IPO')
-rw-r--r--llvm/lib/Transforms/IPO/FunctionImport.cpp195
-rw-r--r--llvm/lib/Transforms/IPO/FunctionSpecialization.cpp50
-rw-r--r--llvm/lib/Transforms/IPO/GlobalOpt.cpp3
-rw-r--r--llvm/lib/Transforms/IPO/IROutliner.cpp3
-rw-r--r--llvm/lib/Transforms/IPO/LowerTypeTests.cpp13
-rw-r--r--llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/SCCP.cpp16
-rw-r--r--llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp28
-rw-r--r--llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp190
9 files changed, 292 insertions, 208 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp
index 7bcb20de46ff..83aa7de5400f 100644
--- a/llvm/lib/Transforms/IPO/FunctionImport.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp
@@ -40,6 +40,7 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/Utils/Cloning.h"
@@ -1550,6 +1551,7 @@ void llvm::computeDeadSymbolsWithConstProp(
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing,
bool ImportEnabled) {
+ llvm::TimeTraceScope timeScope("Drop dead symbols and propagate attributes");
computeDeadSymbolsAndUpdateIndirectCalls(Index, GUIDPreservedSymbols,
isPrevailing);
if (ImportEnabled)
@@ -1664,6 +1666,7 @@ bool llvm::convertToDeclaration(GlobalValue &GV) {
void llvm::thinLTOFinalizeInModule(Module &TheModule,
const GVSummaryMapTy &DefinedGlobals,
bool PropagateAttrs) {
+ llvm::TimeTraceScope timeScope("ThinLTO finalize in module");
DenseSet<Comdat *> NonPrevailingComdats;
auto FinalizeInModule = [&](GlobalValue &GV, bool Propagate = false) {
// See if the global summary analysis computed a new resolved linkage.
@@ -1791,6 +1794,7 @@ void llvm::thinLTOFinalizeInModule(Module &TheModule,
/// Run internalization on \p TheModule based on symmary analysis.
void llvm::thinLTOInternalizeModule(Module &TheModule,
const GVSummaryMapTy &DefinedGlobals) {
+ llvm::TimeTraceScope timeScope("ThinLTO internalize module");
// Declare a callback for the internalize pass that will ask for every
// candidate GlobalValue if it can be internalized or not.
auto MustPreserveGV = [&](const GlobalValue &GV) -> bool {
@@ -1885,6 +1889,7 @@ Expected<bool> FunctionImporter::importFunctions(
// Do the actual import of functions now, one Module at a time
for (const auto &ModName : ImportList.getSourceModules()) {
+ llvm::TimeTraceScope timeScope("Import", ModName);
// Get the module for the import
Expected<std::unique_ptr<Module>> SrcModuleOrErr = ModuleLoader(ModName);
if (!SrcModuleOrErr)
@@ -1900,102 +1905,114 @@ Expected<bool> FunctionImporter::importFunctions(
// Find the globals to import
SetVector<GlobalValue *> GlobalsToImport;
- for (Function &F : *SrcModule) {
- if (!F.hasName())
- continue;
- auto GUID = F.getGUID();
- auto MaybeImportType = ImportList.getImportType(ModName, GUID);
- bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition;
-
- LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
- << " importing function"
- << (ImportDefinition
- ? " definition "
- : (MaybeImportType ? " declaration " : " "))
- << GUID << " " << F.getName() << " from "
- << SrcModule->getSourceFileName() << "\n");
- if (ImportDefinition) {
- if (Error Err = F.materialize())
- return std::move(Err);
- // MemProf should match function's definition and summary,
- // 'thinlto_src_module' is needed.
- if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
- // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
- // statistics and debugging.
- F.setMetadata(
- "thinlto_src_module",
- MDNode::get(DestModule.getContext(),
- {MDString::get(DestModule.getContext(),
- SrcModule->getModuleIdentifier())}));
- F.setMetadata(
- "thinlto_src_file",
- MDNode::get(DestModule.getContext(),
- {MDString::get(DestModule.getContext(),
- SrcModule->getSourceFileName())}));
+ {
+ llvm::TimeTraceScope functionsScope("Functions");
+ for (Function &F : *SrcModule) {
+ if (!F.hasName())
+ continue;
+ auto GUID = F.getGUID();
+ auto MaybeImportType = ImportList.getImportType(ModName, GUID);
+ bool ImportDefinition =
+ MaybeImportType == GlobalValueSummary::Definition;
+
+ LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
+ << " importing function"
+ << (ImportDefinition
+ ? " definition "
+ : (MaybeImportType ? " declaration " : " "))
+ << GUID << " " << F.getName() << " from "
+ << SrcModule->getSourceFileName() << "\n");
+ if (ImportDefinition) {
+ if (Error Err = F.materialize())
+ return std::move(Err);
+ // MemProf should match function's definition and summary,
+ // 'thinlto_src_module' is needed.
+ if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
+ // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
+ // statistics and debugging.
+ F.setMetadata(
+ "thinlto_src_module",
+ MDNode::get(DestModule.getContext(),
+ {MDString::get(DestModule.getContext(),
+ SrcModule->getModuleIdentifier())}));
+ F.setMetadata(
+ "thinlto_src_file",
+ MDNode::get(DestModule.getContext(),
+ {MDString::get(DestModule.getContext(),
+ SrcModule->getSourceFileName())}));
+ }
+ GlobalsToImport.insert(&F);
}
- GlobalsToImport.insert(&F);
}
}
- for (GlobalVariable &GV : SrcModule->globals()) {
- if (!GV.hasName())
- continue;
- auto GUID = GV.getGUID();
- auto MaybeImportType = ImportList.getImportType(ModName, GUID);
- bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition;
-
- LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
- << " importing global"
- << (ImportDefinition
- ? " definition "
- : (MaybeImportType ? " declaration " : " "))
- << GUID << " " << GV.getName() << " from "
- << SrcModule->getSourceFileName() << "\n");
- if (ImportDefinition) {
- if (Error Err = GV.materialize())
- return std::move(Err);
- ImportedGVCount += GlobalsToImport.insert(&GV);
+ {
+ llvm::TimeTraceScope globalsScope("Globals");
+ for (GlobalVariable &GV : SrcModule->globals()) {
+ if (!GV.hasName())
+ continue;
+ auto GUID = GV.getGUID();
+ auto MaybeImportType = ImportList.getImportType(ModName, GUID);
+ bool ImportDefinition =
+ MaybeImportType == GlobalValueSummary::Definition;
+
+ LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
+ << " importing global"
+ << (ImportDefinition
+ ? " definition "
+ : (MaybeImportType ? " declaration " : " "))
+ << GUID << " " << GV.getName() << " from "
+ << SrcModule->getSourceFileName() << "\n");
+ if (ImportDefinition) {
+ if (Error Err = GV.materialize())
+ return std::move(Err);
+ ImportedGVCount += GlobalsToImport.insert(&GV);
+ }
}
}
- for (GlobalAlias &GA : SrcModule->aliases()) {
- if (!GA.hasName() || isa<GlobalIFunc>(GA.getAliaseeObject()))
- continue;
- auto GUID = GA.getGUID();
- auto MaybeImportType = ImportList.getImportType(ModName, GUID);
- bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition;
-
- LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
- << " importing alias"
- << (ImportDefinition
- ? " definition "
- : (MaybeImportType ? " declaration " : " "))
- << GUID << " " << GA.getName() << " from "
- << SrcModule->getSourceFileName() << "\n");
- if (ImportDefinition) {
- if (Error Err = GA.materialize())
- return std::move(Err);
- // Import alias as a copy of its aliasee.
- GlobalObject *GO = GA.getAliaseeObject();
- if (Error Err = GO->materialize())
- return std::move(Err);
- auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA);
- LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << GO->getGUID() << " "
- << GO->getName() << " from "
+ {
+ llvm::TimeTraceScope aliasesScope("Aliases");
+ for (GlobalAlias &GA : SrcModule->aliases()) {
+ if (!GA.hasName() || isa<GlobalIFunc>(GA.getAliaseeObject()))
+ continue;
+ auto GUID = GA.getGUID();
+ auto MaybeImportType = ImportList.getImportType(ModName, GUID);
+ bool ImportDefinition =
+ MaybeImportType == GlobalValueSummary::Definition;
+
+ LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
+ << " importing alias"
+ << (ImportDefinition
+ ? " definition "
+ : (MaybeImportType ? " declaration " : " "))
+ << GUID << " " << GA.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
- if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
- // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
- // statistics and debugging.
- Fn->setMetadata(
- "thinlto_src_module",
- MDNode::get(DestModule.getContext(),
- {MDString::get(DestModule.getContext(),
- SrcModule->getModuleIdentifier())}));
- Fn->setMetadata(
- "thinlto_src_file",
- MDNode::get(DestModule.getContext(),
- {MDString::get(DestModule.getContext(),
- SrcModule->getSourceFileName())}));
+ if (ImportDefinition) {
+ if (Error Err = GA.materialize())
+ return std::move(Err);
+ // Import alias as a copy of its aliasee.
+ GlobalObject *GO = GA.getAliaseeObject();
+ if (Error Err = GO->materialize())
+ return std::move(Err);
+ auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA);
+ LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << GO->getGUID()
+ << " " << GO->getName() << " from "
+ << SrcModule->getSourceFileName() << "\n");
+ if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
+ // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
+ // statistics and debugging.
+ Fn->setMetadata(
+ "thinlto_src_module",
+ MDNode::get(DestModule.getContext(),
+ {MDString::get(DestModule.getContext(),
+ SrcModule->getModuleIdentifier())}));
+ Fn->setMetadata(
+ "thinlto_src_file",
+ MDNode::get(DestModule.getContext(),
+ {MDString::get(DestModule.getContext(),
+ SrcModule->getSourceFileName())}));
+ }
+ GlobalsToImport.insert(Fn);
}
- GlobalsToImport.insert(Fn);
}
}
diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
index 9196a0147c43..30459caee160 100644
--- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp
@@ -89,6 +89,8 @@ static cl::opt<bool> SpecializeLiteralConstant(
"Enable specialization of functions that take a literal constant as an "
"argument"));
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
+
bool InstCostVisitor::canEliminateSuccessor(BasicBlock *BB,
BasicBlock *Succ) const {
unsigned I = 0;
@@ -784,9 +786,31 @@ bool FunctionSpecializer::run() {
// Update the known call sites to call the clone.
for (CallBase *Call : S.CallSites) {
+ Function *Clone = S.Clone;
LLVM_DEBUG(dbgs() << "FnSpecialization: Redirecting " << *Call
- << " to call " << S.Clone->getName() << "\n");
+ << " to call " << Clone->getName() << "\n");
Call->setCalledFunction(S.Clone);
+ auto &BFI = GetBFI(*Call->getFunction());
+ std::optional<uint64_t> Count =
+ BFI.getBlockProfileCount(Call->getParent());
+ if (Count && !ProfcheckDisableMetadataFixes) {
+ std::optional<llvm::Function::ProfileCount> MaybeCloneCount =
+ Clone->getEntryCount();
+ assert(MaybeCloneCount && "Clone entry count was not set!");
+ uint64_t CallCount = *Count + MaybeCloneCount->getCount();
+ Clone->setEntryCount(CallCount);
+ if (std::optional<llvm::Function::ProfileCount> MaybeOriginalCount =
+ S.F->getEntryCount()) {
+ uint64_t OriginalCount = MaybeOriginalCount->getCount();
+ if (OriginalCount >= CallCount) {
+ S.F->setEntryCount(OriginalCount - CallCount);
+ } else {
+ // This should generally not happen as that would mean there are
+ // more computed calls to the function than what was recorded.
+ LLVM_DEBUG(S.F->setEntryCount(0));
+ }
+ }
+ }
}
Clones.push_back(S.Clone);
@@ -838,14 +862,24 @@ bool FunctionSpecializer::run() {
}
void FunctionSpecializer::removeDeadFunctions() {
- for (Function *F : FullySpecialized) {
+ for (Function *F : DeadFunctions) {
LLVM_DEBUG(dbgs() << "FnSpecialization: Removing dead function "
<< F->getName() << "\n");
if (FAM)
FAM->clear(*F, F->getName());
+
+ // Remove all the callsites that were proven unreachable once, and replace
+ // them with poison.
+ for (User *U : make_early_inc_range(F->users())) {
+ assert((isa<CallInst>(U) || isa<InvokeInst>(U)) &&
+ "User of dead function must be call or invoke");
+ Instruction *CS = cast<Instruction>(U);
+ CS->replaceAllUsesWith(PoisonValue::get(CS->getType()));
+ CS->eraseFromParent();
+ }
F->eraseFromParent();
}
- FullySpecialized.clear();
+ DeadFunctions.clear();
}
/// Clone the function \p F and remove the ssa_copy intrinsics added by
@@ -1033,6 +1067,9 @@ Function *FunctionSpecializer::createSpecialization(Function *F,
// clone must.
Clone->setLinkage(GlobalValue::InternalLinkage);
+ if (F->getEntryCount() && !ProfcheckDisableMetadataFixes)
+ Clone->setEntryCount(0);
+
// Initialize the lattice state of the arguments of the function clone,
// marking the argument on which we specialized the function constant
// with the given value.
@@ -1206,8 +1243,11 @@ void FunctionSpecializer::updateCallSites(Function *F, const Spec *Begin,
// If the function has been completely specialized, the original function
// is no longer needed. Mark it unreachable.
- if (NCallsLeft == 0 && Solver.isArgumentTrackedFunction(F)) {
+ // NOTE: If the address of a function is taken, we cannot treat it as dead
+ // function.
+ if (NCallsLeft == 0 && Solver.isArgumentTrackedFunction(F) &&
+ !F->hasAddressTaken()) {
Solver.markFunctionUnreachable(F);
- FullySpecialized.insert(F);
+ DeadFunctions.insert(F);
}
}
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index d7edd1288309..f88d51f443bc 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -2551,7 +2551,8 @@ static bool OptimizeNonTrivialIFuncs(
}))
continue;
- assert(!Callees.empty() && "Expecting successful collection of versions");
+ if (Callees.empty())
+ continue;
LLVM_DEBUG(dbgs() << "Statically resolving calls to function "
<< Resolver->getName() << "\n");
diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp
index c57981ae4ca0..fdf0c3ac8007 100644
--- a/llvm/lib/Transforms/IPO/IROutliner.cpp
+++ b/llvm/lib/Transforms/IPO/IROutliner.cpp
@@ -686,9 +686,6 @@ Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group,
/* Outlined code is optimized code by definition. */
DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);
- // Don't add any new variables to the subprogram.
- DB.finalizeSubprogram(OutlinedSP);
-
// Attach subprogram to the function.
F->setSubprogram(OutlinedSP);
// We're done with the DIBuilder.
diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
index 57844a10aa9c..821a9d82ddb0 100644
--- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
+++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
@@ -504,10 +504,7 @@ class LowerTypeTestsModule {
void importTypeTest(CallInst *CI);
void importFunction(Function *F, bool isJumpTableCanonical);
- BitSetInfo
- buildBitSet(Metadata *TypeId,
- const DenseMap<GlobalTypeMember *, uint64_t> &GlobalLayout);
- ByteArrayInfo *createByteArray(BitSetInfo &BSI);
+ ByteArrayInfo *createByteArray(const BitSetInfo &BSI);
void allocateByteArrays();
Value *createBitSetTest(IRBuilder<> &B, const TypeIdLowering &TIL,
Value *BitOffset);
@@ -578,9 +575,9 @@ public:
/// Build a bit set for TypeId using the object layouts in
/// GlobalLayout.
-BitSetInfo LowerTypeTestsModule::buildBitSet(
- Metadata *TypeId,
- const DenseMap<GlobalTypeMember *, uint64_t> &GlobalLayout) {
+static BitSetInfo
+buildBitSet(Metadata *TypeId,
+ const DenseMap<GlobalTypeMember *, uint64_t> &GlobalLayout) {
BitSetBuilder BSB;
// Compute the byte offset of each address associated with this type
@@ -615,7 +612,7 @@ static Value *createMaskedBitTest(IRBuilder<> &B, Value *Bits,
return B.CreateICmpNE(MaskedBits, ConstantInt::get(BitsType, 0));
}
-ByteArrayInfo *LowerTypeTestsModule::createByteArray(BitSetInfo &BSI) {
+ByteArrayInfo *LowerTypeTestsModule::createByteArray(const BitSetInfo &BSI) {
// Create globals to stand in for byte arrays and masks. These never actually
// get initialized, we RAUW and erase them later in allocateByteArrays() once
// we know the offset and mask to use.
diff --git a/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp b/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp
index b8c99f1f3389..7f9693169af0 100644
--- a/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp
+++ b/llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp
@@ -3965,6 +3965,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
void ModuleCallsiteContextGraph::updateAllocationCall(
CallInfo &Call, AllocationType AllocType) {
std::string AllocTypeString = getAllocTypeAttributeString(AllocType);
+ removeAnyExistingAmbiguousAttribute(cast<CallBase>(Call.call()));
auto A = llvm::Attribute::get(Call.call()->getFunction()->getContext(),
"memprof", AllocTypeString);
cast<CallBase>(Call.call())->addFnAttr(A);
@@ -5501,6 +5502,7 @@ bool MemProfContextDisambiguation::applyImport(Module &M) {
// clone J-1 (J==0 is the original clone and does not have a VMaps
// entry).
CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
+ removeAnyExistingAmbiguousAttribute(CBClone);
CBClone->addFnAttr(A);
ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofAttribute", CBClone)
<< ore::NV("AllocationCall", CBClone) << " in clone "
diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp
index d50de34dfa48..2ecadd529170 100644
--- a/llvm/lib/Transforms/IPO/SCCP.cpp
+++ b/llvm/lib/Transforms/IPO/SCCP.cpp
@@ -169,6 +169,13 @@ static bool runIPSCCP(
for (Function &F : M) {
if (F.isDeclaration())
continue;
+ // Skip the dead functions marked by FunctionSpecializer, avoiding removing
+ // blocks in dead functions. Set MadeChanges if there is any dead function
+ // that will be removed later.
+ if (IsFuncSpecEnabled && Specializer.isDeadFunction(&F)) {
+ MadeChanges = true;
+ continue;
+ }
SmallVector<BasicBlock *, 512> BlocksToErase;
@@ -326,12 +333,15 @@ static bool runIPSCCP(
LLVM_DEBUG(dbgs() << "Found that GV '" << GV->getName()
<< "' is constant!\n");
for (User *U : make_early_inc_range(GV->users())) {
- // We can remove LoadInst here, because we already replaced its users
- // with a constant.
+ // We can remove LoadInst here. The LoadInsts in dead functions marked by
+ // FuncSpec are not simplified to constants, thus poison them.
assert((isa<StoreInst>(U) || isa<LoadInst>(U)) &&
"Only Store|Load Instruction can be user of GlobalVariable at "
"reaching here.");
- cast<Instruction>(U)->eraseFromParent();
+ Instruction *I = cast<Instruction>(U);
+ if (isa<LoadInst>(I))
+ I->replaceAllUsesWith(PoisonValue::get(I->getType()));
+ I->eraseFromParent();
}
// Try to create a debug constant expression for the global variable
diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
index 838f97c8f49a..2340fe556538 100644
--- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
+++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
@@ -269,6 +269,12 @@ static bool enableUnifiedLTO(Module &M) {
}
#endif
+bool mustEmitToMergedModule(const GlobalValue *GV) {
+ // The __cfi_check definition is filled in by the CrossDSOCFI pass which
+ // runs only in the merged module.
+ return GV->getName() == "__cfi_check";
+}
+
// If it's possible to split M into regular and thin LTO parts, do so and write
// a multi-module bitcode file with the two parts to OS. Otherwise, write only a
// regular LTO bitcode file to OS.
@@ -350,19 +356,13 @@ void splitAndWriteThinLTOBitcode(
});
}
- auto MustEmitToMergedModule = [](const GlobalValue *GV) {
- // The __cfi_check definition is filled in by the CrossDSOCFI pass which
- // runs only in the merged module.
- return GV->getName() == "__cfi_check";
- };
-
ValueToValueMapTy VMap;
std::unique_ptr<Module> MergedM(
CloneModule(M, VMap, [&](const GlobalValue *GV) -> bool {
if (const auto *C = GV->getComdat())
if (MergedMComdats.count(C))
return true;
- if (MustEmitToMergedModule(GV))
+ if (mustEmitToMergedModule(GV))
return true;
if (auto *F = dyn_cast<Function>(GV))
return EligibleVirtualFns.count(F);
@@ -380,7 +380,7 @@ void splitAndWriteThinLTOBitcode(
cloneUsedGlobalVariables(M, *MergedM, /*CompilerUsed*/ true);
for (Function &F : *MergedM)
- if (!F.isDeclaration() && !MustEmitToMergedModule(&F)) {
+ if (!F.isDeclaration() && !mustEmitToMergedModule(&F)) {
// Reset the linkage of all functions eligible for virtual constant
// propagation. The canonical definitions live in the thin LTO module so
// that they can be imported.
@@ -406,7 +406,7 @@ void splitAndWriteThinLTOBitcode(
if (const auto *C = GV->getComdat())
if (MergedMComdats.count(C))
return false;
- if (MustEmitToMergedModule(GV))
+ if (mustEmitToMergedModule(GV))
return false;
return true;
});
@@ -529,11 +529,13 @@ bool enableSplitLTOUnit(Module &M) {
return EnableSplitLTOUnit;
}
-// Returns whether this module needs to be split because it uses type metadata.
-bool hasTypeMetadata(Module &M) {
+// Returns whether this module needs to be split (if splitting is enabled).
+bool requiresSplit(Module &M) {
for (auto &GO : M.global_objects()) {
if (GO.hasMetadata(LLVMContext::MD_type))
return true;
+ if (mustEmitToMergedModule(&GO))
+ return true;
}
return false;
}
@@ -543,9 +545,9 @@ bool writeThinLTOBitcode(raw_ostream &OS, raw_ostream *ThinLinkOS,
Module &M, const ModuleSummaryIndex *Index,
const bool ShouldPreserveUseListOrder) {
std::unique_ptr<ModuleSummaryIndex> NewIndex = nullptr;
- // See if this module has any type metadata. If so, we try to split it
+ // See if this module needs to be split. If so, we try to split it
// or at least promote type ids to enable WPD.
- if (hasTypeMetadata(M)) {
+ if (requiresSplit(M)) {
if (enableSplitLTOUnit(M)) {
splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M,
ShouldPreserveUseListOrder);
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index aec484f8a18f..bfb25c806e53 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -60,6 +60,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/TypeMetadataUtils.h"
#include "llvm/Bitcode/BitcodeReader.h"
@@ -68,6 +69,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
@@ -82,12 +84,15 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndexYAML.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/ProfDataUtils.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GlobPattern.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/FunctionAttrs.h"
@@ -95,6 +100,7 @@
#include "llvm/Transforms/Utils/CallPromotionUtils.h"
#include "llvm/Transforms/Utils/Evaluator.h"
#include <algorithm>
+#include <cmath>
#include <cstddef>
#include <map>
#include <set>
@@ -167,6 +173,8 @@ static cl::list<std::string>
cl::desc("Prevent function(s) from being devirtualized"),
cl::Hidden, cl::CommaSeparated);
+extern cl::opt<bool> ProfcheckDisableMetadataFixes;
+
/// With Clang, a pure virtual class's deleting destructor is emitted as a
/// `llvm.trap` intrinsic followed by an unreachable IR instruction. In the
/// context of whole program devirtualization, the deleting destructor of a pure
@@ -451,21 +459,21 @@ struct VirtualCallSite {
void
emitRemark(const StringRef OptName, const StringRef TargetName,
- function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter) {
+ function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter) {
Function *F = CB.getCaller();
DebugLoc DLoc = CB.getDebugLoc();
BasicBlock *Block = CB.getParent();
using namespace ore;
- OREGetter(F).emit(OptimizationRemark(DEBUG_TYPE, OptName, DLoc, Block)
- << NV("Optimization", OptName)
- << ": devirtualized a call to "
- << NV("FunctionName", TargetName));
+ OREGetter(*F).emit(OptimizationRemark(DEBUG_TYPE, OptName, DLoc, Block)
+ << NV("Optimization", OptName)
+ << ": devirtualized a call to "
+ << NV("FunctionName", TargetName));
}
void replaceAndErase(
const StringRef OptName, const StringRef TargetName, bool RemarksEnabled,
- function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
+ function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter,
Value *New) {
if (RemarksEnabled)
emitRemark(OptName, TargetName, OREGetter);
@@ -570,25 +578,24 @@ void VTableSlotInfo::addCallSite(Value *VTable, CallBase &CB,
struct DevirtModule {
Module &M;
- function_ref<AAResults &(Function &)> AARGetter;
- function_ref<DominatorTree &(Function &)> LookupDomTree;
+ ModuleAnalysisManager &MAM;
+ FunctionAnalysisManager &FAM;
- ModuleSummaryIndex *ExportSummary;
- const ModuleSummaryIndex *ImportSummary;
+ ModuleSummaryIndex *const ExportSummary;
+ const ModuleSummaryIndex *const ImportSummary;
- IntegerType *Int8Ty;
- PointerType *Int8PtrTy;
- IntegerType *Int32Ty;
- IntegerType *Int64Ty;
- IntegerType *IntPtrTy;
+ IntegerType *const Int8Ty;
+ PointerType *const Int8PtrTy;
+ IntegerType *const Int32Ty;
+ IntegerType *const Int64Ty;
+ IntegerType *const IntPtrTy;
/// Sizeless array type, used for imported vtables. This provides a signal
/// to analyzers that these imports may alias, as they do for example
/// when multiple unique return values occur in the same vtable.
- ArrayType *Int8Arr0Ty;
-
- bool RemarksEnabled;
- function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter;
+ ArrayType *const Int8Arr0Ty;
+ const bool RemarksEnabled;
+ std::function<OptimizationRemarkEmitter &(Function &)> OREGetter;
MapVector<VTableSlot, VTableSlotInfo> CallSlots;
// Calls that have already been optimized. We may add a call to multiple
@@ -611,12 +618,11 @@ struct DevirtModule {
std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
PatternList FunctionsToSkip;
- DevirtModule(Module &M, function_ref<AAResults &(Function &)> AARGetter,
- function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
- function_ref<DominatorTree &(Function &)> LookupDomTree,
+ DevirtModule(Module &M, ModuleAnalysisManager &MAM,
ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary)
- : M(M), AARGetter(AARGetter), LookupDomTree(LookupDomTree),
+ : M(M), MAM(MAM),
+ FAM(MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager()),
ExportSummary(ExportSummary), ImportSummary(ImportSummary),
Int8Ty(Type::getInt8Ty(M.getContext())),
Int8PtrTy(PointerType::getUnqual(M.getContext())),
@@ -624,7 +630,10 @@ struct DevirtModule {
Int64Ty(Type::getInt64Ty(M.getContext())),
IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)),
Int8Arr0Ty(ArrayType::get(Type::getInt8Ty(M.getContext()), 0)),
- RemarksEnabled(areRemarksEnabled()), OREGetter(OREGetter) {
+ RemarksEnabled(areRemarksEnabled()),
+ OREGetter([&](Function &F) -> OptimizationRemarkEmitter & {
+ return FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+ }) {
assert(!(ExportSummary && ImportSummary));
FunctionsToSkip.init(SkipFunctionNames);
}
@@ -653,7 +662,7 @@ struct DevirtModule {
VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res);
- void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Constant *JT,
+ void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
bool &IsExported);
void tryICallBranchFunnel(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
VTableSlotInfo &SlotInfo,
@@ -738,10 +747,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, function_ref<AAResults &(Function &)> AARGetter,
- function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
- function_ref<DominatorTree &(Function &)> LookupDomTree);
+ static bool runForTesting(Module &M, ModuleAnalysisManager &MAM);
};
struct DevirtIndex {
@@ -782,25 +788,13 @@ struct DevirtIndex {
} // end anonymous namespace
PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
- ModuleAnalysisManager &AM) {
- auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
- auto AARGetter = [&](Function &F) -> AAResults & {
- return FAM.getResult<AAManager>(F);
- };
- auto OREGetter = [&](Function *F) -> OptimizationRemarkEmitter & {
- return FAM.getResult<OptimizationRemarkEmitterAnalysis>(*F);
- };
- auto LookupDomTree = [&FAM](Function &F) -> DominatorTree & {
- return FAM.getResult<DominatorTreeAnalysis>(F);
- };
+ ModuleAnalysisManager &MAM) {
if (UseCommandLine) {
- if (!DevirtModule::runForTesting(M, AARGetter, OREGetter, LookupDomTree))
+ if (!DevirtModule::runForTesting(M, MAM))
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
- if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary,
- ImportSummary)
- .run())
+ if (!DevirtModule(M, MAM, ExportSummary, ImportSummary).run())
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
@@ -832,8 +826,8 @@ typeIDVisibleToRegularObj(StringRef TypeID,
// function for the base type and thus only contains a reference to the
// type info (_ZTI). To catch this case we query using the type info
// symbol corresponding to the TypeID.
- std::string typeInfo = ("_ZTI" + TypeID).str();
- return IsVisibleToRegularObj(typeInfo);
+ std::string TypeInfo = ("_ZTI" + TypeID).str();
+ return IsVisibleToRegularObj(TypeInfo);
}
static bool
@@ -842,7 +836,7 @@ skipUpdateDueToValidation(GlobalVariable &GV,
SmallVector<MDNode *, 2> Types;
GV.getMetadata(LLVMContext::MD_type, Types);
- for (auto Type : Types)
+ for (auto *Type : Types)
if (auto *TypeID = dyn_cast<MDString>(Type->getOperand(1).get()))
return typeIDVisibleToRegularObj(TypeID->getString(),
IsVisibleToRegularObj);
@@ -881,6 +875,7 @@ void llvm::updateVCallVisibilityInModule(
void llvm::updatePublicTypeTestCalls(Module &M,
bool WholeProgramVisibilityEnabledInLTO) {
+ llvm::TimeTraceScope timeScope("Update public type test calls");
Function *PublicTypeTestFunc =
Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test);
if (!PublicTypeTestFunc)
@@ -912,9 +907,9 @@ void llvm::getVisibleToRegularObjVtableGUIDs(
ModuleSummaryIndex &Index,
DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols,
function_ref<bool(StringRef)> IsVisibleToRegularObj) {
- for (const auto &typeID : Index.typeIdCompatibleVtableMap()) {
- if (typeIDVisibleToRegularObj(typeID.first, IsVisibleToRegularObj))
- for (const TypeIdOffsetVtableInfo &P : typeID.second)
+ for (const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
+ if (typeIDVisibleToRegularObj(TypeID.first, IsVisibleToRegularObj))
+ for (const TypeIdOffsetVtableInfo &P : TypeID.second)
VisibleToRegularObjSymbols.insert(P.VTableVI.getGUID());
}
}
@@ -957,7 +952,7 @@ void llvm::runWholeProgramDevirtOnIndex(
void llvm::updateIndexWPDForExports(
ModuleSummaryIndex &Summary,
- function_ref<bool(StringRef, ValueInfo)> isExported,
+ function_ref<bool(StringRef, ValueInfo)> IsExported,
std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap) {
for (auto &T : LocalWPDTargetsMap) {
auto &VI = T.first;
@@ -965,7 +960,7 @@ void llvm::updateIndexWPDForExports(
assert(VI.getSummaryList().size() == 1 &&
"Devirt of local target has more than one copy");
auto &S = VI.getSummaryList()[0];
- if (!isExported(S->modulePath(), VI))
+ if (!IsExported(S->modulePath(), VI))
continue;
// It's been exported by a cross module import.
@@ -995,10 +990,7 @@ static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary) {
return ErrorSuccess();
}
-bool DevirtModule::runForTesting(
- Module &M, function_ref<AAResults &(Function &)> AARGetter,
- function_ref<OptimizationRemarkEmitter &(Function *)> OREGetter,
- function_ref<DominatorTree &(Function &)> LookupDomTree) {
+bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM) {
std::unique_ptr<ModuleSummaryIndex> Summary =
std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false);
@@ -1023,7 +1015,7 @@ bool DevirtModule::runForTesting(
}
bool Changed =
- DevirtModule(M, AARGetter, OREGetter, LookupDomTree,
+ DevirtModule(M, MAM,
ClSummaryAction == PassSummaryAction::Export ? Summary.get()
: nullptr,
ClSummaryAction == PassSummaryAction::Import ? Summary.get()
@@ -1071,7 +1063,7 @@ void DevirtModule::buildTypeIdentifierMap(
}
for (MDNode *Type : Types) {
- auto TypeID = Type->getOperand(1).get();
+ auto *TypeID = Type->getOperand(1).get();
uint64_t Offset =
cast<ConstantInt>(
@@ -1120,7 +1112,7 @@ bool DevirtModule::tryFindVirtualCallTargets(
// Save the symbol used in the vtable to use as the devirtualization
// target.
- auto GV = dyn_cast<GlobalValue>(C);
+ auto *GV = dyn_cast<GlobalValue>(C);
assert(GV);
TargetsForSlot.push_back({GV, &TM});
}
@@ -1284,7 +1276,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Apply(P.second);
}
-static bool AddCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee) {
+static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee) {
// We can't add calls if we haven't seen a definition
if (Callee.getSummaryList().empty())
return false;
@@ -1359,7 +1351,7 @@ bool DevirtModule::trySingleImplDevirt(
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.
- AddCalls(SlotInfo, TheFnVI);
+ addCalls(SlotInfo, TheFnVI);
Res->TheKind = WholeProgramDevirtResolution::SingleImpl;
Res->SingleImplName = std::string(TheFn->getName());
@@ -1400,7 +1392,7 @@ bool DevirtIndex::trySingleImplDevirt(MutableArrayRef<ValueInfo> TargetsForSlot,
DevirtTargets.insert(TheFn);
auto &S = TheFn.getSummaryList()[0];
- bool IsExported = AddCalls(SlotInfo, TheFn);
+ bool IsExported = addCalls(SlotInfo, TheFn);
if (IsExported)
ExportedGUIDs.insert(TheFn.getGUID());
@@ -1497,13 +1489,19 @@ void DevirtModule::tryICallBranchFunnel(
ReturnInst::Create(M.getContext(), nullptr, BB);
bool IsExported = false;
- applyICallBranchFunnel(SlotInfo, JT, IsExported);
+ applyICallBranchFunnel(SlotInfo, *JT, IsExported);
if (IsExported)
Res->TheKind = WholeProgramDevirtResolution::BranchFunnel;
+
+ if (!JT->getEntryCount().has_value()) {
+ // FIXME: we could pass through thinlto the necessary information.
+ setExplicitlyUnknownFunctionEntryCount(*JT);
+ }
}
void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
- Constant *JT, bool &IsExported) {
+ Function &JT, bool &IsExported) {
+ DenseMap<Function *, double> FunctionEntryCounts;
auto Apply = [&](CallSiteInfo &CSInfo) {
if (CSInfo.isExported())
IsExported = true;
@@ -1531,8 +1529,7 @@ void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
NumBranchFunnel++;
if (RemarksEnabled)
- VCallSite.emitRemark("branch-funnel",
- JT->stripPointerCasts()->getName(), OREGetter);
+ VCallSite.emitRemark("branch-funnel", JT.getName(), OREGetter);
// Pass the address of the vtable in the nest register, which is r10 on
// x86_64.
@@ -1548,11 +1545,28 @@ void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
llvm::append_range(Args, CB.args());
CallBase *NewCS = nullptr;
+ if (!JT.isDeclaration() && !ProfcheckDisableMetadataFixes) {
+ // Accumulate the call frequencies of the original call site, and use
+ // that as total entry count for the funnel function.
+ auto &F = *CB.getCaller();
+ auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
+ auto EC = BFI.getBlockFreq(&F.getEntryBlock());
+ auto CC = F.getEntryCount(/*AllowSynthetic=*/true);
+ double CallCount = 0.0;
+ if (EC.getFrequency() != 0 && CC && CC->getCount() != 0) {
+ double CallFreq =
+ static_cast<double>(
+ BFI.getBlockFreq(CB.getParent()).getFrequency()) /
+ EC.getFrequency();
+ CallCount = CallFreq * CC->getCount();
+ }
+ FunctionEntryCounts[&JT] += CallCount;
+ }
if (isa<CallInst>(CB))
- NewCS = IRB.CreateCall(NewFT, JT, Args);
+ NewCS = IRB.CreateCall(NewFT, &JT, Args);
else
NewCS =
- IRB.CreateInvoke(NewFT, JT, cast<InvokeInst>(CB).getNormalDest(),
+ IRB.CreateInvoke(NewFT, &JT, cast<InvokeInst>(CB).getNormalDest(),
cast<InvokeInst>(CB).getUnwindDest(), Args);
NewCS->setCallingConv(CB.getCallingConv());
@@ -1586,6 +1600,11 @@ void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
Apply(SlotInfo.CSInfo);
for (auto &P : SlotInfo.ConstCSInfo)
Apply(P.second);
+ for (auto &[F, C] : FunctionEntryCounts) {
+ assert(!F->getEntryCount(/*AllowSynthetic=*/true) &&
+ "Unexpected entry count for funnel that was freshly synthesized");
+ F->setEntryCount(static_cast<uint64_t>(std::round(C)));
+ }
}
bool DevirtModule::tryEvaluateFunctionsWithArgs(
@@ -1597,7 +1616,7 @@ bool DevirtModule::tryEvaluateFunctionsWithArgs(
// TODO: Skip for now if the vtable symbol was an alias to a function,
// need to evaluate whether it would be correct to analyze the aliasee
// function for this optimization.
- auto Fn = dyn_cast<Function>(Target.Fn);
+ auto *Fn = dyn_cast<Function>(Target.Fn);
if (!Fn)
return false;
@@ -1836,11 +1855,11 @@ bool DevirtModule::tryVirtualConstProp(
// TODO: Skip for now if the vtable symbol was an alias to a function,
// need to evaluate whether it would be correct to analyze the aliasee
// function for this optimization.
- auto Fn = dyn_cast<Function>(TargetsForSlot[0].Fn);
+ auto *Fn = dyn_cast<Function>(TargetsForSlot[0].Fn);
if (!Fn)
return false;
// This only works if the function returns an integer.
- auto RetType = dyn_cast<IntegerType>(Fn->getReturnType());
+ auto *RetType = dyn_cast<IntegerType>(Fn->getReturnType());
if (!RetType)
return false;
unsigned BitWidth = RetType->getBitWidth();
@@ -1871,12 +1890,12 @@ bool DevirtModule::tryVirtualConstProp(
// TODO: Skip for now if the vtable symbol was an alias to a function,
// need to evaluate whether it would be correct to analyze the aliasee
// function for this optimization.
- auto Fn = dyn_cast<Function>(Target.Fn);
+ auto *Fn = dyn_cast<Function>(Target.Fn);
if (!Fn)
return false;
if (Fn->isDeclaration() ||
- !computeFunctionBodyMemoryAccess(*Fn, AARGetter(*Fn))
+ !computeFunctionBodyMemoryAccess(*Fn, FAM.getResult<AAManager>(*Fn))
.doesNotAccessMemory() ||
Fn->arg_empty() || !Fn->arg_begin()->use_empty() ||
Fn->getReturnType() != RetType)
@@ -1992,11 +2011,11 @@ void DevirtModule::rebuildGlobal(VTableBits &B) {
// Build an anonymous global containing the before bytes, followed by the
// original initializer, followed by the after bytes.
- auto NewInit = ConstantStruct::getAnon(
+ auto *NewInit = ConstantStruct::getAnon(
{ConstantDataArray::get(M.getContext(), B.Before.Bytes),
B.GV->getInitializer(),
ConstantDataArray::get(M.getContext(), B.After.Bytes)});
- auto NewGV =
+ auto *NewGV =
new GlobalVariable(M, NewInit->getType(), B.GV->isConstant(),
GlobalVariable::PrivateLinkage, NewInit, "", B.GV);
NewGV->setSection(B.GV->getSection());
@@ -2009,7 +2028,7 @@ void DevirtModule::rebuildGlobal(VTableBits &B) {
// Build an alias named after the original global, pointing at the second
// element (the original initializer).
- auto Alias = GlobalAlias::create(
+ auto *Alias = GlobalAlias::create(
B.GV->getInitializer()->getType(), 0, B.GV->getLinkage(), "",
ConstantExpr::getInBoundsGetElementPtr(
NewInit->getType(), NewGV,
@@ -2050,7 +2069,7 @@ void DevirtModule::scanTypeTestUsers(
// Search for virtual calls based on %p and add them to DevirtCalls.
SmallVector<DevirtCallSite, 1> DevirtCalls;
SmallVector<CallInst *, 1> Assumes;
- auto &DT = LookupDomTree(*CI->getFunction());
+ auto &DT = FAM.getResult<DominatorTreeAnalysis>(*CI->getFunction());
findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI, DT);
Metadata *TypeId =
@@ -2127,7 +2146,7 @@ void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
SmallVector<Instruction *, 1> LoadedPtrs;
SmallVector<Instruction *, 1> Preds;
bool HasNonCallUses = false;
- auto &DT = LookupDomTree(*CI->getFunction());
+ auto &DT = FAM.getResult<DominatorTreeAnalysis>(*CI->getFunction());
findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds,
HasNonCallUses, CI, DT);
@@ -2259,18 +2278,18 @@ void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
if (Res.TheKind == WholeProgramDevirtResolution::BranchFunnel) {
// The type of the function is irrelevant, because it's bitcast at calls
// anyhow.
- Constant *JT = cast<Constant>(
+ auto *JT = cast<Function>(
M.getOrInsertFunction(getGlobalName(Slot, {}, "branch_funnel"),
Type::getVoidTy(M.getContext()))
.getCallee());
bool IsExported = false;
- applyICallBranchFunnel(SlotInfo, JT, IsExported);
+ applyICallBranchFunnel(SlotInfo, *JT, IsExported);
assert(!IsExported);
}
}
void DevirtModule::removeRedundantTypeTests() {
- auto True = ConstantInt::getTrue(M.getContext());
+ auto *True = ConstantInt::getTrue(M.getContext());
for (auto &&U : NumUnsafeUsesForTypeTest) {
if (U.second == 0) {
U.first->replaceAllUsesWith(True);
@@ -2490,18 +2509,17 @@ bool DevirtModule::run() {
// Generate remarks for each devirtualized function.
for (const auto &DT : DevirtTargets) {
GlobalValue *GV = DT.second;
- auto F = dyn_cast<Function>(GV);
+ auto *F = dyn_cast<Function>(GV);
if (!F) {
- auto A = dyn_cast<GlobalAlias>(GV);
+ auto *A = dyn_cast<GlobalAlias>(GV);
assert(A && isa<Function>(A->getAliasee()));
F = dyn_cast<Function>(A->getAliasee());
assert(F);
}
using namespace ore;
- OREGetter(F).emit(OptimizationRemark(DEBUG_TYPE, "Devirtualized", F)
- << "devirtualized "
- << NV("FunctionName", DT.first));
+ OREGetter(*F).emit(OptimizationRemark(DEBUG_TYPE, "Devirtualized", F)
+ << "devirtualized " << NV("FunctionName", DT.first));
}
}