From 97179e46a8fbbda0053a3fce69ed3fd5d488acdc Mon Sep 17 00:00:00 2001
From: beetrees <b@beetr.ee>
Date: Fri, 23 Aug 2024 12:39:31 +0100
Subject: [PATCH] Fix ABI for `f16` builtins on Intel Apple targets

---
 src/float/extend.rs |   2 +
 src/float/trunc.rs  |   3 ++
 src/macros.rs       | 100 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+)

diff --git a/src/float/extend.rs b/src/float/extend.rs
index 2f392255f..9fabcde25 100644
--- a/src/float/extend.rs
+++ b/src/float/extend.rs
@@ -86,6 +86,7 @@ intrinsics! {
 intrinsics! {
     #[avr_skip]
     #[aapcs_on_arm]
+    #[apple_f16_arg_abi]
     #[arm_aeabi_alias = __aeabi_h2f]
     #[cfg(f16_enabled)]
     pub extern "C" fn __extendhfsf2(a: f16) -> f32 {
@@ -94,6 +95,7 @@ intrinsics! {
 
     #[avr_skip]
     #[aapcs_on_arm]
+    #[apple_f16_arg_abi]
     #[cfg(f16_enabled)]
     pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 {
         extend(a)
diff --git a/src/float/trunc.rs b/src/float/trunc.rs
index c54ff7805..5c17cd96a 100644
--- a/src/float/trunc.rs
+++ b/src/float/trunc.rs
@@ -134,6 +134,7 @@ intrinsics! {
 intrinsics! {
     #[avr_skip]
     #[aapcs_on_arm]
+    #[apple_f16_ret_abi]
     #[arm_aeabi_alias = __aeabi_f2h]
     #[cfg(f16_enabled)]
     pub extern "C" fn __truncsfhf2(a: f32) -> f16 {
@@ -142,6 +143,7 @@ intrinsics! {
 
     #[avr_skip]
     #[aapcs_on_arm]
+    #[apple_f16_ret_abi]
     #[cfg(f16_enabled)]
     pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 {
         trunc(a)
@@ -149,6 +151,7 @@ intrinsics! {
 
     #[avr_skip]
     #[aapcs_on_arm]
+    #[apple_f16_ret_abi]
     #[arm_aeabi_alias = __aeabi_d2h]
     #[cfg(f16_enabled)]
     pub extern "C" fn __truncdfhf2(a: f64) -> f16 {
diff --git a/src/macros.rs b/src/macros.rs
index f7c6d0bfe..f51e49e98 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -276,6 +276,106 @@ macro_rules! intrinsics {
         intrinsics!($($rest)*);
     );
 
+    // `arm_aeabi_alias` would conflict with `f16_apple_{arg,ret}_abi` not handled here. Avoid macro ambiguity by combining in a
+    // single `#[]`.
+    (
+        #[apple_f16_arg_abi]
+        #[arm_aeabi_alias = $alias:ident]
+        $($t:tt)*
+    ) => {
+        intrinsics! {
+            #[apple_f16_arg_abi, arm_aeabi_alias = $alias]
+            $($t)*
+        }
+    };
+    (
+        #[apple_f16_ret_abi]
+        #[arm_aeabi_alias = $alias:ident]
+        $($t:tt)*
+    ) => {
+        intrinsics! {
+            #[apple_f16_ret_abi, arm_aeabi_alias = $alias]
+            $($t)*
+        }
+    };
+
+    // On x86 (32-bit and 64-bit) Apple platforms, `f16` is passed and returned like a `u16` unless
+    // the builtin involves `f128`.
+    (
+        // `arm_aeabi_alias` would conflict if not handled here. Avoid macro ambiguity by combining
+        // in a single `#[]`.
+        #[apple_f16_arg_abi $(, arm_aeabi_alias = $alias:ident)?]
+        $(#[$($attr:tt)*])*
+        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) $(-> $ret:ty)? {
+            $($body:tt)*
+        }
+
+        $($rest:tt)*
+    ) => (
+        #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))]
+        $(#[$($attr)*])*
+        pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
+            $($body)*
+        }
+
+        #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))]
+        mod $name {
+            #[no_mangle]
+            #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")]
+            $(#[$($attr)*])*
+            extern $abi fn $name( $($argname: u16),* ) $(-> $ret)? {
+                super::$name($(f16::from_bits($argname)),*)
+            }
+        }
+
+        #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))]
+        intrinsics! {
+            $(#[arm_aeabi_alias = $alias])?
+            $(#[$($attr)*])*
+            pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
+                $($body)*
+            }
+        }
+
+        intrinsics!($($rest)*);
+    );
+    (
+        #[apple_f16_ret_abi $(, arm_aeabi_alias = $alias:ident)?]
+        $(#[$($attr:tt)*])*
+        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) $(-> $ret:ty)? {
+            $($body:tt)*
+        }
+
+        $($rest:tt)*
+    ) => (
+        #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64")))]
+        $(#[$($attr)*])*
+        pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
+            $($body)*
+        }
+
+        #[cfg(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"), not(feature = "mangled-names")))]
+        mod $name {
+            #[no_mangle]
+            #[cfg_attr(not(all(windows, target_env = "gnu")), linkage = "weak")]
+            $(#[$($attr)*])*
+            extern $abi fn $name( $($argname: $ty),* ) -> u16 {
+                super::$name($($argname),*).to_bits()
+            }
+        }
+
+        #[cfg(not(all(target_vendor = "apple", any(target_arch = "x86", target_arch = "x86_64"))))]
+        intrinsics! {
+            $(#[arm_aeabi_alias = $alias])?
+            $(#[$($attr)*])*
+            pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
+                $($body)*
+            }
+        }
+
+        intrinsics!($($rest)*);
+    );
+
     // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
     // build under `__aeabi_*` aliases, and LLVM will call these instead of the
     // original function. The aliasing here is used to generate these symbols in