[llvm] 86d3577 - [X86] Simplify hasCalleePopSRet, NFCI (#176519)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 18 14:19:36 PST 2026
Author: Reid Kleckner
Date: 2026-01-18T14:19:32-08:00
New Revision: 86d35771342c99d974c1965f45454862926d13a8
URL: https://github.com/llvm/llvm-project/commit/86d35771342c99d974c1965f45454862926d13a8
DIFF: https://github.com/llvm/llvm-project/commit/86d35771342c99d974c1965f45454862926d13a8.diff
LOG: [X86] Simplify hasCalleePopSRet, NFCI (#176519)
The implementation was rewritten for clarity, and the extra boolean
parameter to the sibcall eligibility check was removed in favor of
recalculating this property. The compile time impact should be
negigible, the vast majority of callers will return early on the
TT.isX86_32() check.
The comments now try to clarify which platforms have this
callee-pop-sret behavior, which was always hard for me to figure out
from the previous code.
I was able to remove two ambiguous checks for `canGuaranteeTCO`, and
what those checks were really doing was checking for `fastcc` and other
calling conventions that pass arguments in registers. Instead of looking
for the `inreg` IR attribute, now the code looks at the CCValAssign to
check if it the pointer is passed in memory or registers, so it works
smoothly with conventions like `fastcc` that don't require explicit
`inreg` annotations.
Added:
Modified:
llvm/lib/Target/X86/X86ISelLowering.h
llvm/lib/Target/X86/X86ISelLoweringCall.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h
index 1d164253ccc80..8881dc3ea1912 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.h
+++ b/llvm/lib/Target/X86/X86ISelLowering.h
@@ -1747,10 +1747,10 @@ namespace llvm {
// Call lowering helpers.
/// Check whether the call is eligible for sibling call optimization.
- bool isEligibleForSiblingCallOpt(TargetLowering::CallLoweringInfo &CLI,
- CCState &CCInfo,
- SmallVectorImpl<CCValAssign> &ArgLocs,
- bool IsCalleePopSRet) const;
+ bool
+ isEligibleForSiblingCallOpt(TargetLowering::CallLoweringInfo &CLI,
+ CCState &CCInfo,
+ SmallVectorImpl<CCValAssign> &ArgLocs) const;
SDValue EmitTailCallLoadRetAddr(SelectionDAG &DAG, SDValue &OutRetAddr,
SDValue Chain, bool IsTailCall,
bool Is64Bit, int FPDiff,
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 7583da7cc10b2..f8483d3e30e7f 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -1205,50 +1205,31 @@ SDValue X86TargetLowering::LowerCallResult(
return Chain;
}
-//===----------------------------------------------------------------------===//
-// C & StdCall & Fast Calling Convention implementation
-//===----------------------------------------------------------------------===//
-// StdCall calling convention seems to be standard for many Windows' API
-// routines and around. It
diff ers from C calling convention just a little:
-// callee should clean up the stack, not caller. Symbols should be also
-// decorated in some fancy way :) It doesn't support any vector arguments.
-// For info on fast calling convention see Fast Calling Convention (tail call)
-// implementation LowerX86_32FastCCCallTo.
-
/// Determines whether Args, either a set of outgoing arguments to a call, or a
/// set of incoming args of a call, contains an sret pointer that the callee
-/// pops
+/// pops. This happens on most x86-32, System V platforms, unless register
+/// parameters are in use (-mregparm=1+, regcallcc, etc).
template <typename T>
static bool hasCalleePopSRet(const SmallVectorImpl<T> &Args,
+ const SmallVectorImpl<CCValAssign> &ArgLocs,
const X86Subtarget &Subtarget) {
// Not C++20 (yet), so no concepts available.
static_assert(std::is_same_v<T, ISD::OutputArg> ||
std::is_same_v<T, ISD::InputArg>,
"requires ISD::OutputArg or ISD::InputArg");
- // Only 32-bit pops the sret. It's a 64-bit world these days, so early-out
- // for most compilations.
- if (!Subtarget.is32Bit())
- return false;
-
- if (Args.empty())
- return false;
-
- // Most calls do not have an sret argument, check the arg next.
- const ISD::ArgFlagsTy &Flags = Args[0].Flags;
- if (!Flags.isSRet() || Flags.isInReg())
+ // Popping the sret pointer only happens on x86-32 System V ABI platforms
+ // (Linux, Cygwin, BSDs, Mac, etc). That excludes Windows-minus-Cygwin and
+ // MCU.
+ const Triple &TT = Subtarget.getTargetTriple();
+ if (!TT.isX86_32() || TT.isOSMSVCRT() || TT.isOSIAMCU())
return false;
- // The MSVCabi does not pop the sret.
- if (Subtarget.getTargetTriple().isOSMSVCRT())
- return false;
-
- // MCUs don't pop the sret
- if (Subtarget.isTargetMCU())
- return false;
-
- // Callee pops argument
- return true;
+ // Check if the first argument is marked sret and if it is passed in memory.
+ bool IsSRetInMem = false;
+ if (!Args.empty())
+ IsSRetInMem = Args.front().Flags.isSRet() && ArgLocs.front().isMemLoc();
+ return IsSRetInMem;
}
/// Make a copy of an aggregate at address specified by "Src" to address
@@ -1894,7 +1875,7 @@ SDValue X86TargetLowering::LowerFormalArguments(
} else {
FuncInfo->setBytesToPopOnReturn(0); // Callee pops nothing.
// If this is an sret function, the return should pop the hidden pointer.
- if (!canGuaranteeTCO(CallConv) && hasCalleePopSRet(Ins, Subtarget))
+ if (hasCalleePopSRet(Ins, ArgLocs, Subtarget))
FuncInfo->setBytesToPopOnReturn(4);
}
@@ -2073,8 +2054,6 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
bool IsWin64 = Subtarget.isCallingConvWin64(CallConv);
bool ShouldGuaranteeTCO = shouldGuaranteeTCO(
CallConv, MF.getTarget().Options.GuaranteedTailCallOpt);
- bool IsCalleePopSRet =
- !ShouldGuaranteeTCO && hasCalleePopSRet(Outs, Subtarget);
X86MachineFunctionInfo *X86Info = MF.getInfo<X86MachineFunctionInfo>();
bool HasNCSR = (CB && isa<CallInst>(CB) &&
CB->hasFnAttr("no_caller_saved_registers"));
@@ -2136,8 +2115,7 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// be a tail call that doesn't require heroics like moving the return
// address or swapping byval arguments. We treat some musttail calls as
// sibling calls to avoid unnecessary argument copies.
- IsSibcall =
- isEligibleForSiblingCallOpt(CLI, CCInfo, ArgLocs, IsCalleePopSRet);
+ IsSibcall = isEligibleForSiblingCallOpt(CLI, CCInfo, ArgLocs);
isTailCall = IsSibcall || IsMustTail;
}
@@ -2735,12 +2713,13 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Create the CALLSEQ_END node.
unsigned NumBytesForCalleeToPop = 0; // Callee pops nothing.
if (X86::isCalleePop(CallConv, Is64Bit, isVarArg,
- DAG.getTarget().Options.GuaranteedTailCallOpt))
+ DAG.getTarget().Options.GuaranteedTailCallOpt)) {
NumBytesForCalleeToPop = NumBytes; // Callee pops everything
- else if (!canGuaranteeTCO(CallConv) && IsCalleePopSRet)
+ } else if (hasCalleePopSRet(Outs, ArgLocs, Subtarget)) {
// If this call passes a struct-return pointer, the callee
// pops that struct pointer.
NumBytesForCalleeToPop = 4;
+ }
// Returns a glue for retval copy to use.
if (!IsSibcall) {
@@ -2947,7 +2926,7 @@ mayBeSRetTailCallCompatible(const TargetLowering::CallLoweringInfo &CLI,
/// emission in all cases.
bool X86TargetLowering::isEligibleForSiblingCallOpt(
TargetLowering::CallLoweringInfo &CLI, CCState &CCInfo,
- SmallVectorImpl<CCValAssign> &ArgLocs, bool IsCalleePopSRet) const {
+ SmallVectorImpl<CCValAssign> &ArgLocs) const {
SelectionDAG &DAG = CLI.DAG;
const SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
const SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
@@ -3012,7 +2991,7 @@ bool X86TargetLowering::isEligibleForSiblingCallOpt(
// sret. Condition #b is harder to determine.
if (!mayBeSRetTailCallCompatible(CLI, SRetReg))
return false;
- } else if (IsCalleePopSRet)
+ } else if (hasCalleePopSRet(Outs, ArgLocs, Subtarget))
// The callee pops an sret, so we cannot tail-call, as our caller doesn't
// expect that.
return false;
More information about the llvm-commits
mailing list