[CGP] Be less conservative about tail-duplicating a ret to allow tail calls
CGP tail-duplicates rets into blocks that end with a call that feed the ret.
This puts the call in tail position, potentially allowing the DAG builder to
lower it as a tail call. To avoid tail duplication in cases where we won't
form the tail call, CGP tried to predict whether this is going to be possible,
and avoids doing it when lowering as a tail call will definitely fail.
However, it was being too conservative by always throwing away calls to
functions with a signext/zeroext attribute on the return type.
Instead, we can use the same logic the builder uses to determine whether the
attributes work out.
Differential Revision: https://reviews.llvm.org/D24315
llvm-svn: 280894
diff --git a/llvm/lib/CodeGen/Analysis.cpp b/llvm/lib/CodeGen/Analysis.cpp
index ebbcaeb..6582d24 100644
--- a/llvm/lib/CodeGen/Analysis.cpp
+++ b/llvm/lib/CodeGen/Analysis.cpp
@@ -525,6 +525,47 @@
F, I, Ret, *TM.getSubtargetImpl(*F)->getTargetLowering());
}
+bool llvm::attributesPermitTailCall(const Function *F, const Instruction *I,
+ const ReturnInst *Ret,
+ const TargetLoweringBase &TLI,
+ bool *AllowDifferingSizes) {
+ // ADS may be null, so don't write to it directly.
+ bool DummyADS;
+ bool &ADS = AllowDifferingSizes ? *AllowDifferingSizes : DummyADS;
+ ADS = true;
+
+ AttrBuilder CallerAttrs(F->getAttributes(),
+ AttributeSet::ReturnIndex);
+ AttrBuilder CalleeAttrs(cast<CallInst>(I)->getAttributes(),
+ AttributeSet::ReturnIndex);
+
+ // Noalias is completely benign as far as calling convention goes, it
+ // shouldn't affect whether the call is a tail call.
+ CallerAttrs = CallerAttrs.removeAttribute(Attribute::NoAlias);
+ CalleeAttrs = CalleeAttrs.removeAttribute(Attribute::NoAlias);
+
+ if (CallerAttrs.contains(Attribute::ZExt)) {
+ if (!CalleeAttrs.contains(Attribute::ZExt))
+ return false;
+
+ ADS = false;
+ CallerAttrs.removeAttribute(Attribute::ZExt);
+ CalleeAttrs.removeAttribute(Attribute::ZExt);
+ } else if (CallerAttrs.contains(Attribute::SExt)) {
+ if (!CalleeAttrs.contains(Attribute::SExt))
+ return false;
+
+ ADS = false;
+ CallerAttrs.removeAttribute(Attribute::SExt);
+ CalleeAttrs.removeAttribute(Attribute::SExt);
+ }
+
+ // If they're still different, there's some facet we don't understand
+ // (currently only "inreg", but in future who knows). It may be OK but the
+ // only safe option is to reject the tail call.
+ return CallerAttrs == CalleeAttrs;
+}
+
bool llvm::returnTypeIsEligibleForTailCall(const Function *F,
const Instruction *I,
const ReturnInst *Ret,
@@ -538,37 +579,8 @@
if (isa<UndefValue>(Ret->getOperand(0))) return true;
// Make sure the attributes attached to each return are compatible.
- AttrBuilder CallerAttrs(F->getAttributes(),
- AttributeSet::ReturnIndex);
- AttrBuilder CalleeAttrs(cast<CallInst>(I)->getAttributes(),
- AttributeSet::ReturnIndex);
-
- // Noalias is completely benign as far as calling convention goes, it
- // shouldn't affect whether the call is a tail call.
- CallerAttrs = CallerAttrs.removeAttribute(Attribute::NoAlias);
- CalleeAttrs = CalleeAttrs.removeAttribute(Attribute::NoAlias);
-
- bool AllowDifferingSizes = true;
- if (CallerAttrs.contains(Attribute::ZExt)) {
- if (!CalleeAttrs.contains(Attribute::ZExt))
- return false;
-
- AllowDifferingSizes = false;
- CallerAttrs.removeAttribute(Attribute::ZExt);
- CalleeAttrs.removeAttribute(Attribute::ZExt);
- } else if (CallerAttrs.contains(Attribute::SExt)) {
- if (!CalleeAttrs.contains(Attribute::SExt))
- return false;
-
- AllowDifferingSizes = false;
- CallerAttrs.removeAttribute(Attribute::SExt);
- CalleeAttrs.removeAttribute(Attribute::SExt);
- }
-
- // If they're still different, there's some facet we don't understand
- // (currently only "inreg", but in future who knows). It may be OK but the
- // only safe option is to reject the tail call.
- if (CallerAttrs != CalleeAttrs)
+ bool AllowDifferingSizes;
+ if (!attributesPermitTailCall(F, I, Ret, TLI, &AllowDifferingSizes))
return false;
const Value *RetVal = Ret->getOperand(0), *CallVal = I;
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 15600af..3bdf60c 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -23,6 +23,7 @@
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/MemoryBuiltins.h"
+#include "llvm/CodeGen/Analysis.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -1983,14 +1984,6 @@
if (PN && PN->getParent() != BB)
return false;
- // It's not safe to eliminate the sign / zero extension of the return value.
- // See llvm::isInTailCallPosition().
- const Function *F = BB->getParent();
- AttributeSet CallerAttrs = F->getAttributes();
- if (CallerAttrs.hasAttribute(AttributeSet::ReturnIndex, Attribute::ZExt) ||
- CallerAttrs.hasAttribute(AttributeSet::ReturnIndex, Attribute::SExt))
- return false;
-
// Make sure there are no instructions between the PHI and return, or that the
// return is the first instruction in the block.
if (PN) {
@@ -2010,13 +2003,15 @@
/// Only dup the ReturnInst if the CallInst is likely to be emitted as a tail
/// call.
+ const Function *F = BB->getParent();
SmallVector<CallInst*, 4> TailCalls;
if (PN) {
for (unsigned I = 0, E = PN->getNumIncomingValues(); I != E; ++I) {
CallInst *CI = dyn_cast<CallInst>(PN->getIncomingValue(I));
// Make sure the phi value is indeed produced by the tail call.
if (CI && CI->hasOneUse() && CI->getParent() == PN->getIncomingBlock(I) &&
- TLI->mayBeEmittedAsTailCall(CI))
+ TLI->mayBeEmittedAsTailCall(CI) &&
+ attributesPermitTailCall(F, CI, RetI, *TLI))
TailCalls.push_back(CI);
}
} else {
@@ -2033,7 +2028,8 @@
continue;
CallInst *CI = dyn_cast<CallInst>(&*RI);
- if (CI && CI->use_empty() && TLI->mayBeEmittedAsTailCall(CI))
+ if (CI && CI->use_empty() && TLI->mayBeEmittedAsTailCall(CI) &&
+ attributesPermitTailCall(F, CI, RetI, *TLI))
TailCalls.push_back(CI);
}
}