[compiler-rt] [llvm] [SPARC] Allow overaligned `alloca`s (PR #107223)

via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 28 17:01:48 PDT 2024


https://github.com/koachan updated https://github.com/llvm/llvm-project/pull/107223

>From fc64dede4b5e96ea675b7394bcae2aed0bff4502 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sat, 31 Aug 2024 17:35:20 +0700
Subject: [PATCH 1/8] [WIP][SPARC] Allow overaligned `alloca`s

SPARC doesn't do stack realignment, so let LLVM know about it in
`SparcFrameLowering`. This has the side effect of making all overaligned
allocations go through `LowerDYNAMIC_STACKALLOC`, so implement the missing
logic there for overaligned allocations.
This allows the SPARC backend to not crash on overaligned `alloca`s.
---
 llvm/lib/Target/Sparc/SparcFrameLowering.cpp |  34 +-----
 llvm/lib/Target/Sparc/SparcISelLowering.cpp  |  42 ++++---
 llvm/lib/Target/Sparc/SparcRegisterInfo.cpp  |  23 ----
 llvm/lib/Target/Sparc/SparcRegisterInfo.h    |   3 -
 llvm/test/CodeGen/SPARC/alloca-align.ll      | 113 +++++++++++++++++++
 llvm/test/CodeGen/SPARC/fail-alloca-align.ll |  23 ----
 llvm/test/CodeGen/SPARC/fp128.ll             |  16 +--
 llvm/test/CodeGen/SPARC/stack-align.ll       |  53 ++++++---
 8 files changed, 184 insertions(+), 123 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPARC/alloca-align.ll
 delete mode 100644 llvm/test/CodeGen/SPARC/fail-alloca-align.ll

diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index 000418be9a9e33..b28642aee4ca06 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -35,7 +35,8 @@ DisableLeafProc("disable-sparc-leaf-proc",
 SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST)
     : TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
                           ST.is64Bit() ? Align(16) : Align(8), 0,
-                          ST.is64Bit() ? Align(16) : Align(8)) {}
+                          ST.is64Bit() ? Align(16) : Align(8),
+                          /* StackRealignable */ false) {}
 
 void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF,
                                           MachineBasicBlock &MBB,
@@ -97,12 +98,6 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
   // Debug location must be unknown since the first debug location is used
   // to determine the end of the prologue.
   DebugLoc dl;
-  bool NeedsStackRealignment = RegInfo.shouldRealignStack(MF);
-
-  if (NeedsStackRealignment && !RegInfo.canRealignStack(MF))
-    report_fatal_error("Function \"" + Twine(MF.getName()) + "\" required "
-                       "stack re-alignment, but LLVM couldn't handle it "
-                       "(probably because it has a dynamic alloca).");
 
   // Get the number of bytes to allocate from the FrameInfo
   int NumBytes = (int) MFI.getStackSize();
@@ -168,31 +163,6 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF,
       MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA));
   BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
       .addCFIIndex(CFIIndex);
-
-  if (NeedsStackRealignment) {
-    int64_t Bias = Subtarget.getStackPointerBias();
-    unsigned regUnbiased;
-    if (Bias) {
-      // This clobbers G1 which we always know is available here.
-      regUnbiased = SP::G1;
-      // add %o6, BIAS, %g1
-      BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), regUnbiased)
-        .addReg(SP::O6).addImm(Bias);
-    } else
-      regUnbiased = SP::O6;
-
-    // andn %regUnbiased, MaxAlign-1, %regUnbiased
-    Align MaxAlign = MFI.getMaxAlign();
-    BuildMI(MBB, MBBI, dl, TII.get(SP::ANDNri), regUnbiased)
-        .addReg(regUnbiased)
-        .addImm(MaxAlign.value() - 1U);
-
-    if (Bias) {
-      // add %g1, -BIAS, %o6
-      BuildMI(MBB, MBBI, dl, TII.get(SP::ADDri), SP::O6)
-        .addReg(regUnbiased).addImm(-Bias);
-    }
-  }
 }
 
 MachineBasicBlock::iterator SparcFrameLowering::
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 42b8248006d1fd..06bd2aa27e904f 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -2764,20 +2764,27 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
                                        const SparcSubtarget *Subtarget) {
   SDValue Chain = Op.getOperand(0);  // Legalize the chain.
   SDValue Size  = Op.getOperand(1);  // Legalize the size.
-  MaybeAlign Alignment =
-      cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
+  SDValue Alignment = Op.getOperand(2); // Legalize the alignment.
+  MaybeAlign MaybeAlignment =
+      cast<ConstantSDNode>(Alignment)->getMaybeAlignValue();
   Align StackAlign = Subtarget->getFrameLowering()->getStackAlign();
   EVT VT = Size->getValueType(0);
   SDLoc dl(Op);
 
-  // TODO: implement over-aligned alloca. (Note: also implies
-  // supporting support for overaligned function frames + dynamic
-  // allocations, at all, which currently isn't supported)
-  if (Alignment && *Alignment > StackAlign) {
-    const MachineFunction &MF = DAG.getMachineFunction();
-    report_fatal_error("Function \"" + Twine(MF.getName()) + "\": "
-                       "over-aligned dynamic alloca not supported.");
-  }
+  int64_t Bias = Subtarget->getStackPointerBias();
+  unsigned SPReg = SP::O6;
+  SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT);
+  SDValue AlignedPtr = SP;
+
+  bool IsOveraligned = MaybeAlignment && *MaybeAlignment > StackAlign;
+  if (IsOveraligned)
+    AlignedPtr = DAG.getNode(
+        ISD::AND, dl, VT,
+        DAG.getNode(
+            ISD::SUB, dl, VT,
+            DAG.getNode(ISD::ADD, dl, VT, SP, DAG.getConstant(Bias, dl, VT)),
+            Alignment),
+        DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(0, dl, VT), Alignment));
 
   // The resultant pointer needs to be above the register spill area
   // at the bottom of the stack.
@@ -2811,12 +2818,17 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
     regSpillArea = 96;
   }
 
-  unsigned SPReg = SP::O6;
-  SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT);
-  SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value
-  Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP);    // Output chain
+  AlignedPtr = DAG.getNode(ISD::SUB, dl, VT, AlignedPtr, Size);
 
-  regSpillArea += Subtarget->getStackPointerBias();
+  // If we are allocating overaligned memory then the bias is already accounted
+  // for in AlignedPtr calculation, so:
+  // - We do not need to adjust the regSpillArea; but
+  // - We do need to decrement AlignedPtr by bias to obtain the new SP.
+  regSpillArea += IsOveraligned ? 0 : Bias;
+  SDValue NewSP =
+      DAG.getNode(ISD::SUB, dl, VT, AlignedPtr,
+                  DAG.getConstant(IsOveraligned ? Bias : 0, dl, VT));
+  Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP);
 
   SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP,
                                DAG.getConstant(regSpillArea, dl, VT));
diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
index 71a27f77d2c6bf..e4db27a63076d8 100644
--- a/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
+++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
@@ -226,26 +226,3 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
 Register SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
   return SP::I6;
 }
