[llvm] r260319 - Add convergent-removing bits to FunctionAttrs pass.

Justin Lebar via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 9 15:03:23 PST 2016


Author: jlebar
Date: Tue Feb  9 17:03:22 2016
New Revision: 260319

URL: http://llvm.org/viewvc/llvm-project?rev=260319&view=rev
Log:
Add convergent-removing bits to FunctionAttrs pass.

Summary:
Remove the convergent attribute on any functions which provably do not
contain or invoke any convergent functions.

After this change, we'll be able to modify clang to conservatively add
'convergent' to all functions when compiling CUDA.

Reviewers:  jingyue, joker.eph

Subscribers: llvm-commits, tra, jhen, hfinkel, resistor, chandlerc, arsenm

Differential Revision: http://reviews.llvm.org/D17013

Added:
    llvm/trunk/test/Transforms/FunctionAttrs/convergent.ll
Modified:
    llvm/trunk/include/llvm/IR/Function.h
    llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp

Modified: llvm/trunk/include/llvm/IR/Function.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Function.h?rev=260319&r1=260318&r2=260319&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Function.h (original)
+++ llvm/trunk/include/llvm/IR/Function.h Tue Feb  9 17:03:22 2016
@@ -339,6 +339,9 @@ public:
   void setConvergent() {
     addFnAttr(Attribute::Convergent);
   }
+  void setNotConvergent() {
+    removeFnAttr(Attribute::Convergent);
+  }
 
   /// Determine if the function is known not to recurse, directly or
   /// indirectly.

Modified: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=260319&r1=260318&r2=260319&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp Tue Feb  9 17:03:22 2016
@@ -935,6 +935,68 @@ static bool addNonNullAttrs(const SCCNod
   return MadeChange;
 }
 
