[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