-
-// Sparc has no architectural need for stack realignment support,
-// except that LLVM unfortunately currently implements overaligned
-// stack objects by depending upon stack realignment support.
-// If that ever changes, this can probably be deleted.
-bool SparcRegisterInfo::canRealignStack(const MachineFunction &MF) const {
-  if (!TargetRegisterInfo::canRealignStack(MF))
-    return false;
-
-  // Sparc always has a fixed frame pointer register, so don't need to
-  // worry about needing to reserve it. [even if we don't have a frame
-  // pointer for our frame, it still cannot be used for other things,
-  // or register window traps will be SADNESS.]
-
-  // If there's a reserved call frame, we can use SP to access locals.
-  if (getFrameLowering(MF)->hasReservedCallFrame(MF))
-    return true;
-
-  // Otherwise, we'd need a base pointer, but those aren't implemented
-  // for SPARC at the moment.
-
-  return false;
-}
diff --git a/llvm/lib/Target/Sparc/SparcRegisterInfo.h b/llvm/lib/Target/Sparc/SparcRegisterInfo.h
index 58c85f33635f2d..eae859ce1a519e 100644
--- a/llvm/lib/Target/Sparc/SparcRegisterInfo.h
+++ b/llvm/lib/Target/Sparc/SparcRegisterInfo.h
@@ -40,9 +40,6 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo {
                            RegScavenger *RS = nullptr) const override;
 
   Register getFrameRegister(const MachineFunction &MF) const override;
-
-  bool canRealignStack(const MachineFunction &MF) const override;
-
 };
 
 } // end namespace llvm
diff --git a/llvm/test/CodeGen/SPARC/alloca-align.ll b/llvm/test/CodeGen/SPARC/alloca-align.ll
new file mode 100644
index 00000000000000..1ece601437ea4a
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/alloca-align.ll
@@ -0,0 +1,113 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK32
+; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK64
+
+define void @variable_alloca_with_overalignment(i32 %num) {
+; CHECK32-LABEL: variable_alloca_with_overalignment:
+; CHECK32:         .cfi_startproc
+; CHECK32-NEXT:  ! %bb.0:
+; CHECK32-NEXT:    save %sp, -96, %sp
+; CHECK32-NEXT:    .cfi_def_cfa_register %fp
+; CHECK32-NEXT:    .cfi_window_save
+; CHECK32-NEXT:    .cfi_register %o7, %i7
+; CHECK32-NEXT:    add %sp, -64, %i1
+; CHECK32-NEXT:    and %i1, -64, %i1
+; CHECK32-NEXT:    add %i1, -16, %sp
+; CHECK32-NEXT:    add %i0, 7, %i0
+; CHECK32-NEXT:    and %i0, -8, %i0
+; CHECK32-NEXT:    sub %sp, %i0, %i0
+; CHECK32-NEXT:    add %i1, 80, %o0
+; CHECK32-NEXT:    add %i0, -8, %sp
+; CHECK32-NEXT:    call foo
+; CHECK32-NEXT:    add %i0, 88, %o1
+; CHECK32-NEXT:    ret
+; CHECK32-NEXT:    restore
+;
+; CHECK64-LABEL: variable_alloca_with_overalignment:
+; CHECK64:         .cfi_startproc
+; CHECK64-NEXT:  ! %bb.0:
+; CHECK64-NEXT:    save %sp, -128, %sp
+; CHECK64-NEXT:    .cfi_def_cfa_register %fp
+; CHECK64-NEXT:    .cfi_window_save
+; CHECK64-NEXT:    .cfi_register %o7, %i7
+; CHECK64-NEXT:    add %sp, 1983, %i1
+; CHECK64-NEXT:    and %i1, -64, %i1
+; CHECK64-NEXT:    add %i1, -2063, %sp
+; CHECK64-NEXT:    add %i1, -1935, %o0
+; CHECK64-NEXT:    srl %i0, 0, %i0
+; CHECK64-NEXT:    add %i0, 15, %i0
+; CHECK64-NEXT:    sethi 4194303, %i1
+; CHECK64-NEXT:    or %i1, 1008, %i1
+; CHECK64-NEXT:    sethi 0, %i2
+; CHECK64-NEXT:    or %i2, 1, %i2
+; CHECK64-NEXT:    sllx %i2, 32, %i2
+; CHECK64-NEXT:    or %i2, %i1, %i1
+; CHECK64-NEXT:    and %i0, %i1, %i0
+; CHECK64-NEXT:    sub %sp, %i0, %i0
+; CHECK64-NEXT:    add %i0, 2175, %o1
+; CHECK64-NEXT:    mov %i0, %sp
+; CHECK64-NEXT:    call foo
+; CHECK64-NEXT:    add %sp, -48, %sp
+; CHECK64-NEXT:    add %sp, 48, %sp
+; CHECK64-NEXT:    ret
+; CHECK64-NEXT:    restore
+  %aligned = alloca i32, align 64
+  %var_size = alloca i8, i32 %num, align 4
+  call void @foo(ptr %aligned, ptr %var_size)
+  ret void
+}
+
+;; Same but with the alloca itself overaligned
+define void @variable_alloca_with_overalignment_2(i32 %num) {
+; CHECK32-LABEL: variable_alloca_with_overalignment_2:
+; CHECK32:         .cfi_startproc
+; CHECK32-NEXT:  ! %bb.0:
+; CHECK32-NEXT:    save %sp, -96, %sp
+; CHECK32-NEXT:    .cfi_def_cfa_register %fp
+; CHECK32-NEXT:    .cfi_window_save
+; CHECK32-NEXT:    .cfi_register %o7, %i7
+; CHECK32-NEXT:    add %i0, 7, %i0
+; CHECK32-NEXT:    and %i0, -8, %i0
+; CHECK32-NEXT:    add %sp, -64, %i1
+; CHECK32-NEXT:    and %i1, -64, %i1
+; CHECK32-NEXT:    sub %i1, %i0, %i0
+; CHECK32-NEXT:    add %i0, -8, %sp
+; CHECK32-NEXT:    add %i0, 88, %o1
+; CHECK32-NEXT:    call foo
+; CHECK32-NEXT:    mov %g0, %o0
+; CHECK32-NEXT:    ret
+; CHECK32-NEXT:    restore
+;
+; CHECK64-LABEL: variable_alloca_with_overalignment_2:
+; CHECK64:         .cfi_startproc
+; CHECK64-NEXT:  ! %bb.0:
+; CHECK64-NEXT:    save %sp, -128, %sp
+; CHECK64-NEXT:    .cfi_def_cfa_register %fp
+; CHECK64-NEXT:    .cfi_window_save
+; CHECK64-NEXT:    .cfi_register %o7, %i7
+; CHECK64-NEXT:    srl %i0, 0, %i0
+; CHECK64-NEXT:    add %i0, 15, %i0
+; CHECK64-NEXT:    sethi 4194303, %i1
+; CHECK64-NEXT:    or %i1, 1008, %i1
+; CHECK64-NEXT:    sethi 0, %i2
+; CHECK64-NEXT:    or %i2, 1, %i2
+; CHECK64-NEXT:    sllx %i2, 32, %i2
+; CHECK64-NEXT:    or %i2, %i1, %i1
+; CHECK64-NEXT:    and %i0, %i1, %i0
+; CHECK64-NEXT:    add %sp, 1983, %i1
+; CHECK64-NEXT:    and %i1, -64, %i1
+; CHECK64-NEXT:    sub %i1, %i0, %i0
+; CHECK64-NEXT:    add %i0, -2047, %sp
+; CHECK64-NEXT:    add %i0, -1919, %o1
+; CHECK64-NEXT:    add %sp, -48, %sp
+; CHECK64-NEXT:    call foo
+; CHECK64-NEXT:    mov %g0, %o0
+; CHECK64-NEXT:    add %sp, 48, %sp
+; CHECK64-NEXT:    ret
+; CHECK64-NEXT:    restore
+  %var_size = alloca i8, i32 %num, align 64
+  call void @foo(ptr null, ptr %var_size)
+  ret void
+}
+
+declare void @foo(ptr, ptr);
diff --git a/llvm/test/CodeGen/SPARC/fail-alloca-align.ll b/llvm/test/CodeGen/SPARC/fail-alloca-align.ll
deleted file mode 100644
index e2dc235389b1dc..00000000000000
--- a/llvm/test/CodeGen/SPARC/fail-alloca-align.ll
+++ /dev/null
@@ -1,23 +0,0 @@
-;; Sparc backend can't currently handle variable allocas with
-;; alignment greater than the stack alignment.  This code ought to
-;; compile, but doesn't currently.
-
-;; RUN: not --crash llc -march=sparc < %s 2>&1 | FileCheck %s
-;; RUN: not --crash llc -march=sparcv9 < %s 2>&1 | FileCheck %s
-;; CHECK: ERROR: Function {{.*}} required stack re-alignment
-
-define void @variable_alloca_with_overalignment(i32 %num) {
-  %aligned = alloca i32, align 64
-  %var_size = alloca i8, i32 %num, align 4
-  call void @foo(ptr %aligned, ptr %var_size)
-  ret void
-}
-
-;; Same but with the alloca itself overaligned
-define void @variable_alloca_with_overalignment_2(i32 %num) {
-  %var_size = alloca i8, i32 %num, align 64
-  call void @foo(ptr null, ptr %var_size)
-  ret void
-}
-
-declare void @foo(ptr, ptr);
diff --git a/llvm/test/CodeGen/SPARC/fp128.ll b/llvm/test/CodeGen/SPARC/fp128.ll
index 80f3da285e053f..3e43d3eb5da70f 100644
--- a/llvm/test/CodeGen/SPARC/fp128.ll
+++ b/llvm/test/CodeGen/SPARC/fp128.ll
@@ -54,18 +54,10 @@ entry:
 
 ; CHECK-LABEL: f128_spill_large:
 ; CHECK:       sethi 4, %g1
