aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/Analysis.cpp
diff options
context:
space:
mode:
authorMichael Kuperstein <mkuper@google.com>2016-09-08 00:48:37 +0000
committerMichael Kuperstein <mkuper@google.com>2016-09-08 00:48:37 +0000
commitf79af6f8c4baf5018ef36aa462ca6f142fb2ed28 (patch)
tree95cff9d84b5b4f2e3d874a2a92bb5b687b858f55 /llvm/lib/CodeGen/Analysis.cpp
parent2c2a91e349405731a4849b516326a7b979645de6 (diff)
downloadllvm-f79af6f8c4baf5018ef36aa462ca6f142fb2ed28.zip
llvm-f79af6f8c4baf5018ef36aa462ca6f142fb2ed28.tar.gz
llvm-f79af6f8c4baf5018ef36aa462ca6f142fb2ed28.tar.bz2
[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
Diffstat (limited to 'llvm/lib/CodeGen/Analysis.cpp')
-rw-r--r--llvm/lib/CodeGen/Analysis.cpp44
1 files changed, 28 insertions, 16 deletions
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,19 +525,15 @@ bool llvm::isInTailCallPosition(ImmutableCallSite CS, const TargetMachine &TM) {
F, I, Ret, *TM.getSubtargetImpl(*F)->getTargetLowering());
}
-bool llvm::returnTypeIsEligibleForTailCall(const Function *F,
- const Instruction *I,
- const ReturnInst *Ret,
- const TargetLoweringBase &TLI) {
- // If the block ends with a void return or unreachable, it doesn't matter
- // what the call's return type is.
- if (!Ret || Ret->getNumOperands() == 0) return true;
+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;
- // If the return value is undef, it doesn't matter what the call's
- // return type is.
- 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(),
@@ -548,19 +544,18 @@ bool llvm::returnTypeIsEligibleForTailCall(const Function *F,
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;
+ ADS = false;
CallerAttrs.removeAttribute(Attribute::ZExt);
CalleeAttrs.removeAttribute(Attribute::ZExt);
} else if (CallerAttrs.contains(Attribute::SExt)) {
if (!CalleeAttrs.contains(Attribute::SExt))
return false;
- AllowDifferingSizes = false;
+ ADS = false;
CallerAttrs.removeAttribute(Attribute::SExt);
CalleeAttrs.removeAttribute(Attribute::SExt);
}
@@ -568,7 +563,24 @@ bool llvm::returnTypeIsEligibleForTailCall(const Function *F,
// 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)
+ return CallerAttrs == CalleeAttrs;
+}
+
+bool llvm::returnTypeIsEligibleForTailCall(const Function *F,
+ const Instruction *I,
+ const ReturnInst *Ret,
+ const TargetLoweringBase &TLI) {
+ // If the block ends with a void return or unreachable, it doesn't matter
+ // what the call's return type is.
+ if (!Ret || Ret->getNumOperands() == 0) return true;
+
+ // If the return value is undef, it doesn't matter what the call's
+ // return type is.
+ if (isa<UndefValue>(Ret->getOperand(0))) return true;
+
+ // Make sure the attributes attached to each return are compatible.
+ bool AllowDifferingSizes;
+ if (!attributesPermitTailCall(F, I, Ret, TLI, &AllowDifferingSizes))
return false;
const Value *RetVal = Ret->getOperand(0), *CallVal = I;