Skip to content

[22.x][LoongArch] Revert musttail/byval/sret Changes#191525

Merged
c-rhodes merged 1 commit into
llvm:release/22.xfrom
lenary:pr/22.x/revert-loongarch-musttail
Apr 17, 2026
Merged

[22.x][LoongArch] Revert musttail/byval/sret Changes#191525
c-rhodes merged 1 commit into
llvm:release/22.xfrom
lenary:pr/22.x/revert-loongarch-musttail

Conversation

@lenary

@lenary lenary commented Apr 10, 2026

Copy link
Copy Markdown
Member

This reverts:

There's a lifetime issue in the implementation, where an SDValue is saved and may be used outside the current basic block.

The corresponding revert on main is
501417b (#191508) - in this case only the LoongArch changes made it to the 22.x branches, so this commit only affects that architecture.

@llvmbot

llvmbot commented Apr 10, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-backend-loongarch

Author: Sam Elliott (lenary)

Changes

This reverts:

There's a lifetime issue in the implementation, where an SDValue is saved and may be used outside the current basic block.

The corresponding revert on main is
501417b (#191508) - in this case only the LoongArch changes made it to the 22.x branches, so this commit only affects that architecture.


Patch is 35.10 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/191525.diff

5 Files Affected:

  • (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+25-80)
  • (modified) llvm/lib/Target/LoongArch/LoongArchMachineFunctionInfo.h (-14)
  • (removed) llvm/test/CodeGen/LoongArch/issue187832.ll (-48)
  • (removed) llvm/test/CodeGen/LoongArch/musttail.ll (-567)
  • (modified) llvm/test/CodeGen/LoongArch/tail-calls.ll (+9-4)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 7cb61bafb5ad3..2cfe3b2bc1a99 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -8157,7 +8157,6 @@ SDValue LoongArchTargetLowering::LowerFormalArguments(
     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
 
   MachineFunction &MF = DAG.getMachineFunction();
-  auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
 
   switch (CallConv) {
   default:
@@ -8221,8 +8220,6 @@ SDValue LoongArchTargetLowering::LowerFormalArguments(
       continue;
     }
     InVals.push_back(ArgValue);
-    if (Ins[InsIdx].Flags.isByVal())
-      LoongArchFI->addIncomingByValArgs(ArgValue);
   }
 
   if (IsVarArg) {
@@ -8231,6 +8228,7 @@ SDValue LoongArchTargetLowering::LowerFormalArguments(
     const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
     MachineFrameInfo &MFI = MF.getFrameInfo();
     MachineRegisterInfo &RegInfo = MF.getRegInfo();
+    auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
 
     // Offset of the first variable argument from stack pointer, and size of
     // the vararg save area. For now, the varargs save area is either zero or
@@ -8280,8 +8278,6 @@ SDValue LoongArchTargetLowering::LowerFormalArguments(
     LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
   }
 
-  LoongArchFI->setArgumentStackSize(CCInfo.getStackSize());
-
   // All stores are grouped in one node to allow the matching between
   // the size of Ins and InVals. This only happens for vararg functions.
   if (!OutChains.empty()) {
@@ -8338,11 +8334,9 @@ bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
   auto &Outs = CLI.Outs;
   auto &Caller = MF.getFunction();
   auto CallerCC = Caller.getCallingConv();
-  auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
 
-  // If the stack arguments for this call do not fit into our own save area then
-  // the call cannot be made tail.
-  if (CCInfo.getStackSize() > LoongArchFI->getArgumentStackSize())
+  // Do not tail call opt if the stack is used to pass parameters.
+  if (CCInfo.getStackSize() != 0)
     return false;
 
   // Do not tail call opt if any parameters need to be passed indirectly.
@@ -8354,19 +8348,13 @@ bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
   // semantics.
   auto IsCallerStructRet = Caller.hasStructRetAttr();
   auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
-  if (IsCallerStructRet != IsCalleeStructRet)
+  if (IsCallerStructRet || IsCalleeStructRet)
     return false;
 
-  // Do not tail call opt if caller's and callee's byval arguments do not match.
-  for (unsigned i = 0, j = 0; i < Outs.size(); ++i) {
-    if (!Outs[i].Flags.isByVal())
-      continue;
-    if (j >= LoongArchFI->getIncomingByValArgsSize())
-      return false;
-    if (LoongArchFI->getIncomingByValArgs(j).getValueType() != Outs[i].ArgVT)
+  // Do not tail call opt if either the callee or caller has a byval argument.
+  for (auto &Arg : Outs)
+    if (Arg.Flags.isByVal())
       return false;
-    ++j;
-  }
 
   // The callee has to preserve all registers the caller needs to preserve.
   const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
@@ -8376,14 +8364,6 @@ bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
     if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
       return false;
   }
-
-  // If the callee takes no arguments then go on to check the results of the
-  // call.
-  const MachineRegisterInfo &MRI = MF.getRegInfo();
-  const SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
-  if (!parametersInCSRMatch(MRI, CallerPreserved, ArgLocs, OutVals))
-    return false;
-
   return true;
 }
 
@@ -8411,7 +8391,6 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
   bool &IsTailCall = CLI.IsTailCall;
 
   MachineFunction &MF = DAG.getMachineFunction();
-  auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
 
   // Analyze the operands of the call, assigning locations to each operand.
   SmallVector<CCValAssign> ArgLocs;
@@ -8437,7 +8416,7 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
 
   // Create local copies for byval args.
   SmallVector<SDValue> ByValArgs;
-  for (unsigned i = 0, j = 0, e = Outs.size(); i != e; ++i) {
+  for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
     ISD::ArgFlagsTy Flags = Outs[i].Flags;
     if (!Flags.isByVal())
       continue;
@@ -8445,39 +8424,22 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
     SDValue Arg = OutVals[i];
     unsigned Size = Flags.getByValSize();
     Align Alignment = Flags.getNonZeroByValAlign();
+
+    int FI =
+        MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
+    SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
     SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
-    SDValue Dst;
 
-    if (IsTailCall) {
-      SDValue CallerArg = LoongArchFI->getIncomingByValArgs(j++);
-      if (isa<GlobalAddressSDNode>(Arg) || isa<ExternalSymbolSDNode>(Arg) ||
-          isa<FrameIndexSDNode>(Arg))
-        Dst = CallerArg;
-    } else {
-      int FI =
-          MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
-      Dst = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
-    }
-    if (Dst) {
-      Chain =
-          DAG.getMemcpy(Chain, DL, Dst, Arg, SizeNode, Alignment,
-                        /*IsVolatile=*/false,
-                        /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
-                        MachinePointerInfo(), MachinePointerInfo());
-      ByValArgs.push_back(Dst);
-    }
+    Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
+                          /*IsVolatile=*/false,
+                          /*AlwaysInline=*/false, /*CI=*/nullptr, std::nullopt,
+                          MachinePointerInfo(), MachinePointerInfo());
+    ByValArgs.push_back(FIPtr);
   }
 
   if (!IsTailCall)
     Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
 
-  // During a tail call, stores to the argument area must happen after all of
-  // the function's incoming arguments have been loaded because they may alias.
-  // This is done by folding in a TokenFactor from LowerFormalArguments, but
-  // there's no point in doing so repeatedly so this tracks whether that's
-  // happened yet.
-  bool AfterFormalArgLoads = false;
-
   // Copy argument values to their designated locations.
   SmallVector<std::pair<Register, SDValue>> RegsToPass;
   SmallVector<SDValue> MemOpChains;
@@ -8572,44 +8534,27 @@ LoongArchTargetLowering::LowerCall(CallLoweringInfo &CLI,
     }
 
     // Use local copy if it is a byval arg.
-    if (Flags.isByVal()) {
-      if (!IsTailCall || (isa<GlobalAddressSDNode>(ArgValue) ||
-                          isa<ExternalSymbolSDNode>(ArgValue) ||
-                          isa<FrameIndexSDNode>(ArgValue)))
-        ArgValue = ByValArgs[j++];
-    }
+    if (Flags.isByVal())
+      ArgValue = ByValArgs[j++];
 
     if (VA.isRegLoc()) {
       // Queue up the argument copies and emit them at the end.
       RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
     } else {
       assert(VA.isMemLoc() && "Argument not register or memory");
-      SDValue DstAddr;
-      MachinePointerInfo DstInfo;
-      int32_t Offset = VA.getLocMemOffset();
+      assert(!IsTailCall && "Tail call not allowed if stack is used "
+                            "for passing parameters");
 
       // Work out the address of the stack slot.
       if (!StackPtr.getNode())
         StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
-
-      if (IsTailCall) {
-        unsigned OpSize = divideCeil(VA.getValVT().getSizeInBits(), 8);
-        int FI = MF.getFrameInfo().CreateFixedObject(OpSize, Offset, true);
-        DstAddr = DAG.getFrameIndex(FI, PtrVT);
-        DstInfo = MachinePointerInfo::getFixedStack(MF, FI);
-        if (!AfterFormalArgLoads) {
-          Chain = DAG.getStackArgumentTokenFactor(Chain);
-          AfterFormalArgLoads = true;
-        }
-      } else {
-        SDValue PtrOff = DAG.getIntPtrConstant(Offset, DL);
-        DstAddr = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, PtrOff);
-        DstInfo = MachinePointerInfo::getStack(MF, Offset);
-      }
+      SDValue Address =
+          DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
+                      DAG.getIntPtrConstant(VA.getLocMemOffset(), DL));
 
       // Emit the store.
       MemOpChains.push_back(
-          DAG.getStore(Chain, DL, ArgValue, DstAddr, DstInfo));
+          DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
     }
   }
 
