[llvm] [X86] Reuse unchanged incoming stack args for tail calls (PR #208248)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 8 09:02:46 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: AxXxB
<details>
<summary>Changes</summary>
When a musttail call forwards an incoming stack argument unchanged to the
same outgoing stack offset, X86 lowering still creates a fixed object and
stores the value back to the stack. In the common same-signature tail-call
case this materializes unnecessary stack traffic before the tail jump.
Reuse the incoming stack slot when MatchingStackOffset proves that the
outgoing argument already resides at the required offset. Keep byval
arguments on the existing copy path and limit the first reuse path to
non-negative fixed stack offsets.
The test covers unchanged stack arguments, a changed stack argument, and a
phi case where only the modified stack argument is stored.
Tested with `ninja -C build -j8 llc` and
`build/bin/llvm-lit -q llvm/test/CodeGen/X86`.
Assisted-by: OpenAI Codex
---
Full diff: https://github.com/llvm/llvm-project/pull/208248.diff
2 Files Affected:
- (modified) llvm/lib/Target/X86/X86ISelLoweringCall.cpp (+30-2)
- (added) llvm/test/CodeGen/X86/preserve-nonecc-tailcall-stack-args.ll (+51)
``````````diff
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 819e0a023c1c5..335b76eef955b 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -2084,6 +2084,28 @@ X86TargetLowering::ByValCopyKind X86TargetLowering::ByValNeedsCopyForTailCall(
return CopyViaTemp;
}
+static bool MatchingStackOffset(SDValue Arg, unsigned Offset,
+ ISD::ArgFlagsTy Flags, MachineFrameInfo &MFI,
+ const MachineRegisterInfo *MRI,
+ const X86InstrInfo *TII,
+ const CCValAssign &VA);
+
+static bool canReuseIncomingTailCallStackArg(
+ SDValue Arg, int32_t Offset, ISD::ArgFlagsTy Flags, MachineFunction &MF,
+ const X86Subtarget &Subtarget, const CCValAssign &VA) {
+ // ByVal tailcall arguments have extra temporary-copy handling above this
+ // point. Keep the first reuse pass limited to direct scalar/vector stack
+ // arguments, matching the common musttail same-signature case.
+ if (Flags.isByVal())
+ return false;
+
+ if (Offset < 0)
+ return false;
+
+ return MatchingStackOffset(Arg, unsigned(Offset), Flags, MF.getFrameInfo(),
+ &MF.getRegInfo(), Subtarget.getInstrInfo(), VA);
+}
+
SDValue
X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const {
@@ -2532,8 +2554,14 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (Flags.isInAlloca() || Flags.isPreallocated())
continue;
// Create frame index.
- int32_t Offset = VA.getLocMemOffset()+FPDiff;
- uint32_t OpSize = (VA.getLocVT().getSizeInBits()+7)/8;
+ int32_t Offset = VA.getLocMemOffset() + FPDiff;
+ uint32_t OpSize = (VA.getLocVT().getSizeInBits() + 7) / 8;
+
+ if (Is64Bit && isTailCall &&
+ canReuseIncomingTailCallStackArg(Arg, Offset, Flags, MF, Subtarget,
+ VA))
+ continue;
+
FI = MF.getFrameInfo().CreateFixedObject(OpSize, Offset, true);
FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
diff --git a/llvm/test/CodeGen/X86/preserve-nonecc-tailcall-stack-args.ll b/llvm/test/CodeGen/X86/preserve-nonecc-tailcall-stack-args.ll
new file mode 100644
index 0000000000000..939efecf417c7
--- /dev/null
+++ b/llvm/test/CodeGen/X86/preserve-nonecc-tailcall-stack-args.ll
@@ -0,0 +1,51 @@
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -relocation-model=static | FileCheck %s
+
+declare preserve_nonecc void @next(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64)
+declare preserve_nonecc void @next_with_cond(i1, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64)
+
+define preserve_nonecc void @static_tail_unchanged(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12, i64 %a13, i64 %a14, i64 %a15, i64 %a16, i64 %a17, i64 %a18, i64 %a19, i64 %a20, i64 %a21, i64 %a22, i64 %a23, i64 %a24, i64 %a25, i64 %a26, i64 %a27, i64 %a28, i64 %a29, i64 %a30, i64 %a31, i64 %a32, i64 %a33, i64 %a34, i64 %a35) {
+; CHECK-LABEL: static_tail_unchanged:
+; CHECK: # %bb.0:
+; CHECK-NEXT: jmp next at PLT # TAILCALL
+entry:
+ musttail call preserve_nonecc void @next(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12, i64 %a13, i64 %a14, i64 %a15, i64 %a16, i64 %a17, i64 %a18, i64 %a19, i64 %a20, i64 %a21, i64 %a22, i64 %a23, i64 %a24, i64 %a25, i64 %a26, i64 %a27, i64 %a28, i64 %a29, i64 %a30, i64 %a31, i64 %a32, i64 %a33, i64 %a34, i64 %a35)
+ ret void
+}
+
+define preserve_nonecc void @static_tail_changed(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12, i64 %a13, i64 %a14, i64 %a15, i64 %a16, i64 %a17, i64 %a18, i64 %a19, i64 %a20, i64 %a21, i64 %a22, i64 %a23, i64 %a24, i64 %a25, i64 %a26, i64 %a27, i64 %a28, i64 %a29, i64 %a30, i64 %a31, i64 %a32, i64 %a33, i64 %a34, i64 %a35) {
+; CHECK-LABEL: static_tail_changed:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movq 168(%rsp), %r10
+; CHECK-NEXT: incq %r10
+; CHECK-NEXT: movq %r10, 168(%rsp)
+; CHECK-NEXT: jmp next at PLT # TAILCALL
+entry:
+ %a32x = add i64 %a32, 1
+ musttail call preserve_nonecc void @next(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12, i64 %a13, i64 %a14, i64 %a15, i64 %a16, i64 %a17, i64 %a18, i64 %a19, i64 %a20, i64 %a21, i64 %a22, i64 %a23, i64 %a24, i64 %a25, i64 %a26, i64 %a27, i64 %a28, i64 %a29, i64 %a30, i64 %a31, i64 %a32x, i64 %a33, i64 %a34, i64 %a35)
+ ret void
+}
+
+define preserve_nonecc void @phi_tail(i1 %cond, i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12, i64 %a13, i64 %a14, i64 %a15, i64 %a16, i64 %a17, i64 %a18, i64 %a19, i64 %a20, i64 %a21, i64 %a22, i64 %a23, i64 %a24, i64 %a25, i64 %a26, i64 %a27, i64 %a28, i64 %a29, i64 %a30, i64 %a31, i64 %a32, i64 %a33, i64 %a34, i64 %a35) {
+; CHECK-LABEL: phi_tail:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movq 176(%rsp), %r10
+; CHECK-NEXT: testb $1, %dil
+; CHECK-NEXT: je .LBB2_2
+; CHECK: # %bb.1:
+; CHECK-NEXT: incq %r10
+; CHECK: .LBB2_2:
+; CHECK-NEXT: movq %r10, 176(%rsp)
+; CHECK-NEXT: movzbl %dil, %edi
+; CHECK-NEXT: jmp next_with_cond at PLT # TAILCALL
+entry:
+ br i1 %cond, label %a, label %b
+a:
+ %a32x = add i64 %a32, 1
+ br label %join
+b:
+ br label %join
+join:
+ %a32m = phi i64 [ %a32x, %a ], [ %a32, %b ]
+ musttail call preserve_nonecc void @next_with_cond(i1 %cond, i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, i64 %a9, i64 %a10, i64 %a11, i64 %a12, i64 %a13, i64 %a14, i64 %a15, i64 %a16, i64 %a17, i64 %a18, i64 %a19, i64 %a20, i64 %a21, i64 %a22, i64 %a23, i64 %a24, i64 %a25, i64 %a26, i64 %a27, i64 %a28, i64 %a29, i64 %a30, i64 %a31, i64 %a32m, i64 %a33, i64 %a34, i64 %a35)
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/208248
More information about the llvm-commits
mailing list