[llvm] [Hexagon] Fix hasFP to respect frame-pointer attribute unconditionally (PR #181524)

via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 14 21:09:46 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-hexagon

Author: Brian Cain (androm3da)

<details>
<summary>Changes</summary>

HexagonFrameLowering::hasFPImpl() incorrectly gated the DisableFramePointerElim check behind MFI.getStackSize() > 0. This meant leaf functions with no stack allocation would not get a frame pointer even when "frame-pointer"="all" (-fno-omit-frame-pointer) was set, violating the user/ABI request. Every other LLVM target checks DisableFramePointerElim unconditionally.

Move the DisableFramePointerElim and EliminateFramePointer checks outside the getStackSize() > 0 guard so they are always evaluated. Update affected tests whose CHECK patterns change due to the now- correct allocframe emission.

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


5 Files Affected:

- (modified) llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp (+8-4) 
- (modified) llvm/test/CodeGen/Hexagon/bfloat_vec.ll (+63-44) 
- (modified) llvm/test/CodeGen/Hexagon/constp-extract.ll (+3-3) 
- (added) llvm/test/CodeGen/Hexagon/frame-pointer-attr.ll (+28) 
- (modified) llvm/test/CodeGen/Hexagon/hasfp-crash1.ll (+1-1) 


``````````diff
diff --git a/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp b/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
index df612262def5e..027bc116036c4 100644
--- a/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
@@ -1153,11 +1153,15 @@ bool HexagonFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   if (HasAlloca || HasExtraAlign)
     return true;
 
+  // If FP-elimination is disabled, we have to use FP. This must not be
+  // gated on stack size: the user/ABI-requested frame pointer is needed
+  // regardless of whether the function currently has a stack frame.
+  // Every other target checks DisableFramePointerElim unconditionally.
+  const TargetMachine &TM = MF.getTarget();
+  if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer)
+    return true;
+
   if (MFI.getStackSize() > 0) {
-    // If FP-elimination is disabled, we have to use FP at this point.
-    const TargetMachine &TM = MF.getTarget();
-    if (TM.Options.DisableFramePointerElim(MF) || !EliminateFramePointer)
-      return true;
     if (EnableStackOVFSanitizer)
       return true;
   }
diff --git a/llvm/test/CodeGen/Hexagon/bfloat_vec.ll b/llvm/test/CodeGen/Hexagon/bfloat_vec.ll
index 47be92aaf0b31..1e5cb3c197261 100644
--- a/llvm/test/CodeGen/Hexagon/bfloat_vec.ll
+++ b/llvm/test/CodeGen/Hexagon/bfloat_vec.ll
@@ -7,81 +7,86 @@ define dso_local void @bf16_vec_add(ptr noundef %c, ptr noundef %a, ptr noundef
 ; CHECK-LABEL: bf16_vec_add:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[R7:r[0-9]+]] = #-4
