https://github.com/fpetrogalli updated 
https://github.com/llvm/llvm-project/pull/154216

>From fa421d46c6f2d307e47c4bacbfc85f9e5c0efabd Mon Sep 17 00:00:00 2001
From: Francesco Petrogalli <francesco.petroga...@apple.com>
Date: Mon, 18 Aug 2025 10:01:25 -0700
Subject: [PATCH 1/3] [arm][macho] Force -mframe-pointer=non-leaf for -Oz and
 -Os

The change in [1] uncovered a bug in the emission of the frame
pointer.

Specifically, before the fix in [1], non-leaf functions with a tail
call were not emitting the frame pointer even if the default behavior
emitted by clang was "frame-pointer=all".

After the fix in [1], we had a set of internal build failures, caused
by the fact that suddenly all non-leaf functions with tail calls
started needing extra 4/8/16 bytes because of the extra push/pop
instructions emitted to handle the frame pointer. Because of this, the
size constraints we had on the firmware binaries were not met anymore.

These projects are built with -Oz, therefore we have changed the
default behavior of the Driver to emit -mframe-pointer=non-leaf when
targeting anything that cares about size on MachO for armv7 (-Oz and -Os).

The default behavior is also checked against
-mno-omit-leaf-frame-pointer.

An LLVM codegen test has also been added to make sure the test case we
have in our firmware does not regress.

[1] https://github.com/llvm/llvm-project/pull/109628
---
 clang/lib/Driver/ToolChains/CommonArgs.cpp    | 15 +++++++--
 clang/test/Driver/frame-pointer-elim.c        | 26 ++++++++++++++++
 clang/test/Driver/frame-pointer.c             | 14 +++++++++
 .../CodeGen/ARM/macho-leaf-functions-fp.ll    | 31 +++++++++++++++++++
 4 files changed, 84 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll

diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index eb88f7bd4b469..73f005b66bad4 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -151,11 +151,22 @@ static bool useFramePointerForTargetByDefault(const 
llvm::opt::ArgList &Args,
   return true;
 }
 
-static bool useLeafFramePointerForTargetByDefault(const llvm::Triple &Triple) {
+static bool
+useLeafFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
+                                      const llvm::Triple &Triple) {
   if (Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
       (Triple.isAndroid() && !Triple.isARM()))
     return false;
 
+  if (Triple.isARM() && Triple.isOSBinFormatMachO()) {
+    if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+      if (A->getOption().matches(options::OPT_O)) {
+        StringRef S(A->getValue());
+        if (S == "s" || S == "z")
+          return false;
+      }
+    }
+  }
   return true;
 }
 
@@ -252,7 +263,7 @@ getFramePointerKind(const llvm::opt::ArgList &Args,
                    clang::driver::options::OPT_fomit_frame_pointer, DefaultFP);
 
   bool DefaultLeafFP =
