[Analysis] Attribute alignment should not prevent tail call optimization

Fixes tail folding issue mentioned in D100879.
Reviewed By: dmgreen
Differential Revision: https://reviews.llvm.org/D101230
This commit is contained in:
Dávid Bolvanský 2021-04-24 19:55:04 +02:00
parent 0eb3299d28
commit ef2dc7ed9f
4 changed files with 58 additions and 17 deletions

View File

@ -560,14 +560,12 @@ bool llvm::attributesPermitTailCall(const Function *F, const Instruction *I,
// Following attributes are completely benign as far as calling convention
// goes, they shouldn't affect whether the call is a tail call.
CallerAttrs.removeAttribute(Attribute::NoAlias);
CalleeAttrs.removeAttribute(Attribute::NoAlias);
CallerAttrs.removeAttribute(Attribute::NonNull);
CalleeAttrs.removeAttribute(Attribute::NonNull);
CallerAttrs.removeAttribute(Attribute::Dereferenceable);
CalleeAttrs.removeAttribute(Attribute::Dereferenceable);
CallerAttrs.removeAttribute(Attribute::DereferenceableOrNull);
CalleeAttrs.removeAttribute(Attribute::DereferenceableOrNull);
for (const auto &Attr : {Attribute::Alignment, Attribute::Dereferenceable,
Attribute::DereferenceableOrNull, Attribute::NoAlias,
Attribute::NonNull}) {
CallerAttrs.removeAttribute(Attr);
CalleeAttrs.removeAttribute(Attr);
}
if (CallerAttrs.contains(Attribute::ZExt)) {
if (!CalleeAttrs.contains(Attribute::ZExt))

View File

@ -57,18 +57,20 @@ bool TargetLowering::isInTailCallPosition(SelectionDAG &DAG, SDNode *Node,
return false;
// Conservatively require the attributes of the call to match those of
// the return. Ignore NoAlias and NonNull because they don't affect the
// the return. Ignore following attributes because they don't affect the
// call sequence.
AttributeList CallerAttrs = F.getAttributes();
if (AttrBuilder(CallerAttrs, AttributeList::ReturnIndex)
.removeAttribute(Attribute::NoAlias)
.removeAttribute(Attribute::NonNull)
.hasAttributes())
AttrBuilder CallerAttrs(F.getAttributes(), AttributeList::ReturnIndex);
for (const auto &Attr : {Attribute::Alignment, Attribute::Dereferenceable,
Attribute::DereferenceableOrNull, Attribute::NoAlias,
Attribute::NonNull})
CallerAttrs.removeAttribute(Attr);
if (CallerAttrs.hasAttributes())
return false;
// It's not safe to eliminate the sign / zero extension of the return value.
if (CallerAttrs.hasAttribute(AttributeList::ReturnIndex, Attribute::ZExt) ||
CallerAttrs.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt))
if (CallerAttrs.contains(Attribute::ZExt) ||
CallerAttrs.contains(Attribute::SExt))
return false;
// Check if the only use is a function return node.

View File

@ -99,7 +99,7 @@ entry:
ret void
}
; Check that NonNull attributes don't inhibit tailcalls.
; Check that nonnull attributes don't inhibit tailcalls.
declare nonnull i8* @nonnull_callee(i8* %p, i32 %val)
define i8* @nonnull_caller(i8* %p, i32 %val) {
@ -110,3 +110,28 @@ entry:
%call = tail call i8* @nonnull_callee(i8* %p, i32 %val)
ret i8* %call
}
; Check that noalias attributes don't inhibit tailcalls.
declare noalias i8* @noalias_callee(i8* %p, i32 %val)
define i8* @noalias_caller(i8* %p, i32 %val) {
; CHECK-LABEL: noalias_caller:
; CHECK-TAIL: b noalias_callee
; CHECK-NO-TAIL: bl noalias_callee
entry:
%call = tail call i8* @noalias_callee(i8* %p, i32 %val)
ret i8* %call
}
; Check that alignment attributes don't inhibit tailcalls.
declare align 8 i8* @align8_callee(i8* %p, i32 %val)
define i8* @align8_caller(i8* %p, i32 %val) {
; CHECK-LABEL: align8_caller:
; CHECK-TAIL: b align8_callee
; CHECK-NO-TAIL: bl align8_callee
entry:
%call = tail call i8* @align8_callee(i8* %p, i32 %val)
ret i8* %call
}

View File

@ -34,3 +34,19 @@ define i8* @test4() nounwind {
%ret = tail call dereferenceable_or_null(8) i8* @foo()
ret i8* %ret
}
define align 8 i8* @test5() nounwind {
; CHECK-LABEL: test5:
; CHECK: # %bb.0:
; CHECK-NEXT: jmp foo # TAILCALL
%ret = tail call i8* @foo()
ret i8* %ret
}
define i8* @test6() nounwind {
; CHECK-LABEL: test6:
; CHECK: # %bb.0:
; CHECK-NEXT: jmp foo # TAILCALL
%ret = tail call align 8 i8* @foo()
ret i8* %ret
}