#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PriorityWorklist.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
/// for a better technique.
SmallDenseSet<std::pair<LazyCallGraph::Node *, LazyCallGraph::SCC *>, 4>
&InlinedInternalEdges;
+
+ /// Weak VHs to keep track of indirect calls for the purposes of detecting
+ /// devirtualization.
+ ///
+ /// This is a map to avoid having duplicate entries. If a Value is
+ /// deallocated, its corresponding WeakTrackingVH will be nulled out. When
+ /// checking if a Value is in the map or not, also check if the corresponding
+ /// WeakTrackingVH is null to avoid issues with a new Value sharing the same
+ /// address as a deallocated one.
+ SmallMapVector<Value *, WeakTrackingVH, 16> IndirectVHs;
};
/// The core module pass which does a post-order walk of the SCCs and
// a pointer that we can update.
LazyCallGraph::SCC *C = &InitialC;
- // Collect value handles for all of the indirect call sites.
- SmallVector<WeakTrackingVH, 8> CallHandles;
-
// Struct to track the counts of direct and indirect calls in each function
// of the SCC.
struct CallCount {
// Put value handles on all of the indirect calls and return the number of
// direct calls for each function in the SCC.
- auto ScanSCC = [](LazyCallGraph::SCC &C,
- SmallVectorImpl<WeakTrackingVH> &CallHandles) {
- assert(CallHandles.empty() && "Must start with a clear set of handles.");
-
- SmallDenseMap<Function *, CallCount> CallCounts;
- CallCount CountLocal = {0, 0};
- for (LazyCallGraph::Node &N : C) {
- CallCount &Count =
- CallCounts.insert(std::make_pair(&N.getFunction(), CountLocal))
- .first->second;
- for (Instruction &I : instructions(N.getFunction()))
- if (auto *CB = dyn_cast<CallBase>(&I)) {
- if (CB->getCalledFunction()) {
- ++Count.Direct;
- } else {
- ++Count.Indirect;
- CallHandles.push_back(WeakTrackingVH(&I));
- }
+ auto ScanSCC =
+ [](LazyCallGraph::SCC &C,
+ SmallMapVector<Value *, WeakTrackingVH, 16> &CallHandles) {
+ assert(CallHandles.empty() &&
+ "Must start with a clear set of handles.");
+
+ SmallDenseMap<Function *, CallCount> CallCounts;
+ CallCount CountLocal = {0, 0};
+ for (LazyCallGraph::Node &N : C) {
+ CallCount &Count =
+ CallCounts.insert(std::make_pair(&N.getFunction(), CountLocal))
+ .first->second;
+ for (Instruction &I : instructions(N.getFunction()))
+ if (auto *CB = dyn_cast<CallBase>(&I)) {
+ if (CB->getCalledFunction()) {
+ ++Count.Direct;
+ } else {
+ ++Count.Indirect;
+ CallHandles.insert({CB, WeakTrackingVH(CB)});
+ }
+ }
}
- }
- return CallCounts;
- };
+ return CallCounts;
+ };
+ UR.IndirectVHs.clear();
// Populate the initial call handles and get the initial call counts.
- auto CallCounts = ScanSCC(*C, CallHandles);
+ auto CallCounts = ScanSCC(*C, UR.IndirectVHs);
for (int Iteration = 0;; ++Iteration) {
-
if (!PI.runBeforePass<LazyCallGraph::SCC>(Pass, *C))
continue;
assert(C->begin() != C->end() && "Cannot have an empty SCC!");
// Check whether any of the handles were devirtualized.
- auto IsDevirtualizedHandle = [&](WeakTrackingVH &CallH) {
- if (!CallH)
- return false;
- auto *CB = dyn_cast<CallBase>(CallH);
- if (!CB)
- return false;
-
- // If the call is still indirect, leave it alone.
- Function *F = CB->getCalledFunction();
- if (!F)
- return false;
-
- LLVM_DEBUG(dbgs() << "Found devirtualized call from "
- << CB->getParent()->getParent()->getName() << " to "
- << F->getName() << "\n");
-
- // We now have a direct call where previously we had an indirect call,
- // so iterate to process this devirtualization site.
- return true;
- };
- bool Devirt = llvm::any_of(CallHandles, IsDevirtualizedHandle);
+ bool Devirt = llvm::any_of(UR.IndirectVHs, [](auto &P) -> bool {
+ if (P.second) {
+ CallBase *CB = cast<CallBase>(P.second);
+ if (CB->getCalledFunction()) {
+ LLVM_DEBUG(dbgs() << "Found devirtualized call: " << *CB << "\n");
+ return true;
+ }
+ }
+ return false;
+ });
// Rescan to build up a new set of handles and count how many direct
// calls remain. If we decide to iterate, this also sets up the input to
// the next iteration.
- CallHandles.clear();
- auto NewCallCounts = ScanSCC(*C, CallHandles);
+ UR.IndirectVHs.clear();
+ auto NewCallCounts = ScanSCC(*C, UR.IndirectVHs);
// If we haven't found an explicit devirtualization already see if we
// have decreased the number of indirect calls and increased the number
CGSCCUpdateResult UR = {
RCWorklist, CWorklist, InvalidRefSCCSet, InvalidSCCSet,
- nullptr, nullptr, PreservedAnalyses::all(), InlinedInternalEdges};
+ nullptr, nullptr, PreservedAnalyses::all(), InlinedInternalEdges,
+ {}};
// Request PassInstrumentation from analysis manager, will use it to run
// instrumenting callbacks for the passes later.
#include "llvm/IR/Instruction.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/PassManagerImpl.h"
+#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
// First walk the function and handle all called functions. We do this first
// because if there is a single call edge, whether there are ref edges is
// irrelevant.
- for (Instruction &I : instructions(F))
- if (auto *CB = dyn_cast<CallBase>(&I))
- if (Function *Callee = CB->getCalledFunction())
+ for (Instruction &I : instructions(F)) {
+ if (auto *CB = dyn_cast<CallBase>(&I)) {
+ if (Function *Callee = CB->getCalledFunction()) {
if (Visited.insert(Callee).second && !Callee->isDeclaration()) {
Node *CalleeN = G.lookup(*Callee);
if (!CalleeN) {
else if (!E->isCall())
PromotedRefTargets.insert(CalleeN);
}
+ } else {
+ // We can miss devirtualization if an indirect call is created then
+ // promoted before updateCGAndAnalysisManagerForPass runs.
+ auto *Entry = UR.IndirectVHs.find(CB);
+ if (Entry == UR.IndirectVHs.end())
+ UR.IndirectVHs.insert({CB, WeakTrackingVH(CB)});
+ else if (!Entry->second)
+ Entry->second = WeakTrackingVH(CB);
+ }
+ }
+ }
// Now walk all references.
for (Instruction &I : instructions(F))