summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
authorJustin Lebar <jlebar@google.com>2016-03-14 20:18:54 +0000
committerJustin Lebar <jlebar@google.com>2016-03-14 20:18:54 +0000
commit9d943978599267b458d55ef0be0c3f5253aa0455 (patch)
treeb4bc98e3be20bb028f757e06156a543539f0fe6f /llvm/lib/Transforms
parentca35b090f808b6f079eb846e4bddaa889011f37d (diff)
downloadbcm5719-llvm-9d943978599267b458d55ef0be0c3f5253aa0455.tar.gz
bcm5719-llvm-9d943978599267b458d55ef0be0c3f5253aa0455.zip
[attrs] Handle convergent CallSites.
Summary: Previously we had a notion of convergent functions but not of convergent calls. This is insufficient to correctly analyze calls where the target is unknown, e.g. indirect calls. Now a call is convergent if it targets a known-convergent function, or if it's explicitly marked as convergent. As usual, we can remove convergent where we can prove that no convergent operations are performed in the call. Originally landed as r261544, then reverted in r261544 for (incidental) build breakage. Re-landed here with no changes. Reviewers: chandlerc, jingyue Subscribers: llvm-commits, tra, jhen, hfinkel Differential Revision: http://reviews.llvm.org/D17739 llvm-svn: 263481
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp73
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp11
2 files changed, 44 insertions, 40 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 7885ec7d612..b145771b40a 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -903,49 +903,44 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes,
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.
+/// Remove the convergent attribute from all functions in the SCC if every
+/// callsite within the SCC is not convergent (except for calls to functions
+/// within the SCC). Returns true if changes were made.
static bool removeConvergentAttrs(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 = [&](Function *F) {
- if (!F->isConvergent())
- return true;
-
- // Can't remove convergent from declarations.
- if (F->isDeclaration())
- return false;
-
- for (Instruction &I : instructions(*F))
- if (auto CS = CallSite(&I)) {
- // Can't remove convergent if any of F's callees -- ignoring functions
- // in the SCC itself -- are convergent. This needs to consider both
- // function calls and intrinsic calls. We also assume indirect calls
- // might call a convergent function.
- // FIXME: We should revisit this when we put convergent onto calls
- // instead of functions so that indirect calls which should be
- // convergent are required to be marked as such.
- Function *Callee = CS.getCalledFunction();
- if (!Callee || (SCCNodes.count(Callee) == 0 && Callee->isConvergent()))
- return false;
- }
-
- return true;
- };
+ // For every function in SCC, ensure that either
+ // * it is not convergent, or
+ // * we can remove its convergent attribute.
+ bool HasConvergentFn = false;
+ for (Function *F : SCCNodes) {
+ if (!F->isConvergent()) continue;
+ HasConvergentFn = true;
+
+ // Can't remove convergent from function declarations.
+ if (F->isDeclaration()) return false;
+
+ // Can't remove convergent if any of our functions has a convergent call to a
+ // function not in the SCC.
+ for (Instruction &I : instructions(*F)) {
+ CallSite CS(&I);
+ // Bail if CS is a convergent call to a function not in the SCC.
+ if (CS && CS.isConvergent() &&
+ SCCNodes.count(CS.getCalledFunction()) == 0)
+ return false;
+ }
+ }
- // 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(SCCNodes, CanRemoveConvergent))
- return false;
+ // If the SCC doesn't have any convergent functions, we have nothing to do.
+ if (!HasConvergentFn) return false;
- // If we got here, all of the SCC's callees are non-convergent. Therefore all
- // of the SCC's functions can be marked as non-convergent.
+ // If we got here, all of the calls the SCC makes to functions not in the SCC
+ // are non-convergent. Therefore all of the SCC's functions can also be made
+ // non-convergent. We'll remove the attr from the callsites in
+ // InstCombineCalls.
for (Function *F : SCCNodes) {
- if (F->isConvergent())
- DEBUG(dbgs() << "Removing convergent attr from " << F->getName() << "\n");
+ if (!F->isConvergent()) continue;
+
+ DEBUG(dbgs() << "Removing convergent attr from fn " << F->getName()
+ << "\n");
F->setNotConvergent();
}
return true;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index f6ed6900a6a..1de05dc89de 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2179,7 +2179,15 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) {
if (!isa<Function>(Callee) && transformConstExprCastCall(CS))
return nullptr;
- if (Function *CalleeF = dyn_cast<Function>(Callee))
+ if (Function *CalleeF = dyn_cast<Function>(Callee)) {
+ // Remove the convergent attr on calls when the callee is not convergent.
+ if (CS.isConvergent() && !CalleeF->isConvergent()) {
+ DEBUG(dbgs() << "Removing convergent attr from instr "
+ << CS.getInstruction() << "\n");
+ CS.setNotConvergent();
+ return CS.getInstruction();
+ }
+
// If the call and callee calling conventions don't match, this call must
// be unreachable, as the call is undefined.
if (CalleeF->getCallingConv() != CS.getCallingConv() &&
@@ -2204,6 +2212,7 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) {
Constant::getNullValue(CalleeF->getType()));
return nullptr;
}
+ }
if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
// If CS does not return void then replaceAllUsesWith undef.
OpenPOWER on IntegriCloud