-      useLeafFramePointerForTargetByDefault(Triple) ||
+      useLeafFramePointerForTargetByDefault(Args, Triple) ||
       (EnableFP && framePointerImpliesLeafFramePointer(Args, Triple));
   bool EnableLeafFP = Args.hasFlag(
       clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
diff --git a/clang/test/Driver/frame-pointer-elim.c 
b/clang/test/Driver/frame-pointer-elim.c
index 6e21671f43775..c7206986a18ad 100644
--- a/clang/test/Driver/frame-pointer-elim.c
+++ b/clang/test/Driver/frame-pointer-elim.c
@@ -221,5 +221,31 @@
 // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer 
%s 2>&1 |  \
 // RUN:   FileCheck --check-prefix=KEEP-RESERVED %s
 
+// At all optimization levels, -fno-omit-frame-pointer gives the default 
behavior.
+// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
+
+// All all optimization levels, the frame pointer is "none" if 
-fomit-frame-pointer is specified.
+// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
+
+// At -Oz/-Os, -fno-omit-frame-pointer + -mno-omit-leaf-frame-pointer give 
frame-pointer=all
+// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 
-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-ALL %s
+// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 
-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-ALL %s
+
+// At -O0/1/2/3, -fomit-frame-pointer wins over -mno-omit-leaf-frame-pointer
+// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
+
 void f0() {}
 void f1() { f0(); }
diff --git a/clang/test/Driver/frame-pointer.c 
b/clang/test/Driver/frame-pointer.c
index 2015fa520c2a2..5a9eec5a9ae4a 100644
--- a/clang/test/Driver/frame-pointer.c
+++ b/clang/test/Driver/frame-pointer.c
@@ -80,12 +80,26 @@
 // RUN: %clang --target=loongarch64 -### -S -O3 %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECK3-64 %s
 // RUN: %clang --target=loongarch64 -### -S -Os %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECKs-64 %s
 
+// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECKs-32-MACHO %s
+// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECKz-32-MACHO %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK0-32-MACHO %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK1-32-MACHO %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK2-32-MACHO %s
+// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK3-32-MACHO %s
+
 // CHECK0-32: -mframe-pointer=all
 // CHECK1-32-NOT: -mframe-pointer=all
 // CHECK2-32-NOT: -mframe-pointer=all
 // CHECK3-32-NOT: -mframe-pointer=all
 // CHECKs-32-NOT: -mframe-pointer=all
 
+// CHECKs-32-MACHO: -mframe-pointer=non-leaf
+// CHECKz-32-MACHO: -mframe-pointer=non-leaf
+// CHECK0-32-MACHO: -mframe-pointer=all
+// CHECK1-32-MACHO: -mframe-pointer=all
+// CHECK2-32-MACHO: -mframe-pointer=all
+// CHECK3-32-MACHO: -mframe-pointer=all
+
 // CHECK0-64: -mframe-pointer=all
 // CHECK1-64-NOT: -mframe-pointer=all
 // CHECK2-64-NOT: -mframe-pointer=all
diff --git a/llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll 
b/llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll
new file mode 100644
index 0000000000000..5bb19825a7655
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 5
+; RUN: llc < %s | FileCheck %s
+
+target triple = "thumbv7-apple-macho"
+
+define void @foo(ptr %0) "frame-pointer"="all" {
+; CHECK-LABEL: foo:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    push {r7, lr}
+; CHECK-NEXT:    mov r7, sp
+; CHECK-NEXT:    ldrh r0, [r0]
+; CHECK-NEXT:    pop.w {r7, lr}
+; CHECK-NEXT:    b bar
+  %2 = load i16, ptr %0, align 2
+  tail call void @bar(i16 %2)
+  ret void
+}
+
+declare void @bar(i16) "frame-pointer"="all"
+
+define void @foo_02(ptr %0) "frame-pointer"="non-leaf" {
+; CHECK-LABEL: foo_02:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    ldrh r0, [r0]
+; CHECK-NEXT:    b bar_02
+  %2 = load i16, ptr %0, align 2
+  tail call void @bar_02(i16 %2)
+  ret void
+}
+
+declare void @bar_02(i16) "frame-pointer"="non-leaf"

>From 1b8049761ed8922c6dc4283b6da0f2ff833aa1f8 Mon Sep 17 00:00:00 2001
From: Francesco Petrogalli <francesco.petroga...@apple.com>
Date: Mon, 25 Aug 2025 10:27:05 -0700
Subject: [PATCH 2/3] Revert "[arm][macho] Force -mframe-pointer=non-leaf for
 -Oz and -Os"

This reverts commit fa421d46c6f2d307e47c4bacbfc85f9e5c0efabd.
---
 clang/lib/Driver/ToolChains/CommonArgs.cpp    | 15 ++-------
 clang/test/Driver/frame-pointer-elim.c        | 26 ----------------
 clang/test/Driver/frame-pointer.c             | 14 ---------
 .../CodeGen/ARM/macho-leaf-functions-fp.ll    | 31 -------------------
 4 files changed, 2 insertions(+), 84 deletions(-)
 delete mode 100644 llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll

diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 73f005b66bad4..eb88f7bd4b469 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -151,22 +151,11 @@ static bool useFramePointerForTargetByDefault(const 
llvm::opt::ArgList &Args,
   return true;
 }
 
-static bool
-useLeafFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
-                                      const llvm::Triple &Triple) {
+static bool useLeafFramePointerForTargetByDefault(const llvm::Triple &Triple) {
   if (Triple.isAArch64() || Triple.isPS() || Triple.isVE() ||
       (Triple.isAndroid() && !Triple.isARM()))
     return false;
 
-  if (Triple.isARM() && Triple.isOSBinFormatMachO()) {
-    if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
-      if (A->getOption().matches(options::OPT_O)) {
-        StringRef S(A->getValue());
-        if (S == "s" || S == "z")
-          return false;
-      }
-    }
-  }
   return true;
 }
 
