[compiler-rt] [llvm] [compiler-rt] Restrict __gnu_h2f_ieee and __gnu_f2h_ieee to arm32 EABI (PR #220170)

Trevor Gross via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 4 23:45:35 PDT 2026


https://github.com/tgross35 updated https://github.com/llvm/llvm-project/pull/220170

>From dcf6fee24e8cd78cbdc238c3e61681f8f78317b5 Mon Sep 17 00:00:00 2001
From: Trevor Gross <tg at trevorgross.com>
Date: Tue, 1 Sep 2026 04:00:31 -0500
Subject: [PATCH 1/2] [compiler-rt] Use integers for __gnu_h2f_ieee and
 __gnu_f2h_ieee

In libgcc, these conversion routines use integers in the signature. In
practice this has worked because the AAPCS calling convention passes and
returns floats the same as the same-sized integer, but this may not be
the case on all platforms. Thus, update the signatures to match GCC.
---
 compiler-rt/lib/builtins/extendhfsf2.c  | 12 ++++++++----
 compiler-rt/lib/builtins/fp_extend.h    | 18 +++++++++++++++++-
 compiler-rt/lib/builtins/fp_trunc.h     | 18 +++++++++++++++++-
 compiler-rt/lib/builtins/truncsfhf2.c   | 12 ++++++++----
 llvm/include/llvm/IR/RuntimeLibcalls.td |  4 ++++
 5 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/compiler-rt/lib/builtins/extendhfsf2.c b/compiler-rt/lib/builtins/extendhfsf2.c
index c0f25cdadcd4f..3a7719bb0aad9 100644
--- a/compiler-rt/lib/builtins/extendhfsf2.c
+++ b/compiler-rt/lib/builtins/extendhfsf2.c
@@ -16,14 +16,18 @@ COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) {
   return __extendXfYf2__(a);
 }
 
+// arm32-gnueabi-only routine that uses integers in the signature. This should
+// be gnueabi-specific, but LLVM currently emits it on more eabi platforms.
+COMPILER_RT_ABI uint32_t __gnu_h2f_ieee(uint16_t a) {
+  // Call the __inline version to avoid an extra indirection, since
+  // __extendhfsf2 won't be linked if this is used.
+  return dstToRep(__extendXfYf2__(srcFromRep(a)));
+}
+
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); }
 AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); }
 #else
-COMPILER_RT_ALIAS(__extendhfsf2, __gnu_h2f_ieee)
 COMPILER_RT_ALIAS(__extendhfsf2, __aeabi_h2f)
 #endif
-#else
-COMPILER_RT_ABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); }
 #endif
diff --git a/compiler-rt/lib/builtins/fp_extend.h b/compiler-rt/lib/builtins/fp_extend.h
index 22bf2b2514e57..dab19e13054e2 100644
--- a/compiler-rt/lib/builtins/fp_extend.h
+++ b/compiler-rt/lib/builtins/fp_extend.h
@@ -157,7 +157,7 @@ static inline dst_rep_t construct_dst_rep(dst_rep_t sign, dst_rep_t exp, dst_rep
   return (sign << (dstBits - 1)) | (exp << (dstBits - 1 - dstExpBits)) | sigFrac;
 }
 
