diff options
author | Brian Homerding <homerdin@gmail.com> | 2019-07-08 15:57:56 +0000 |
---|---|---|
committer | Brian Homerding <homerdin@gmail.com> | 2019-07-08 15:57:56 +0000 |
commit | b4b21d807e4f47f1f87b05fddf6bb3167b14476e (patch) | |
tree | 2ca1fdfcf72d73e5d6245cbd845c3f372e0a9dc9 /llvm/lib/Transforms/IPO/FunctionAttrs.cpp | |
parent | b52a0c0cc88f0d66ae8ea770f92ed3448aee88a7 (diff) | |
download | bcm5719-llvm-b4b21d807e4f47f1f87b05fddf6bb3167b14476e.tar.gz bcm5719-llvm-b4b21d807e4f47f1f87b05fddf6bb3167b14476e.zip |
Add, and infer, a nofree function attribute
This patch adds a function attribute, nofree, to indicate that a function does
not, directly or indirectly, call a memory-deallocation function (e.g., free,
C++'s operator delete).
Reviewers: jdoerfert
Differential Revision: https://reviews.llvm.org/D49165
llvm-svn: 365336
Diffstat (limited to 'llvm/lib/Transforms/IPO/FunctionAttrs.cpp')
-rw-r--r-- | llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 9e95e796da6..a3fb7d1d57a 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -27,6 +27,7 @@ #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" @@ -75,6 +76,7 @@ STATISTIC(NumNoAlias, "Number of function returns marked noalias"); STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull"); STATISTIC(NumNoRecurse, "Number of functions marked as norecurse"); STATISTIC(NumNoUnwind, "Number of functions marked as nounwind"); +STATISTIC(NumNoFree, "Number of functions marked as nofree"); // FIXME: This is disabled by default to avoid exposing security vulnerabilities // in C/C++ code compiled by clang: @@ -88,6 +90,10 @@ static cl::opt<bool> DisableNoUnwindInference( "disable-nounwind-inference", cl::Hidden, cl::desc("Stop inferring nounwind attribute during function-attrs pass")); +static cl::opt<bool> DisableNoFreeInference( + "disable-nofree-inference", cl::Hidden, + cl::desc("Stop inferring nofree attribute during function-attrs pass")); + namespace { using SCCNodeSet = SmallSetVector<Function *, 8>; @@ -1227,6 +1233,25 @@ static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes) { return true; } +/// Helper for NoFree inference predicate InstrBreaksAttribute. +static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) { + CallSite CS(&I); + if (!CS) + return false; + + Function *Callee = CS.getCalledFunction(); + if (!Callee) + return true; + + if (Callee->doesNotFreeMemory()) + return false; + + if (SCCNodes.count(Callee) > 0) + return false; + + return true; +} + /// Infer attributes from all functions in the SCC by scanning every /// instruction for compliance to the attribute assumptions. Currently it /// does: @@ -1280,6 +1305,29 @@ static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) { }, /* RequiresExactDefinition= */ true}); + if (!DisableNoFreeInference) + // Request to infer nofree attribute for all the functions in the SCC if + // every callsite within the SCC does not directly or indirectly free + // memory (except for calls to functions within the SCC). Note that nofree + // attribute suffers from derefinement - results may change depending on + // how functions are optimized. Thus it can be inferred only from exact + // definitions. + AI.registerAttrInference(AttributeInferer::InferenceDescriptor{ + Attribute::NoFree, + // Skip functions known not to free memory. + [](const Function &F) { return F.doesNotFreeMemory(); }, + // Instructions that break non-deallocating assumption. + [SCCNodes](Instruction &I) { + return InstrBreaksNoFree(I, SCCNodes); + }, + [](Function &F) { + LLVM_DEBUG(dbgs() + << "Adding nofree attr to fn " << F.getName() << "\n"); + F.setDoesNotFreeMemory(); + ++NumNoFree; + }, + /* RequiresExactDefinition= */ true}); + // Perform all the requested attribute inference actions. return AI.run(SCCNodes); } @@ -1322,7 +1370,8 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) { } template <typename AARGetterT> -static bool deriveAttrsInPostOrder(SCCNodeSet &SCCNodes, AARGetterT &&AARGetter, +static bool deriveAttrsInPostOrder(SCCNodeSet &SCCNodes, + AARGetterT &&AARGetter, bool HasUnknownCall) { bool Changed = false; @@ -1353,6 +1402,11 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C, FunctionAnalysisManager &FAM = AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); + const ModuleAnalysisManager &MAM = + AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C, CG).getManager(); + assert(C.size() > 0 && "Cannot handle an empty SCC!"); + Module &M = *C.begin()->getFunction().getParent(); + // We pass a lambda into functions to wire them up to the analysis manager // for getting function analyses. auto AARGetter = [&](Function &F) -> AAResults & { |