+/// Removes convergent attributes where we can prove that none of the SCC's
+/// callees are themselves convergent.  Returns true if successful at removing
+/// the attribute.
+static bool removeConvergentAttrs(const CallGraphSCC &SCC,
+                                  const SCCNodeSet &SCCNodes) {
+  // Determines whether a function can be made non-convergent, ignoring all
+  // other functions in SCC.  (A function can *actually* be made non-convergent
+  // only if all functions in its SCC can be made convergent.)
+  auto CanRemoveConvergent = [&] (CallGraphNode *CGN) {
+    Function *F = CGN->getFunction();
+    if (!F) return false;
+
+    if (!F->isConvergent()) return true;
+
+    // Can't remove convergent from declarations.
+    if (F->isDeclaration()) return false;
+
+    // Don't remove convergent from optnone functions.
+    if (F->hasFnAttribute(Attribute::OptimizeNone))
+      return false;
+
+    // Can't remove convergent if any of F's callees -- ignoring functions in the
+    // SCC itself -- are convergent.
+    if (llvm::any_of(*CGN, [&](const CallGraphNode::CallRecord &CR) {
+          Function *F = CR.second->getFunction();
+          return SCCNodes.count(F) == 0 && (!F || F->isConvergent());
+        }))
+      return false;
+
+    // CGN doesn't contain calls to intrinsics, so iterate over all of F's
+    // callsites, looking for any calls to convergent intrinsics.  If we find one,
+    // F must remain marked as convergent.
+    auto IsConvergentIntrinsicCall = [](Instruction &I) {
+      CallSite CS(cast<Value>(&I));
+      if (!CS)
+        return false;
+      Function *Callee = CS.getCalledFunction();
+      return Callee && Callee->isIntrinsic() && Callee->isConvergent();
+    };
+    return !llvm::any_of(*F, [=](BasicBlock &BB) {
+      return llvm::any_of(BB, IsConvergentIntrinsicCall);
+    });
+  };
+
+  // We can remove the convergent attr from functions in the SCC if they all can
+  // be made non-convergent (because they call only non-convergent functions,
+  // other than each other).
+  if (!llvm::all_of(SCC, CanRemoveConvergent)) return false;
+
+  // If we got here, all of the SCC's callees are non-convergent, and none of
+  // the optnone functions in the SCC are marked as convergent.  Therefore all
+  // of the SCC's functions can be marked as non-convergent.
+  for (CallGraphNode *CGN : SCC)
+    if (Function *F = CGN->getFunction()) {
+      if (F->isConvergent())
+        DEBUG(dbgs() << "Removing convergent attr from " << F->getName()
+                     << "\n");
+      F->setNotConvergent();
+    }
+  return true;
+}
+
 static bool setDoesNotRecurse(Function &F) {
   if (F.doesNotRecurse())
     return false;
@@ -1011,6 +1073,7 @@ bool PostOrderFunctionAttrs::runOnSCC(Ca
   if (!ExternalNode) {
     Changed |= addNoAliasAttrs(SCCNodes);
     Changed |= addNonNullAttrs(SCCNodes, *TLI);
+    Changed |= removeConvergentAttrs(SCC, SCCNodes);
   }
 
   Changed |= addNoRecurseAttrs(SCC);

Added: llvm/trunk/test/Transforms/FunctionAttrs/convergent.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/convergent.ll?rev=260319&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/FunctionAttrs/convergent.ll (added)
+++ llvm/trunk/test/Transforms/FunctionAttrs/convergent.ll Tue Feb  9 17:03:22 2016
@@ -0,0 +1,94 @@
+; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -S | FileCheck %s
+
+; CHECK: Function Attrs
+; CHECK-NOT: convergent
+; CHECK-NEXT: define i32 @nonleaf()
+define i32 @nonleaf() convergent {
+  %a = call i32 @leaf()
+  ret i32 %a
+}
+
+; CHECK: Function Attrs
+; CHECK-NOT: convergent
+; CHECK-NEXT: define i32 @leaf()
+define i32 @leaf() convergent {
+  ret i32 0
+}
+
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: declare i32 @k()
+declare i32 @k() convergent
+
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: define i32 @extern()
+define i32 @extern() convergent {
+  %a = call i32 @k()
+  ret i32 %a
+}
+
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: define i32 @call_extern()
+define i32 @call_extern() convergent {
+  %a = call i32 @extern()
+  ret i32 %a
+}
+
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: declare void @llvm.cuda.syncthreads()
+declare void @llvm.cuda.syncthreads() convergent
+
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: define i32 @intrinsic()
+define i32 @intrinsic() convergent {
+  call void @llvm.cuda.syncthreads()
+  ret i32 0
+}
+
+ at xyz = global i32 ()* null
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: define i32 @functionptr()
+define i32 @functionptr() convergent {
+  %1 = load i32 ()*, i32 ()** @xyz
+  %2 = call i32 %1()
+  ret i32 %2
+}
+
+; CHECK: Function Attrs
+; CHECK-NOT: convergent
+; CHECK-NEXT: define i32 @recursive1()
+define i32 @recursive1() convergent {
+  %a = call i32 @recursive2()
+  ret i32 %a
+}
+
+; CHECK: Function Attrs
+; CHECK-NOT: convergent
+; CHECK-NEXT: define i32 @recursive2()
+define i32 @recursive2() convergent {
+  %a = call i32 @recursive1()
+  ret i32 %a
+}
+
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: define i32 @noopt()
+define i32 @noopt() convergent optnone noinline {
+  %a = call i32 @noopt_friend()
+  ret i32 0
+}
+
+; A function which is mutually-recursive with a convergent, optnone function
+; shouldn't have its convergent attribute stripped.
+; CHECK: Function Attrs
+; CHECK-SAME: convergent
+; CHECK-NEXT: define i32 @noopt_friend()
+define i32 @noopt_friend() convergent {
+  %a = call i32 @noopt()
+  ret i32 0
+}




More information about the llvm-commits mailing list