[llvm] r260813 - [attrs] Move the norecurse deduction to operate on the node set rather

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 13 00:47:52 PST 2016


Author: chandlerc
Date: Sat Feb 13 02:47:51 2016
New Revision: 260813

URL: http://llvm.org/viewvc/llvm-project?rev=260813&view=rev
Log:
[attrs] Move the norecurse deduction to operate on the node set rather
than the SCC object, and have it scan the instruction stream directly
rather than relying on call records.

This makes the behavior of this routine consistent between libc routines
and LLVM intrinsics for libc routines. We can go and start teaching it
about those being norecurse, but we should behave the same for the
intrinsic and the libc routine rather than differently. I chatted with
James Molloy and the inconsistency doesn't seem intentional and likely
is due to intrinsic calls not being modelled in the call graph analyses.

This also fixes a bug where we would deduce norecurse on optnone
functions, when generally we try to handle optnone functions as-if they
were replaceable and thus unanalyzable.

Modified:
    llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
    llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
    llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll
    llvm/trunk/test/Transforms/FunctionAttrs/optnone.ll

Modified: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=260813&r1=260812&r2=260813&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp Sat Feb 13 02:47:51 2016
@@ -991,31 +991,32 @@ static bool setDoesNotRecurse(Function &
   return true;
 }
 
-static bool addNoRecurseAttrs(const CallGraphSCC &SCC) {
+static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
   // Try and identify functions that do not recurse.
 
   // If the SCC contains multiple nodes we know for sure there is recursion.
-  if (!SCC.isSingular())
+  if (SCCNodes.size() != 1)
     return false;
 
-  const CallGraphNode *CGN = *SCC.begin();
-  Function *F = CGN->getFunction();
+  Function *F = *SCCNodes.begin();
   if (!F || F->isDeclaration() || F->doesNotRecurse())
     return false;
 
   // If all of the calls in F are identifiable and are to norecurse functions, F
   // is norecurse. This check also detects self-recursion as F is not currently
   // marked norecurse, so any called from F to F will not be marked norecurse.
-  if (std::all_of(CGN->begin(), CGN->end(),
-                  [](const CallGraphNode::CallRecord &CR) {
-                    Function *F = CR.second->getFunction();
-                    return F && F->doesNotRecurse();
-                  }))
-    // Function calls a potentially recursive function.
-    return setDoesNotRecurse(*F);
+  for (Instruction &I : instructions(*F))
+    if (auto CS = CallSite(&I)) {
+      Function *Callee = CS.getCalledFunction();
+      if (!Callee || Callee == F || !Callee->doesNotRecurse())
+        // Function calls a potentially recursive function.
+        return false;
+    }
 
-  // Nothing else we can deduce usefully during the postorder traversal.
-  return false;
+  // Every call was to a non-recursive function other than this function, and
+  // we have no indirect recursion as the SCC size is one. This function cannot
+  // recurse.
+  return setDoesNotRecurse(*F);
 }
 
 bool PostOrderFunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
@@ -1060,9 +1061,9 @@ bool PostOrderFunctionAttrs::runOnSCC(Ca
     Changed |= addNoAliasAttrs(SCCNodes);
     Changed |= addNonNullAttrs(SCCNodes, *TLI);
     Changed |= removeConvergentAttrs(SCCNodes);
+    Changed |= addNoRecurseAttrs(SCCNodes);
   }
 
-  Changed |= addNoRecurseAttrs(SCC);
   return Changed;
 }
 

Modified: llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll?rev=260813&r1=260812&r2=260813&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll (original)
+++ llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll Sat Feb 13 02:47:51 2016
@@ -43,13 +43,13 @@ define void @test1_no(i32* %p) nounwind
 ; This is unusual, since the function is memcpy, but as above, this
 ; isn't necessarily invalid.
 
-; CHECK: define void @test2_yes(i8* nocapture %p, i8* nocapture %q, i64 %n) #0 {
+; CHECK: define void @test2_yes(i8* nocapture %p, i8* nocapture %q, i64 %n) #4 {
 define void @test2_yes(i8* %p, i8* %q, i64 %n) nounwind {
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 %n, i32 1, i1 false), !tbaa !1
   ret void
 }
 
-; CHECK: define void @test2_no(i8* nocapture %p, i8* nocapture readonly %q, i64 %n) #1 {
+; CHECK: define void @test2_no(i8* nocapture %p, i8* nocapture readonly %q, i64 %n) #3 {
 define void @test2_no(i8* %p, i8* %q, i64 %n) nounwind {
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %p, i8* %q, i64 %n, i32 1, i1 false), !tbaa !2
   ret void
@@ -76,7 +76,8 @@ declare void @llvm.memcpy.p0i8.p0i8.i64(
 ; CHECK: attributes #1 = { norecurse nounwind }
 ; CHECK: attributes #2 = { nounwind readonly }
 ; CHECK: attributes #3 = { nounwind }
-; CHECK: attributes #4 = { argmemonly nounwind }
+; CHECK: attributes #4 = { nounwind readnone }
+; CHECK: attributes #5 = { argmemonly nounwind }
 
 ; Root note.
 !0 = !{ }

Modified: llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll?rev=260813&r1=260812&r2=260813&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/norecurse.ll Sat Feb 13 02:47:51 2016
@@ -29,6 +29,13 @@ define i32 @extern() {
 }
 declare i32 @k() readnone
 
+; CHECK: define void @intrinsic(i8* nocapture %dest, i8* nocapture readonly %src, i32 %len) {
+define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
+  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i32 1, i1 false)
+  ret void
+}
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
+
 ; CHECK: define internal i32 @called_by_norecurse() #0
 define internal i32 @called_by_norecurse() {
   %a = call i32 @k()

Modified: llvm/trunk/test/Transforms/FunctionAttrs/optnone.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/optnone.ll?rev=260813&r1=260812&r2=260813&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/optnone.ll (original)
+++ llvm/trunk/test/Transforms/FunctionAttrs/optnone.ll Sat Feb 13 02:47:51 2016
@@ -16,11 +16,9 @@ define void @test_optnone(i8* %p) noinli
 
 declare i8 @strlen(i8*) noinline optnone
 ; CHECK-LABEL: @strlen
-; CHECK: (i8*) #2
+; CHECK: (i8*) #1
 
 ; CHECK-LABEL: attributes #0
 ; CHECK: = { norecurse readnone }
 ; CHECK-LABEL: attributes #1
-; CHECK: = { noinline norecurse optnone }
-; CHECK-LABEL: attributes #2
 ; CHECK: = { noinline optnone }




More information about the llvm-commits mailing list