[Attributor] Create a call site position for AACalledges

This patch adds a call site position for AACallEdges, this
allows us to ask questions about which functions a specific
`CallBase` might call.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D106208
This commit is contained in:
Kuter Dinel
2021-09-12 06:02:51 +03:00
parent fb7fbe4314
commit 2cc6f7c8e1

View File

@@ -9347,102 +9347,12 @@ struct AANoUndefCallSiteReturned final
void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(noundef) }
};
struct AACallEdgesFunction : public AACallEdges {
AACallEdgesFunction(const IRPosition &IRP, Attributor &A)
: AACallEdges(IRP, A) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
ChangeStatus Change = ChangeStatus::UNCHANGED;
bool OldHasUnknownCallee = HasUnknownCallee;
bool OldHasUnknownCalleeNonAsm = HasUnknownCalleeNonAsm;
auto AddCalledFunction = [&](Function *Fn) {
if (CalledFunctions.insert(Fn)) {
Change = ChangeStatus::CHANGED;
LLVM_DEBUG(dbgs() << "[AACallEdges] New call edge: " << Fn->getName()
<< "\n");
}
};
auto VisitValue = [&](Value &V, const Instruction *CtxI, bool &HasUnknown,
bool Stripped) -> bool {
if (Function *Fn = dyn_cast<Function>(&V)) {
AddCalledFunction(Fn);
} else {
LLVM_DEBUG(dbgs() << "[AACallEdges] Unrecognized value: " << V << "\n");
HasUnknown = true;
HasUnknownCalleeNonAsm = true;
}
// Explore all values.
return true;
};
// Process any value that we might call.
auto ProcessCalledOperand = [&](Value *V, Instruction *Ctx) {
if (!genericValueTraversal<bool>(A, IRPosition::value(*V), *this,
HasUnknownCallee, VisitValue, nullptr,
false)) {
// If we haven't gone through all values, assume that there are unknown
// callees.
HasUnknownCallee = true;
HasUnknownCalleeNonAsm = true;
}
};
auto ProcessCallInst = [&](Instruction &Inst) {
CallBase &CB = static_cast<CallBase &>(Inst);
if (CB.isInlineAsm()) {
HasUnknownCallee = true;
return true;
}
// Process callee metadata if available.
if (auto *MD = Inst.getMetadata(LLVMContext::MD_callees)) {
for (auto &Op : MD->operands()) {
Function *Callee = mdconst::extract_or_null<Function>(Op);
if (Callee)
AddCalledFunction(Callee);
}
// Callees metadata grantees that the called function is one of its
// operands, So we are done.
return true;
}
// The most simple case.
ProcessCalledOperand(CB.getCalledOperand(), &Inst);
// Process callback functions.
SmallVector<const Use *, 4u> CallbackUses;
AbstractCallSite::getCallbackUses(CB, CallbackUses);
for (const Use *U : CallbackUses)
ProcessCalledOperand(U->get(), &Inst);
return true;
};
// Visit all callable instructions.
bool UsedAssumedInformation = false;
if (!A.checkForAllCallLikeInstructions(ProcessCallInst, *this,
UsedAssumedInformation)) {
// If we haven't looked at all call like instructions, assume that there
// are unknown callees.
HasUnknownCallee = true;
HasUnknownCalleeNonAsm = true;
}
// Track changes.
if (OldHasUnknownCallee != HasUnknownCallee ||
OldHasUnknownCalleeNonAsm != HasUnknownCalleeNonAsm)
Change = ChangeStatus::CHANGED;
return Change;
}
struct AACallEdgesImpl : public AACallEdges {
AACallEdgesImpl(const IRPosition &IRP, Attributor &A) : AACallEdges(IRP, A) {}
virtual const SetVector<Function *> &getOptimisticEdges() const override {
return CalledFunctions;
};
}
virtual bool hasUnknownCallee() const override { return HasUnknownCallee; }
@@ -9457,7 +9367,26 @@ struct AACallEdgesFunction : public AACallEdges {
void trackStatistics() const override {}
/// Optimistic set of functions that might be called by this function.
protected:
void addCalledFunction(Function *Fn, ChangeStatus &Change) {
if (CalledFunctions.insert(Fn)) {
Change = ChangeStatus::CHANGED;
LLVM_DEBUG(dbgs() << "[AACallEdges] New call edge: " << Fn->getName()
<< "\n");
}
}
void setHasUnknownCallee(bool NonAsm, ChangeStatus &Change) {
if (!HasUnknownCallee)
Change = ChangeStatus::CHANGED;
if (NonAsm && !HasUnknownCalleeNonAsm)
Change = ChangeStatus::CHANGED;
HasUnknownCalleeNonAsm |= NonAsm;
HasUnknownCallee = true;
}
private:
/// Optimistic set of functions that might be called by this position.
SetVector<Function *> CalledFunctions;
/// Is there any call with a unknown callee.
@@ -9467,6 +9396,105 @@ struct AACallEdgesFunction : public AACallEdges {
bool HasUnknownCalleeNonAsm = false;
};
struct AACallEdgesCallSite : public AACallEdgesImpl {
AACallEdgesCallSite(const IRPosition &IRP, Attributor &A)
: AACallEdgesImpl(IRP, A) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
ChangeStatus Change = ChangeStatus::UNCHANGED;
auto VisitValue = [&](Value &V, const Instruction *CtxI, bool &HasUnknown,
bool Stripped) -> bool {
if (Function *Fn = dyn_cast<Function>(&V)) {
addCalledFunction(Fn, Change);
} else {
LLVM_DEBUG(dbgs() << "[AACallEdges] Unrecognized value: " << V << "\n");
setHasUnknownCallee(true, Change);
}
// Explore all values.
return true;
};
// Process any value that we might call.
auto ProcessCalledOperand = [&](Value *V) {
bool DummyValue = false;
if (!genericValueTraversal<bool>(A, IRPosition::value(*V), *this,
DummyValue, VisitValue, nullptr,
false)) {
// If we haven't gone through all values, assume that there are unknown
// callees.
setHasUnknownCallee(true, Change);
}
};
CallBase *CB = static_cast<CallBase *>(getCtxI());
if (CB->isInlineAsm()) {
setHasUnknownCallee(false, Change);
return Change;
}
// Process callee metadata if available.
if (auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees)) {
for (auto &Op : MD->operands()) {
Function *Callee = mdconst::extract_or_null<Function>(Op);
if (Callee)
addCalledFunction(Callee, Change);
}
return Change;
}
// The most simple case.
ProcessCalledOperand(CB->getCalledOperand());
// Process callback functions.
SmallVector<const Use *, 4u> CallbackUses;
AbstractCallSite::getCallbackUses(*CB, CallbackUses);
for (const Use *U : CallbackUses)
ProcessCalledOperand(U->get());
return Change;
}
};
struct AACallEdgesFunction : public AACallEdgesImpl {
AACallEdgesFunction(const IRPosition &IRP, Attributor &A)
: AACallEdgesImpl(IRP, A) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
ChangeStatus Change = ChangeStatus::UNCHANGED;
auto ProcessCallInst = [&](Instruction &Inst) {
CallBase &CB = static_cast<CallBase &>(Inst);
auto &CBEdges = A.getAAFor<AACallEdges>(
*this, IRPosition::callsite_function(CB), DepClassTy::REQUIRED);
if (CBEdges.hasNonAsmUnknownCallee())
setHasUnknownCallee(false, Change);
if (CBEdges.hasUnknownCallee())
setHasUnknownCallee(true, Change);
for (Function *F : CBEdges.getOptimisticEdges())
addCalledFunction(F, Change);
return true;
};
// Visit all callable instructions.
bool UsedAssumedInformation = false;
if (!A.checkForAllCallLikeInstructions(ProcessCallInst, *this,
UsedAssumedInformation)) {
// If we haven't looked at all call like instructions, assume that there
// are unknown callees.
setHasUnknownCallee(true, Change);
}
return Change;
}
};
struct AAFunctionReachabilityFunction : public AAFunctionReachability {
AAFunctionReachabilityFunction(const IRPosition &IRP, Attributor &A)
: AAFunctionReachability(IRP, A) {}
@@ -9715,6 +9743,7 @@ CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAWillReturn)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoReturn)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReturnedValues)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryLocation)
CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AACallEdges)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonNull)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoAlias)
@@ -9734,7 +9763,6 @@ CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReachability)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUndefinedBehavior)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AACallEdges)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAFunctionReachability)
CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryBehavior)