summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHal Finkel <hfinkel@anl.gov>2016-07-10 22:02:55 +0000
committerHal Finkel <hfinkel@anl.gov>2016-07-10 22:02:55 +0000
commitd66a7b05dbdc42f9894e0ef5bbba4ff8c37d1e6d (patch)
treef6a5c8bc9aa0a504c36868e479401c9a3d31e7ca
parent3b66caa290ab1dbf96b5fea74f12d59452794adf (diff)
downloadbcm5719-llvm-d66a7b05dbdc42f9894e0ef5bbba4ff8c37d1e6d.tar.gz
bcm5719-llvm-d66a7b05dbdc42f9894e0ef5bbba4ff8c37d1e6d.zip
Let FuncAttrs infer the 'returned' argument attribute
A function can have one argument with the 'returned' attribute, indicating that the associated argument is always the return value of the function. Add FuncAttrs inference logic. Differential Revision: http://reviews.llvm.org/D22202 llvm-svn: 275027
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp42
-rw-r--r--llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll2
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nocapture.ll6
-rw-r--r--llvm/test/Transforms/FunctionAttrs/readattrs.ll4
4 files changed, 48 insertions, 6 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index fff54408541..3f87a1b233f 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -42,6 +42,7 @@ using namespace llvm;
STATISTIC(NumReadNone, "Number of functions marked readnone");
STATISTIC(NumReadOnly, "Number of functions marked readonly");
STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
+STATISTIC(NumReturned, "Number of arguments marked returned");
STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
STATISTIC(NumNoAlias, "Number of function returns marked noalias");
@@ -483,6 +484,45 @@ determinePointerReadAttrs(Argument *A,
return IsRead ? Attribute::ReadOnly : Attribute::ReadNone;
}
+/// Deduce returned attributes for the SCC.
+static bool addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes) {
+ bool Changed = false;
+
+ AttrBuilder B;
+ B.addAttribute(Attribute::Returned);
+
+ // Check each function in turn, determining if an argument is always returned.
+ for (Function *F : SCCNodes) {
+ // We can infer and propagate function attributes only when we know that the
+ // definition we'll get at link time is *exactly* the definition we see now.
+ // For more details, see GlobalValue::mayBeDerefined.
+ if (!F->hasExactDefinition())
+ continue;
+
+ if (F->getReturnType()->isVoidTy())
+ continue;
+
+ SmallPtrSet<Value *, 2> RetArgs;
+ for (BasicBlock &BB : *F)
+ if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
+ // Note that stripPointerCasts should look through functions with
+ // returned arguments.
+ Value *RetVal = Ret->getReturnValue()->stripPointerCasts();
+ if (RetVal->getType() == F->getReturnType() && isa<Argument>(RetVal))
+ RetArgs.insert(RetVal);
+ }
+
+ if (RetArgs.size() == 1) {
+ auto *A = cast<Argument>(*RetArgs.begin());
+ A->addAttr(AttributeSet::get(F->getContext(), A->getArgNo() + 1, B));
+ ++NumReturned;
+ Changed = true;
+ }
+ }
+
+ return Changed;
+}
+
/// Deduce nocapture attributes for the SCC.
static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
bool Changed = false;
@@ -1024,6 +1064,7 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
}
bool Changed = false;
+ Changed |= addArgumentReturnedAttrs(SCCNodes);
Changed |= addReadAttrs(SCCNodes, AARGetter);
Changed |= addArgumentAttrs(SCCNodes);
@@ -1089,6 +1130,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {
SCCNodes.insert(F);
}
+ Changed |= addArgumentReturnedAttrs(SCCNodes);
Changed |= addReadAttrs(SCCNodes, AARGetter);
Changed |= addArgumentAttrs(SCCNodes);
diff --git a/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll b/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
index ec1db095728..0d0231b42ae 100644
--- a/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
+++ b/llvm/test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
@@ -14,7 +14,7 @@ define i32* @b(i32 *%q) {
ret i32* %tmp
}
-; CHECK: define i32* @c(i32* readnone %r)
+; CHECK: define i32* @c(i32* readnone returned %r)
@g = global i32 0
define i32* @c(i32 *%r) {
%a = icmp eq i32* %r, null
diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
index 020d8bcd4c7..e137a3800ce 100644
--- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll
@@ -1,7 +1,7 @@
; RUN: opt < %s -functionattrs -S | FileCheck %s
@g = global i32* null ; <i32**> [#uses=1]
-; CHECK: define i32* @c1(i32* readnone %q)
+; CHECK: define i32* @c1(i32* readnone returned %q)
define i32* @c1(i32* %q) {
ret i32* %q
}
@@ -140,7 +140,7 @@ define void @test1_1(i8* %x1_1, i8* %y1_1) {
ret void
}
-; CHECK: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* %y1_2)
+; CHECK: define i8* @test1_2(i8* nocapture readnone %x1_2, i8* returned %y1_2)
define i8* @test1_2(i8* %x1_2, i8* %y1_2) {
call void @test1_1(i8* %x1_2, i8* %y1_2)
store i32* null, i32** @g
@@ -168,7 +168,7 @@ define void @test4_1(i8* %x4_1) {
ret void
}
-; CHECK: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone %y4_2, i8* nocapture readnone %z4_2)
+; CHECK: define i8* @test4_2(i8* nocapture readnone %x4_2, i8* readnone returned %y4_2, i8* nocapture readnone %z4_2)
define i8* @test4_2(i8* %x4_2, i8* %y4_2, i8* %z4_2) {
call void @test4_1(i8* null)
store i32* null, i32** @g
diff --git a/llvm/test/Transforms/FunctionAttrs/readattrs.ll b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
index 65861a55fc2..988557e2715 100644
--- a/llvm/test/Transforms/FunctionAttrs/readattrs.ll
+++ b/llvm/test/Transforms/FunctionAttrs/readattrs.ll
@@ -11,7 +11,7 @@ define void @test1_2(i8* %x1_2, i8* %y1_2, i8* %z1_2) {
ret void
}
-; CHECK: define i8* @test2(i8* readnone %p)
+; CHECK: define i8* @test2(i8* readnone returned %p)
define i8* @test2(i8* %p) {
store i32 0, i32* @x
ret i8* %p
@@ -53,7 +53,7 @@ define void @test7_1(i32* inalloca %a) {
ret void
}
-; CHECK: define i32* @test8_1(i32* readnone %p)
+; CHECK: define i32* @test8_1(i32* readnone returned %p)
define i32* @test8_1(i32* %p) {
entry:
ret i32* %p
OpenPOWER on IntegriCloud