Skip to content

[clang][ARM] disable frame pointers by default for bare metal ARM targets #117140

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 7 commits into from
Dec 6, 2024

Conversation

stuij
Copy link
Member

@stuij stuij commented Nov 21, 2024

because:

  • This brings Clang in line with GCC for which this is the default for ARM
  • It frees up a register, so performance increase, especially on Thumb/6-M
  • It will decrease code size

…gets

because:
- This brings Clang in line with GCC for which this is the default for ARM
- It frees up a register, so performance increase, especially on Thumb/6-M
- It will also decrease code size
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Nov 21, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 21, 2024

@llvm/pr-subscribers-backend-arm
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Ties Stuij (stuij)

Changes

because:

  • This brings Clang in line with GCC for which this is the default for ARM
  • It frees up a register, so performance increase, especially on Thumb/6-M
  • It will decrease code size

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

4 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/BareMetal.cpp (+7-1)
  • (modified) clang/lib/Driver/ToolChains/BareMetal.h (+2)
  • (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+5)
  • (modified) clang/test/Driver/frame-pointer-elim.c (+29)
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index f9a73f60973e4c..13b510e7e70994 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -128,8 +128,11 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
   }
 }
 
+namespace clang {
+namespace driver {
+namespace toolchains {
 /// Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
-static bool isARMBareMetal(const llvm::Triple &Triple) {
+bool isARMBareMetal(const llvm::Triple &Triple) {
   if (Triple.getArch() != llvm::Triple::arm &&
       Triple.getArch() != llvm::Triple::thumb &&
       Triple.getArch() != llvm::Triple::armeb &&
@@ -148,6 +151,9 @@ static bool isARMBareMetal(const llvm::Triple &Triple) {
 
   return true;
 }
+} // namespace clang
+} // namespace driver
+} // namespace clang
 
 /// Is the triple {aarch64.aarch64_be}-none-elf?
 static bool isAArch64BareMetal(const llvm::Triple &Triple) {
diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h
index b385c8cf76aab0..ae09bcedd78a28 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.h
+++ b/clang/lib/Driver/ToolChains/BareMetal.h
@@ -19,6 +19,8 @@ namespace driver {
 
 namespace toolchains {
 
+bool isARMBareMetal(const llvm::Triple &Triple);
+
 class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain {
 public:
   BareMetal(const Driver &D, const llvm::Triple &Triple,
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 8d977149e62485..8d54d0a8649cc9 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -19,6 +19,7 @@
 #include "Arch/SystemZ.h"
 #include "Arch/VE.h"
 #include "Arch/X86.h"
+#include "BareMetal.h"
 #include "HIPAMD.h"
 #include "Hexagon.h"
 #include "MSP430.h"
@@ -151,6 +152,10 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args,
     }
   }
 
+  if (toolchains::isARMBareMetal(Triple)) {
+    return false;
+  }
+
   return true;
 }
 
diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c
index cdedcc7ae4c89f..667c47b34bc703 100644
--- a/clang/test/Driver/frame-pointer-elim.c
+++ b/clang/test/Driver/frame-pointer-elim.c
@@ -162,5 +162,34 @@
 // RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
 // RUN: not %clang -### --target=riscv64-linux-android -mbig-endian -O1 -S %s 2>&1 | \
 // RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+
+// On ARM backend bare metal targets, frame pointer is omitted
+// RUN: %clang -### --target=arm-arm-none-eabi -S %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NONE %s
+// RUN: %clang -### --target=arm-arm-none-eabihf -S %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NONE %s
+// RUN: %clang -### --target=arm-arm-none-eabi -S -fno-omit-frame-pointer %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN: %clang -### --target=arm-arm-none-eabihf -S -fno-omit-frame-pointer %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN: %clang -### --target=arm-arm-none-eabi -S -O1 %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NONE %s
+// RUN: %clang -### --target=arm-arm-none-eabihf -S -O1 %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-NONE %s
+// RUN: %clang -### --target=arm-arm-none-eabi -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+// RUN: %clang -### --target=arm-arm-none-eabihf -S -O1 -fno-omit-frame-pointer %s 2>&1 | \
+// RUN:   FileCheck --check-prefix=KEEP-ALL %s
+
+// AArch64 bare metal targets behave like hosted targets
+// RUN: %clang -### --target=aarch64-none-elf -S %s 2>&1 |  \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang -### --target=aarch64-none-elf -S -O1 %s 2>&1 |  \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang -### --target=aarch64-none-elf -S -fno-omit-frame-pointer %s 2>&1 |  \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+// RUN: %clang -### --target=aarch64-none-elf -S -O1 -fno-omit-frame-pointer %s 2>&1 |  \
+// RUN:   FileCheck --check-prefix=KEEP-NON-LEAF %s
+
 void f0() {}
 void f1() { f0(); }

@stuij
Copy link
Member Author

stuij commented Nov 21, 2024

This change was discussed in the LLVM Embedded Toolchains working group sync up two weeks ago, and at the time people were in agreement that it made sense:

https://discourse.llvm.org/t/llvm-embedded-toolchains-working-group-sync-up/63270/73#p-334070-peter-frame-pointers-on-or-off-by-default-7

Copy link

github-actions bot commented Nov 21, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

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

What are your thoughts on moving the definition into the BareMetal.h header, then adding cases for arm, armeb, thumb, and thumbeb to the existing getArch switch in CommonArgs.cpp#L85? Then we should be able to inline isARMBareMetal and elide the getArch checks in it.

@stuij
Copy link
Member Author

stuij commented Nov 25, 2024

I feel that in useFramePointerForTargetByDef fn, in general things are predicated first on platform and then on arch. That L85 arch switch statement seems to serve as a "these arches don't do anything special" early return.

It's up to interpretation, but putting the different Arm variants there seems less elegant to me (that might not be saying much..). I'd say let's leave it alone for now, and if the bare metal logic gets more impenetrable at some point, refactor.

also add a few more non-apple embedded tests and make isARMBareMetal slightly
more elegant
To make it clearer what the fn is testing for.
@stuij stuij requested a review from petrhosek December 5, 2024 10:45
@stuij stuij merged commit 2f4eac6 into llvm:main Dec 6, 2024
9 checks passed
@stuij stuij deleted the fp-off branch December 6, 2024 14:05
@asb
Copy link
Contributor

asb commented Dec 9, 2024

I think this change in behaviour deserves an entry in clang/docs/ReleaseNotes.rst

stuij added a commit to stuij/LLVM-embedded-toolchain-for-Arm that referenced this pull request Dec 20, 2024
Pull request #109628 automatically turned on frame pointers for leaf functions
in Clang when frame pointers are enabled. This triggered a latent bug in
picolibc for armv4t and armv5te, which consequentially broke our tests for them.

There is currently a pull request that fixes this
bug (picolibc/picolibc#897), but we don't have to wait
for this to merge to reinstate the tests, because we recently changed the
behaviour of Clang to by default omit frame pointers altogether
(llvm/llvm-project#117140), and that is how picolibc is
built now. In general the advice is that you shouldn't build AArch32 targets
with frame pointers enabled for various reasons.
stuij added a commit to ARM-software/LLVM-embedded-toolchain-for-Arm that referenced this pull request Dec 22, 2024
Pull request #109628 automatically turned on frame pointers for leaf functions
in Clang when frame pointers are enabled. This triggered a latent bug in
picolibc for armv4t and armv5te, which consequentially broke our tests for them.

There is currently a pull request that fixes this
bug (picolibc/picolibc#897), but we don't have to wait
for this to merge to reinstate the tests, because we recently changed the
behaviour of Clang to by default omit frame pointers altogether
(llvm/llvm-project#117140), and that is how picolibc is
built now. In general the advice is that you shouldn't build AArch32 targets
with frame pointers enabled for various reasons.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:ARM clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants