Add basic library support for `f16` and `f128`

Implement basic operation traits that get lowered to intrinsics. This
includes codegen tests for implemented operations.
This commit is contained in:
Trevor Gross 2024-03-06 05:40:29 -06:00
parent 88bcc79f31
commit 454de78ea3
8 changed files with 296 additions and 29 deletions

View File

@ -34,8 +34,10 @@ macro_rules! impl_float_to_int {
} }
} }
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!(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); impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
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 // Conversion traits for primitive integer and float types
// Conversions T -> T are covered by a blanket impl and therefore excluded // Conversions T -> T are covered by a blanket impl and therefore excluded
@ -163,7 +165,12 @@ 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")]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
// float -> float // float -> float
impl_from!(f16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
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")]); impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
macro_rules! impl_float_from_bool { macro_rules! impl_float_from_bool {
($float:ty) => { ($float:ty) => {

View File

@ -11,5 +11,7 @@ macro_rules! floating {
}; };
} }
floating! { f16 }
floating! { f32 } floating! { f32 }
floating! { f64 } floating! { f64 }
floating! { f128 }

View File

@ -109,7 +109,7 @@ macro_rules! add_impl {
)*) )*)
} }
add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The subtraction operator `-`. /// The subtraction operator `-`.
/// ///
@ -218,7 +218,7 @@ macro_rules! sub_impl {
)*) )*)
} }
sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The multiplication operator `*`. /// The multiplication operator `*`.
/// ///
@ -348,7 +348,7 @@ macro_rules! mul_impl {
)*) )*)
} }
mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The division operator `/`. /// The division operator `/`.
/// ///
@ -506,7 +506,7 @@ macro_rules! div_impl_float {
)*) )*)
} }
div_impl_float! { f32 f64 } div_impl_float! { f16 f32 f64 f128 }
/// The remainder operator `%`. /// The remainder operator `%`.
/// ///
@ -623,7 +623,7 @@ macro_rules! rem_impl_float {
)*) )*)
} }
rem_impl_float! { f32 f64 } rem_impl_float! { f16 f32 f64 f128 }
/// The unary negation operator `-`. /// The unary negation operator `-`.
/// ///
@ -698,7 +698,7 @@ macro_rules! neg_impl {
)*) )*)
} }
neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } neg_impl! { isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The addition assignment operator `+=`. /// The addition assignment operator `+=`.
/// ///
@ -765,7 +765,7 @@ macro_rules! add_assign_impl {
)+) )+)
} }
add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The subtraction assignment operator `-=`. /// The subtraction assignment operator `-=`.
/// ///
@ -832,7 +832,7 @@ macro_rules! sub_assign_impl {
)+) )+)
} }
sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The multiplication assignment operator `*=`. /// The multiplication assignment operator `*=`.
/// ///
@ -890,7 +890,7 @@ macro_rules! mul_assign_impl {
)+) )+)
} }
mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The division assignment operator `/=`. /// The division assignment operator `/=`.
/// ///
@ -947,7 +947,7 @@ macro_rules! div_assign_impl {
)+) )+)
} }
div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }
/// The remainder assignment operator `%=`. /// The remainder assignment operator `%=`.
/// ///
@ -1008,4 +1008,4 @@ macro_rules! rem_assign_impl {
)+) )+)
} }
rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 }

129
tests/codegen/float/f128.rs Normal file
View File

@ -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
}

129
tests/codegen/float/f16.rs Normal file
View File

@ -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
}

View File