-; CHECK:       sethi 4, %g1
-; CHECK-NEXT:  add %g1, %sp, %g1
-; CHECK-NEXT:  std %f{{.+}}, [%g1]
-; CHECK:       sethi 4, %g1
-; CHECK-NEXT:  add %g1, %sp, %g1
-; CHECK-NEXT:  std %f{{.+}}, [%g1+8]
-; CHECK:       sethi 4, %g1
-; CHECK-NEXT:  add %g1, %sp, %g1
-; CHECK-NEXT:  ldd [%g1], %f{{.+}}
-; CHECK:       sethi 4, %g1
-; CHECK-NEXT:  add %g1, %sp, %g1
-; CHECK-NEXT:  ldd [%g1+8], %f{{.+}}
+; CHECK:       std %f{{.+}}, [%fp+-16]
+; CHECK-NEXT:  std %f{{.+}}, [%fp+-8]
+; CHECK:       ldd [%fp+-16], %f{{.+}}
+; CHECK-NEXT:  ldd [%fp+-8], %f{{.+}}
 
 define void @f128_spill_large(ptr noalias sret(<251 x fp128>) %scalar.result, ptr byval(<251 x fp128>) %a) {
 entry:
diff --git a/llvm/test/CodeGen/SPARC/stack-align.ll b/llvm/test/CodeGen/SPARC/stack-align.ll
index 6632237f08e274..e2dfe854d643a1 100644
--- a/llvm/test/CodeGen/SPARC/stack-align.ll
+++ b/llvm/test/CodeGen/SPARC/stack-align.ll
@@ -1,24 +1,47 @@
-; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK,CHECK32
-; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK,CHECK64
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK32
+; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK64
 declare void @stack_realign_helper(i32 %a, ptr %b)
 
 ;; This is a function where we have a local variable of 64-byte
-;; alignment.  We want to see that the stack is aligned (the initial
-;; andn), that the local var is accessed via stack pointer (to %o1), and that
+;; alignment.  We want to see that the stack is aligned (the initial add/and),
+;; that the local var is accessed via stack pointer (to %o1), and that
 ;; the argument is accessed via frame pointer not stack pointer (to %o0).
 
-;; CHECK-LABEL: stack_realign:
-;; CHECK32:      andn %sp, 63, %sp
-;; CHECK32-NEXT: ld [%fp+92], %o0
-;; CHECK64:      add %sp, 2047, %g1
-;; CHECK64-NEXT: andn %g1, 63, %g1
-;; CHECK64-NEXT: add %g1, -2047, %sp
-;; CHECK64-NEXT: ld [%fp+2227], %o0
-;; CHECK-NEXT:   call stack_realign_helper
-;; CHECK32-NEXT: add %sp, 128, %o1
-;; CHECK64-NEXT: add %sp, 2239, %o1
-
 define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g) {
+; CHECK32-LABEL: stack_realign:
+; CHECK32:         .cfi_startproc
+; CHECK32-NEXT:  ! %bb.0: ! %entry
+; CHECK32-NEXT:    save %sp, -96, %sp
+; CHECK32-NEXT:    .cfi_def_cfa_register %fp
+; CHECK32-NEXT:    .cfi_window_save
+; CHECK32-NEXT:    .cfi_register %o7, %i7
+; CHECK32-NEXT:    ld [%fp+92], %o0
+; CHECK32-NEXT:    add %sp, -64, %i0
+; CHECK32-NEXT:    and %i0, -64, %i0
+; CHECK32-NEXT:    add %i0, -16, %sp
+; CHECK32-NEXT:    call stack_realign_helper
+; CHECK32-NEXT:    add %i0, 80, %o1
+; CHECK32-NEXT:    ret
+; CHECK32-NEXT:    restore
+;
+; CHECK64-LABEL: stack_realign:
+; CHECK64:         .cfi_startproc
+; CHECK64-NEXT:  ! %bb.0: ! %entry
+; CHECK64-NEXT:    save %sp, -128, %sp
+; CHECK64-NEXT:    .cfi_def_cfa_register %fp
+; CHECK64-NEXT:    .cfi_window_save
+; CHECK64-NEXT:    .cfi_register %o7, %i7
+; CHECK64-NEXT:    add %sp, 1983, %i0
+; CHECK64-NEXT:    and %i0, -64, %i0
+; CHECK64-NEXT:    add %i0, -2063, %sp
+; CHECK64-NEXT:    add %i0, -1935, %o1
+; CHECK64-NEXT:    add %sp, -48, %sp
+; CHECK64-NEXT:    call stack_realign_helper
+; CHECK64-NEXT:    ld [%fp+2227], %o0
+; CHECK64-NEXT:    add %sp, 48, %sp
+; CHECK64-NEXT:    ret
+; CHECK64-NEXT:    restore
 entry:
   %aligned = alloca i32, align 64
   call void @stack_realign_helper(i32 %g, ptr %aligned)

>From 3c870426faa9389c8849f0e0a34ec5e7c67a33e5 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Wed, 4 Sep 2024 11:36:27 +0700
Subject: [PATCH 2/8] Update generic test

---
 llvm/test/CodeGen/Generic/ForceStackAlign.ll | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/llvm/test/CodeGen/Generic/ForceStackAlign.ll b/llvm/test/CodeGen/Generic/ForceStackAlign.ll
index 7993b3eff65b68..811a192e752ab1 100644
--- a/llvm/test/CodeGen/Generic/ForceStackAlign.ll
+++ b/llvm/test/CodeGen/Generic/ForceStackAlign.ll
@@ -5,9 +5,6 @@
 ; CHECK-LABEL: @f
 ; CHECK-LABEL: @g
 
-; Stack realignment not supported.
-; XFAIL: target=sparc{{.*}}
-
 ; NVPTX can only select dynamic_stackalloc on sm_52+ and with ptx73+
 ; XFAIL: target=nvptx{{.*}}
 

>From 54408df0337fb973200673657390cda50cbc2c3f Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Thu, 12 Sep 2024 09:40:02 +0700
Subject: [PATCH 3/8] Apply code suggestions

---
 llvm/lib/Target/Sparc/SparcFrameLowering.cpp  |  2 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp   | 29 +++++----
 .../CodeGen/SPARC/2013-05-17-CallFrame.ll     | 18 ++----
 llvm/test/CodeGen/SPARC/alloca-align.ll       | 60 +++++++------------
 llvm/test/CodeGen/SPARC/stack-align.ll        | 26 +++-----
 5 files changed, 51 insertions(+), 84 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index b28642aee4ca06..399d55c439cbb4 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -36,7 +36,7 @@ SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST)
     : TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
                           ST.is64Bit() ? Align(16) : Align(8), 0,
                           ST.is64Bit() ? Align(16) : Align(8),
