]> granicus.if.org Git - llvm/commitdiff
Revert "Revert r275027 - Let FuncAttrs infer the 'returned' argument attribute"
authorHal Finkel <hfinkel@anl.gov>
Sat, 16 Jul 2016 07:21:28 +0000 (07:21 +0000)
committerHal Finkel <hfinkel@anl.gov>
Sat, 16 Jul 2016 07:21:28 +0000 (07:21 +0000)
This reverts commit r275042; the initial commit triggered self-hosting failures
on ARM/AArch64. James Molloy identified the problematic backend code, which has
been disabled in r275677. Trying again...

Original commit message:

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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275678 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/IPO/FunctionAttrs.cpp
test/Transforms/FunctionAttrs/2009-01-02-LocalStores.ll
test/Transforms/FunctionAttrs/nocapture.ll
test/Transforms/FunctionAttrs/readattrs.ll

index fff5440854148d2a953e5d2beb7ca5e94c123be9..9c9e4822199ac36eb5f591e90901e63fe1af1f09 100644 (file)
@@ -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,53 @@ 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;
+
+    auto FindRetArg = [&]() -> Value * {
+      Value *RetArg = nullptr;
+      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)) {
+            if (!RetArg)
+              RetArg = RetVal;
+            else if (RetArg != RetVal)
+              return nullptr;
+          }
+        }
+
+      return RetArg;
+    };
+
+    if (Value *RetArg = FindRetArg()) {
+      auto *A = cast<Argument>(RetArg);
+      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 +1072,7 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
   }
 
   bool Changed = false;
+  Changed |= addArgumentReturnedAttrs(SCCNodes);
   Changed |= addReadAttrs(SCCNodes, AARGetter);
   Changed |= addArgumentAttrs(SCCNodes);
 
@@ -1089,6 +1138,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {
     SCCNodes.insert(F);
   }
 
+  Changed |= addArgumentReturnedAttrs(SCCNodes);
   Changed |= addReadAttrs(SCCNodes, AARGetter);
   Changed |= addArgumentAttrs(SCCNodes);
 
index ec1db095728355f78893a83f4727c663714e6d43..0d0231b42ae5fa27a85f4f9b8a2da6f5c26d1157 100644 (file)
@@ -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
index 020d8bcd4c76f5145b388af10ddce2549c13e348..e137a3800ce41a4c630efe70de70aa95cb664ea5 100644 (file)
@@ -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
index 65861a55fc2d711af8d25b2c34edcf6e5d0b1b5a..988557e27152811da9a38af9e7848b0785b75be7 100644 (file)
@@ -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