Skip to content

[AArch64][SVE] Avoid using the SVE stack size before it is determined (hopefully mostly a NFC) #147561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 9, 2025

Conversation

MacDue
Copy link
Member

@MacDue MacDue commented Jul 8, 2025

This patch adds asserts to getStackSizeSVE() and getSVECalleeSavedStackSize() to check they are only called after the SVE stack size has been determined.

This patch then fixes issues in three places:

  • AArch64FrameLowering::homogeneousPrologEpilog()
    • This function is called before callee saves or SVE stack sizes have been determined
    • This check has been updated to use isLikelyToHaveSVEStack()
    • isLikelyToHaveSVEStack() conservatively returns if a function is likely to have an SVE stack
  • produceCompactUnwindFrame()
    • This function checked the SVE CS stack size before callee-saves had been determined
    • This has been replaced with a more conservative isSVECC() check
  • AArch64FrameLowering::resolveFrameOffsetReference()
    • This was hit by some post-PEI MIR tests
    • This case was fixed by adding "stackSizeSVE" to the YAML for AArch64FunctionInfo

This patch adds asserts to `getStackSizeSVE()` and
`getSVECalleeSavedStackSize()` to check they are only called after
the SVE stack size has been determined.

This patch then fixes issues in three places:

* AArch64FrameLowering::homogeneousPrologEpilog()
  - This function is called before callee saves or SVE stack sizes
    have been determined.
  - This check has been updated to use isLikelyToHaveSVEStack().
    This `isLikelyToHaveSVEStack()` conservatively returns if a function
    is likely to have an SVE stack.
* produceCompactUnwindFrame()
  - This function checked the SVE CS stack size before callee-saves
    had been determined.
  - This has been replaced with a more conservative isSVECC() check.
* AArch64FrameLowering::resolveFrameOffsetReference()
  - This was hit by some MIR tests for post-PEI MIR.
  - This case was fixed by adding "stackSizeSVE" to the YAML for
    AArch64FunctionInfo.
@MacDue MacDue changed the title [AArch64][SVE] Avoid using the SVE stack size before it is determined (hopefully a NFC) [AArch64][SVE] Avoid using the SVE stack size before it is determined (hopefully mostly a NFC) Jul 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 8, 2025

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-debuginfo

Author: Benjamin Maxwell (MacDue)

Changes

This patch adds asserts to getStackSizeSVE() and getSVECalleeSavedStackSize() to check they are only called after the SVE stack size has been determined.

This patch then fixes issues in three places:

  • AArch64FrameLowering::homogeneousPrologEpilog()
    • This function is called before callee saves or SVE stack sizes have been determined
    • This check has been updated to use isLikelyToHaveSVEStack()
    • isLikelyToHaveSVEStack() conservatively returns if a function is likely to have an SVE stack
  • produceCompactUnwindFrame()
    • This function checked the SVE CS stack size before callee-saves had been determined
    • This has been replaced with a more conservative isSVECC() check
  • AArch64FrameLowering::resolveFrameOffsetReference()
    • This was hit by some post-PEI MIR tests
    • This case was fixed by adding "stackSizeSVE" to the YAML for AArch64FunctionInfo

Full diff: https://github.com/llvm/llvm-project/pull/147561.diff

5 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+23-2)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp (+6-1)
  • (modified) llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h (+10-1)
  • (modified) llvm/test/DebugInfo/AArch64/asan-stack-vars.mir (+2)
  • (modified) llvm/test/DebugInfo/AArch64/compiler-gen-bbs-livedebugvalues.mir (+2)
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 6f1ce5bdbe286..261261f476bcf 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -335,6 +335,26 @@ static Register findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB,
                                                  bool HasCall = false);
 static bool requiresSaveVG(const MachineFunction &MF);
 
+// Conservatively, returns true if the function is likely to have an SVE vectors
+// on the stack. This function is safe to be called before callee-saves or
+// object offsets have been determined.
+static bool isLikelyToHaveSVEStack(MachineFunction &MF) {
+  auto *AFI = MF.getInfo<AArch64FunctionInfo>();
+  if (AFI->isSVECC())
+    return true;
+
+  if (AFI->hasCalculatedStackSizeSVE())
+    return bool(getSVEStackSize(MF));
+
+  const MachineFrameInfo &MFI = MF.getFrameInfo();
+  for (int FI = MFI.getObjectIndexBegin(); FI < MFI.getObjectIndexEnd(); FI++) {
+    if (MFI.getStackID(FI) == TargetStackID::ScalableVector)
+      return true;
+  }
+
+  return false;
+}
+
 /// Returns true if a homogeneous prolog or epilog code can be emitted
 /// for the size optimization. If possible, a frame helper call is injected.
 /// When Exit block is given, this check is for epilog.