diff --git a/llvm/lib/Target/LoongArch/LoongArchMachineFunctionInfo.h b/llvm/lib/Target/LoongArch/LoongArchMachineFunctionInfo.h
index 4159b97bcf598..904985c189dba 100644
--- a/llvm/lib/Target/LoongArch/LoongArchMachineFunctionInfo.h
+++ b/llvm/lib/Target/LoongArch/LoongArchMachineFunctionInfo.h
@@ -32,17 +32,10 @@ class LoongArchMachineFunctionInfo : public MachineFunctionInfo {
   /// Size of stack frame to save callee saved registers
   unsigned CalleeSavedStackSize = 0;
 
-  /// Amount of bytes on stack consumed by the arguments being passed on
-  /// the stack
-  unsigned ArgumentStackSize = 0;
-
   /// FrameIndex of the spill slot when there is no scavenged register in
   /// insertIndirectBranch.
   int BranchRelaxationSpillFrameIndex = -1;
 
-  /// Incoming ByVal arguments
-  SmallVector<SDValue, 8> IncomingByValArgs;
-
   /// Registers that have been sign extended from i32.
   SmallVector<Register, 8> SExt32Registers;
 
@@ -70,9 +63,6 @@ class LoongArchMachineFunctionInfo : public MachineFunctionInfo {
   unsigned getCalleeSavedStackSize() const { return CalleeSavedStackSize; }
   void setCalleeSavedStackSize(unsigned Size) { CalleeSavedStackSize = Size; }
 
-  unsigned getArgumentStackSize() const { return ArgumentStackSize; }
-  void setArgumentStackSize(unsigned size) { ArgumentStackSize = size; }
-
   int getBranchRelaxationSpillFrameIndex() {
     return BranchRelaxationSpillFrameIndex;
   }
@@ -80,10 +70,6 @@ class LoongArchMachineFunctionInfo : public MachineFunctionInfo {
     BranchRelaxationSpillFrameIndex = Index;
   }
 
-  void addIncomingByValArgs(SDValue Val) { IncomingByValArgs.push_back(Val); }
-  SDValue getIncomingByValArgs(int Idx) { return IncomingByValArgs[Idx]; }
-  unsigned getIncomingByValArgsSize() const { return IncomingByValArgs.size(); }
-
   void addSExt32Register(Register Reg) { SExt32Registers.push_back(Reg); }
 
   bool isSExt32Register(Register Reg) const {
diff --git a/llvm/test/CodeGen/LoongArch/issue187832.ll b/llvm/test/CodeGen/LoongArch/issue187832.ll
deleted file mode 100644
index b483a7640e171..0000000000000
--- a/llvm/test/CodeGen/LoongArch/issue187832.ll
+++ /dev/null
@@ -1,48 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -mtriple=loongarch32 %s -o - | FileCheck %s --check-prefix=LA32
-; RUN: llc -mtriple=loongarch64 %s -o - | FileCheck %s --check-prefix=LA64
-
-%Box = type { i32, i32, i32, i8, [3 x i8], i32, i8, [1 x i8], i16, i16, i8, [5 x i8], { i64, ptr }, { i64, ptr }, { i64, ptr } }
-
-define void @test(ptr byval(%Box) %0) nounwind {
-; LA32-LABEL: test:
-; LA32:       # %bb.0:
-; LA32-NEXT:    addi.w $sp, $sp, -112
-; LA32-NEXT:    st.w $ra, $sp, 108 # 4-byte Folded Spill
-; LA32-NEXT:    st.w $fp, $sp, 104 # 4-byte Folded Spill
-; LA32-NEXT:    addi.w $fp, $sp, 24
-; LA32-NEXT:    ori $a2, $zero, 80
-; LA32-NEXT:    move $a0, $fp
-; LA32-NEXT:    move $a1, $zero
-; LA32-NEXT:    bl memcpy
-; LA32-NEXT:    st.w $zero, $sp, 8
-; LA32-NEXT:    st.w $zero, $sp, 4
-; LA32-NEXT:    st.w $zero, $sp, 0
-; LA32-NEXT:    move $a0, $zero
-; LA32-NEXT:    move $a1, $zero
-; LA32-NEXT:    move $a2, $zero
-; LA32-NEXT:    move $a3, $fp
-; LA32-NEXT:    move $a4, $zero
-; LA32-NEXT:    move $a5, $zero
-; LA32-NEXT:    move $a6, $zero
-; LA32-NEXT:    move $a7, $zero
-; LA32-NEXT:    jirl $ra, $zero, 0
-; LA32-NEXT:    ld.w $fp, $sp, 104 # 4-byte Folded Reload
-; LA32-NEXT:    ld.w $ra, $sp, 108 # 4-byte Folded Reload
-; LA32-NEXT:    addi.w $sp, $sp, 112
-; LA32-NEXT:    ret
-;
-; LA64-LABEL: test:
-; LA64:       # %bb.0:
-; LA64-NEXT:    movgr2fr.d $fa0, $zero
-; LA64-NEXT:    move $a0, $zero
-; LA64-NEXT:    move $a1, $zero
-; LA64-NEXT:    move $a2, $zero
-; LA64-NEXT:    move $a3, $zero
-; LA64-NEXT:    move $a4, $zero
-; LA64-NEXT:    move $a5, $zero
-; LA64-NEXT:    move $a6, $zero
-; LA64-NEXT:    jr $a0
-  tail call void null(ptr null, double 0.000000e+00, ptr byval(%Box) null, { i64, ptr } zeroinitializer, i32 0, i64 0, i1 false)
-  ret void
-}
diff --git a/llvm/test/CodeGen/LoongArch/musttail.ll b/llvm/test/CodeGen/LoongArch/musttail.ll
deleted file mode 100644
index 23369ddd81fca..0000000000000
--- a/llvm/test/CodeGen/LoongArch/musttail.ll
+++ /dev/null
@@ -1,567 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -mtriple=loongarch32 %s -o - | FileCheck %s --check-prefix=LA32
-; RUN: llc -mtriple=loongarch64 %s -o - | FileCheck %s --check-prefix=LA64
-
-declare i32 @many_args_callee(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9)
-
-define i32 @many_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) {
-; LA32-LABEL: many_args_tail:
-; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a0, $zero, 8
-; LA32-NEXT:    st.w $a0, $sp, 0
-; LA32-NEXT:    ori $a0, $zero, 9
-; LA32-NEXT:    ori $a1, $zero, 1
-; LA32-NEXT:    ori $a2, $zero, 2
-; LA32-NEXT:    ori $a3, $zero, 3
-; LA32-NEXT:    ori $a4, $zero, 4
-; LA32-NEXT:    ori $a5, $zero, 5
-; LA32-NEXT:    ori $a6, $zero, 6
-; LA32-NEXT:    ori $a7, $zero, 7
-; LA32-NEXT:    st.w $a0, $sp, 4
-; LA32-NEXT:    move $a0, $zero
-; LA32-NEXT:    b many_args_callee
-;
-; LA64-LABEL: many_args_tail:
-; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a0, $zero, 8
-; LA64-NEXT:    st.d $a0, $sp, 0
-; LA64-NEXT:    ori $a0, $zero, 9
-; LA64-NEXT:    ori $a1, $zero, 1
-; LA64-NEXT:    ori $a2, $zero, 2
-; LA64-NEXT:    ori $a3, $zero, 3
-; LA64-NEXT:    ori $a4, $zero, 4
-; LA64-NEXT:    ori $a5, $zero, 5
-; LA64-NEXT:    ori $a6, $zero, 6
-; LA64-NEXT:    ori $a7, $zero, 7
-; LA64-NEXT:    st.d $a0, $sp, 8
-; LA64-NEXT:    move $a0, $zero
-; LA64-NEXT:    pcaddu18i $t8, %call36(many_args_callee)
-; LA64-NEXT:    jr $t8
-  %ret = tail call i32 @many_args_callee(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9)
-  ret i32 %ret
-}
-
-define i32 @many_args_musttail(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) {
-; LA32-LABEL: many_args_musttail:
-; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a0, $zero, 8
-; LA32-NEXT:    st.w $a0, $sp, 0
-; LA32-NEXT:    ori $a0, $zero, 9
-; LA32-NEXT:    ori $a1, $zero, 1
-; LA32-NEXT:    ori $a2, $zero, 2
-; LA32-NEXT:    ori $a3, $zero, 3
-; LA32-NEXT:    ori $a4, $zero, 4
-; LA32-NEXT:    ori $a5, $zero, 5
-; LA32-NEXT:    ori $a6, $zero, 6
-; LA32-NEXT:    ori $a7, $zero, 7
-; LA32-NEXT:    st.w $a0, $sp, 4
-; LA32-NEXT:    move $a0, $zero
-; LA32-NEXT:    b many_args_callee
-;
-; LA64-LABEL: many_args_musttail:
-; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a0, $zero, 8
-; LA64-NEXT:    st.d $a0, $sp, 0
-; LA64-NEXT:    ori $a0, $zero, 9
-; LA64-NEXT:    ori $a1, $zero, 1
-; LA64-NEXT:    ori $a2, $zero, 2
-; LA64-NEXT:    ori $a3, $zero, 3
-; LA64-NEXT:    ori $a4, $zero, 4
-; LA64-NEXT:    ori $a5, $zero, 5
-; LA64-NEXT:    ori $a6, $zero, 6
-; LA64-NEXT:    ori $a7, $zero, 7
-; LA64-NEXT:    st.d $a0, $sp, 8
-; LA64-NEXT:    move $a0, $zero
-; LA64-NEXT:    pcaddu18i $t8, %call36(many_args_callee)
-; LA64-NEXT:    jr $t8
-  %ret = musttail call i32 @many_args_callee(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9)
-  ret i32 %ret
-}
-
-; This function has more arguments than it's tail-callee. This isn't valid for
-; the musttail attribute, but can still be tail-called as a non-guaranteed
-; optimisation, because the outgoing arguments to @many_args_callee fit in the
-; stack space allocated by the caller of @more_args_tail.
-define i32 @more_args_tail(i32 %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) {
-; LA32-LABEL: more_args_tail:
-; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a0, $zero, 8
-; LA32-NEXT:    st.w $a0, $sp, 0
-; LA32-NEXT:    ori $a0, $zero, 9
-; LA32-NEXT:    ori $a1, $zero, 1
-; LA32-NEXT:    ori $a2, $zero, 2
-; LA32-NEXT:    ori $a3, $zero, 3
-; LA32-NEXT:    ori $a4, $zero, 4
-; LA32-NEXT:    ori $a5, $zero, 5
-; LA32-NEXT:    ori $a6, $zero, 6
-; LA32-NEXT:    ori $a7, $zero, 7
-; LA32-NEXT:    st.w $a0, $sp, 4
-; LA32-NEXT:    move $a0, $zero
-; LA32-NEXT:    b many_args_callee
-;
-; LA64-LABEL: more_args_tail:
-; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a0, $zero, 8
-; LA64-NEXT:    st.d $a0, $sp, 0
-; LA64-NEXT:    ori $a0, $zero, 9
-; LA64-NEXT:    ori $a1, $zero, 1
-; LA64-NEXT:    ori $a2, $zero, 2
-; LA64-NEXT:    ori $a3, $zero, 3
-; LA64-NEXT:    ori $a4, $zero, 4
-; LA64-NEXT:    ori $a5, $zero, 5
-; LA64-NEXT:    ori $a6, $zero, 6
-; LA64-NEXT:    ori $a7, $zero, 7
-; LA64-NEXT:    st.d $a0, $sp, 8
-; LA64-NEXT:    move $a0, $zero
-; LA64-NEXT:    pcaddu18i $t8, %call36(many_args_callee)
-; LA64-NEXT:    jr $t8
-  %ret = tail call i32 @many_args_callee(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9)
-  ret i32 %ret
-}
-
-; Again, this isn't valid for musttail, but can be tail-called in practice
-; because the stack size if the same.
-define i32 @different_args_tail_32bit(i64 %0, i64 %1, i64 %2, i64 %3, i64 %4) nounwind {
-; LA32-LABEL: different_args_tail_32bit:
-; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a0, $zero, 8
-; LA32-NEXT:    st.w $a0, $sp, 0
-; LA32-NEXT:    ori $a0, $zero, 9
-; LA32-NEXT:    ori $a1, $zero, 1
-; LA32-NEXT:    ori $a2, $zero, 2
-; LA32-NEXT:    ori $a3, $zero, 3
-; LA32-NEXT:    ori $a4, $zero, 4
-; LA32-NEXT:    ori $a5, $zero, 5
-; LA32-NEXT:    ori $a6, $zero, 6
-; LA32-NEXT:    ori $a7, $zero, 7
-; LA32-NEXT:    st.w $a0, $sp, 4
-; LA32-NEXT:    move $a0, $zero
-; LA32-NEXT:    b many_args_callee
-;
-; LA64-LABEL: different_args_tail_32bit:
-; LA64:       # %bb.0:
-; LA64-NEXT:    addi.d $sp, $sp, -32
-; LA64-NEXT:    st.d $ra, $sp, 24 # 8-byte Folded Spill
-; LA64-NEXT:    ori $a0, $zero, 9
-; LA64-NEXT:    st.d $a0, $sp, 8
-; LA64-NEXT:    ori $a0, $zero, 8
-; LA64-NEXT:    ori $a1, $zero, 1
-; LA64-NEXT:    ori $a2, $zero, 2
-; LA64-NEXT:    ori $a3, $zero, 3
-; LA64-NEXT:    ori $a4, $zero, 4
-; LA64-NEXT:    ori $a5, $zero, 5
-; LA64-NEXT:    ori $a6, $zero, 6
-; LA64-NEXT:    ori $a7, $zero, 7
-; LA64-NEXT:    st.d $a0, $sp, 0
-; LA64-NEXT:    move $a0, $zero
-; LA64-NEXT:    pcaddu18i $ra, %call36(many_args_callee)
-; LA64-NEXT:    jirl $ra, $ra, 0
-; LA64-NEXT:    ld.d $ra, $sp, 24 # 8-byte Folded Reload
-; LA64-NEXT:    addi.d $sp, $sp, 32
-; LA64-NEXT:    ret
-  %ret = tail call i32 @many_args_callee(i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9)
-  ret i32 %ret
-}
-
-define i32 @different_args_tail_64bit(i128 %0, i128 %1, i128 %2, i128 %3, i128 %4) nounwind {
-; LA32-LABEL: different_args_tail_64bit:
-; LA32:       # %bb.0:
-; LA32-NEXT:    addi.w $sp, $sp, -16
-; LA32-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
-; LA32-NEXT:    ori $a0, $zero, 9
-; LA32-NEXT:    st.w $a0, $sp, 4
-; LA32-NEXT:    ori $a0, $zero, 8
-; LA32-NEXT:    ori $a1, $zero, 1
-; LA32-NEXT:    ori $a2, $zero, 2
-; LA32-NEXT:    ori $a3, $zero, 3
-; LA32-NEXT:    ori $a4, $zero, 4
-; LA32-NEXT:    ori $a5, $zero, 5
-; LA32-NEXT:    ori $a6, $zero, 6
-; LA32-NEXT:    ori $a7, $zero, 7
-; LA32-NEXT:    st.w $a0, $sp, 0
-; LA32-NEXT:    move $a0, $zero
-; LA32-NEXT:    bl many_args_callee
-; LA32-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
-; LA32-NEXT:    addi.w $sp, $sp, 16
-; LA32-NEXT:    ret
-;
-; LA64-LABEL: different_args_tail_64bit:
-; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a0, $zero, 8
-; LA64-NEXT:    st.d $a0, $sp, 0
-; LA64-NEXT:    ori $a0, $zero, 9
-; LA64-NEXT:    ori $a1, $zero, 1
-; LA64-NEXT:    ori $a2, $zero, 2
-; LA64-NEXT:    ori $a3, $zero, 3
-; LA64-NEXT:    ori $a4, $zero, 4
-; LA64-NEXT:    or...
[truncated]

@heiher heiher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, lets start again.

@github-project-automation github-project-automation Bot moved this from Needs Triage to Needs Merge in LLVM Release Status Apr 11, 2026
This reverts:
- 2b839f6 (llvm#168506)
- d40e607 (llvm#188006)

There's a lifetime issue in the implementation, where an SDValue is
saved and may be used outside the current basic block.

The corresponding revert on `main` is
501417b (llvm#191508) - in this case only
the LoongArch changes made it to the 22.x branches, so this commit only
affects that architecture.
@c-rhodes c-rhodes force-pushed the pr/22.x/revert-loongarch-musttail branch from 76a2447 to fa56327 Compare April 17, 2026 09:45
@c-rhodes c-rhodes merged commit fa56327 into llvm:release/22.x Apr 17, 2026
1 check was pending
@github-project-automation github-project-automation Bot moved this from Needs Merge to Done in LLVM Release Status Apr 17, 2026
@lenary lenary deleted the pr/22.x/revert-loongarch-musttail branch April 21, 2026 20:51
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request May 17, 2026
…=folkertdev

explicit tail calls: ignore some tests on unsupported LLVM targets

Fixes rust-lang#148748

Add ignore derivatives to two tests that cause the most platforms to fail, there are two reasons:

All tests involving `musttail` should fail on these platforms due to poor support overall by LLVM, but since they have low usage and supposedly already have many tests failing we limit ignores to the two "worst" tests.

```
//@ ignore-aix
//@ ignore-csky
//@ ignore-mips
//@ ignore-mips64
//@ ignore-powerpc
//@ ignore-powerpc64
//@ ignore-thumb
```

aix/powerpc issue: llvm/llvm-project#187119
thumb issue: llvm/llvm-project#73167
mips has been fixed but it is in a different LLVM version than what is pinned by Rust: llvm/llvm-project#57795

These were caused by argument/returns that do not fit in registers (e.g., indirect), they had a fix but were reverted due to lifetime issues:

```
//@ ignore-riscv64
//@ ignore-loongarch32
//@ ignore-loongarch64
```

RISC-V had a fix which got reverted: llvm/llvm-project#191508
LoongArch fix also got reverted: llvm/llvm-project#191525

Also add missing compiletest directive names for `ignore-csky`, `ignore-mips`, and `ignore-mips64`.

r? folkertdev
rust-timer added a commit to rust-lang/rust that referenced this pull request May 18, 2026
Rollup merge of #156585 - InvalidPathException:llvm-error, r=folkertdev

explicit tail calls: ignore some tests on unsupported LLVM targets

Fixes #148748

Add ignore derivatives to two tests that cause the most platforms to fail, there are two reasons:

All tests involving `musttail` should fail on these platforms due to poor support overall by LLVM, but since they have low usage and supposedly already have many tests failing we limit ignores to the two "worst" tests.

```
//@ ignore-aix
//@ ignore-csky
//@ ignore-mips
//@ ignore-mips64
//@ ignore-powerpc
//@ ignore-powerpc64
//@ ignore-thumb
```

aix/powerpc issue: llvm/llvm-project#187119
thumb issue: llvm/llvm-project#73167
mips has been fixed but it is in a different LLVM version than what is pinned by Rust: llvm/llvm-project#57795

These were caused by argument/returns that do not fit in registers (e.g., indirect), they had a fix but were reverted due to lifetime issues:

```
//@ ignore-riscv64
//@ ignore-loongarch32
//@ ignore-loongarch64
```

RISC-V had a fix which got reverted: llvm/llvm-project#191508
LoongArch fix also got reverted: llvm/llvm-project#191525

Also add missing compiletest directive names for `ignore-csky`, `ignore-mips`, and `ignore-mips64`.

r? folkertdev
github-actions Bot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request May 18, 2026
explicit tail calls: ignore some tests on unsupported LLVM targets

Fixes rust-lang/rust#148748

Add ignore derivatives to two tests that cause the most platforms to fail, there are two reasons:

All tests involving `musttail` should fail on these platforms due to poor support overall by LLVM, but since they have low usage and supposedly already have many tests failing we limit ignores to the two "worst" tests.

```
//@ ignore-aix
//@ ignore-csky
//@ ignore-mips
//@ ignore-mips64
//@ ignore-powerpc
//@ ignore-powerpc64
//@ ignore-thumb
```

aix/powerpc issue: llvm/llvm-project#187119
thumb issue: llvm/llvm-project#73167
mips has been fixed but it is in a different LLVM version than what is pinned by Rust: llvm/llvm-project#57795

These were caused by argument/returns that do not fit in registers (e.g., indirect), they had a fix but were reverted due to lifetime issues:

```
//@ ignore-riscv64
//@ ignore-loongarch32
//@ ignore-loongarch64
```

RISC-V had a fix which got reverted: llvm/llvm-project#191508
LoongArch fix also got reverted: llvm/llvm-project#191525

Also add missing compiletest directive names for `ignore-csky`, `ignore-mips`, and `ignore-mips64`.

r? folkertdev
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

4 participants