From 5bdb9dd5353d468c303315c8fa0d6baf4b33c998 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 6 Mar 2024 05:40:29 -0600 Subject: [PATCH] Add basic library support for `f16` and `f128` Implement basic operation traits that get lowered to intrinsics. This does not yet create a new module for these types. Additionally, add codegn tests for the implemented operations. --- library/core/src/clone.rs | 3 + library/core/src/cmp.rs | 6 ++ library/core/src/convert/num.rs | 17 +++++ library/core/src/default.rs | 5 ++ library/core/src/fmt/nofloat.rs | 5 ++ library/core/src/lib.rs | 2 + library/core/src/marker.rs | 7 ++ library/core/src/ops/arith.rs | 33 ++++++++ tests/codegen/float/f128.rs | 129 ++++++++++++++++++++++++++++++++ tests/codegen/float/f16.rs | 129 ++++++++++++++++++++++++++++++++ 10 files changed, 336 insertions(+) create mode 100644 tests/codegen/float/f128.rs create mode 100644 tests/codegen/float/f16.rs diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index ba86334f9505c..44ae72bcd26bf 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -231,6 +231,9 @@ mod impls { bool char } + #[cfg(not(bootstrap))] + impl_clone! { f16 f128 } + #[unstable(feature = "never_type", issue = "35121")] impl Clone for ! { #[inline] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index a2f07814726ac..0a7c42d084cd7 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1489,6 +1489,9 @@ mod impls { bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + #[cfg(not(bootstrap))] + partial_eq_impl! { f16 f128 } + macro_rules! eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -1541,6 +1544,9 @@ mod impls { partial_ord_impl! { f32 f64 } + #[cfg(not(bootstrap))] + partial_ord_impl! { f16 f128 } + macro_rules! ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 46a9006c14665..4cb7b0394d590 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -38,6 +38,11 @@ macro_rules! impl_float_to_int { impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +#[cfg(not(bootstrap))] +impl_float_to_int!(f16 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +#[cfg(not(bootstrap))] +impl_float_to_int!(f128 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + // Conversion traits for primitive integer and float types // Conversions T -> T are covered by a blanket impl and therefore excluded // Some conversions from and to usize/isize are not implemented due to portability concerns @@ -166,6 +171,18 @@ impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" // float -> float impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +// todo: these are insta-stable regardless of the gate, right? +#[cfg(not(bootstrap))] +impl_from! { f16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +#[cfg(not(bootstrap))] +impl_from! { f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +#[cfg(not(bootstrap))] +impl_from! { f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +#[cfg(not(bootstrap))] +impl_from! { f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } +#[cfg(not(bootstrap))] +impl_from! { f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } + macro_rules! impl_float_from_bool { ($float:ty) => { #[stable(feature = "float_from_bool", since = "1.68.0")] diff --git a/library/core/src/default.rs b/library/core/src/default.rs index a1303fcd82158..971ec1f02ef38 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -178,3 +178,8 @@ default_impl! { i128, 0, "Returns the default value of `0`" } default_impl! { f32, 0.0f32, "Returns the default value of `0.0`" } default_impl! { f64, 0.0f64, "Returns the default value of `0.0`" } + +#[cfg(not(bootstrap))] +default_impl! { f16, 0.0f16, "Returns the default value of `0.0`" } +#[cfg(not(bootstrap))] +default_impl! { f128, 0.0f128, "Returns the default value of `0.0`" } diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs index cfb94cd9de530..3b019203f7e0a 100644 --- a/library/core/src/fmt/nofloat.rs +++ b/library/core/src/fmt/nofloat.rs @@ -13,3 +13,8 @@ macro_rules! floating { floating! { f32 } floating! { f64 } + +#[cfg(not(bootstrap))] +floating! { f16 } +#[cfg(not(bootstrap))] +floating! { f128 } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9b786feba8988..d825f69c37e5f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -205,6 +205,8 @@ #![cfg_attr(bootstrap, feature(diagnostic_namespace))] #![cfg_attr(bootstrap, feature(exhaustive_patterns))] #![cfg_attr(bootstrap, feature(platform_intrinsics))] +#![cfg_attr(not(bootstrap), feature(f128))] +#![cfg_attr(not(bootstrap), feature(f16))] #![cfg_attr(not(bootstrap), feature(freeze_impls))] #![cfg_attr(not(bootstrap), feature(min_exhaustive_patterns))] #![feature(abi_unadjusted)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a56a2578c2241..3591af2c07cf4 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -429,6 +429,13 @@ marker_impls! { } +// todo: which feature gate should we use? +#[cfg(not(bootstrap))] +marker_impls! { + #[stable(feature = "rust1", since = "1.0.0")] + Copy for f16, f128 +} + #[unstable(feature = "never_type", issue = "35121")] impl Copy for ! {} diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index fd50f80474833..4086e59ebd599 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -111,6 +111,9 @@ macro_rules! add_impl { add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +add_impl! { f16 f128 } + /// The subtraction operator `-`. /// /// Note that `Rhs` is `Self` by default, but this is not mandatory. For @@ -220,6 +223,9 @@ macro_rules! sub_impl { sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +sub_impl! { f16 f128 } + /// The multiplication operator `*`. /// /// Note that `Rhs` is `Self` by default, but this is not mandatory. @@ -350,6 +356,9 @@ macro_rules! mul_impl { mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +mul_impl! { f16 f128 } + /// The division operator `/`. /// /// Note that `Rhs` is `Self` by default, but this is not mandatory. @@ -508,6 +517,9 @@ macro_rules! div_impl_float { div_impl_float! { f32 f64 } +#[cfg(not(bootstrap))] +div_impl_float! { f16 f128 } + /// The remainder operator `%`. /// /// Note that `Rhs` is `Self` by default, but this is not mandatory. @@ -625,6 +637,9 @@ macro_rules! rem_impl_float { rem_impl_float! { f32 f64 } +#[cfg(not(bootstrap))] +rem_impl_float! { f16 f128 } + /// The unary negation operator `-`. /// /// # Examples @@ -700,6 +715,9 @@ macro_rules! neg_impl { neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +neg_impl! { f16 f128 } + /// The addition assignment operator `+=`. /// /// # Examples @@ -767,6 +785,9 @@ macro_rules! add_assign_impl { add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +add_assign_impl! { f16 f128 } + /// The subtraction assignment operator `-=`. /// /// # Examples @@ -834,6 +855,9 @@ macro_rules! sub_assign_impl { sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +sub_assign_impl! { f16 f128 } + /// The multiplication assignment operator `*=`. /// /// # Examples @@ -892,6 +916,9 @@ macro_rules! mul_assign_impl { mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +mul_assign_impl! { f16 f128 } + /// The division assignment operator `/=`. /// /// # Examples @@ -949,6 +976,9 @@ macro_rules! div_assign_impl { div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } +#[cfg(not(bootstrap))] +div_assign_impl! { f16 f128 } + /// The remainder assignment operator `%=`. /// /// # Examples @@ -1009,3 +1039,6 @@ macro_rules! rem_assign_impl { } rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +#[cfg(not(bootstrap))] +rem_assign_impl! { f16 f128 } diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs new file mode 100644 index 0000000000000..97d545e028307 --- /dev/null +++ b/tests/codegen/float/f128.rs @@ -0,0 +1,129 @@ +// Verify that our intrinsics generate the correct LLVM calls for f128 + +#![crate_type = "lib"] +#![feature(f128)] +#![feature(core_intrinsics)] + +// CHECK-LABEL: i1 @f128_eq( +#[no_mangle] +pub fn f128_eq(a: f128, b: f128) -> bool { + // CHECK: fcmp oeq fp128 %{{.+}}, %{{.+}} + a == b +} + +// CHECK-LABEL: i1 @f128_ne( +#[no_mangle] +pub fn f128_ne(a: f128, b: f128) -> bool { + // CHECK: fcmp une fp128 %{{.+}}, %{{.+}} + a != b +} + +// CHECK-LABEL: i1 @f128_gt( +#[no_mangle] +pub fn f128_gt(a: f128, b: f128) -> bool { + // CHECK: fcmp ogt fp128 %{{.+}}, %{{.+}} + a > b +} + +// CHECK-LABEL: i1 @f128_ge( +#[no_mangle] +pub fn f128_ge(a: f128, b: f128) -> bool { + // CHECK: fcmp oge fp128 %{{.+}}, %{{.+}} + a >= b +} + +// CHECK-LABEL: i1 @f128_lt( +#[no_mangle] +pub fn f128_lt(a: f128, b: f128) -> bool { + // CHECK: fcmp olt fp128 %{{.+}}, %{{.+}} + a < b +} + +// CHECK-LABEL: i1 @f128_le( +#[no_mangle] +pub fn f128_le(a: f128, b: f128) -> bool { + // CHECK: fcmp ole fp128 %{{.+}}, %{{.+}} + a <= b +} + +// CHECK-LABEL: fp128 @f128_neg( +#[no_mangle] +pub fn f128_neg(a: f128) -> f128 { + // CHECK: fneg fp128 + -a +} + +// CHECK-LABEL: fp128 @f128_add( +#[no_mangle] +pub fn f128_add(a: f128, b: f128) -> f128 { + // CHECK: fadd fp128 %{{.+}}, %{{.+}} + a + b +} + +// CHECK-LABEL: fp128 @f128_sub( +#[no_mangle] +pub fn f128_sub(a: f128, b: f128) -> f128 { + // CHECK: fsub fp128 %{{.+}}, %{{.+}} + a - b +} + +// CHECK-LABEL: fp128 @f128_mul( +#[no_mangle] +pub fn f128_mul(a: f128, b: f128) -> f128 { + // CHECK: fmul fp128 %{{.+}}, %{{.+}} + a * b +} + +// CHECK-LABEL: fp128 @f128_div( +#[no_mangle] +pub fn f128_div(a: f128, b: f128) -> f128 { + // CHECK: fdiv fp128 %{{.+}}, %{{.+}} + a / b +} + +// CHECK-LABEL: fp128 @f128_rem( +#[no_mangle] +pub fn f128_rem(a: f128, b: f128) -> f128 { + // CHECK: frem fp128 %{{.+}}, %{{.+}} + a % b +} + +// CHECK-LABEL: void @f128_add_assign( +#[no_mangle] +pub fn f128_add_assign(a: &mut f128, b: f128) { + // CHECK: fadd fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a += b; +} + +// CHECK-LABEL: void @f128_sub_assign( +#[no_mangle] +pub fn f128_sub_assign(a: &mut f128, b: f128) { + // CHECK: fsub fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a -= b; +} + +// CHECK-LABEL: void @f128_mul_assign( +#[no_mangle] +pub fn f128_mul_assign(a: &mut f128, b: f128) { + // CHECK: fmul fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a *= b +} + +// CHECK-LABEL: void @f128_div_assign( +#[no_mangle] +pub fn f128_div_assign(a: &mut f128, b: f128) { + // CHECK: fdiv fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a /= b +} + +// CHECK-LABEL: void @f128_rem_assign( +#[no_mangle] +pub fn f128_rem_assign(a: &mut f128, b: f128) { + // CHECK: frem fp128 %{{.+}}, %{{.+}} + // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}} + *a %= b +} diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs new file mode 100644 index 0000000000000..d1f75cc3b6851 --- /dev/null +++ b/tests/codegen/float/f16.rs @@ -0,0 +1,129 @@ +// Verify that our intrinsics generate the correct LLVM calls for f16 + +#![crate_type = "lib"] +#![feature(f16)] +#![feature(core_intrinsics)] + +// CHECK-LABEL: i1 @f16_eq( +#[no_mangle] +pub fn f16_eq(a: f16, b: f16) -> bool { + // CHECK: fcmp oeq half %{{.+}}, %{{.+}} + a == b +} + +// CHECK-LABEL: i1 @f16_ne( +#[no_mangle] +pub fn f16_ne(a: f16, b: f16) -> bool { + // CHECK: fcmp une half %{{.+}}, %{{.+}} + a != b +} + +// CHECK-LABEL: i1 @f16_gt( +#[no_mangle] +pub fn f16_gt(a: f16, b: f16) -> bool { + // CHECK: fcmp ogt half %{{.+}}, %{{.+}} + a > b +} + +// CHECK-LABEL: i1 @f16_ge( +#[no_mangle] +pub fn f16_ge(a: f16, b: f16) -> bool { + // CHECK: fcmp oge half %{{.+}}, %{{.+}} + a >= b +} + +// CHECK-LABEL: i1 @f16_lt( +#[no_mangle] +pub fn f16_lt(a: f16, b: f16) -> bool { + // CHECK: fcmp olt half %{{.+}}, %{{.+}} + a < b +} + +// CHECK-LABEL: i1 @f16_le( +#[no_mangle] +pub fn f16_le(a: f16, b: f16) -> bool { + // CHECK: fcmp ole half %{{.+}}, %{{.+}} + a <= b +} + +// CHECK-LABEL: half @f16_neg( +#[no_mangle] +pub fn f16_neg(a: f16) -> f16 { + // CHECK: fneg half %{{.+}} + -a +} + +// CHECK-LABEL: half @f16_add( +#[no_mangle] +pub fn f16_add(a: f16, b: f16) -> f16 { + // CHECK: fadd half %{{.+}}, %{{.+}} + a + b +} + +// CHECK-LABEL: half @f16_sub( +#[no_mangle] +pub fn f16_sub(a: f16, b: f16) -> f16 { + // CHECK: fsub half %{{.+}}, %{{.+}} + a - b +} + +// CHECK-LABEL: half @f16_mul( +#[no_mangle] +pub fn f16_mul(a: f16, b: f16) -> f16 { + // CHECK: fmul half %{{.+}}, %{{.+}} + a * b +} + +// CHECK-LABEL: half @f16_div( +#[no_mangle] +pub fn f16_div(a: f16, b: f16) -> f16 { + // CHECK: fdiv half %{{.+}}, %{{.+}} + a / b +} + +// CHECK-LABEL: half @f16_rem( +#[no_mangle] +pub fn f16_rem(a: f16, b: f16) -> f16 { + // CHECK: frem half %{{.+}}, %{{.+}} + a % b +} + +// CHECK-LABEL: void @f16_add_assign( +#[no_mangle] +pub fn f16_add_assign(a: &mut f16, b: f16) { + // CHECK: fadd half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a += b; +} + +// CHECK-LABEL: void @f16_sub_assign( +#[no_mangle] +pub fn f16_sub_assign(a: &mut f16, b: f16) { + // CHECK: fsub half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a -= b; +} + +// CHECK-LABEL: void @f16_mul_assign( +#[no_mangle] +pub fn f16_mul_assign(a: &mut f16, b: f16) { + // CHECK: fmul half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a *= b +} + +// CHECK-LABEL: void @f16_div_assign( +#[no_mangle] +pub fn f16_div_assign(a: &mut f16, b: f16) { + // CHECK: fdiv half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a /= b +} + +// CHECK-LABEL: void @f16_rem_assign( +#[no_mangle] +pub fn f16_rem_assign(a: &mut f16, b: f16) { + // CHECK: frem half %{{.+}}, %{{.+}} + // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}} + *a %= b +}