[llvm] 9ff2eb1 - SwiftTailCC: teach verifier musttail rules applicable to this CC.
Tim Northover via llvm-commits
llvm-commits at lists.llvm.org
Fri May 28 03:12:16 PDT 2021
Author: Tim Northover
Date: 2021-05-28T11:12:00+01:00
New Revision: 9ff2eb1ea596a52ad2b5cfab826548c3af0a1e6e
URL: https://github.com/llvm/llvm-project/commit/9ff2eb1ea596a52ad2b5cfab826548c3af0a1e6e
DIFF: https://github.com/llvm/llvm-project/commit/9ff2eb1ea596a52ad2b5cfab826548c3af0a1e6e.diff
LOG: SwiftTailCC: teach verifier musttail rules applicable to this CC.
SwiftTailCC has a different set of requirements than the C calling convention
for a tail call. The exact argument sequence doesn't have to match, but fewer
ABI-affecting attributes are allowed.
Also make sure the musttail diagnostic triggers if a musttail call isn't
actually a tail call.
Added:
llvm/test/CodeGen/AArch64/tailcc-notail.ll
llvm/test/CodeGen/ARM/tailcc-notail.ll
llvm/test/CodeGen/X86/tailcc-notail.ll
llvm/test/Verifier/swifttailcc-musttail-valid.ll
llvm/test/Verifier/swifttailcc-musttail.ll
llvm/test/Verifier/tailcc-musttail.ll
Modified:
llvm/docs/LangRef.rst
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
llvm/lib/IR/Verifier.cpp
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
llvm/lib/Target/ARM/ARMISelLowering.cpp
llvm/lib/Target/X86/X86ISelLowering.cpp
llvm/test/CodeGen/AArch64/swifttail-call.ll
llvm/test/CodeGen/X86/tailcall-swifttailcc.ll
Removed:
################################################################################
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index d6bfafaccb61..6d6c72cbb66b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -11344,16 +11344,25 @@ This instruction requires several arguments:
- The call must immediately precede a :ref:`ret <i_ret>` instruction,
or a pointer bitcast followed by a ret instruction.
- The ret instruction must return the (possibly bitcasted) value
- produced by the call or void.
- - The caller and callee prototypes must match. Pointer types of
- parameters or return types may
diff er in pointee type, but not
- in address space.
+ produced by the call, undef, or void.
- The calling conventions of the caller and callee must match.
- - All ABI-impacting function attributes, such as sret, byval, inreg,
- returned, and inalloca, must match.
- The callee must be varargs iff the caller is varargs. Bitcasting a
non-varargs function to the appropriate varargs type is legal so
long as the non-varargs prefixes obey the other rules.
+ - The return type must not undergo automatic conversion to an `sret` pointer.
+
+ In addition, if the calling convention is not `swifttailcc` or `tailcc`:
+
+ - All ABI-impacting function attributes, such as sret, byval, inreg,
+ returned, and inalloca, must match.
+ - The caller and callee prototypes must match. Pointer types of parameters
+ or return types may
diff er in pointee type, but not in address space.
+
+ On the other hand, if the calling convention is `swifttailcc` or `swiftcc`:
+
+ - Only these ABI-impacting attributes attributes are allowed: sret, byval,
+ swiftself, and swiftasync.
+ - Prototypes are not required to match.
Tail call optimization for calls marked ``tail`` is guaranteed to occur if
the following conditions are met:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 08ca62b445e6..ab77ef4a2d8b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2924,7 +2924,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
// with deopt state.
LowerCallSiteWithDeoptBundle(&I, getValue(Callee), EHPadBB);
} else {
- LowerCallTo(I, getValue(Callee), false, EHPadBB);
+ LowerCallTo(I, getValue(Callee), false, false, EHPadBB);
}
// If the value of the invoke is used outside of its defining block, make it
@@ -5734,7 +5734,7 @@ void SelectionDAGBuilder::lowerCallToExternalSymbol(const CallInst &I,
SDValue Callee = DAG.getExternalSymbol(
FunctionName,
DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()));
- LowerCallTo(I, Callee, I.isTailCall());
+ LowerCallTo(I, Callee, I.isTailCall(), I.isMustTailCall());
}
/// Given a @llvm.call.preallocated.setup, return the corresponding
@@ -7420,6 +7420,7 @@ SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI,
void SelectionDAGBuilder::LowerCallTo(const CallBase &CB, SDValue Callee,
bool isTailCall,
+ bool isMustTailCall,
const BasicBlock *EHPadBB) {
auto &DL = DAG.getDataLayout();
FunctionType *FTy = CB.getFunctionType();
@@ -7436,7 +7437,7 @@ void SelectionDAGBuilder::LowerCallTo(const CallBase &CB, SDValue Callee,
// attribute.
auto *Caller = CB.getParent()->getParent();
if (Caller->getFnAttribute("disable-tail-calls").getValueAsString() ==
- "true")
+ "true" && !isMustTailCall)
isTailCall = false;
// We can't tail call inside a function with a swifterror argument. Lowering
@@ -8060,7 +8061,7 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
// Check if we can potentially perform a tail call. More detailed checking
// is be done within LowerCallTo, after more information about the call is
// known.
- LowerCallTo(I, Callee, I.isTailCall());
+ LowerCallTo(I, Callee, I.isTailCall(), I.isMustTailCall());
}
namespace {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index 084ad5d0d8c6..df5be156821f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -553,7 +553,7 @@ class SelectionDAGBuilder {
void CopyToExportRegsIfNeeded(const Value *V);
void ExportFromCurrentBlock(const Value *V);
void LowerCallTo(const CallBase &CB, SDValue Callee, bool IsTailCall,
- const BasicBlock *EHPadBB = nullptr);
+ bool IsMustTailCall, const BasicBlock *EHPadBB = nullptr);
// Lower range metadata from 0 to N to assert zext to an integer of nearest
// floor power of two.
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index bcb88c6a2cd2..692760d8d647 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -537,6 +537,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal);
void verifySwiftErrorValue(const Value *SwiftErrorVal);
+ void verifyTailCCMustTailAttrs(AttrBuilder Attrs, StringRef Context);
void verifyMustTailCall(CallInst &CI);
bool verifyAttributeCount(AttributeList Attrs, unsigned Params);
void verifyAttributeTypes(AttributeSet Attrs, bool IsFunction,
@@ -3387,6 +3388,20 @@ void Verifier::visitCallBase(CallBase &Call) {
visitInstruction(Call);
}
+void Verifier::verifyTailCCMustTailAttrs(AttrBuilder Attrs,
+ StringRef Context) {
+ Assert(!Attrs.contains(Attribute::InAlloca),
+ Twine("inalloca attribute not allowed in ") + Context);
+ Assert(!Attrs.contains(Attribute::InReg),
+ Twine("inreg attribute not allowed in ") + Context);
+ Assert(!Attrs.contains(Attribute::SwiftError),
+ Twine("swifterror attribute not allowed in ") + Context);
+ Assert(!Attrs.contains(Attribute::Preallocated),
+ Twine("preallocated attribute not allowed in ") + Context);
+ Assert(!Attrs.contains(Attribute::ByRef),
+ Twine("byref attribute not allowed in ") + Context);
+}
+
/// Two types are "congruent" if they are identical, or if they are both pointer
/// types with
diff erent pointee types and the same address space.
static bool isTypeCongruent(Type *L, Type *R) {
@@ -3422,22 +3437,9 @@ static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) {
void Verifier::verifyMustTailCall(CallInst &CI) {
Assert(!CI.isInlineAsm(), "cannot use musttail call with inline asm", &CI);
- // - The caller and callee prototypes must match. Pointer types of
- // parameters or return types may
diff er in pointee type, but not
- // address space.
Function *F = CI.getParent()->getParent();
FunctionType *CallerTy = F->getFunctionType();
FunctionType *CalleeTy = CI.getFunctionType();
- if (!CI.getCalledFunction() || !CI.getCalledFunction()->isIntrinsic()) {
- Assert(CallerTy->getNumParams() == CalleeTy->getNumParams(),
- "cannot guarantee tail call due to mismatched parameter counts",
- &CI);
- for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) {
- Assert(
- isTypeCongruent(CallerTy->getParamType(I), CalleeTy->getParamType(I)),
- "cannot guarantee tail call due to mismatched parameter types", &CI);
- }
- }
Assert(CallerTy->isVarArg() == CalleeTy->isVarArg(),
"cannot guarantee tail call due to mismatched varargs", &CI);
Assert(isTypeCongruent(CallerTy->getReturnType(), CalleeTy->getReturnType()),
@@ -3447,19 +3449,6 @@ void Verifier::verifyMustTailCall(CallInst &CI) {
Assert(F->getCallingConv() == CI.getCallingConv(),
"cannot guarantee tail call due to mismatched calling conv", &CI);
- // - All ABI-impacting function attributes, such as sret, byval, inreg,
- // returned, preallocated, and inalloca, must match.
- AttributeList CallerAttrs = F->getAttributes();
- AttributeList CalleeAttrs = CI.getAttributes();
- for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) {
- AttrBuilder CallerABIAttrs = getParameterABIAttributes(I, CallerAttrs);
- AttrBuilder CalleeABIAttrs = getParameterABIAttributes(I, CalleeAttrs);
- Assert(CallerABIAttrs == CalleeABIAttrs,
- "cannot guarantee tail call due to mismatched ABI impacting "
- "function attributes",
- &CI, CI.getOperand(I));
- }
-
// - The call must immediately precede a :ref:`ret <i_ret>` instruction,
// or a pointer bitcast followed by a ret instruction.
// - The ret instruction must return the (possibly bitcasted) value
@@ -3479,8 +3468,59 @@ void Verifier::verifyMustTailCall(CallInst &CI) {
ReturnInst *Ret = dyn_cast_or_null<ReturnInst>(Next);
Assert(Ret, "musttail call must precede a ret with an optional bitcast",
&CI);
- Assert(!Ret->getReturnValue() || Ret->getReturnValue() == RetVal,
+ Assert(!Ret->getReturnValue() || Ret->getReturnValue() == RetVal ||
+ isa<UndefValue>(Ret->getReturnValue()),
"musttail call result must be returned", Ret);
+
+ AttributeList CallerAttrs = F->getAttributes();
+ AttributeList CalleeAttrs = CI.getAttributes();
+ if (CI.getCallingConv() == CallingConv::SwiftTail ||
+ CI.getCallingConv() == CallingConv::Tail) {
+ StringRef CCName =
+ CI.getCallingConv() == CallingConv::Tail ? "tailcc" : "swifttailcc";
+
+ // - Only sret, byval, swiftself, and swiftasync ABI-impacting attributes
+ // are allowed in swifttailcc call
+ for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) {
+ AttrBuilder ABIAttrs = getParameterABIAttributes(I, CallerAttrs);
+ SmallString<32> Context{CCName, StringRef(" musttail caller")};
+ verifyTailCCMustTailAttrs(ABIAttrs, Context);
+ }
+ for (int I = 0, E = CalleeTy->getNumParams(); I != E; ++I) {
+ AttrBuilder ABIAttrs = getParameterABIAttributes(I, CalleeAttrs);
+ SmallString<32> Context{CCName, StringRef(" musttail callee")};
+ verifyTailCCMustTailAttrs(ABIAttrs, Context);
+ }
+ // - Varargs functions are not allowed
+ Assert(!CallerTy->isVarArg(), Twine("cannot guarantee ") + CCName +
+ " tail call for varargs function");
+ return;
+ }
+
+ // - The caller and callee prototypes must match. Pointer types of
+ // parameters or return types may
diff er in pointee type, but not
+ // address space.
+ if (!CI.getCalledFunction() || !CI.getCalledFunction()->isIntrinsic()) {
+ Assert(CallerTy->getNumParams() == CalleeTy->getNumParams(),
+ "cannot guarantee tail call due to mismatched parameter counts",
+ &CI);
+ for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) {
+ Assert(
+ isTypeCongruent(CallerTy->getParamType(I), CalleeTy->getParamType(I)),
+ "cannot guarantee tail call due to mismatched parameter types", &CI);
+ }
+ }
+
+ // - All ABI-impacting function attributes, such as sret, byval, inreg,
+ // returned, preallocated, and inalloca, must match.
+ for (int I = 0, E = CallerTy->getNumParams(); I != E; ++I) {
+ AttrBuilder CallerABIAttrs = getParameterABIAttributes(I, CallerAttrs);
+ AttrBuilder CalleeABIAttrs = getParameterABIAttributes(I, CalleeAttrs);
+ Assert(CallerABIAttrs == CalleeABIAttrs,
+ "cannot guarantee tail call due to mismatched ABI impacting "
+ "function attributes",
+ &CI, CI.getOperand(I));
+ }
}
void Verifier::visitCallInst(CallInst &CI) {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index d949a6e95d32..dc5dd73c7cfd 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -5529,9 +5529,6 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
// Check if it's really possible to do a tail call.
IsTailCall = isEligibleForTailCallOptimization(
Callee, CallConv, IsVarArg, Outs, OutVals, Ins, DAG);
- if (!IsTailCall && CLI.CB && CLI.CB->isMustTailCall())
- report_fatal_error("failed to perform tail call elimination on a call "
- "site marked musttail");
// A sibling call is one where we're under the usual C ABI and not planning
// to change that but can still do a tail call:
@@ -5543,6 +5540,10 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
++NumTailCalls;
}
+ if (!IsTailCall && CLI.CB && CLI.CB->isMustTailCall())
+ report_fatal_error("failed to perform tail call elimination on a call "
+ "site marked musttail");
+
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 4dee7438c955..8a9d02901dc7 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -2308,9 +2308,6 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
Callee, CallConv, isVarArg, isStructRet,
MF.getFunction().hasStructRetAttr(), Outs, OutVals, Ins, DAG,
PreferIndirect);
- if (!isTailCall && CLI.CB && CLI.CB->isMustTailCall())
- report_fatal_error("failed to perform tail call elimination on a call "
- "site marked musttail");
if (isTailCall && !getTargetMachine().Options.GuaranteedTailCallOpt &&
CallConv != CallingConv::Tail && CallConv != CallingConv::SwiftTail)
@@ -2322,6 +2319,9 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
++NumTailCalls;
}
+ if (!isTailCall && CLI.CB && CLI.CB->isMustTailCall())
+ report_fatal_error("failed to perform tail call elimination on a call "
+ "site marked musttail");
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 71d1399fa8c5..ab13ebf86120 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -3942,7 +3942,8 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (CallConv == CallingConv::X86_INTR)
report_fatal_error("X86 interrupts may not be called directly");
- if (Subtarget.isPICStyleGOT() && !IsGuaranteeTCO) {
+ bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
+ if (Subtarget.isPICStyleGOT() && !IsGuaranteeTCO && !IsMustTail) {
// If we are using a GOT, disable tail calls to external symbols with
// default visibility. Tail calling such a symbol requires using a GOT
// relocation, which forces early binding of the symbol. This breaks code
@@ -3954,13 +3955,8 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
isTailCall = false;
}
- bool IsMustTail = CLI.CB && CLI.CB->isMustTailCall();
- if (IsMustTail) {
- // Force this to be a tail call. The verifier rules are enough to ensure
- // that we can lower this successfully without moving the return address
- // around.
- isTailCall = true;
- } else if (isTailCall) {
+
+ if (isTailCall && !IsMustTail) {
// Check if it's really possible to do a tail call.
isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
isVarArg, SR != NotStructReturn,
@@ -3976,6 +3972,10 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
++NumTailCalls;
}
+ if (IsMustTail && !isTailCall)
+ report_fatal_error("failed to perform tail call elimination on a call "
+ "site marked musttail");
+
assert(!(isVarArg && canGuaranteeTCO(CallConv)) &&
"Var args not supported with calling convention fastcc, ghc or hipe");
@@ -4005,7 +4005,9 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
NumBytes = GetAlignedArgumentStackSize(NumBytes, DAG);
int FPDiff = 0;
- if (isTailCall && !IsSibcall && !IsMustTail) {
+ if (isTailCall &&
+ shouldGuaranteeTCO(CallConv,
+ MF.getTarget().Options.GuaranteedTailCallOpt)) {
// Lower arguments at fp - stackoffset + fp
diff .
unsigned NumBytesCallerPushed = X86Info->getBytesToPopOnReturn();
diff --git a/llvm/test/CodeGen/AArch64/swifttail-call.ll b/llvm/test/CodeGen/AArch64/swifttail-call.ll
index 70c5a58f4124..64109958a2f0 100644
--- a/llvm/test/CodeGen/AArch64/swifttail-call.ll
+++ b/llvm/test/CodeGen/AArch64/swifttail-call.ll
@@ -10,7 +10,7 @@ define swifttailcc void @caller_to0_from0() nounwind {
; COMMON-LABEL: caller_to0_from0:
; COMMON-NEXT: // %bb.
- tail call swifttailcc void @callee_stack0()
+ musttail call swifttailcc void @callee_stack0()
ret void
; COMMON-NEXT: b callee_stack0
@@ -19,7 +19,7 @@ define swifttailcc void @caller_to0_from0() nounwind {
define swifttailcc void @caller_to0_from8([8 x i64], i64) {
; COMMON-LABEL: caller_to0_from8:
- tail call swifttailcc void @callee_stack0()
+ musttail call swifttailcc void @callee_stack0()
ret void
; COMMON: add sp, sp, #16
@@ -31,7 +31,7 @@ define swifttailcc void @caller_to8_from0() {
; Key point is that the "42" should go #16 below incoming stack
; pointer (we didn't have arg space to reuse).
- tail call swifttailcc void @callee_stack8([8 x i64] undef, i64 42)
+ musttail call swifttailcc void @callee_stack8([8 x i64] undef, i64 42)
ret void
; COMMON: str {{x[0-9]+}}, [sp, #-16]!
@@ -43,7 +43,7 @@ define swifttailcc void @caller_to8_from8([8 x i64], i64 %a) {
; COMMON-NOT: sub sp,
; Key point is that the "%a" should go where at SP on entry.
- tail call swifttailcc void @callee_stack8([8 x i64] undef, i64 42)
+ musttail call swifttailcc void @callee_stack8([8 x i64] undef, i64 42)
ret void
; COMMON: str {{x[0-9]+}}, [sp]
@@ -57,7 +57,7 @@ define swifttailcc void @caller_to16_from8([8 x i64], i64 %a) {
; Important point is that the call reuses the "dead" argument space
; above %a on the stack. If it tries to go below incoming-SP then the
; callee will not deallocate the space, even in swifttailcc.
- tail call swifttailcc void @callee_stack16([8 x i64] undef, i64 42, i64 2)
+ musttail call swifttailcc void @callee_stack16([8 x i64] undef, i64 42, i64 2)
; COMMON: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp]
; COMMON-NEXT: b callee_stack16
@@ -70,7 +70,7 @@ define swifttailcc void @caller_to8_from24([8 x i64], i64 %a, i64 %b, i64 %c) {
; COMMON-NOT: sub sp,
; Key point is that the "%a" should go where at #16 above SP on entry.
- tail call swifttailcc void @callee_stack8([8 x i64] undef, i64 42)
+ musttail call swifttailcc void @callee_stack8([8 x i64] undef, i64 42)
ret void
; COMMON: str {{x[0-9]+}}, [sp, #16]!
@@ -84,7 +84,7 @@ define swifttailcc void @caller_to16_from16([8 x i64], i64 %a, i64 %b) {
; Here we want to make sure that both loads happen before the stores:
; otherwise either %a or %b will be wrongly clobbered.
- tail call swifttailcc void @callee_stack16([8 x i64] undef, i64 %b, i64 %a)
+ musttail call swifttailcc void @callee_stack16([8 x i64] undef, i64 %b, i64 %a)
ret void
; COMMON: ldp {{x[0-9]+}}, {{x[0-9]+}}, [sp]
diff --git a/llvm/test/CodeGen/AArch64/tailcc-notail.ll b/llvm/test/CodeGen/AArch64/tailcc-notail.ll
new file mode 100644
index 000000000000..9fedddb75e16
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/tailcc-notail.ll
@@ -0,0 +1,8 @@
+; RUN: not --crash llc -mtriple=arm64-apple-ios %s -o - 2>&1 | FileCheck %s
+
+; CHECK: LLVM ERROR: failed to perform tail call elimination on a call site marked musttail
+declare tailcc [16 x i64] @callee()
+define tailcc [16 x i64] @caller() {
+ %res = musttail call tailcc [16 x i64] @callee()
+ ret [16 x i64] %res
+}
diff --git a/llvm/test/CodeGen/ARM/tailcc-notail.ll b/llvm/test/CodeGen/ARM/tailcc-notail.ll
new file mode 100644
index 000000000000..9df036af1a40
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/tailcc-notail.ll
@@ -0,0 +1,8 @@
+; RUN: not --crash llc -mtriple=thumbv7k-apple-ios %s -o - 2>&1 | FileCheck %s
+
+; CHECK: LLVM ERROR: failed to perform tail call elimination on a call site marked musttail
+declare tailcc [16 x i64] @callee()
+define tailcc [16 x i64] @caller() {
+ %res = musttail call tailcc [16 x i64] @callee()
+ ret [16 x i64] %res
+}
diff --git a/llvm/test/CodeGen/X86/tailcall-swifttailcc.ll b/llvm/test/CodeGen/X86/tailcall-swifttailcc.ll
index 6c92280d01e8..bccb8451d2bb 100644
--- a/llvm/test/CodeGen/X86/tailcall-swifttailcc.ll
+++ b/llvm/test/CodeGen/X86/tailcall-swifttailcc.ll
@@ -8,7 +8,7 @@ define dso_local swifttailcc i32 @tailcaller(i32 %in1, i32 %in2) nounwind {
; CHECK-NOT: addq
; CHECK: jmp tailcallee
entry:
- %tmp11 = tail call swifttailcc i32 @tailcallee(i32 %in1, i32 %in2, i32 %in1, i32 %in2)
+ %tmp11 = musttail call swifttailcc i32 @tailcallee(i32 %in1, i32 %in2, i32 %in1, i32 %in2)
ret i32 %tmp11
}
@@ -26,7 +26,7 @@ declare dso_local swifttailcc noalias i8* @noalias_callee()
define dso_local swifttailcc i8* @alias_caller() nounwind {
; CHECK-LABEL: alias_caller:
; CHECK: jmp noalias_callee # TAILCALL
- %p = tail call swifttailcc noalias i8* @noalias_callee()
+ %p = musttail call swifttailcc noalias i8* @noalias_callee()
ret i8* %p
}
@@ -35,7 +35,7 @@ declare dso_local swifttailcc i32 @i32_callee()
define dso_local swifttailcc i32 @ret_undef() nounwind {
; CHECK-LABEL: ret_undef:
; CHECK: jmp i32_callee # TAILCALL
- %p = tail call swifttailcc i32 @i32_callee()
+ %p = musttail call swifttailcc i32 @i32_callee()
ret i32 undef
}
@@ -52,7 +52,7 @@ define dso_local swifttailcc void @void_test(i32, i32, i32, i32) {
; CHECK-LABEL: void_test:
; CHECK: jmp void_test
entry:
- tail call swifttailcc void @void_test( i32 %0, i32 %1, i32 %2, i32 %3)
+ musttail call swifttailcc void @void_test( i32 %0, i32 %1, i32 %2, i32 %3)
ret void
}
@@ -60,6 +60,6 @@ define dso_local swifttailcc i1 @i1test(i32, i32, i32, i32) {
; CHECK-LABEL: i1test:
; CHECK: jmp i1test
entry:
- %4 = tail call swifttailcc i1 @i1test( i32 %0, i32 %1, i32 %2, i32 %3)
+ %4 = musttail call swifttailcc i1 @i1test( i32 %0, i32 %1, i32 %2, i32 %3)
ret i1 %4
}
diff --git a/llvm/test/CodeGen/X86/tailcc-notail.ll b/llvm/test/CodeGen/X86/tailcc-notail.ll
new file mode 100644
index 000000000000..bc3af425482f
--- /dev/null
+++ b/llvm/test/CodeGen/X86/tailcc-notail.ll
@@ -0,0 +1,8 @@
+; RUN: not --crash llc -mtriple=x86_64-linux-gnu %s -o - 2>&1 | FileCheck %s
+
+; CHECK: LLVM ERROR: failed to perform tail call elimination on a call site marked musttail
+declare tailcc [16 x i64] @callee()
+define tailcc [16 x i64] @caller() {
+ %res = musttail call tailcc [16 x i64] @callee()
+ ret [16 x i64] %res
+}
diff --git a/llvm/test/Verifier/swifttailcc-musttail-valid.ll b/llvm/test/Verifier/swifttailcc-musttail-valid.ll
new file mode 100644
index 000000000000..f4042359ae18
--- /dev/null
+++ b/llvm/test/Verifier/swifttailcc-musttail-valid.ll
@@ -0,0 +1,11 @@
+; RUN: opt -verify %s
+
+define swifttailcc void @valid_attrs(i64* sret(i64) %ret, i8* byval(i8) %byval, i8* swiftself %self, i8* swiftasync %ctx) {
+ musttail call swifttailcc void @valid_attrs(i64* sret(i64) %ret, i8* byval(i8) %byval, i8* swiftself %self, i8* swiftasync %ctx)
+ ret void
+}
+
+define swifttailcc void @mismatch_parms() {
+ musttail call swifttailcc void @valid_attrs(i64* sret(i64) undef, i8* byval(i8) undef, i8* swiftself undef, i8* swiftasync undef)
+ ret void
+}
diff --git a/llvm/test/Verifier/swifttailcc-musttail.ll b/llvm/test/Verifier/swifttailcc-musttail.ll
new file mode 100644
index 000000000000..6e41b43403f7
--- /dev/null
+++ b/llvm/test/Verifier/swifttailcc-musttail.ll
@@ -0,0 +1,72 @@
+; RUN: not opt -verify %s 2>&1 | FileCheck %s
+
+declare swifttailcc void @simple()
+
+define swifttailcc void @inreg(i8* inreg) {
+; CHECK: inreg attribute not allowed in swifttailcc musttail caller
+ musttail call swifttailcc void @simple()
+ ret void
+}
+
+define swifttailcc void @inalloca(i8* inalloca(i8)) {
+; CHECK: inalloca attribute not allowed in swifttailcc musttail caller
+ musttail call swifttailcc void @simple()
+ ret void
+}
+
+define swifttailcc void @swifterror(i8** swifterror) {
+; CHECK: swifterror attribute not allowed in swifttailcc musttail caller
+ musttail call swifttailcc void @simple()
+ ret void
+}
+
+define swifttailcc void @preallocated(i8* preallocated(i8)) {
+; CHECK: preallocated attribute not allowed in swifttailcc musttail caller
+ musttail call swifttailcc void @simple()
+ ret void
+}
+
+define swifttailcc void @byref(i8* byref(i8)) {
+; CHECK: byref attribute not allowed in swifttailcc musttail caller
+ musttail call swifttailcc void @simple()
+ ret void
+}
+
+define swifttailcc void @call_inreg() {
+; CHECK: inreg attribute not allowed in swifttailcc musttail callee
+ musttail call swifttailcc void @inreg(i8* inreg undef)
+ ret void
+}
+
+define swifttailcc void @call_inalloca() {
+; CHECK: inalloca attribute not allowed in swifttailcc musttail callee
+ musttail call swifttailcc void @inalloca(i8* inalloca(i8) undef)
+ ret void
+}
+
+define swifttailcc void @call_swifterror() {
+; CHECK: swifterror attribute not allowed in swifttailcc musttail callee
+ %err = alloca swifterror i8*
+ musttail call swifttailcc void @swifterror(i8** swifterror %err)
+ ret void
+}
+
+define swifttailcc void @call_preallocated() {
+; CHECK: preallocated attribute not allowed in swifttailcc musttail callee
+ musttail call swifttailcc void @preallocated(i8* preallocated(i8) undef)
+ ret void
+}
+
+define swifttailcc void @call_byref() {
+; CHECK: byref attribute not allowed in swifttailcc musttail callee
+ musttail call swifttailcc void @byref(i8* byref(i8) undef)
+ ret void
+}
+
+
+declare swifttailcc void @varargs(...)
+define swifttailcc void @call_varargs(...) {
+; CHECK: cannot guarantee swifttailcc tail call for varargs function
+ musttail call swifttailcc void(...) @varargs(...)
+ ret void
+}
diff --git a/llvm/test/Verifier/tailcc-musttail.ll b/llvm/test/Verifier/tailcc-musttail.ll
new file mode 100644
index 000000000000..011edee2399c
--- /dev/null
+++ b/llvm/test/Verifier/tailcc-musttail.ll
@@ -0,0 +1,72 @@
+; RUN: not opt -verify %s 2>&1 | FileCheck %s
+
+declare tailcc void @simple()
+
+define tailcc void @inreg(i8* inreg) {
+; CHECK: inreg attribute not allowed in tailcc musttail caller
+ musttail call tailcc void @simple()
+ ret void
+}
+
+define tailcc void @inalloca(i8* inalloca(i8)) {
+; CHECK: inalloca attribute not allowed in tailcc musttail caller
+ musttail call tailcc void @simple()
+ ret void
+}
+
+define tailcc void @swifterror(i8** swifterror) {
+; CHECK: swifterror attribute not allowed in tailcc musttail caller
+ musttail call tailcc void @simple()
+ ret void
+}
+
+define tailcc void @preallocated(i8* preallocated(i8)) {
+; CHECK: preallocated attribute not allowed in tailcc musttail caller
+ musttail call tailcc void @simple()
+ ret void
+}
+
+define tailcc void @byref(i8* byref(i8)) {
+; CHECK: byref attribute not allowed in tailcc musttail caller
+ musttail call tailcc void @simple()
+ ret void
+}
+
+define tailcc void @call_inreg() {
+; CHECK: inreg attribute not allowed in tailcc musttail callee
+ musttail call tailcc void @inreg(i8* inreg undef)
+ ret void
+}
+
+define tailcc void @call_inalloca() {
+; CHECK: inalloca attribute not allowed in tailcc musttail callee
+ musttail call tailcc void @inalloca(i8* inalloca(i8) undef)
+ ret void
+}
+
+define tailcc void @call_swifterror() {
+; CHECK: swifterror attribute not allowed in tailcc musttail callee
+ %err = alloca swifterror i8*
+ musttail call tailcc void @swifterror(i8** swifterror %err)
+ ret void
+}
+
+define tailcc void @call_preallocated() {
+; CHECK: preallocated attribute not allowed in tailcc musttail callee
+ musttail call tailcc void @preallocated(i8* preallocated(i8) undef)
+ ret void
+}
+
+define tailcc void @call_byref() {
+; CHECK: byref attribute not allowed in tailcc musttail callee
+ musttail call tailcc void @byref(i8* byref(i8) undef)
+ ret void
+}
+
+
+declare tailcc void @varargs(...)
+define tailcc void @call_varargs(...) {
+; CHECK: cannot guarantee tailcc tail call for varargs function
+ musttail call tailcc void(...) @varargs(...)
+ ret void
+}
More information about the llvm-commits
mailing list