@@ -350,8 +370,9 @@ bool AArch64FrameLowering::homogeneousPrologEpilog(
   // TODO: Window is supported yet.
   if (needsWinCFI(MF))
     return false;
+
   // TODO: SVE is not supported yet.
-  if (getSVEStackSize(MF))
+  if (isLikelyToHaveSVEStack(MF))
     return false;
 
   // Bail on stack adjustment needed on return for simplicity.
@@ -2997,7 +3018,7 @@ static bool produceCompactUnwindFrame(MachineFunction &MF) {
          !(Subtarget.getTargetLowering()->supportSwiftError() &&
            Attrs.hasAttrSomewhere(Attribute::SwiftError)) &&
          MF.getFunction().getCallingConv() != CallingConv::SwiftTail &&
-         !requiresSaveVG(MF) && AFI->getSVECalleeSavedStackSize() == 0;
+         !requiresSaveVG(MF) && !AFI->isSVECC();
 }
 
 static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2,
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 4b04b80121ffa..b4197a04840b7 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -25,7 +25,10 @@ using namespace llvm;
 
 yaml::AArch64FunctionInfo::AArch64FunctionInfo(
     const llvm::AArch64FunctionInfo &MFI)
-    : HasRedZone(MFI.hasRedZone()) {}
+    : HasRedZone(MFI.hasRedZone()),
+      StackSizeSVE(MFI.hasCalculatedStackSizeSVE()
+                       ? std::optional<uint64_t>(MFI.getStackSizeSVE())
+                       : std::nullopt) {}
 
 void yaml::AArch64FunctionInfo::mappingImpl(yaml::IO &YamlIO) {
   MappingTraits<AArch64FunctionInfo>::mapping(YamlIO, *this);
@@ -35,6 +38,8 @@ void AArch64FunctionInfo::initializeBaseYamlFields(
     const yaml::AArch64FunctionInfo &YamlMFI) {
   if (YamlMFI.HasRedZone)
     HasRedZone = YamlMFI.HasRedZone;
+  if (YamlMFI.StackSizeSVE)
+    setStackSizeSVE(*YamlMFI.StackSizeSVE);
 }
 
 static std::pair<bool, bool> GetSignReturnAddress(const Function &F) {
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index e61f2280865b4..800787cc0b4f5 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -82,6 +82,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   unsigned CalleeSavedStackSize = 0;
   unsigned SVECalleeSavedStackSize = 0;
   bool HasCalleeSavedStackSize = false;
+  bool HasSVECalleeSavedStackSize = false;
 
   /// Number of TLS accesses using the special (combinable)
   /// _TLS_MODULE_BASE_ symbol.
@@ -306,7 +307,10 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
     StackSizeSVE = S;
   }
 
-  uint64_t getStackSizeSVE() const { return StackSizeSVE; }
+  uint64_t getStackSizeSVE() const {
+    assert(hasCalculatedStackSizeSVE());
+    return StackSizeSVE;
+  }
 
   bool hasStackFrame() const { return HasStackFrame; }
   void setHasStackFrame(bool s) { HasStackFrame = s; }
@@ -400,8 +404,11 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   // Saves the CalleeSavedStackSize for SVE vectors in 'scalable bytes'
   void setSVECalleeSavedStackSize(unsigned Size) {
     SVECalleeSavedStackSize = Size;
+    HasSVECalleeSavedStackSize = true;
   }
   unsigned getSVECalleeSavedStackSize() const {
+    assert(HasSVECalleeSavedStackSize &&
+           "SVECalleeSavedStackSize has not been calculated");
     return SVECalleeSavedStackSize;
   }
 
@@ -592,6 +599,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
 namespace yaml {
 struct AArch64FunctionInfo final : public yaml::MachineFunctionInfo {
   std::optional<bool> HasRedZone;
+  std::optional<uint64_t> StackSizeSVE;
 
   AArch64FunctionInfo() = default;
   AArch64FunctionInfo(const llvm::AArch64FunctionInfo &MFI);
@@ -603,6 +611,7 @@ struct AArch64FunctionInfo final : public yaml::MachineFunctionInfo {
 template <> struct MappingTraits<AArch64FunctionInfo> {
   static void mapping(IO &YamlIO, AArch64FunctionInfo &MFI) {
     YamlIO.mapOptional("hasRedZone", MFI.HasRedZone);
+    YamlIO.mapOptional("stackSizeSVE", MFI.StackSizeSVE);
   }
 };
 
diff --git a/llvm/test/DebugInfo/AArch64/asan-stack-vars.mir b/llvm/test/DebugInfo/AArch64/asan-stack-vars.mir
index be3d1c0007998..5d644c3e5416c 100644
--- a/llvm/test/DebugInfo/AArch64/asan-stack-vars.mir
+++ b/llvm/test/DebugInfo/AArch64/asan-stack-vars.mir
@@ -365,6 +365,8 @@ frameInfo:
   stackProtector:  '%stack.0.StackGuardSlot'
   maxCallFrameSize: 0
   localFrameSize:  144
+machineFunctionInfo:
+  stackSizeSVE:    0
 stack:
   - { id: 0, name: StackGuardSlot, offset: -40, size: 8, alignment: 8,
       stack-id: default, local-offset: -8 }
diff --git a/llvm/test/DebugInfo/AArch64/compiler-gen-bbs-livedebugvalues.mir b/llvm/test/DebugInfo/AArch64/compiler-gen-bbs-livedebugvalues.mir
index d97ef2214f054..013d93378a204 100644
--- a/llvm/test/DebugInfo/AArch64/compiler-gen-bbs-livedebugvalues.mir
+++ b/llvm/test/DebugInfo/AArch64/compiler-gen-bbs-livedebugvalues.mir
@@ -68,6 +68,8 @@ frameInfo:
   adjustsStack:    true
   hasCalls:        true
   maxCallFrameSize: 0
+machineFunctionInfo:
+  stackSizeSVE:     0
 stack:
   - { id: 0, type: spill-slot, offset: -20, size: 4, alignment: 4, stack-id: default }
   - { id: 1, type: spill-slot, offset: -8, size: 8, alignment: 8, stack-id: default,

Copy link
Collaborator

@efriedma-quic efriedma-quic left a comment

Choose a reason for hiding this comment

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

LGTM

@MacDue MacDue merged commit c3d9f31 into llvm:main Jul 9, 2025
12 checks passed
@MacDue MacDue deleted the add_assert branch July 9, 2025 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants