[compiler-rt] [llvm] [compiler-rt] Use integers for __gnu_h2f_ieee and __gnu_f2h_ieee (PR #220167)

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


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

>From aa030fc5f8d6ce89611c922a415686dbdafc71ea 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] [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..6aea27a1e7a36 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..8cf0036fe943b 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> {



More information about the llvm-commits mailing list