aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/IPO/FunctionAttrs.cpp')
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp149
1 files changed, 103 insertions, 46 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index cf56f67..4445d56 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -71,7 +71,9 @@ using namespace llvm;
#define DEBUG_TYPE "function-attrs"
STATISTIC(NumMemoryAttr, "Number of functions with improved memory attribute");
-STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
+STATISTIC(NumCapturesNone, "Number of arguments marked captures(none)");
+STATISTIC(NumCapturesPartial, "Number of arguments marked with captures "
+ "attribute other than captures(none)");
STATISTIC(NumReturned, "Number of arguments marked returned");
STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
@@ -108,6 +110,13 @@ static cl::opt<bool> DisableThinLTOPropagation(
"disable-thinlto-funcattrs", cl::init(true), cl::Hidden,
cl::desc("Don't propagate function-attrs in thinLTO"));
+static void addCapturesStat(CaptureInfo CI) {
+ if (capturesNothing(CI))
+ ++NumCapturesNone;
+ else
+ ++NumCapturesPartial;
+}
+
namespace {
using SCCNodeSet = SmallSetVector<Function *, 8>;
@@ -494,6 +503,9 @@ namespace {
/// SCC of the arguments.
struct ArgumentGraphNode {
Argument *Definition;
+ /// CaptureComponents for this argument, excluding captures via Uses.
+ /// We don't distinguish between other/return captures here.
+ CaptureComponents CC = CaptureComponents::None;
SmallVector<ArgumentGraphNode *, 4> Uses;
};
@@ -535,18 +547,36 @@ public:
struct ArgumentUsesTracker : public CaptureTracker {
ArgumentUsesTracker(const SCCNodeSet &SCCNodes) : SCCNodes(SCCNodes) {}
- void tooManyUses() override { Captured = true; }
+ void tooManyUses() override { CI = CaptureInfo::all(); }
+
+ Action captured(const Use *U, UseCaptureInfo UseCI) override {
+ if (updateCaptureInfo(U, UseCI.UseCC)) {
+ // Don't bother continuing if we already capture everything.
+ if (capturesAll(CI.getOtherComponents()))
+ return Stop;
+ return Continue;
+ }
+
+ // For SCC argument tracking, we're not going to analyze other/ret
+ // components separately, so don't follow the return value.
+ return ContinueIgnoringReturn;
+ }
- bool captured(const Use *U) override {
+ bool updateCaptureInfo(const Use *U, CaptureComponents CC) {
CallBase *CB = dyn_cast<CallBase>(U->getUser());
if (!CB) {
- Captured = true;
+ if (isa<ReturnInst>(U->getUser()))
+ CI |= CaptureInfo::retOnly(CC);
+ else
+ // Conservatively assume that the captured value might make its way
+ // into the return value as well. This could be made more precise.
+ CI |= CaptureInfo(CC);
return true;
}
Function *F = CB->getCalledFunction();
if (!F || !F->hasExactDefinition() || !SCCNodes.count(F)) {
- Captured = true;
+ CI |= CaptureInfo(CC);
return true;
}
@@ -560,22 +590,24 @@ struct ArgumentUsesTracker : public CaptureTracker {
// use. In this case it does not matter if the callee is within our SCC
// or not -- we've been captured in some unknown way, and we have to be
// conservative.
- Captured = true;
+ CI |= CaptureInfo(CC);
return true;
}
if (UseIndex >= F->arg_size()) {
assert(F->isVarArg() && "More params than args in non-varargs call");
- Captured = true;
+ CI |= CaptureInfo(CC);
return true;
}
+ // TODO(captures): Could improve precision by remembering maximum
+ // capture components for the argument.
Uses.push_back(&*std::next(F->arg_begin(), UseIndex));
return false;
}
- // True only if certainly captured (used outside our SCC).
- bool Captured = false;
+ // Does not include potential captures via Uses in the SCC.
+ CaptureInfo CI = CaptureInfo::none();
// Uses within our SCC.
SmallVector<Argument *, 4> Uses;
@@ -1190,6 +1222,15 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
bool SkipInitializes) {
ArgumentGraph AG;
+ auto DetermineAccessAttrsForSingleton = [](Argument *A) {
+ SmallPtrSet<Argument *, 8> Self;
+ Self.insert(A);
+ Attribute::AttrKind R = determinePointerAccessAttrs(A, Self);
+ if (R != Attribute::None)
+ return addAccessAttr(A, R);
+ return false;
+ };
+
// Check each function in turn, determining which pointer arguments are not
// captured.
for (Function *F : SCCNodes) {
@@ -1210,7 +1251,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (A.getType()->isPointerTy() && !A.hasNoCaptureAttr()) {
A.addAttr(Attribute::getWithCaptureInfo(A.getContext(),
CaptureInfo::none()));
- ++NumNoCapture;
+ ++NumCapturesNone;
Changed.insert(F);
}
}
@@ -1221,21 +1262,23 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (!A.getType()->isPointerTy())
continue;
bool HasNonLocalUses = false;
- if (!A.hasNoCaptureAttr()) {
+ CaptureInfo OrigCI = A.getAttributes().getCaptureInfo();
+ if (!capturesNothing(OrigCI)) {
ArgumentUsesTracker Tracker(SCCNodes);
PointerMayBeCaptured(&A, &Tracker);
- if (!Tracker.Captured) {
+ CaptureInfo NewCI = Tracker.CI & OrigCI;
+ if (NewCI != OrigCI) {
if (Tracker.Uses.empty()) {
- // If it's trivially not captured, mark it nocapture now.
- A.addAttr(Attribute::getWithCaptureInfo(A.getContext(),
- CaptureInfo::none()));
- ++NumNoCapture;
+ // If the information is complete, add the attribute now.
+ A.addAttr(Attribute::getWithCaptureInfo(A.getContext(), NewCI));
+ addCapturesStat(NewCI);
Changed.insert(F);
} else {
// If it's not trivially captured and not trivially not captured,
// then it must be calling into another function in our SCC. Save
// its particulars for Argument-SCC analysis later.
ArgumentGraphNode *Node = AG[&A];
+ Node->CC = CaptureComponents(NewCI);
for (Argument *Use : Tracker.Uses) {
Node->Uses.push_back(AG[Use]);
if (Use != &A)
@@ -1250,12 +1293,8 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
// an SCC? Note that we don't allow any calls at all here, or else our
// result will be dependent on the iteration order through the
// functions in the SCC.
- SmallPtrSet<Argument *, 8> Self;
- Self.insert(&A);
- Attribute::AttrKind R = determinePointerAccessAttrs(&A, Self);
- if (R != Attribute::None)
- if (addAccessAttr(&A, R))
- Changed.insert(F);
+ if (DetermineAccessAttrsForSingleton(&A))
+ Changed.insert(F);
}
if (!SkipInitializes && !A.onlyReadsMemory()) {
if (inferInitializes(A, *F))
@@ -1281,17 +1320,17 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (ArgumentSCC[0]->Uses.size() == 1 &&
ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
Argument *A = ArgumentSCC[0]->Definition;
- A->addAttr(Attribute::getWithCaptureInfo(A->getContext(),
- CaptureInfo::none()));
- ++NumNoCapture;
- Changed.insert(A->getParent());
-
- // Infer the access attributes given the new nocapture one
- SmallPtrSet<Argument *, 8> Self;
- Self.insert(&*A);
- Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
- if (R != Attribute::None)
- addAccessAttr(A, R);
+ CaptureInfo OrigCI = A->getAttributes().getCaptureInfo();
+ CaptureInfo NewCI = CaptureInfo(ArgumentSCC[0]->CC) & OrigCI;
+ if (NewCI != OrigCI) {
+ A->addAttr(Attribute::getWithCaptureInfo(A->getContext(), NewCI));
+ addCapturesStat(NewCI);
+ Changed.insert(A->getParent());
+ }
+
+ // Infer the access attributes given the new captures one
+ if (DetermineAccessAttrsForSingleton(A))
+ Changed.insert(A->getParent());
}
continue;
}
@@ -1303,27 +1342,45 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
ArgumentSCCNodes.insert(I->Definition);
}
- bool SCCCaptured = false;
+ // At the SCC level, only track merged CaptureComponents. We're not
+ // currently prepared to handle propagation of return-only captures across
+ // the SCC.
+ CaptureComponents CC = CaptureComponents::None;
for (ArgumentGraphNode *N : ArgumentSCC) {
for (ArgumentGraphNode *Use : N->Uses) {
Argument *A = Use->Definition;
- if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A))
- continue;
- SCCCaptured = true;
+ if (ArgumentSCCNodes.count(A))
+ CC |= Use->CC;
+ else
+ CC |= CaptureComponents(A->getAttributes().getCaptureInfo());
break;
}
- if (SCCCaptured)
+ if (capturesAll(CC))
break;
}
- if (SCCCaptured)
- continue;
- for (ArgumentGraphNode *N : ArgumentSCC) {
- Argument *A = N->Definition;
- A->addAttr(
- Attribute::getWithCaptureInfo(A->getContext(), CaptureInfo::none()));
- ++NumNoCapture;
- Changed.insert(A->getParent());
+ if (!capturesAll(CC)) {
+ for (ArgumentGraphNode *N : ArgumentSCC) {
+ Argument *A = N->Definition;
+ CaptureInfo OrigCI = A->getAttributes().getCaptureInfo();
+ CaptureInfo NewCI = CaptureInfo(N->CC | CC) & OrigCI;
+ if (NewCI != OrigCI) {
+ A->addAttr(Attribute::getWithCaptureInfo(A->getContext(), NewCI));
+ addCapturesStat(NewCI);
+ Changed.insert(A->getParent());
+ }
+ }
+ }
+
+ // TODO(captures): Ignore address-only captures.
+ if (capturesAnything(CC)) {
+ // As the pointer may be captured, determine the pointer attributes
+ // looking at each argument invidivually.
+ for (ArgumentGraphNode *N : ArgumentSCC) {
+ if (DetermineAccessAttrsForSingleton(N->Definition))
+ Changed.insert(N->Definition->getParent());
+ }
+ continue;
}
// We also want to compute readonly/readnone/writeonly. With a small number