-// Two helper routines for conversion to and from the representation of
+// Helper routines for conversion to and from the representation of
 // floating-point data as integer values follow.
 
 static inline src_rep_t srcToRep(src_t x) {
@@ -168,6 +168,22 @@ static inline src_rep_t srcToRep(src_t x) {
   return rep.i;
 }
 
+static inline src_t srcFromRep(src_rep_t x) {
+  const union {
+    src_t f;
+    src_rep_t i;
+  } rep = {.i = x};
+  return rep.f;
+}
+
+static inline dst_rep_t dstToRep(dst_t x) {
+  const union {
+    dst_t f;
+    dst_rep_t i;
+  } rep = {.f = x};
+  return rep.i;
+}
+
 static inline dst_t dstFromRep(dst_rep_t x) {
   const union {
     dst_t f;
diff --git a/compiler-rt/lib/builtins/fp_trunc.h b/compiler-rt/lib/builtins/fp_trunc.h
index a1bd881eb57c9..7010ed46fe9cd 100644
--- a/compiler-rt/lib/builtins/fp_trunc.h
+++ b/compiler-rt/lib/builtins/fp_trunc.h
@@ -148,7 +148,7 @@ static inline dst_rep_t construct_dst_rep(dst_rep_t sign, dst_rep_t exp, dst_rep
   return result;
 }
 
-// End of specialization parameters.  Two helper routines for conversion to and
+// End of specialization parameters.  Helper routines for conversion to and
 // from the representation of floating-point data as integer values follow.
 
 static inline src_rep_t srcToRep(src_t x) {
@@ -159,6 +159,22 @@ static inline src_rep_t srcToRep(src_t x) {
   return rep.i;
 }
 
+static inline src_t srcFromRep(src_rep_t x) {
+  const union {
+    src_t f;
+    src_rep_t i;
+  } rep = {.i = x};
+  return rep.f;
+}
+
+static inline dst_rep_t dstToRep(dst_t x) {
+  const union {
+    dst_t f;
+    dst_rep_t i;
+  } rep = {.f = x};
+  return rep.i;
+}
+
 static inline dst_t dstFromRep(dst_rep_t x) {
   const union {
     dst_t f;
diff --git a/compiler-rt/lib/builtins/truncsfhf2.c b/compiler-rt/lib/builtins/truncsfhf2.c
index 6ad8621b8bb02..b1da856461453 100644
--- a/compiler-rt/lib/builtins/truncsfhf2.c
+++ b/compiler-rt/lib/builtins/truncsfhf2.c
@@ -16,14 +16,18 @@ COMPILER_RT_ABI NOINLINE dst_t __truncsfhf2(float a) {
   return __truncXfYf2__(a);
 }
 
+// arm32-gnueabi-only routine that uses integers in the signature. This should
+// be gnueabi-specific, but LLVM currently emits it on more eabi platforms.
+COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(uint32_t a) {
+  // Call the __inline version to avoid an extra indirection, since
+  // __truncsfhf2 won't be linked if this is used.
+  return dstToRep(__truncXfYf2__(srcFromRep(a)));
+}
+
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
-AEABI_RTABI dst_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); }
 AEABI_RTABI dst_t __aeabi_f2h(float a) { return __truncsfhf2(a); }
 #else
-COMPILER_RT_ALIAS(__truncsfhf2, __gnu_f2h_ieee)
 COMPILER_RT_ALIAS(__truncsfhf2, __aeabi_f2h)
 #endif
-#else
-COMPILER_RT_ABI dst_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); }
 #endif
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index 078a3a39146ad..0c23f0e761655 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -2608,6 +2608,10 @@ def isNotMachOAndNotTargetAEABI
     : RuntimeLibcallAvailability<(all_of (not IsOSBinFormatMachO),
                                             (not IsTargetAEABI))>;
 
+// Note that these actually pass and return int and short rather than float and
+// _Float16. This happens to work with the AAPCS calling convention where they
+// are treated equally, but may not work on other platforms. __extendhfsf2 and
+// __truncsfhf2 should be used anyway on non-GNUEABIHF targets.
 def GNUEABIHalfConvertCalls :
   LibcallImpls<(add __gnu_f2h_ieee, __gnu_h2f_ieee),
     isNotMachOAndNotTargetAEABI> {

>From 2fa04db341682f8e62e97989f976fdeb635aaaf7 Mon Sep 17 00:00:00 2001
From: Trevor Gross <tg at trevorgross.com>
Date: Mon, 31 Aug 2026 22:38:46 -0500
Subject: [PATCH 2/2] [compiler-rt] Restrict __gnu_h2f_ieee and __gnu_f2h_ieee
 to arm32 EABI

These routines are specific to gnueabi on arm32, so should not be used
on other platforms. LLVM used to emit these on more platforms but this
has not been the case since cc539138acf7 ("[CodeGen] Use __extendhfsf2
and __truncsfhf2 by default (#126880)"). As they are no longer needed,
restrict them to 32-bit Arm with EABI, which matches libgcc.

They cannot be further restricted beacuse LLVM still uses them on
arm32-eabi targets where an environment is not specified, such as
`armv7-unknown-freebsd`.
---
 compiler-rt/lib/builtins/extendhfsf2.c | 2 ++
 compiler-rt/lib/builtins/truncsfhf2.c  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/compiler-rt/lib/builtins/extendhfsf2.c b/compiler-rt/lib/builtins/extendhfsf2.c
index 3a7719bb0aad9..0ae29f142b801 100644
--- a/compiler-rt/lib/builtins/extendhfsf2.c
+++ b/compiler-rt/lib/builtins/extendhfsf2.c
@@ -16,6 +16,7 @@ COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) {
   return __extendXfYf2__(a);
 }
 
+#if defined(__ARM_EABI__)
 // arm32-gnueabi-only routine that uses integers in the signature. This should
 // be gnueabi-specific, but LLVM currently emits it on more eabi platforms.
 COMPILER_RT_ABI uint32_t __gnu_h2f_ieee(uint16_t a) {
@@ -23,6 +24,7 @@ COMPILER_RT_ABI uint32_t __gnu_h2f_ieee(uint16_t a) {
   // __extendhfsf2 won't be linked if this is used.
   return dstToRep(__extendXfYf2__(srcFromRep(a)));
 }
+#endif
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)
diff --git a/compiler-rt/lib/builtins/truncsfhf2.c b/compiler-rt/lib/builtins/truncsfhf2.c
index b1da856461453..e25fa4e10e60c 100644
--- a/compiler-rt/lib/builtins/truncsfhf2.c
+++ b/compiler-rt/lib/builtins/truncsfhf2.c
@@ -16,6 +16,7 @@ COMPILER_RT_ABI NOINLINE dst_t __truncsfhf2(float a) {
   return __truncXfYf2__(a);
 }
 
+#if defined(__ARM_EABI__)
 // arm32-gnueabi-only routine that uses integers in the signature. This should
 // be gnueabi-specific, but LLVM currently emits it on more eabi platforms.
 COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(uint32_t a) {
@@ -23,6 +24,7 @@ COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(uint32_t a) {
   // __truncsfhf2 won't be linked if this is used.
   return dstToRep(__truncXfYf2__(srcFromRep(a)));
 }
+#endif
 
 #if defined(__ARM_EABI__)
 #if defined(COMPILER_RT_ARMHF_TARGET)



More information about the llvm-commits mailing list