-                          /* StackRealignable */ false) {}
+                          /*StackRealignable=*/false) {}
 
 void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF,
                                           MachineBasicBlock &MBB,
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 06bd2aa27e904f..f1fbd5a40a27f0 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -2764,27 +2764,28 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
                                        const SparcSubtarget *Subtarget) {
   SDValue Chain = Op.getOperand(0);  // Legalize the chain.
   SDValue Size  = Op.getOperand(1);  // Legalize the size.
-  SDValue Alignment = Op.getOperand(2); // Legalize the alignment.
+  SDValue Alignment = Op.getOperand(2);
   MaybeAlign MaybeAlignment =
       cast<ConstantSDNode>(Alignment)->getMaybeAlignValue();
-  Align StackAlign = Subtarget->getFrameLowering()->getStackAlign();
   EVT VT = Size->getValueType(0);
   SDLoc dl(Op);
 
   int64_t Bias = Subtarget->getStackPointerBias();
   unsigned SPReg = SP::O6;
   SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT);
-  SDValue AlignedPtr = SP;
-
-  bool IsOveraligned = MaybeAlignment && *MaybeAlignment > StackAlign;
-  if (IsOveraligned)
-    AlignedPtr = DAG.getNode(
-        ISD::AND, dl, VT,
-        DAG.getNode(
-            ISD::SUB, dl, VT,
-            DAG.getNode(ISD::ADD, dl, VT, SP, DAG.getConstant(Bias, dl, VT)),
-            Alignment),
-        DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(0, dl, VT), Alignment));
+  SDValue AllocatedPtr = DAG.getNode(ISD::SUB, dl, VT, SP, Size);
+
+  bool IsOveraligned = MaybeAlignment.has_value();
+  SDValue AlignedPtr =
+      IsOveraligned
+          ? DAG.getNode(ISD::AND, dl, VT,
+                        DAG.getNode(ISD::SUB, dl, VT,
+                                    DAG.getNode(ISD::ADD, dl, VT, AllocatedPtr,
+                                                DAG.getConstant(Bias, dl, VT)),
+                                    Alignment),
+                        DAG.getNode(ISD::SUB, dl, VT,
+                                    DAG.getConstant(0, dl, VT), Alignment))
+          : AllocatedPtr;
 
   // The resultant pointer needs to be above the register spill area
   // at the bottom of the stack.
@@ -2818,8 +2819,6 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
     regSpillArea = 96;
   }
 
-  AlignedPtr = DAG.getNode(ISD::SUB, dl, VT, AlignedPtr, Size);
-
   // If we are allocating overaligned memory then the bias is already accounted
   // for in AlignedPtr calculation, so:
   // - We do not need to adjust the regSpillArea; but
diff --git a/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll b/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll
index 3f6d28385e2679..39782f2ad08c62 100644
--- a/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll
+++ b/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll
@@ -5,19 +5,15 @@
 ; (this should ideally be doing "add 4+7; and -8", instead of
 ;  "add 7; and -8; add 8"; see comments in LowerDYNAMIC_STACKALLOC)
 