@ -6,15 +6,15 @@ LL | 1 +
| |
= help: the trait `Add<()>` is not implemented for `{integer}` = help: the trait `Add<()>` is not implemented for `{integer}`
= help: the following other types implement trait `Add<Rhs>`: = help: the following other types implement trait `Add<Rhs>`:
<&'a f128 as Add<f128>>
<&'a f16 as Add<f16>>
<&'a f32 as Add<f32>> <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>> <&'a f64 as Add<f64>>
<&'a i128 as Add<i128>> <&'a i128 as Add<i128>>
<&'a i16 as Add<i16>> <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>> <&'a i32 as Add<i32>>
<&'a i64 as Add<i64>> <&'a i64 as Add<i64>>
<&'a i8 as Add<i8>> and 56 others
<&'a isize as Add<isize>>
and 48 others
error[E0277]: cannot add `()` to `{integer}` error[E0277]: cannot add `()` to `{integer}`
--> $DIR/issue-11771.rs:8:7 --> $DIR/issue-11771.rs:8:7
@ -24,15 +24,15 @@ LL | 1 +
| |
= help: the trait `Add<()>` is not implemented for `{integer}` = help: the trait `Add<()>` is not implemented for `{integer}`
= help: the following other types implement trait `Add<Rhs>`: = help: the following other types implement trait `Add<Rhs>`:
<&'a f128 as Add<f128>>
<&'a f16 as Add<f16>>
<&'a f32 as Add<f32>> <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>> <&'a f64 as Add<f64>>
<&'a i128 as Add<i128>> <&'a i128 as Add<i128>>
<&'a i16 as Add<i16>> <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>> <&'a i32 as Add<i32>>
<&'a i64 as Add<i64>> <&'a i64 as Add<i64>>
<&'a i8 as Add<i8>> and 56 others
<&'a isize as Add<isize>>
and 48 others
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -16,15 +16,15 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new();
| |
= help: the trait `Add<()>` is not implemented for `{integer}` = help: the trait `Add<()>` is not implemented for `{integer}`
= help: the following other types implement trait `Add<Rhs>`: = help: the following other types implement trait `Add<Rhs>`:
<&'a f128 as Add<f128>>
<&'a f16 as Add<f16>>
<&'a f32 as Add<f32>> <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>> <&'a f64 as Add<f64>>
<&'a i128 as Add<i128>> <&'a i128 as Add<i128>>
<&'a i16 as Add<i16>> <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>> <&'a i32 as Add<i32>>
<&'a i64 as Add<i64>> <&'a i64 as Add<i64>>
<&'a i8 as Add<i8>> and 56 others
<&'a isize as Add<isize>>
and 48 others
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -6,15 +6,15 @@ LL | 1 + Some(1);
| |
= help: the trait `Add<Option<{integer}>>` is not implemented for `{integer}` = help: the trait `Add<Option<{integer}>>` is not implemented for `{integer}`
= help: the following other types implement trait `Add<Rhs>`: = help: the following other types implement trait `Add<Rhs>`:
<&'a f128 as Add<f128>>
<&'a f16 as Add<f16>>
<&'a f32 as Add<f32>> <&'a f32 as Add<f32>>
<&'a f64 as Add<f64>> <&'a f64 as Add<f64>>
<&'a i128 as Add<i128>> <&'a i128 as Add<i128>>
<&'a i16 as Add<i16>> <&'a i16 as Add<i16>>
<&'a i32 as Add<i32>> <&'a i32 as Add<i32>>
<&'a i64 as Add<i64>> <&'a i64 as Add<i64>>
<&'a i8 as Add<i8>> and 56 others
<&'a isize as Add<isize>>
and 48 others
error[E0277]: cannot subtract `Option<{integer}>` from `usize` error[E0277]: cannot subtract `Option<{integer}>` from `usize`
--> $DIR/binops.rs:3:16 --> $DIR/binops.rs:3:16
@ -37,15 +37,15 @@ LL | 3 * ();
| |
= help: the trait `Mul<()>` is not implemented for `{integer}` = help: the trait `Mul<()>` is not implemented for `{integer}`
= help: the following other types implement trait `Mul<Rhs>`: = help: the following other types implement trait `Mul<Rhs>`:
<&'a f128 as Mul<f128>>
<&'a f16 as Mul<f16>>
<&'a f32 as Mul<f32>> <&'a f32 as Mul<f32>>
<&'a f64 as Mul<f64>> <&'a f64 as Mul<f64>>
<&'a i128 as Mul<i128>> <&'a i128 as Mul<i128>>
<&'a i16 as Mul<i16>> <&'a i16 as Mul<i16>>
<&'a i32 as Mul<i32>> <&'a i32 as Mul<i32>>
<&'a i64 as Mul<i64>> <&'a i64 as Mul<i64>>
<&'a i8 as Mul<i8>> and 57 others
<&'a isize as Mul<isize>>
and 49 others
error[E0277]: cannot divide `{integer}` by `&str` error[E0277]: cannot divide `{integer}` by `&str`
--> $DIR/binops.rs:5:7 --> $DIR/binops.rs:5:7
@ -55,15 +55,15 @@ LL | 4 / "";
| |
= help: the trait `Div<&str>` is not implemented for `{integer}` = help: the trait `Div<&str>` is not implemented for `{integer}`
= help: the following other types implement trait `Div<Rhs>`: = help: the following other types implement trait `Div<Rhs>`:
<&'a f128 as Div<f128>>
<&'a f16 as Div<f16>>
<&'a f32 as Div<f32>> <&'a f32 as Div<f32>>
<&'a f64 as Div<f64>> <&'a f64 as Div<f64>>
<&'a i128 as Div<i128>> <&'a i128 as Div<i128>>
<&'a i16 as Div<i16>> <&'a i16 as Div<i16>>
<&'a i32 as Div<i32>> <&'a i32 as Div<i32>>
<&'a i64 as Div<i64>> <&'a i64 as Div<i64>>
<&'a i8 as Div<i8>> and 62 others
<&'a isize as Div<isize>>
and 54 others
error[E0277]: can't compare `{integer}` with `String` error[E0277]: can't compare `{integer}` with `String`
--> $DIR/binops.rs:6:7 --> $DIR/binops.rs:6:7