@@ -263,7 +252,7 @@ getFramePointerKind(const llvm::opt::ArgList &Args,
                    clang::driver::options::OPT_fomit_frame_pointer, DefaultFP);
 
   bool DefaultLeafFP =
-      useLeafFramePointerForTargetByDefault(Args, Triple) ||
+      useLeafFramePointerForTargetByDefault(Triple) ||
       (EnableFP && framePointerImpliesLeafFramePointer(Args, Triple));
   bool EnableLeafFP = Args.hasFlag(
       clang::driver::options::OPT_mno_omit_leaf_frame_pointer,
diff --git a/clang/test/Driver/frame-pointer-elim.c 
b/clang/test/Driver/frame-pointer-elim.c
index c7206986a18ad..6e21671f43775 100644
--- a/clang/test/Driver/frame-pointer-elim.c
+++ b/clang/test/Driver/frame-pointer-elim.c
@@ -221,31 +221,5 @@
 // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer 
%s 2>&1 |  \
 // RUN:   FileCheck --check-prefix=KEEP-RESERVED %s
 
-// At all optimization levels, -fno-omit-frame-pointer gives the default 
behavior.
-// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-NON-LEAF %s
-// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-NON-LEAF %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 
-fno-omit-frame-pointer 2>&1 | FileCheck -check-prefix=KEEP-ALL %s
-
-// All all optimization levels, the frame pointer is "none" if 
-fomit-frame-pointer is specified.
-// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 
-fomit-frame-pointer    2>&1 | FileCheck -check-prefix=KEEP-NONE %s
-
-// At -Oz/-Os, -fno-omit-frame-pointer + -mno-omit-leaf-frame-pointer give 
frame-pointer=all
-// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 
-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-ALL %s
-// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 
-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-ALL %s
-
-// At -O0/1/2/3, -fomit-frame-pointer wins over -mno-omit-leaf-frame-pointer
-// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 
-fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | FileCheck 
-check-prefix=KEEP-NONE %s
-
 void f0() {}
 void f1() { f0(); }
diff --git a/clang/test/Driver/frame-pointer.c 
b/clang/test/Driver/frame-pointer.c
index 5a9eec5a9ae4a..2015fa520c2a2 100644
--- a/clang/test/Driver/frame-pointer.c
+++ b/clang/test/Driver/frame-pointer.c
@@ -80,26 +80,12 @@
 // RUN: %clang --target=loongarch64 -### -S -O3 %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECK3-64 %s
 // RUN: %clang --target=loongarch64 -### -S -Os %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECKs-64 %s
 
-// RUN: %clang --target=armv7-apple-macho -### -S -Os %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECKs-32-MACHO %s
-// RUN: %clang --target=armv7-apple-macho -### -S -Oz %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECKz-32-MACHO %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O0 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK0-32-MACHO %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O1 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK1-32-MACHO %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O2 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK2-32-MACHO %s
-// RUN: %clang --target=armv7-apple-macho -### -S -O3 %s -o %t.s 2>&1 | 
FileCheck -check-prefix=CHECK3-32-MACHO %s
-
 // CHECK0-32: -mframe-pointer=all
 // CHECK1-32-NOT: -mframe-pointer=all
 // CHECK2-32-NOT: -mframe-pointer=all
 // CHECK3-32-NOT: -mframe-pointer=all
 // CHECKs-32-NOT: -mframe-pointer=all
 
-// CHECKs-32-MACHO: -mframe-pointer=non-leaf
-// CHECKz-32-MACHO: -mframe-pointer=non-leaf
-// CHECK0-32-MACHO: -mframe-pointer=all
-// CHECK1-32-MACHO: -mframe-pointer=all
-// CHECK2-32-MACHO: -mframe-pointer=all
-// CHECK3-32-MACHO: -mframe-pointer=all
-
 // CHECK0-64: -mframe-pointer=all
 // CHECK1-64-NOT: -mframe-pointer=all
 // CHECK2-64-NOT: -mframe-pointer=all
diff --git a/llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll 
b/llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll
deleted file mode 100644
index 5bb19825a7655..0000000000000
--- a/llvm/test/CodeGen/ARM/macho-leaf-functions-fp.ll
+++ /dev/null
@@ -1,31 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 5
-; RUN: llc < %s | FileCheck %s
-
-target triple = "thumbv7-apple-macho"
-
-define void @foo(ptr %0) "frame-pointer"="all" {
-; CHECK-LABEL: foo:
-; CHECK:       @ %bb.0:
-; CHECK-NEXT:    push {r7, lr}
-; CHECK-NEXT:    mov r7, sp
-; CHECK-NEXT:    ldrh r0, [r0]
-; CHECK-NEXT:    pop.w {r7, lr}
-; CHECK-NEXT:    b bar
-  %2 = load i16, ptr %0, align 2
-  tail call void @bar(i16 %2)
-  ret void
-}
-
-declare void @bar(i16) "frame-pointer"="all"
-
-define void @foo_02(ptr %0) "frame-pointer"="non-leaf" {
-; CHECK-LABEL: foo_02:
-; CHECK:       @ %bb.0:
-; CHECK-NEXT:    ldrh r0, [r0]
-; CHECK-NEXT:    b bar_02
-  %2 = load i16, ptr %0, align 2
-  tail call void @bar_02(i16 %2)
-  ret void
-}
-
-declare void @bar_02(i16) "frame-pointer"="non-leaf"

>From 7d021d6d101498c2c2e90cfeeab61dfc920287d3 Mon Sep 17 00:00:00 2001
From: Francesco Petrogalli <francesco.petroga...@apple.com>
Date: Mon, 18 Aug 2025 10:01:25 -0700
Subject: [PATCH 3/3] Force -mframe-pointer=non-leaf for -Oz and -Os

The change in [1] uncovered a bug in the emission of the frame
pointer.

Specifically, before the fix in [1], non-leaf functions with a tail
call were not emitting the frame pointer even if the default behavior
emitted by clang was "frame-pointer=all".

After the fix in [1], we had a set of internal build failures, caused
by the fact that suddenly all non-leaf function with tail calls in
them started needeing extra 4/8/16 bytes because of the extra push/pop
instructions emitted to handle the frame pointer. Because of this, the
size constraints we had on the firware binaries were not met anymore.

We have changed the default behavior of the Driver to emit
-mframe-pointer=non-leaf targeting ARMV7 on MachO.

The default behavior is also checked against
-mno-omit-leaf-frame-pointer.

An LLVM codegen test has also been added to make sure the test case we
have in our firmware does not regress.

[1] https://github.com/llvm/llvm-project/pull/109628

(cherry picked from commit 435b20e892f45810127c433df84f9a63b4c910e3)
---
 clang/lib/Driver/ToolChains/CommonArgs.cpp |  3 ++
 clang/test/Driver/frame-pointer-elim.c     | 45 +++++++++++++++-------
 clang/test/Driver/frame-pointer.c          |  4 ++
 3 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index eb88f7bd4b469..75a7154e5f12e 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -156,6 +156,9 @@ static bool useLeafFramePointerForTargetByDefault(const 
llvm::Triple &Triple) {
       (Triple.isAndroid() && !Triple.isARM()))
     return false;
 
+  if ((Triple.isThumb() || Triple.isARM()) && Triple.isOSBinFormatMachO())
+    return false;
+
   return true;
 }
 
