From 73c80c634c4f017ea98508e0886cb985c76c0487 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 | 15 ++ library/core/src/default.rs | 4 + library/core/src/fmt/nofloat.rs | 4 + 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 ++++++++++++++++++ tests/ui/binop/binary-op-suggest-deref.stderr | 2 +- tests/ui/issues/issue-11771.stderr | 4 +- tests/ui/issues/issue-50582.stderr | 2 +- tests/ui/mismatched_types/binops.stderr | 10 +- tests/ui/typeck/escaping_bound_vars.stderr | 2 +- 15 files changed, 342 insertions(+), 10 deletions(-) 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..3fe3a48d3d1d3 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -35,8 +35,12 @@ macro_rules! impl_float_to_int { } } +#[cfg(not(bootstrap))] +impl_float_to_int!(f16 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); 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!(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 @@ -164,7 +168,18 @@ impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); // float -> float +// 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")]); impl_from!(f32 => f64, #[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) => { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index a1303fcd82158..93a3a1e4ccc7a 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -176,5 +176,9 @@ default_impl! { i32, 0, "Returns the default value of `0`" } default_impl! { i64, 0, "Returns the default value of `0`" } default_impl! { i128, 0, "Returns the default value of `0`" } +#[cfg(not(bootstrap))] +default_impl! { f16, 0.0f16, "Returns the default value of `0.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! { 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..aa3df69920f6d 100644 --- a/library/core/src/fmt/nofloat.rs +++ b/library/core/src/fmt/nofloat.rs @@ -11,5 +11,9 @@ macro_rules! floating { }; } +#[cfg(not(bootstrap))] +floating! { f16 } floating! { f32 } floating! { f64 } +#[cfg(not(bootstrap))] +floating! { f128 } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6473f772e304b..2b7f704ca6cc9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -206,6 +206,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 +} diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 8a226d712ff58..0482ec409567e 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -255,7 +255,7 @@ LL | _ = &&0 == Foo; i128 usize u8 - and 6 others + and 8 others error[E0369]: binary operation `==` cannot be applied to type `Foo` --> $DIR/binary-op-suggest-deref.rs:60:13 diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index b37140f60f9c1..5df9ef33f8bc0 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -14,7 +14,7 @@ LL | 1 + > > - and 48 others + and 56 others error[E0277]: cannot add `()` to `{integer}` --> $DIR/issue-11771.rs:8:7 @@ -32,7 +32,7 @@ LL | 1 + > > - and 48 others + and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index 7b65fa25ae37e..75e7f682ac4d0 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -24,7 +24,7 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); > > - and 48 others + and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index b18ab7f7608d5..20b5022d1470c 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -14,7 +14,7 @@ LL | 1 + Some(1); > > - and 48 others + and 56 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` --> $DIR/binops.rs:3:16 @@ -45,7 +45,7 @@ LL | 3 * (); > > - and 49 others + and 57 others error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:5:7 @@ -63,7 +63,7 @@ LL | 4 / ""; > > - and 54 others + and 62 others error[E0277]: can't compare `{integer}` with `String` --> $DIR/binops.rs:6:7 @@ -81,7 +81,7 @@ LL | 5 < String::new(); i128 usize u8 - and 6 others + and 8 others error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` --> $DIR/binops.rs:7:7 @@ -99,7 +99,7 @@ LL | 6 == Ok(1); i128 usize u8 - and 6 others + and 8 others error: aborting due to 6 previous errors diff --git a/tests/ui/typeck/escaping_bound_vars.stderr b/tests/ui/typeck/escaping_bound_vars.stderr index 8c7dcdb7f1618..ab3f7d7b970a4 100644 --- a/tests/ui/typeck/escaping_bound_vars.stderr +++ b/tests/ui/typeck/escaping_bound_vars.stderr @@ -40,7 +40,7 @@ LL | (): Test<{ 1 + (<() as Elide(&())>::call) }>, > > - and 48 others + and 56 others error[E0277]: the trait bound `(): Elide<(&(),)>` is not satisfied --> $DIR/escaping_bound_vars.rs:11:18