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 | |
| 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')
| -rw-r--r-- | llvm/lib/Analysis/MemoryBuiltins.cpp | 55 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLLexer.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLToken.h | 1 | ||||
| -rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 4 | ||||
| -rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/IR/Attributes.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/IR/Verifier.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 56 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 11 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 |
11 files changed, 116 insertions, 19 deletions
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index 08254266482..d73419fad6a 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -263,6 +263,19 @@ bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI, return getAllocationData(V, AllocLike, TLI, LookThroughBitCast).hasValue(); } +/// Tests if a value is a call or invoke to a library function that +/// reallocates memory (e.g., realloc). +bool llvm::isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI, + bool LookThroughBitCast) { + return getAllocationData(V, ReallocLike, TLI, LookThroughBitCast).hasValue(); +} + +/// Tests if a functions is a call or invoke to a library function that +/// reallocates memory (e.g., realloc). +bool llvm::isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI) { + return getAllocationDataForFunction(F, ReallocLike, TLI).hasValue(); +} + /// extractMallocCall - Returns the corresponding CallInst if the instruction /// is a malloc call. Since CallInst::CreateMalloc() only creates calls, we /// ignore InvokeInst here. @@ -358,19 +371,8 @@ const CallInst *llvm::extractCallocCall(const Value *I, return isCallocLikeFn(I, TLI) ? cast<CallInst>(I) : nullptr; } -/// isFreeCall - Returns non-null if the value is a call to the builtin free() -const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { - bool IsNoBuiltinCall; - const Function *Callee = - getCalledFunction(I, /*LookThroughBitCast=*/false, IsNoBuiltinCall); - if (Callee == nullptr || IsNoBuiltinCall) - return nullptr; - - StringRef FnName = Callee->getName(); - LibFunc TLIFn; - if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) - return nullptr; - +/// isLibFreeFunction - Returns true if the function is a builtin free() +bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { unsigned ExpectedNumParams; if (TLIFn == LibFunc_free || TLIFn == LibFunc_ZdlPv || // operator delete(void*) @@ -401,22 +403,39 @@ const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { TLIFn == LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t) // delete[](void*, align_val_t, nothrow) ExpectedNumParams = 3; else - return nullptr; + return false; // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin // attribute will exist. - FunctionType *FTy = Callee->getFunctionType(); + FunctionType *FTy = F->getFunctionType(); if (!FTy->getReturnType()->isVoidTy()) - return nullptr; + return false; if (FTy->getNumParams() != ExpectedNumParams) + return false; + if (FTy->getParamType(0) != Type::getInt8PtrTy(F->getContext())) + return false; + + return true; +} + +/// isFreeCall - Returns non-null if the value is a call to the builtin free() +const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { + bool IsNoBuiltinCall; + const Function *Callee = + getCalledFunction(I, /*LookThroughBitCast=*/false, IsNoBuiltinCall); + if (Callee == nullptr || IsNoBuiltinCall) return nullptr; - if (FTy->getParamType(0) != Type::getInt8PtrTy(Callee->getContext())) + + StringRef FnName = Callee->getName(); + LibFunc TLIFn; + if (!TLI || !TLI->getLibFunc(FnName, TLIFn) || !TLI->has(TLIFn)) return nullptr; - return dyn_cast<CallInst>(I); + return isLibFreeFunction(Callee, TLIFn) ? dyn_cast<CallInst>(I) : nullptr; } + //===----------------------------------------------------------------------===// // Utility functions to compute size of objects. // diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index a23afac27b7..5bc628dac1f 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -650,6 +650,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(nobuiltin); KEYWORD(nocapture); KEYWORD(noduplicate); + KEYWORD(nofree); KEYWORD(noimplicitfloat); KEYWORD(noinline); KEYWORD(norecurse); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 085f3bd2999..1256e632551 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1280,6 +1280,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B, case lltok::kw_naked: B.addAttribute(Attribute::Naked); break; case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin); break; case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break; + case lltok::kw_nofree: B.addAttribute(Attribute::NoFree); break; case lltok::kw_noimplicitfloat: B.addAttribute(Attribute::NoImplicitFloat); break; case lltok::kw_noinline: B.addAttribute(Attribute::NoInline); break; diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 8b0118e6942..a6a81865cb7 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -195,6 +195,7 @@ enum Kind { kw_nobuiltin, kw_nocapture, kw_noduplicate, + kw_nofree, kw_noimplicitfloat, kw_noinline, kw_norecurse, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index a339f6eb710..0ba76f0f371 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1278,6 +1278,8 @@ static uint64_t getRawAttributeMask(Attribute::AttrKind Val) { return 1ULL << 61; case Attribute::WillReturn: return 1ULL << 62; + case Attribute::NoFree: + return 1ULL << 63; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; @@ -1442,6 +1444,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::NoCapture; case bitc::ATTR_KIND_NO_DUPLICATE: return Attribute::NoDuplicate; + case bitc::ATTR_KIND_NOFREE: + return Attribute::NoFree; case bitc::ATTR_KIND_NO_IMPLICIT_FLOAT: return Attribute::NoImplicitFloat; case bitc::ATTR_KIND_NO_INLINE: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 547889f82c7..65b9e0bb6a1 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -639,6 +639,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_NO_CAPTURE; case Attribute::NoDuplicate: return bitc::ATTR_KIND_NO_DUPLICATE; + case Attribute::NoFree: + return bitc::ATTR_KIND_NOFREE; case Attribute::NoImplicitFloat: return bitc::ATTR_KIND_NO_IMPLICIT_FLOAT; case Attribute::NoInline: diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index 99fc447c5af..0073eda0838 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -321,6 +321,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return "nocapture"; if (hasAttribute(Attribute::NoDuplicate)) return "noduplicate"; + if (hasAttribute(Attribute::NoFree)) + return "nofree"; if (hasAttribute(Attribute::NoImplicitFloat)) return "noimplicitfloat"; if (hasAttribute(Attribute::NoInline)) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index b0464346557..2655e3ce81e 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1497,6 +1497,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { case Attribute::NoCfCheck: case Attribute::NoUnwind: case Attribute::NoInline: + case Attribute::NoFree: case Attribute::AlwaysInline: case Attribute::OptimizeForSize: case Attribute::StackProtect: 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 & { diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index d486d915998..27f110e24f9 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -22,6 +22,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/Analysis/MemoryBuiltins.h" using namespace llvm; @@ -120,6 +121,13 @@ static bool setNonLazyBind(Function &F) { return true; } +static bool setDoesNotFreeMemory(Function &F) { + if (F.hasFnAttribute(Attribute::NoFree)) + return false; + F.addFnAttr(Attribute::NoFree); + return true; +} + bool llvm::inferLibFuncAttributes(Module *M, StringRef Name, const TargetLibraryInfo &TLI) { Function *F = M->getFunction(Name); @@ -135,6 +143,9 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { bool Changed = false; + if(!isLibFreeFunction(&F, TheLibFunc) && !isReallocLikeFn(&F, &TLI)) + Changed |= setDoesNotFreeMemory(F); + if (F.getParent() != nullptr && F.getParent()->getRtLibUseGOT()) Changed |= setNonLazyBind(F); diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 23a404c11a6..c9e9033d9c1 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -814,6 +814,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::InlineHint: case Attribute::MinSize: case Attribute::NoDuplicate: + case Attribute::NoFree: case Attribute::NoImplicitFloat: case Attribute::NoInline: case Attribute::NonLazyBind: |