diff --git a/clang/test/Driver/frame-pointer-elim.c 
b/clang/test/Driver/frame-pointer-elim.c
index 6e21671f43775..2b2e1e5600f32 100644
--- a/clang/test/Driver/frame-pointer-elim.c
+++ b/clang/test/Driver/frame-pointer-elim.c
@@ -73,12 +73,12 @@
 // RUN: %clang -### -target armv7s-apple-ios -fomit-frame-pointer %s 2>&1 | \
 // RUN:   FileCheck --check-prefix=WARN-OMIT-7S %s
 // WARN-OMIT-7S: warning: optimization flag '-fomit-frame-pointer' is not 
supported for target 'armv7s'
-// WARN-OMIT-7S: "-mframe-pointer=all"
+// WARN-OMIT-7S: "-mframe-pointer=non-leaf"
 
 // RUN: %clang -### -target armv7k-apple-watchos -fomit-frame-pointer %s 2>&1 
| \
 // RUN:   FileCheck --check-prefix=WARN-OMIT-7K %s
 // WARN-OMIT-7K: warning: optimization flag '-fomit-frame-pointer' is not 
supported for target 'armv7k'
-// WARN-OMIT-7K: "-mframe-pointer=all"
+// WARN-OMIT-7K: "-mframe-pointer=non-leaf"
 
 // RUN: %clang -### -target armv7s-apple-ios8.0 -momit-leaf-frame-pointer %s 
