aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/FunctionAttrs.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Transforms/IPO/FunctionAttrs.cpp
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Diffstat (limited to 'lib/Transforms/IPO/FunctionAttrs.cpp')
-rw-r--r--lib/Transforms/IPO/FunctionAttrs.cpp73
1 files changed, 61 insertions, 12 deletions
diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp
index 4e2a82b56eec..5ccd8bc4b0fb 100644
--- a/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -1,9 +1,8 @@
//===- FunctionAttrs.cpp - Pass which marks functions attributes ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -28,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"
@@ -76,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:
@@ -89,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>;
@@ -256,12 +261,15 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
}
}
+ // If the SCC contains both functions that read and functions that write, then
+ // we cannot add readonly attributes.
+ if (ReadsMemory && WritesMemory)
+ return false;
+
// Success! Functions in this SCC do not access memory, or only read memory.
// Give them the appropriate attribute.
bool MadeChange = false;
- assert(!(ReadsMemory && WritesMemory) &&
- "Function marked read-only and write-only");
for (Function *F : SCCNodes) {
if (F->doesNotAccessMemory())
// Already perfect!
@@ -1228,6 +1236,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:
@@ -1281,6 +1308,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);
}
@@ -1301,7 +1351,7 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
return false;
Function *F = *SCCNodes.begin();
- if (!F || F->isDeclaration() || F->doesNotRecurse())
+ if (!F || !F->hasExactDefinition() || F->doesNotRecurse())
return false;
// If all of the calls in F are identifiable and are to norecurse functions, F
@@ -1323,7 +1373,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;
@@ -1367,8 +1418,7 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
bool HasUnknownCall = false;
for (LazyCallGraph::Node &N : C) {
Function &F = N.getFunction();
- if (F.hasFnAttribute(Attribute::OptimizeNone) ||
- F.hasFnAttribute(Attribute::Naked)) {
+ if (F.hasOptNone() || F.hasFnAttribute(Attribute::Naked)) {
// Treat any function we're trying not to optimize as if it were an
// indirect call and omit it from the node set used below.
HasUnknownCall = true;
@@ -1441,8 +1491,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {
bool ExternalNode = false;
for (CallGraphNode *I : SCC) {
Function *F = I->getFunction();
- if (!F || F->hasFnAttribute(Attribute::OptimizeNone) ||
- F->hasFnAttribute(Attribute::Naked)) {
+ if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked)) {
// External node or function we're trying not to optimize - we both avoid
// transform them and avoid leveraging information they provide.
ExternalNode = true;