-; CHECK-NEXT:     [[V0:v[0-9]+]] = vmemu([[R2:r[0-9]+]]+#0)
+; CHECK-NEXT:     r7 = #-4
+; CHECK-NEXT:     r6 = ##131071
+; CHECK-NEXT:     allocframe(#0)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[R2]] = ##32768
-; CHECK-NEXT:     [[V1:v[0-9]+]] = vmemu([[R1:r[0-9]+]]+#0)
+; CHECK-NEXT:     r5 = #16
+; CHECK-NEXT:     v0 = vmemu(r2+#0)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[R6:r[0-9]+]] = ##131071
-; CHECK-NEXT:     [[V2:v[0-9]+]] = vxor([[V0]],[[V0]])
-; CHECK-NEXT:     [[V3:v[0-9]+]] = vxor([[V1]],[[V1]])
+; CHECK-NEXT:     v26 = vsplat(r6)
+; CHECK-NEXT:     r2 = ##32768
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V25:v[0-9]+]] = vsplat([[R2]])
-; CHECK-NEXT:     [[R5:r[0-9]+]] = #16
-; CHECK-NEXT:     [[V5_4:v[0-9]+:[0-9]+]].h = vshuffoe([[V0]].h,[[V2]].h)
+; CHECK-NEXT:     v25 = vsplat(r2)
+; CHECK-NEXT:     v2 = vxor(v0,v0)
+; CHECK-NEXT:     v1 = vmemu(r1+#0)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V26:v[0-9]+]] = vsplat([[R6]])
-; CHECK-NEXT:     [[R4:r[0-9]+]] = #32767
-; CHECK-NEXT:     [[V31_30:v[0-9]+:[0-9]+]].h = vshuffoe([[V1]].h,[[V3]].h)
+; CHECK-NEXT:     r4 = #32767
+; CHECK-NEXT:     v5:4.h = vshuffoe(v0.h,v2.h)
+; CHECK-NEXT:     v3 = vxor(v1,v1)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V5_4]] = vshuff([[V5:v[0-9]+]],[[V4:v[0-9]+]],[[R7]])
+; CHECK-NEXT:     v31:30.h = vshuffoe(v1.h,v3.h)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V31:v[0-9]+]].h = vsplat([[R4]])
-; CHECK-NEXT:     [[V3_2:v[0-9]+:[0-9]+]] = vshuff([[V31]],[[V30:v[0-9]+]],[[R7]])
+; CHECK-NEXT:     v5:4 = vshuff(v5,v4,r7)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V2]].qf32 = vadd([[V2]].sf,[[V4]].sf)
+; CHECK-NEXT:     v31.h = vsplat(r4)
+; CHECK-NEXT:     v3:2 = vshuff(v31,v30,r7)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V3]].qf32 = vadd([[V3]].sf,[[V5]].sf)
+; CHECK-NEXT:     v2.qf32 = vadd(v2.sf,v4.sf)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V2]].sf = [[V2]].qf32
+; CHECK-NEXT:     v3.qf32 = vadd(v3.sf,v5.sf)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V3]].sf = [[V3]].qf32
-; CHECK-NEXT:     [[V27:v[0-9]+]] = vand([[V2]],[[V25]])
-; CHECK-NEXT:     [[V28:v[0-9]+]] = vand([[V2]],[[V26]])
-; CHECK-NEXT:     [[Q2:q[0-9]+]] = vcmp.eq([[V2]].sf,[[V2]].sf)
+; CHECK-NEXT:     v2.sf = v2.qf32
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V29:v[0-9]+]] = vand([[V3]],[[V25]])
-; CHECK-NEXT:     [[V1]] = vand([[V3]],[[V26]])
-; CHECK-NEXT:     [[Q0:q[0-9]+]] = vcmp.eq([[V28]].w,[[V25]].w)
-; CHECK-NEXT:     [[V4]].w = vadd([[V2]].w,[[V27]].w)
+; CHECK-NEXT:     v3.sf = v3.qf32
+; CHECK-NEXT:     v27 = vand(v2,v25)
+; CHECK-NEXT:     v28 = vand(v2,v26)
+; CHECK-NEXT:     q2 = vcmp.eq(v2.sf,v2.sf)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V5]].w = vadd([[V3]].w,[[V29]].w)
-; CHECK-NEXT:     [[Q1:q[0-9]+]] = vcmp.eq([[V1]].w,[[V25]].w)
-; CHECK-NEXT:     [[V30:v[0-9]+]] = vmux([[Q0]],[[V2]],[[V4]])
-; CHECK-NEXT:     [[Q3:q[0-9]+]] = vcmp.eq([[V3]].sf,[[V3]].sf)
+; CHECK-NEXT:     v29 = vand(v3,v25)
+; CHECK-NEXT:     v1 = vand(v3,v26)
+; CHECK-NEXT:     q0 = vcmp.eq(v28.w,v25.w)
+; CHECK-NEXT:     v4.w = vadd(v2.w,v27.w)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V1]] = vmux([[Q1]],[[V3]],[[V5]])
+; CHECK-NEXT:     v5.w = vadd(v3.w,v29.w)
+; CHECK-NEXT:     q1 = vcmp.eq(v1.w,v25.w)
+; CHECK-NEXT:     v30 = vmux(q0,v2,v4)
+; CHECK-NEXT:     q3 = vcmp.eq(v3.sf,v3.sf)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V0]].uw = vlsr([[V30]].uw,[[R5]])
+; CHECK-NEXT:     v1 = vmux(q1,v3,v5)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V1]].uw = vlsr([[V1]].uw,[[R5]])
-; CHECK-NEXT:     [[V0]] = vmux([[Q2]],[[V0]],[[V31]])
+; CHECK-NEXT:     v0.uw = vlsr(v30.uw,r5)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V1]] = vmux([[Q3]],[[V1]],[[V31]])
+; CHECK-NEXT:     v1.uw = vlsr(v1.uw,r5)
+; CHECK-NEXT:     v0 = vmux(q2,v0,v31)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     [[V0]].uh = vpack([[V1]].w,[[V0]].w):sat
+; CHECK-NEXT:     v1 = vmux(q3,v1,v31)
 ; CHECK-NEXT:    }
 ; CHECK-NEXT:    {
-; CHECK-NEXT:     jumpr [[R31:r[0-9]+]]
-; CHECK-NEXT:     vmemu([[R0:r[0-9]+]]+#0) = [[V0]]
+; CHECK-NEXT:     v0.uh = vpack(v1.w,v0.w):sat
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     vmemu(r0+#0) = v0
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r31:30 = dealloc_return(r30):raw
 ; CHECK-NEXT:    }
 
 
@@ -95,11 +100,25 @@ entry:
 
 define dso_local void @copy1d(ptr noundef readonly captures(none) %X, ptr noundef writeonly captures(none) %Y) local_unnamed_addr #0 {
 ; CHECK-LABEL: copy1d:
-; CHECK: v[[X_HI:[0-9]+]] = vmemu(r0+#1)
-; CHECK: v[[X_LO:[0-9]+]] = vmemu(r0+#0)
-; CHECK: vmemu(r1+#1) = v[[X_HI]]
-; CHECK: jumpr [[RET:r[0-9]+]]
-; CHECK: vmemu(r1+#0) = v[[X_LO]]
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    {
+; CHECK-NEXT:     allocframe(r29,#0):raw
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v0 = vmemu(r0+#1)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     v1 = vmemu(r0+#0)
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     vmemu(r1+#1) = v0
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     vmemu(r1+#0) = v1
+; CHECK-NEXT:    }
+; CHECK-NEXT:    {
+; CHECK-NEXT:     r31:30 = dealloc_return(r30):raw
+; CHECK-NEXT:    }
 entry:
   %0 = load <128 x half>, ptr %X, align 2
   store <128 x half> %0, ptr %Y, align 2
diff --git a/llvm/test/CodeGen/Hexagon/constp-extract.ll b/llvm/test/CodeGen/Hexagon/constp-extract.ll
index c72afdc7cfa81..d3e183868d04a 100644
--- a/llvm/test/CodeGen/Hexagon/constp-extract.ll
+++ b/llvm/test/CodeGen/Hexagon/constp-extract.ll
@@ -11,13 +11,13 @@ entry:
   ; extractu(0x000ABCD0, 16, 4)
   ; should evaluate to 0xABCD (dec 43981)
   %0 = call i32 @llvm.hexagon.S2.extractu(i32 703696, i32 16, i32 4)
-; CHECK: 43981
-; CHECK-NOT: extractu
+; CHECK-DAG: 43981
   store i32 %0, ptr @x, align 4
   ; extract(0x000ABCD0, 16, 4)
   ; should evaluate to 0xFFFFABCD (dec 4294945741 or -21555)
   %1 = call i32 @llvm.hexagon.S4.extract(i32 703696, i32 16, i32 4)
-; CHECK: -21555
+; CHECK-DAG: -21555
+; CHECK-NOT: extractu
 ; CHECK-NOT: extract
   store i32 %1, ptr @y, align 4
   ret void
diff --git a/llvm/test/CodeGen/Hexagon/frame-pointer-attr.ll b/llvm/test/CodeGen/Hexagon/frame-pointer-attr.ll
new file mode 100644
index 0000000000000..fa9ed2e5802ad
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/frame-pointer-attr.ll
@@ -0,0 +1,28 @@
+; RUN: llc -mtriple=hexagon -O2 -o - %s | FileCheck %s
+
+; The "frame-pointer"="all" attribute (i.e. -fno-omit-frame-pointer) must be
+; respected even for leaf functions that have no stack usage. Hexagon's
+; hasFPImpl was incorrectly gating the DisableFramePointerElim check behind
+; MFI.getStackSize() > 0, so leaf functions with no stack would skip the
+; check and omit the frame pointer.
+
+; CHECK-LABEL: leaf_fp:
+; CHECK: allocframe
+define i32 @leaf_fp(i32 %a, i32 %b) #0 {
+entry:
+  %add = add nsw i32 %a, %b
+  ret i32 %add
+}
+
+; Verify that without the attribute, the leaf function still omits the
+; frame pointer (the optimization is preserved).
+; CHECK-LABEL: leaf_no_fp:
+; CHECK-NOT: allocframe
+define i32 @leaf_no_fp(i32 %a, i32 %b) #1 {
+entry:
+  %add = add nsw i32 %a, %b
+  ret i32 %add
+}
+
+attributes #0 = { nounwind "frame-pointer"="all" }
+attributes #1 = { nounwind }
diff --git a/llvm/test/CodeGen/Hexagon/hasfp-crash1.ll b/llvm/test/CodeGen/Hexagon/hasfp-crash1.ll
index 6755ad0eb178d..77186bc013eb6 100644
--- a/llvm/test/CodeGen/Hexagon/hasfp-crash1.ll
+++ b/llvm/test/CodeGen/Hexagon/hasfp-crash1.ll
@@ -1,7 +1,7 @@
 ; RUN: llc -mtriple=hexagon < %s | FileCheck %s
 ;
 ; Check that this testcase does not crash.
-; CHECK: jumpr r31
+; CHECK: dealloc_return
 
 target triple = "hexagon"
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/181524


More information about the llvm-commits mailing list