-define void @variable_alloca_with_adj_call_stack(i32 %num) {
+define void @variable_alloca_with_adj_call_stack(i32 %num) nounwind {
 ; V8-LABEL: variable_alloca_with_adj_call_stack:
-; V8:         .cfi_startproc
-; V8-NEXT:  ! %bb.0: ! %entry
+; V8:       ! %bb.0: ! %entry
 ; V8-NEXT:    save %sp, -96, %sp
-; V8-NEXT:    .cfi_def_cfa_register %fp
-; V8-NEXT:    .cfi_window_save
-; V8-NEXT:    .cfi_register %o7, %i7
 ; V8-NEXT:    add %i0, 7, %i0
 ; V8-NEXT:    and %i0, -8, %i0
 ; V8-NEXT:    sub %sp, %i0, %i0
-; V8-NEXT:    add %i0, -8, %sp
-; V8-NEXT:    add %i0, 88, %o0
+; V8-NEXT:    add %i0, 96, %o0
+; V8-NEXT:    mov %i0, %sp
 ; V8-NEXT:    add %sp, -16, %sp
 ; V8-NEXT:    st %o0, [%sp+104]
 ; V8-NEXT:    st %o0, [%sp+100]
@@ -34,12 +30,8 @@ define void @variable_alloca_with_adj_call_stack(i32 %num) {
 ; V8-NEXT:    restore
 ;
 ; SPARC64-LABEL: variable_alloca_with_adj_call_stack:
-; SPARC64:         .cfi_startproc
-; SPARC64-NEXT:  ! %bb.0: ! %entry
+; SPARC64:       ! %bb.0: ! %entry
 ; SPARC64-NEXT:    save %sp, -128, %sp
-; SPARC64-NEXT:    .cfi_def_cfa_register %fp
-; SPARC64-NEXT:    .cfi_window_save
-; SPARC64-NEXT:    .cfi_register %o7, %i7
 ; SPARC64-NEXT:    srl %i0, 0, %i0
 ; SPARC64-NEXT:    add %i0, 15, %i0
 ; SPARC64-NEXT:    sethi 4194303, %i1
diff --git a/llvm/test/CodeGen/SPARC/alloca-align.ll b/llvm/test/CodeGen/SPARC/alloca-align.ll
index 1ece601437ea4a..797050d5a92e72 100644
--- a/llvm/test/CodeGen/SPARC/alloca-align.ll
+++ b/llvm/test/CodeGen/SPARC/alloca-align.ll
@@ -2,38 +2,30 @@
 ; RUN: llc -march=sparc < %s | FileCheck %s --check-prefixes=CHECK32
 ; RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefixes=CHECK64
 
-define void @variable_alloca_with_overalignment(i32 %num) {
+define void @variable_alloca_with_overalignment(i32 %num) nounwind {
 ; CHECK32-LABEL: variable_alloca_with_overalignment:
-; CHECK32:         .cfi_startproc
-; CHECK32-NEXT:  ! %bb.0:
+; CHECK32:       ! %bb.0:
 ; CHECK32-NEXT:    save %sp, -96, %sp
-; CHECK32-NEXT:    .cfi_def_cfa_register %fp
-; CHECK32-NEXT:    .cfi_window_save
-; CHECK32-NEXT:    .cfi_register %o7, %i7
-; CHECK32-NEXT:    add %sp, -64, %i1
+; CHECK32-NEXT:    add %sp, -72, %i1
 ; CHECK32-NEXT:    and %i1, -64, %i1
-; CHECK32-NEXT:    add %i1, -16, %sp
+; CHECK32-NEXT:    add %i1, 96, %o0
+; CHECK32-NEXT:    mov %i1, %sp
 ; CHECK32-NEXT:    add %i0, 7, %i0
 ; CHECK32-NEXT:    and %i0, -8, %i0
 ; CHECK32-NEXT:    sub %sp, %i0, %i0
-; CHECK32-NEXT:    add %i1, 80, %o0
-; CHECK32-NEXT:    add %i0, -8, %sp
+; CHECK32-NEXT:    add %i0, 96, %o1
 ; CHECK32-NEXT:    call foo
-; CHECK32-NEXT:    add %i0, 88, %o1
+; CHECK32-NEXT:    mov %i0, %sp
 ; CHECK32-NEXT:    ret
 ; CHECK32-NEXT:    restore
 ;
 ; CHECK64-LABEL: variable_alloca_with_overalignment:
-; CHECK64:         .cfi_startproc
-; CHECK64-NEXT:  ! %bb.0:
+; CHECK64:       ! %bb.0:
 ; CHECK64-NEXT:    save %sp, -128, %sp
-; CHECK64-NEXT:    .cfi_def_cfa_register %fp
-; CHECK64-NEXT:    .cfi_window_save
-; CHECK64-NEXT:    .cfi_register %o7, %i7
-; CHECK64-NEXT:    add %sp, 1983, %i1
+; CHECK64-NEXT:    add %sp, 1967, %i1
 ; CHECK64-NEXT:    and %i1, -64, %i1
-; CHECK64-NEXT:    add %i1, -2063, %sp
-; CHECK64-NEXT:    add %i1, -1935, %o0
+; CHECK64-NEXT:    add %i1, -2047, %sp
+; CHECK64-NEXT:    add %i1, -1919, %o0
 ; CHECK64-NEXT:    srl %i0, 0, %i0
 ; CHECK64-NEXT:    add %i0, 15, %i0
 ; CHECK64-NEXT:    sethi 4194303, %i1
@@ -58,33 +50,25 @@ define void @variable_alloca_with_overalignment(i32 %num) {
 }
 
 ;; Same but with the alloca itself overaligned
-define void @variable_alloca_with_overalignment_2(i32 %num) {
+define void @variable_alloca_with_overalignment_2(i32 %num) nounwind {
 ; CHECK32-LABEL: variable_alloca_with_overalignment_2:
-; CHECK32:         .cfi_startproc
-; CHECK32-NEXT:  ! %bb.0:
+; CHECK32:       ! %bb.0:
 ; CHECK32-NEXT:    save %sp, -96, %sp
-; CHECK32-NEXT:    .cfi_def_cfa_register %fp
-; CHECK32-NEXT:    .cfi_window_save
-; CHECK32-NEXT:    .cfi_register %o7, %i7
 ; CHECK32-NEXT:    add %i0, 7, %i0
 ; CHECK32-NEXT:    and %i0, -8, %i0
-; CHECK32-NEXT:    add %sp, -64, %i1
-; CHECK32-NEXT:    and %i1, -64, %i1
-; CHECK32-NEXT:    sub %i1, %i0, %i0
-; CHECK32-NEXT:    add %i0, -8, %sp
-; CHECK32-NEXT:    add %i0, 88, %o1
+; CHECK32-NEXT:    sub %sp, %i0, %i0
+; CHECK32-NEXT:    add %i0, -64, %i0
+; CHECK32-NEXT:    and %i0, -64, %i0
+; CHECK32-NEXT:    add %i0, 96, %o1
+; CHECK32-NEXT:    mov %i0, %sp
 ; CHECK32-NEXT:    call foo
 ; CHECK32-NEXT:    mov %g0, %o0
 ; CHECK32-NEXT:    ret
 ; CHECK32-NEXT:    restore
 ;
 ; CHECK64-LABEL: variable_alloca_with_overalignment_2:
-; CHECK64:         .cfi_startproc
-; CHECK64-NEXT:  ! %bb.0:
+; CHECK64:       ! %bb.0:
 ; CHECK64-NEXT:    save %sp, -128, %sp
-; CHECK64-NEXT:    .cfi_def_cfa_register %fp
-; CHECK64-NEXT:    .cfi_window_save
-; CHECK64-NEXT:    .cfi_register %o7, %i7
 ; CHECK64-NEXT:    srl %i0, 0, %i0
 ; CHECK64-NEXT:    add %i0, 15, %i0
 ; CHECK64-NEXT:    sethi 4194303, %i1
@@ -94,9 +78,9 @@ define void @variable_alloca_with_overalignment_2(i32 %num) {
 ; CHECK64-NEXT:    sllx %i2, 32, %i2
 ; CHECK64-NEXT:    or %i2, %i1, %i1
 ; CHECK64-NEXT:    and %i0, %i1, %i0
-; CHECK64-NEXT:    add %sp, 1983, %i1
-; CHECK64-NEXT:    and %i1, -64, %i1
-; CHECK64-NEXT:    sub %i1, %i0, %i0
+; CHECK64-NEXT:    sub %sp, %i0, %i0
+; CHECK64-NEXT:    add %i0, 1983, %i0
+; CHECK64-NEXT:    and %i0, -64, %i0
 ; CHECK64-NEXT:    add %i0, -2047, %sp
 ; CHECK64-NEXT:    add %i0, -1919, %o1
 ; CHECK64-NEXT:    add %sp, -48, %sp
diff --git a/llvm/test/CodeGen/SPARC/stack-align.ll b/llvm/test/CodeGen/SPARC/stack-align.ll
index e2dfe854d643a1..c141cd25a06f52 100644
--- a/llvm/test/CodeGen/SPARC/stack-align.ll
+++ b/llvm/test/CodeGen/SPARC/stack-align.ll
@@ -8,34 +8,26 @@ declare void @stack_realign_helper(i32 %a, ptr %b)
 ;; that the local var is accessed via stack pointer (to %o1), and that
 ;; the argument is accessed via frame pointer not stack pointer (to %o0).
 
-define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g) {
+define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g) nounwind {
 ; CHECK32-LABEL: stack_realign:
-; CHECK32:         .cfi_startproc
-; CHECK32-NEXT:  ! %bb.0: ! %entry
+; CHECK32:       ! %bb.0: ! %entry
 ; CHECK32-NEXT:    save %sp, -96, %sp
-; CHECK32-NEXT:    .cfi_def_cfa_register %fp
-; CHECK32-NEXT:    .cfi_window_save
-; CHECK32-NEXT:    .cfi_register %o7, %i7
 ; CHECK32-NEXT:    ld [%fp+92], %o0
-; CHECK32-NEXT:    add %sp, -64, %i0
+; CHECK32-NEXT:    add %sp, -72, %i0
 ; CHECK32-NEXT:    and %i0, -64, %i0
-; CHECK32-NEXT:    add %i0, -16, %sp
+; CHECK32-NEXT:    add %i0, 96, %o1
 ; CHECK32-NEXT:    call stack_realign_helper
-; CHECK32-NEXT:    add %i0, 80, %o1
+; CHECK32-NEXT:    mov %i0, %sp
 ; CHECK32-NEXT:    ret
 ; CHECK32-NEXT:    restore
 ;
 ; CHECK64-LABEL: stack_realign:
-; CHECK64:         .cfi_startproc
-; CHECK64-NEXT:  ! %bb.0: ! %entry
+; CHECK64:       ! %bb.0: ! %entry
 ; CHECK64-NEXT:    save %sp, -128, %sp
-; CHECK64-NEXT:    .cfi_def_cfa_register %fp
-; CHECK64-NEXT:    .cfi_window_save
-; CHECK64-NEXT:    .cfi_register %o7, %i7
-; CHECK64-NEXT:    add %sp, 1983, %i0
+; CHECK64-NEXT:    add %sp, 1967, %i0
 ; CHECK64-NEXT:    and %i0, -64, %i0
-; CHECK64-NEXT:    add %i0, -2063, %sp
-; CHECK64-NEXT:    add %i0, -1935, %o1
+; CHECK64-NEXT:    add %i0, -2047, %sp
+; CHECK64-NEXT:    add %i0, -1919, %o1
 ; CHECK64-NEXT:    add %sp, -48, %sp
 ; CHECK64-NEXT:    call stack_realign_helper
 ; CHECK64-NEXT:    ld [%fp+2227], %o0

>From cc2a061d49955864d58cf37281275c07fe676a1b Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Thu, 12 Sep 2024 09:41:50 +0700
Subject: [PATCH 4/8] Drop legalize comments

---
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index f1fbd5a40a27f0..0be2d3e95165ae 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -2762,8 +2762,8 @@ static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) {
 
 static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
                                        const SparcSubtarget *Subtarget) {
-  SDValue Chain = Op.getOperand(0);  // Legalize the chain.
-  SDValue Size  = Op.getOperand(1);  // Legalize the size.
+  SDValue Chain = Op.getOperand(0);
+  SDValue Size = Op.getOperand(1);
   SDValue Alignment = Op.getOperand(2);
   MaybeAlign MaybeAlignment =
       cast<ConstantSDNode>(Alignment)->getMaybeAlignValue();

>From bfc07e5d63f58190a061c622ea9b6f1cac954c9c Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Thu, 12 Sep 2024 13:36:10 +0700
Subject: [PATCH 5/8] Fix return value calculation

Upon calculating NewSP we end up with a biased SP again, so we
need to account for that in NewVal return.
---
 llvm/lib/Target/Sparc/SparcISelLowering.cpp | 10 ++++------
 llvm/test/CodeGen/SPARC/alloca-align.ll     |  4 ++--
 llvm/test/CodeGen/SPARC/stack-align.ll      |  2 +-
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 0be2d3e95165ae..565b2cc88d3264 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -2819,18 +2819,16 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
     regSpillArea = 96;
   }
 
-  // If we are allocating overaligned memory then the bias is already accounted
-  // for in AlignedPtr calculation, so:
-  // - We do not need to adjust the regSpillArea; but
-  // - We do need to decrement AlignedPtr by bias to obtain the new SP.
-  regSpillArea += IsOveraligned ? 0 : Bias;
+  // If we are allocating overaligned memory then the AlignedPtr calculation
+  // adds the bias into SP, so we need to restore biased SP by decrementing
+  // AlignedPtr back here.
   SDValue NewSP =
       DAG.getNode(ISD::SUB, dl, VT, AlignedPtr,
                   DAG.getConstant(IsOveraligned ? Bias : 0, dl, VT));
   Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP);
 
   SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP,
-                               DAG.getConstant(regSpillArea, dl, VT));
+                               DAG.getConstant(regSpillArea + Bias, dl, VT));
   SDValue Ops[2] = { NewVal, Chain };
   return DAG.getMergeValues(Ops, dl);
 }
diff --git a/llvm/test/CodeGen/SPARC/alloca-align.ll b/llvm/test/CodeGen/SPARC/alloca-align.ll
index 797050d5a92e72..d90704dcf45449 100644
--- a/llvm/test/CodeGen/SPARC/alloca-align.ll
+++ b/llvm/test/CodeGen/SPARC/alloca-align.ll
@@ -25,7 +25,7 @@ define void @variable_alloca_with_overalignment(i32 %num) nounwind {
 ; CHECK64-NEXT:    add %sp, 1967, %i1
 ; CHECK64-NEXT:    and %i1, -64, %i1
 ; CHECK64-NEXT:    add %i1, -2047, %sp
-; CHECK64-NEXT:    add %i1, -1919, %o0
+; CHECK64-NEXT:    add %i1, 128, %o0
 ; CHECK64-NEXT:    srl %i0, 0, %i0
 ; CHECK64-NEXT:    add %i0, 15, %i0
 ; CHECK64-NEXT:    sethi 4194303, %i1
@@ -82,7 +82,7 @@ define void @variable_alloca_with_overalignment_2(i32 %num) nounwind {
 ; CHECK64-NEXT:    add %i0, 1983, %i0
 ; CHECK64-NEXT:    and %i0, -64, %i0
 ; CHECK64-NEXT:    add %i0, -2047, %sp
-; CHECK64-NEXT:    add %i0, -1919, %o1
+; CHECK64-NEXT:    add %i0, 128, %o1
 ; CHECK64-NEXT:    add %sp, -48, %sp
 ; CHECK64-NEXT:    call foo
 ; CHECK64-NEXT:    mov %g0, %o0
diff --git a/llvm/test/CodeGen/SPARC/stack-align.ll b/llvm/test/CodeGen/SPARC/stack-align.ll
index c141cd25a06f52..e360d35fb09718 100644
--- a/llvm/test/CodeGen/SPARC/stack-align.ll
+++ b/llvm/test/CodeGen/SPARC/stack-align.ll
@@ -27,7 +27,7 @@ define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %
 ; CHECK64-NEXT:    add %sp, 1967, %i0
 ; CHECK64-NEXT:    and %i0, -64, %i0
 ; CHECK64-NEXT:    add %i0, -2047, %sp
-; CHECK64-NEXT:    add %i0, -1919, %o1
+; CHECK64-NEXT:    add %i0, 128, %o1
 ; CHECK64-NEXT:    add %sp, -48, %sp
 ; CHECK64-NEXT:    call stack_realign_helper
 ; CHECK64-NEXT:    ld [%fp+2227], %o0

>From 80f1564f3125f28e83ab7169138afd9b898c5c55 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Mon, 16 Sep 2024 06:32:15 +0700
Subject: [PATCH 6/8] Fix calculation for alignment over 128 bytes

---
 llvm/lib/Target/Sparc/SparcISelLowering.cpp   | 47 +++++++++----------
 .../CodeGen/SPARC/2013-05-17-CallFrame.ll     |  4 +-
 llvm/test/CodeGen/SPARC/alloca-align.ll       | 32 ++++++-------
 llvm/test/CodeGen/SPARC/stack-align.ll        | 14 +++---
 4 files changed, 45 insertions(+), 52 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 565b2cc88d3264..5e34a68e90bb7c 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -2770,22 +2770,8 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
   EVT VT = Size->getValueType(0);
   SDLoc dl(Op);
 
-  int64_t Bias = Subtarget->getStackPointerBias();
   unsigned SPReg = SP::O6;
   SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT);
-  SDValue AllocatedPtr = DAG.getNode(ISD::SUB, dl, VT, SP, Size);
-
-  bool IsOveraligned = MaybeAlignment.has_value();
-  SDValue AlignedPtr =
-      IsOveraligned
-          ? DAG.getNode(ISD::AND, dl, VT,
-                        DAG.getNode(ISD::SUB, dl, VT,
-                                    DAG.getNode(ISD::ADD, dl, VT, AllocatedPtr,
-                                                DAG.getConstant(Bias, dl, VT)),
-                                    Alignment),
-                        DAG.getNode(ISD::SUB, dl, VT,
-                                    DAG.getConstant(0, dl, VT), Alignment))
-          : AllocatedPtr;
 
   // The resultant pointer needs to be above the register spill area
   // at the bottom of the stack.
@@ -2819,17 +2805,30 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
     regSpillArea = 96;
   }
 
-  // If we are allocating overaligned memory then the AlignedPtr calculation
-  // adds the bias into SP, so we need to restore biased SP by decrementing
-  // AlignedPtr back here.
-  SDValue NewSP =
-      DAG.getNode(ISD::SUB, dl, VT, AlignedPtr,
-                  DAG.getConstant(IsOveraligned ? Bias : 0, dl, VT));
-  Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP);
+  int64_t Bias = Subtarget->getStackPointerBias();
+
+  // Debias and increment SP past the reserved spill area.
+  // We need the SP to point to the first usable region before calculating
+  // anything to prevent any of the pointers from becoming out of alignment when
+  // we rebias the SP later on.
+  SDValue StartOfUsableStack = DAG.getNode(
+      ISD::ADD, dl, VT, SP, DAG.getConstant(regSpillArea + Bias, dl, VT));
+  SDValue AllocatedPtr =
+      DAG.getNode(ISD::SUB, dl, VT, StartOfUsableStack, Size);
+
+  bool IsOveraligned = MaybeAlignment.has_value();
+  SDValue AlignedPtr =
+      IsOveraligned
+          ? DAG.getNode(ISD::AND, dl, VT, AllocatedPtr,
+                        DAG.getNode(ISD::SUB, dl, VT,
+                                    DAG.getConstant(0, dl, VT), Alignment))
+          : AllocatedPtr;
 
-  SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP,
-                               DAG.getConstant(regSpillArea + Bias, dl, VT));
-  SDValue Ops[2] = { NewVal, Chain };
+  // Now that we are done, restore the bias and reserved spill area.
+  SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, AlignedPtr,
+                              DAG.getConstant(regSpillArea + Bias, dl, VT));
+  Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP);
+  SDValue Ops[2] = {AlignedPtr, Chain};
   return DAG.getMergeValues(Ops, dl);
 }
 
