1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

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.
This commit is contained in:
Tim Northover 2021-02-10 14:35:16 +00:00
parent 9a76c13b82
commit 859ff3505c
15 changed files with 297 additions and 65 deletions

View File

@ -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 differ 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 differ 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:

View File

@ -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 {

View File

@ -553,7 +553,7 @@ public:
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.

View File

@ -537,6 +537,7 @@ private:
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 different 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 differ 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 differ 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) {

View File

@ -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,

View File

@ -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,

View File

@ -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 + fpdiff.
unsigned NumBytesCallerPushed = X86Info->getBytesToPopOnReturn();

View File

@ -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]

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}