2>&1 | \
 // RUN:   FileCheck --check-prefix=WARN-OMIT-LEAF-7S %s
@@ -190,22 +190,22 @@
 // RUN:   FileCheck --check-prefix=KEEP-NONE %s
 
 // Check that for Apple bare metal targets, we're keeping frame pointers by 
default
-// RUN: %clang -### --target=thumbv6m-apple-none-macho -S %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
-// RUN: %clang -### --target=thumbv6m-apple-none-macho -S 
-fno-omit-frame-pointer %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN: %clang -### --target=armv6m-apple-none-macho -S %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang -### --target=armv6m-apple-none-macho -S 
-fno-omit-frame-pointer %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
 // RUN: %clang -### --target=arm-apple-none-macho -S %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
 // RUN: %clang -### --target=arm-apple-none-macho -S -fno-omit-frame-pointer 
%s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
-// RUN: %clang -### --target=thumbv6m-apple-none-macho -S -O1 %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
-// RUN: %clang -### --target=thumbv6m-apple-none-macho -S -O1 
-fno-omit-frame-pointer %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang -### --target=armv6m-apple-none-macho -S -O1 %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang -### --target=armv6m-apple-none-macho -S -O1 
-fno-omit-frame-pointer %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
 // RUN: %clang -### --target=arm-apple-none-macho -S -O1 %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
 // RUN: %clang -### --target=arm-apple-none-macho -S -O1 
-fno-omit-frame-pointer %s 2>&1 | \
-// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
 
 // AArch64 bare metal targets behave like hosted targets
 // RUN: %clang -### --target=aarch64-none-elf -S %s 2>&1 |  \
@@ -221,5 +221,22 @@
 // RUN: %clang -### --target=aarch64-pc-windows-msvc -S -fomit-frame-pointer 
%s 2>&1 |  \
 // RUN:   FileCheck --check-prefix=KEEP-RESERVED %s
 
+// When targeting Mach-O on Arm, the frame pointer is "none" if
+// -fomit-frame-pointer is specified.
+// RUN: %clang --target=armv7-apple-macho -### -S %s 2>&1      \
+// RUN:         -fomit-frame-pointer \
+// RUN:         | FileCheck -check-prefix=KEEP-NONE %s
+
+// When targeting Mach-O on Arm, -fno-omit-frame-pointer +
+// -mno-omit-leaf-frame-pointer give frame-pointer=all
+// RUN: %clang --target=armv7-apple-macho -### -S %s 2>&1 \
+// RUN:        -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer \
+// RUN:        | FileCheck -check-prefix=KEEP-ALL %s
+
+// When targeting Mach-O on Arm, -fomit-frame-pointer wins over
+// -mno-omit-leaf-frame-pointer
+// RUN: %clang --target=armv7-apple-macho -### -S %s 2>&1 \
+// RUN:        -fomit-frame-pointer -mno-omit-leaf-frame-pointer \
+// RUN:        | FileCheck -check-prefix=KEEP-NONE %s
 void f0() {}
 void f1() { f0(); }
diff --git a/clang/test/Driver/frame-pointer.c 
b/clang/test/Driver/frame-pointer.c
index 2015fa520c2a2..4c69de8951777 100644
--- a/clang/test/Driver/frame-pointer.c
+++ b/clang/test/Driver/frame-pointer.c
@@ -80,12 +80,16 @@
 // RUN: %clang --target=loongarch64 -### -S -O3 %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECK3-64 %s
 // RUN: %clang --target=loongarch64 -### -S -Os %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECKs-64 %s
 
+// RUN: %clang --target=armv7-apple-macho -### -S %s -o %t.s 2>&1 | FileCheck 
-check-prefix=CHECK-32-MACHO %s
+
 // CHECK0-32: -mframe-pointer=all
 // CHECK1-32-NOT: -mframe-pointer=all
 // CHECK2-32-NOT: -mframe-pointer=all
 // CHECK3-32-NOT: -mframe-pointer=all
 // CHECKs-32-NOT: -mframe-pointer=all
 
+// CHECK-32-MACHO: -mframe-pointer=non-leaf
+
 // CHECK0-64: -mframe-pointer=all
 // CHECK1-64-NOT: -mframe-pointer=all
 // CHECK2-64-NOT: -mframe-pointer=all

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to