summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp')
-rw-r--r--llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp110
1 files changed, 75 insertions, 35 deletions
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index 640d9943d1f..e78665f5c0c 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -235,15 +235,18 @@ struct VirtualCallSite {
// of that field for details.
unsigned *NumUnsafeUses;
- void emitRemark() {
+ void emitRemark(const Twine &OptName, const Twine &TargetName) {
Function *F = CS.getCaller();
- emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F,
- CS.getInstruction()->getDebugLoc(),
- "devirtualized call");
+ emitOptimizationRemark(
+ F->getContext(), DEBUG_TYPE, *F,
+ CS.getInstruction()->getDebugLoc(),
+ OptName + ": devirtualized a call to " + TargetName);
}
- void replaceAndErase(Value *New) {
- emitRemark();
+ void replaceAndErase(const Twine &OptName, const Twine &TargetName,
+ bool RemarksEnabled, Value *New) {
+ if (RemarksEnabled)
+ emitRemark(OptName, TargetName);
CS->replaceAllUsesWith(New);
if (auto II = dyn_cast<InvokeInst>(CS.getInstruction())) {
BranchInst::Create(II->getNormalDest(), CS.getInstruction());
@@ -262,6 +265,8 @@ struct DevirtModule {
PointerType *Int8PtrTy;
IntegerType *Int32Ty;
+ bool RemarksEnabled;
+
MapVector<VTableSlot, std::vector<VirtualCallSite>> CallSlots;
// This map keeps track of the number of "unsafe" uses of a loaded function
@@ -277,7 +282,10 @@ struct DevirtModule {
DevirtModule(Module &M)
: M(M), Int8Ty(Type::getInt8Ty(M.getContext())),
Int8PtrTy(Type::getInt8PtrTy(M.getContext())),
- Int32Ty(Type::getInt32Ty(M.getContext())) {}
+ Int32Ty(Type::getInt32Ty(M.getContext())),
+ RemarksEnabled(areRemarksEnabled()) {}
+
+ bool areRemarksEnabled();
void scanTypeTestUsers(Function *TypeTestFunc, Function *AssumeFunc);
void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
@@ -289,16 +297,16 @@ struct DevirtModule {
tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset);
- bool trySingleImplDevirt(ArrayRef<VirtualCallTarget> TargetsForSlot,
+ bool trySingleImplDevirt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites);
bool tryEvaluateFunctionsWithArgs(
MutableArrayRef<VirtualCallTarget> TargetsForSlot,
ArrayRef<ConstantInt *> Args);
bool tryUniformRetValOpt(IntegerType *RetType,
- ArrayRef<VirtualCallTarget> TargetsForSlot,
+ MutableArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites);
bool tryUniqueRetValOpt(unsigned BitWidth,
- ArrayRef<VirtualCallTarget> TargetsForSlot,
+ MutableArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites);
bool tryVirtualConstProp(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
ArrayRef<VirtualCallSite> CallSites);
@@ -413,7 +421,7 @@ bool DevirtModule::tryFindVirtualCallTargets(
}
bool DevirtModule::trySingleImplDevirt(
- ArrayRef<VirtualCallTarget> TargetsForSlot,
+ MutableArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites) {
// See if the program contains a single implementation of this virtual
// function.
@@ -422,9 +430,12 @@ bool DevirtModule::trySingleImplDevirt(
if (TheFn != Target.Fn)
return false;
+ if (RemarksEnabled)
+ TargetsForSlot[0].WasDevirt = true;
// If so, update each call site to call that implementation directly.
for (auto &&VCallSite : CallSites) {
- VCallSite.emitRemark();
+ if (RemarksEnabled)
+ VCallSite.emitRemark("single-impl", TheFn->getName());
VCallSite.CS.setCalledFunction(ConstantExpr::getBitCast(
TheFn, VCallSite.CS.getCalledValue()->getType()));
// This use is no longer unsafe.
@@ -462,7 +473,7 @@ bool DevirtModule::tryEvaluateFunctionsWithArgs(
}
bool DevirtModule::tryUniformRetValOpt(
- IntegerType *RetType, ArrayRef<VirtualCallTarget> TargetsForSlot,
+ IntegerType *RetType, MutableArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites) {
// Uniform return value optimization. If all functions return the same
// constant, replace all calls with that constant.
@@ -473,12 +484,16 @@ bool DevirtModule::tryUniformRetValOpt(
auto TheRetValConst = ConstantInt::get(RetType, TheRetVal);
for (auto Call : CallSites)
- Call.replaceAndErase(TheRetValConst);
+ Call.replaceAndErase("uniform-ret-val", TargetsForSlot[0].Fn->getName(),
+ RemarksEnabled, TheRetValConst);
+ if (RemarksEnabled)
+ for (auto &&Target : TargetsForSlot)
+ Target.WasDevirt = true;
return true;
}
bool DevirtModule::tryUniqueRetValOpt(
- unsigned BitWidth, ArrayRef<VirtualCallTarget> TargetsForSlot,
+ unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites) {
// IsOne controls whether we look for a 0 or a 1.
auto tryUniqueRetValOptFor = [&](bool IsOne) {
@@ -502,8 +517,14 @@ bool DevirtModule::tryUniqueRetValOpt(
OneAddr = B.CreateConstGEP1_64(OneAddr, UniqueMember->Offset);
Value *Cmp = B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
Call.VTable, OneAddr);
- Call.replaceAndErase(Cmp);
+ Call.replaceAndErase("unique-ret-val", TargetsForSlot[0].Fn->getName(),
+ RemarksEnabled, Cmp);
}
+ // Update devirtualization statistics for targets.
+ if (RemarksEnabled)
+ for (auto &&Target : TargetsForSlot)
+ Target.WasDevirt = true;
+
return true;
};
@@ -611,6 +632,10 @@ bool DevirtModule::tryVirtualConstProp(
setAfterReturnValues(TargetsForSlot, AllocAfter, BitWidth, OffsetByte,
OffsetBit);
+ if (RemarksEnabled)
+ for (auto &&Target : TargetsForSlot)
+ Target.WasDevirt = true;
+
// Rewrite each call to a load from OffsetByte/OffsetBit.
for (auto Call : CSByConstantArg.second) {
IRBuilder<> B(Call.CS.getInstruction());
@@ -620,27 +645,21 @@ bool DevirtModule::tryVirtualConstProp(
Value *Bit = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
Value *BitsAndBit = B.CreateAnd(Bits, Bit);
auto IsBitSet = B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
- Call.replaceAndErase(IsBitSet);
+ Call.replaceAndErase("virtual-const-prop-1-bit",
+ TargetsForSlot[0].Fn->getName(),
+ RemarksEnabled, IsBitSet);
} else {
Value *ValAddr = B.CreateBitCast(Addr, RetType->getPointerTo());
Value *Val = B.CreateLoad(RetType, ValAddr);
- Call.replaceAndErase(Val);
+ Call.replaceAndErase("virtual-const-prop",
+ TargetsForSlot[0].Fn->getName(),
+ RemarksEnabled, Val);
}
}
}
return true;
}
-static void emitTargetsRemarks(const std::vector<VirtualCallTarget> &TargetsForSlot) {
- for (const VirtualCallTarget &Target : TargetsForSlot) {
- Function *F = Target.Fn;
- DISubprogram *SP = F->getSubprogram();
- DebugLoc DL = SP ? DebugLoc::get(SP->getScopeLine(), 0, SP) : DebugLoc();
- emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, DL,
- std::string("devirtualized ") + F->getName().str());
- }
-}
-
void DevirtModule::rebuildGlobal(VTableBits &B) {
if (B.Before.Bytes.empty() && B.After.Bytes.empty())
return;
@@ -686,6 +705,15 @@ void DevirtModule::rebuildGlobal(VTableBits &B) {
B.GV->eraseFromParent();
}
+bool DevirtModule::areRemarksEnabled() {
+ const auto &FL = M.getFunctionList();
+ if (FL.empty())
+ return false;
+ const Function &Fn = FL.front();
+ auto DI = DiagnosticInfoOptimizationRemark(DEBUG_TYPE, Fn, DebugLoc(), "");
+ return DI.isEnabled();
+}
+
void DevirtModule::scanTypeTestUsers(Function *TypeTestFunc,
Function *AssumeFunc) {
// Find all virtual calls via a virtual table pointer %p under an assumption
@@ -837,6 +865,7 @@ bool DevirtModule::run() {
// For each (type, offset) pair:
bool DidVirtualConstProp = false;
+ std::map<std::string, Function*> DevirtTargets;
for (auto &S : CallSlots) {
// Search each of the members of the type identifier for the virtual
// function implementation at offset S.first.ByteOffset, and add to
@@ -846,14 +875,25 @@ bool DevirtModule::run() {
S.first.ByteOffset))
continue;
- if (trySingleImplDevirt(TargetsForSlot, S.second)) {
- emitTargetsRemarks(TargetsForSlot);
- continue;
- }
+ if (!trySingleImplDevirt(TargetsForSlot, S.second) &&
+ tryVirtualConstProp(TargetsForSlot, S.second))
+ DidVirtualConstProp = true;
+
+ // Collect functions devirtualized at least for one call site for stats.
+ if (RemarksEnabled)
+ for (const auto &T : TargetsForSlot)
+ if (T.WasDevirt)
+ DevirtTargets[T.Fn->getName()] = T.Fn;
+ }
- if (tryVirtualConstProp(TargetsForSlot, S.second)) {
- emitTargetsRemarks(TargetsForSlot);
- DidVirtualConstProp = true;
+ if (RemarksEnabled) {
+ // Generate remarks for each devirtualized function.
+ for (const auto &DT : DevirtTargets) {
+ Function *F = DT.second;
+ DISubprogram *SP = F->getSubprogram();
+ DebugLoc DL = SP ? DebugLoc::get(SP->getScopeLine(), 0, SP) : DebugLoc();
+ emitOptimizationRemark(F->getContext(), DEBUG_TYPE, *F, DL,
+ Twine("devirtualized ") + F->getName());
}
}
OpenPOWER on IntegriCloud