diff --git a/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll b/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll
index 39782f2ad08c62..9ebedfb68102fe 100644
--- a/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll
+++ b/llvm/test/CodeGen/SPARC/2013-05-17-CallFrame.ll
@@ -12,8 +12,8 @@ define void @variable_alloca_with_adj_call_stack(i32 %num) nounwind {
 ; V8-NEXT:    add %i0, 7, %i0
 ; V8-NEXT:    and %i0, -8, %i0
 ; V8-NEXT:    sub %sp, %i0, %i0
-; V8-NEXT:    add %i0, 96, %o0
-; V8-NEXT:    mov %i0, %sp
+; V8-NEXT:    add %i0, -8, %sp
+; V8-NEXT:    add %i0, 88, %o0
 ; V8-NEXT:    add %sp, -16, %sp
 ; V8-NEXT:    st %o0, [%sp+104]
 ; V8-NEXT:    st %o0, [%sp+100]
diff --git a/llvm/test/CodeGen/SPARC/alloca-align.ll b/llvm/test/CodeGen/SPARC/alloca-align.ll
index d90704dcf45449..f6330f16df4737 100644
--- a/llvm/test/CodeGen/SPARC/alloca-align.ll
+++ b/llvm/test/CodeGen/SPARC/alloca-align.ll
@@ -6,26 +6,24 @@ define void @variable_alloca_with_overalignment(i32 %num) nounwind {
 ; CHECK32-LABEL: variable_alloca_with_overalignment:
 ; CHECK32:       ! %bb.0:
 ; CHECK32-NEXT:    save %sp, -96, %sp
-; CHECK32-NEXT:    add %sp, -72, %i1
-; CHECK32-NEXT:    and %i1, -64, %i1
-; CHECK32-NEXT:    add %i1, 96, %o0
-; CHECK32-NEXT:    mov %i1, %sp
+; CHECK32-NEXT:    add %sp, 80, %i1
+; CHECK32-NEXT:    and %i1, -64, %o0
+; CHECK32-NEXT:    add %o0, -96, %sp
 ; CHECK32-NEXT:    add %i0, 7, %i0
 ; CHECK32-NEXT:    and %i0, -8, %i0
 ; CHECK32-NEXT:    sub %sp, %i0, %i0
-; CHECK32-NEXT:    add %i0, 96, %o1
+; CHECK32-NEXT:    add %i0, -8, %sp
 ; CHECK32-NEXT:    call foo
-; CHECK32-NEXT:    mov %i0, %sp
+; CHECK32-NEXT:    add %i0, 88, %o1
 ; CHECK32-NEXT:    ret
 ; CHECK32-NEXT:    restore
 ;
 ; CHECK64-LABEL: variable_alloca_with_overalignment:
 ; CHECK64:       ! %bb.0:
 ; CHECK64-NEXT:    save %sp, -128, %sp
-; CHECK64-NEXT:    add %sp, 1967, %i1
-; CHECK64-NEXT:    and %i1, -64, %i1
-; CHECK64-NEXT:    add %i1, -2047, %sp
-; CHECK64-NEXT:    add %i1, 128, %o0
+; CHECK64-NEXT:    add %sp, 2159, %i1
+; CHECK64-NEXT:    and %i1, -64, %o0
+; CHECK64-NEXT:    add %o0, -2175, %sp
 ; CHECK64-NEXT:    srl %i0, 0, %i0
 ; CHECK64-NEXT:    add %i0, 15, %i0
 ; CHECK64-NEXT:    sethi 4194303, %i1
@@ -57,10 +55,9 @@ define void @variable_alloca_with_overalignment_2(i32 %num) nounwind {
 ; CHECK32-NEXT:    add %i0, 7, %i0
 ; CHECK32-NEXT:    and %i0, -8, %i0
 ; CHECK32-NEXT:    sub %sp, %i0, %i0
-; CHECK32-NEXT:    add %i0, -64, %i0
-; CHECK32-NEXT:    and %i0, -64, %i0
-; CHECK32-NEXT:    add %i0, 96, %o1
-; CHECK32-NEXT:    mov %i0, %sp
+; CHECK32-NEXT:    add %i0, 88, %i0
+; CHECK32-NEXT:    and %i0, -64, %o1
+; CHECK32-NEXT:    add %o1, -96, %sp
 ; CHECK32-NEXT:    call foo
 ; CHECK32-NEXT:    mov %g0, %o0
 ; CHECK32-NEXT:    ret
@@ -79,10 +76,9 @@ define void @variable_alloca_with_overalignment_2(i32 %num) nounwind {
 ; CHECK64-NEXT:    or %i2, %i1, %i1
 ; CHECK64-NEXT:    and %i0, %i1, %i0
 ; CHECK64-NEXT:    sub %sp, %i0, %i0
-; CHECK64-NEXT:    add %i0, 1983, %i0
-; CHECK64-NEXT:    and %i0, -64, %i0
-; CHECK64-NEXT:    add %i0, -2047, %sp
-; CHECK64-NEXT:    add %i0, 128, %o1
+; CHECK64-NEXT:    add %i0, 2175, %i0
+; CHECK64-NEXT:    and %i0, -64, %o1
+; CHECK64-NEXT:    add %o1, -2175, %sp
 ; CHECK64-NEXT:    add %sp, -48, %sp
 ; CHECK64-NEXT:    call foo
 ; CHECK64-NEXT:    mov %g0, %o0
diff --git a/llvm/test/CodeGen/SPARC/stack-align.ll b/llvm/test/CodeGen/SPARC/stack-align.ll
index e360d35fb09718..c861b2d0296f0b 100644
--- a/llvm/test/CodeGen/SPARC/stack-align.ll
+++ b/llvm/test/CodeGen/SPARC/stack-align.ll
@@ -13,21 +13,19 @@ define void @stack_realign(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %
 ; CHECK32:       ! %bb.0: ! %entry
 ; CHECK32-NEXT:    save %sp, -96, %sp
 ; CHECK32-NEXT:    ld [%fp+92], %o0
-; CHECK32-NEXT:    add %sp, -72, %i0
-; CHECK32-NEXT:    and %i0, -64, %i0
-; CHECK32-NEXT:    add %i0, 96, %o1
+; CHECK32-NEXT:    add %sp, 80, %i0
+; CHECK32-NEXT:    and %i0, -64, %o1
 ; CHECK32-NEXT:    call stack_realign_helper
-; CHECK32-NEXT:    mov %i0, %sp
+; CHECK32-NEXT:    add %o1, -96, %sp
 ; CHECK32-NEXT:    ret
 ; CHECK32-NEXT:    restore
 ;
 ; CHECK64-LABEL: stack_realign:
 ; CHECK64:       ! %bb.0: ! %entry
 ; CHECK64-NEXT:    save %sp, -128, %sp
-; CHECK64-NEXT:    add %sp, 1967, %i0
-; CHECK64-NEXT:    and %i0, -64, %i0
-; CHECK64-NEXT:    add %i0, -2047, %sp
-; CHECK64-NEXT:    add %i0, 128, %o1
+; CHECK64-NEXT:    add %sp, 2159, %i0
+; CHECK64-NEXT:    and %i0, -64, %o1
+; CHECK64-NEXT:    add %o1, -2175, %sp
 ; CHECK64-NEXT:    add %sp, -48, %sp
 ; CHECK64-NEXT:    call stack_realign_helper
 ; CHECK64-NEXT:    ld [%fp+2227], %o0

>From f671f2d9cd02831a413adffc02c7caf156a9c3e8 Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Sat, 12 Oct 2024 21:49:32 +0700
Subject: [PATCH 7/8] XFAIL alloca_vla_interact.cpp asan test for SPARC

---
 compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp b/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp
index 96ac4c7db291a0..b98bb726dcebc3 100644
--- a/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp
+++ b/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp
@@ -3,6 +3,9 @@
 //
 // REQUIRES: stable-runtime
 
+// See https://github.com/llvm/llvm-project/issues/110956
+// XFAIL: target=sparc{{.*}}
+
 // This testcase checks correct interaction between VLAs and allocas.
 
 #include <assert.h>

>From 54c7669a244a7838dec55fc8de3ab9eaeafa127a Mon Sep 17 00:00:00 2001
From: Koakuma <koachan at protonmail.com>
Date: Tue, 29 Oct 2024 06:58:00 +0700
Subject: [PATCH 8/8] Apply suggestions

---
 llvm/lib/Target/Sparc/SparcFrameLowering.cpp | 8 +-------
 llvm/lib/Target/Sparc/SparcISelLowering.cpp  | 3 +--
 2 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index 399d55c439cbb4..4ff389605e944c 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -227,8 +227,7 @@ bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
-         RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
-         MFI.isFrameAddressTaken();
+         MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken();
 }
 
 StackOffset
@@ -254,11 +253,6 @@ SparcFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
   } else if (isFixed) {
     // Otherwise, argument access should always use %fp.
     UseFP = true;
-  } else if (RegInfo->hasStackRealignment(MF)) {
-    // If there is dynamic stack realignment, all local object
-    // references need to be via %sp, to take account of the
-    // re-alignment.
-    UseFP = false;
   } else {
     // Finally, default to using %fp.
     UseFP = true;
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 5e34a68e90bb7c..44f083e4f70cdb 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -2820,8 +2820,7 @@ static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
   SDValue AlignedPtr =
       IsOveraligned
           ? DAG.getNode(ISD::AND, dl, VT, AllocatedPtr,
-                        DAG.getNode(ISD::SUB, dl, VT,
-                                    DAG.getConstant(0, dl, VT), Alignment))
+                        DAG.getConstant(-MaybeAlignment->value(), dl, VT))
           : AllocatedPtr;
 
   // Now that we are done, restore the bias and reserved spill area.



More information about the llvm-commits mailing list