about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-23 14:14:48 +0000
committerbors <bors@rust-lang.org>2024-06-23 14:14:48 +0000
commitaabbf84b45a5e7b868c33e959d7e5cc985097d19 (patch)
tree7ef2e780f99167b9ef3889d52b2c457d223d5db4
parentc3d7fb398569407350abe044e786bc7890c90397 (diff)
parent28ce7cd03eebd3b28334624422dfa0c24fb89e54 (diff)
downloadrust-aabbf84b45a5e7b868c33e959d7e5cc985097d19.tar.gz
rust-aabbf84b45a5e7b868c33e959d7e5cc985097d19.zip
Auto merge of #123088 - tgross35:f16-f128-pattern-analysis, r=Nadrieril
Replace `f16` and `f128` pattern matching stubs with real implementations

This section of code depends on `rustc_apfloat` rather than our internal types, so this is one potential ICE that we should be able to melt now.

r? `@Nadrieril`
-rw-r--r--compiler/rustc_middle/src/thir.rs12
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs27
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs50
-rw-r--r--tests/crashes/122587-1.rs5
-rw-r--r--tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs14
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs78
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs1
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr6
-rw-r--r--tests/ui/match/match-float.rs45
-rw-r--r--tests/ui/pattern/usefulness/floats.rs48
-rw-r--r--tests/ui/pattern/usefulness/floats.stderr72
13 files changed, 323 insertions, 43 deletions
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 7c8b0ec671a..c97af68c29e 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -1047,6 +1047,12 @@ impl<'tcx> PatRangeBoundary<'tcx> {
         let b = other.eval_bits(ty, tcx, param_env);
 
         match ty.kind() {
+            ty::Float(ty::FloatTy::F16) => {
+                use rustc_apfloat::Float;
+                let a = rustc_apfloat::ieee::Half::from_bits(a);
+                let b = rustc_apfloat::ieee::Half::from_bits(b);
+                a.partial_cmp(&b)
+            }
             ty::Float(ty::FloatTy::F32) => {
                 use rustc_apfloat::Float;
                 let a = rustc_apfloat::ieee::Single::from_bits(a);
@@ -1059,6 +1065,12 @@ impl<'tcx> PatRangeBoundary<'tcx> {
                 let b = rustc_apfloat::ieee::Double::from_bits(b);
                 a.partial_cmp(&b)
             }
+            ty::Float(ty::FloatTy::F128) => {
+                use rustc_apfloat::Float;
+                let a = rustc_apfloat::ieee::Quad::from_bits(a);
+                let b = rustc_apfloat::ieee::Quad::from_bits(b);
+                a.partial_cmp(&b)
+            }
             ty::Int(ity) => {
                 let size = rustc_target::abi::Integer::from_int_ty(&tcx, *ity).size();
                 let a = size.sign_extend(a) as i128;
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 1b5efcee903..9307e380681 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1196,7 +1196,7 @@ impl<'tcx> Ty<'tcx> {
     /// Returns the minimum and maximum values for the given numeric type (including `char`s) or
     /// returns `None` if the type is not numeric.
     pub fn numeric_min_and_max_as_bits(self, tcx: TyCtxt<'tcx>) -> Option<(u128, u128)> {
-        use rustc_apfloat::ieee::{Double, Single};
+        use rustc_apfloat::ieee::{Double, Half, Quad, Single};
         Some(match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = self.int_size_and_signed(tcx);
@@ -1206,12 +1206,14 @@ impl<'tcx> Ty<'tcx> {
                 (min, max)
             }
             ty::Char => (0, std::char::MAX as u128),
+            ty::Float(ty::FloatTy::F16) => ((-Half::INFINITY).to_bits(), Half::INFINITY.to_bits()),
             ty::Float(ty::FloatTy::F32) => {
                 ((-Single::INFINITY).to_bits(), Single::INFINITY.to_bits())
             }
             ty::Float(ty::FloatTy::F64) => {
                 ((-Double::INFINITY).to_bits(), Double::INFINITY.to_bits())
             }
+            ty::Float(ty::FloatTy::F128) => ((-Quad::INFINITY).to_bits(), Quad::INFINITY.to_bits()),
             _ => return None,
         })
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 192d706bce2..dda6c88008b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -369,10 +369,10 @@ impl<'tcx> ConstToPat<'tcx> {
             ty::Float(flt) => {
                 let v = cv.unwrap_leaf();
                 let is_nan = match flt {
-                    ty::FloatTy::F16 => unimplemented!("f16_f128"),
+                    ty::FloatTy::F16 => v.to_f16().is_nan(),
                     ty::FloatTy::F32 => v.to_f32().is_nan(),
                     ty::FloatTy::F64 => v.to_f64().is_nan(),
-                    ty::FloatTy::F128 => unimplemented!("f16_f128"),
+                    ty::FloatTy::F128 => v.to_f128().is_nan(),
                 };
                 if is_nan {
                     // NaNs are not ever equal to anything so they make no sense as patterns.
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 44f09b66bf6..fb103705475 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -182,7 +182,7 @@ use std::iter::once;
 
 use smallvec::SmallVec;
 
-use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
+use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS};
 use rustc_index::bit_set::{BitSet, GrowableBitSet};
 use rustc_index::IndexVec;
 
@@ -692,8 +692,10 @@ pub enum Constructor<Cx: PatCx> {
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
+    F16Range(IeeeFloat<HalfS>, IeeeFloat<HalfS>, RangeEnd),
     F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd),
     F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
+    F128Range(IeeeFloat<QuadS>, IeeeFloat<QuadS>, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
     Str(Cx::StrLit),
     /// Constants that must not be matched structurally. They are treated as black boxes for the
@@ -735,8 +737,10 @@ impl<Cx: PatCx> Clone for Constructor<Cx> {
             Constructor::UnionField => Constructor::UnionField,
             Constructor::Bool(b) => Constructor::Bool(*b),
             Constructor::IntRange(range) => Constructor::IntRange(*range),
+            Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end),
             Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end),
             Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end),
+            Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end),
             Constructor::Str(value) => Constructor::Str(value.clone()),
             Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
             Constructor::Or => Constructor::Or,
@@ -812,6 +816,14 @@ impl<Cx: PatCx> Constructor<Cx> {
             (Bool(self_b), Bool(other_b)) => self_b == other_b,
 
             (IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range),
+            (F16Range(self_from, self_to, self_end), F16Range(other_from, other_to, other_end)) => {
+                self_from.ge(other_from)
+                    && match self_to.partial_cmp(other_to) {
+                        Some(Ordering::Less) => true,
+                        Some(Ordering::Equal) => other_end == self_end,
+                        _ => false,
+                    }
+            }
             (F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
                 self_from.ge(other_from)
                     && match self_to.partial_cmp(other_to) {
@@ -828,6 +840,17 @@ impl<Cx: PatCx> Constructor<Cx> {
                         _ => false,
                     }
             }
+            (
+                F128Range(self_from, self_to, self_end),
+                F128Range(other_from, other_to, other_end),
+            ) => {
+                self_from.ge(other_from)
+                    && match self_to.partial_cmp(other_to) {
+                        Some(Ordering::Less) => true,
+                        Some(Ordering::Equal) => other_end == self_end,
+                        _ => false,
+                    }
+            }
             (Str(self_val), Str(other_val)) => {
                 // FIXME Once valtrees are available we can directly use the bytes
                 // in the `Str` variant of the valtree for the comparison here.
@@ -906,8 +929,10 @@ impl<Cx: PatCx> Constructor<Cx> {
             Bool(b) => write!(f, "{b}")?,
             // Best-effort, will render signed ranges incorrectly
             IntRange(range) => write!(f, "{range:?}")?,
+            F16Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
             F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
             F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
+            F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
             Str(value) => write!(f, "{value:?}")?,
             Opaque(..) => write!(f, "<constant pattern>")?,
             Or => {
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 8391c694c64..d4dd4dd858c 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -247,8 +247,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                 }
                 _ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
             },
-            Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
-            | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[],
+            Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
+            | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
+            | PrivateUninhabited | Wildcard => &[],
             Or => {
                 bug!("called `Fields::wildcards` on an `Or` ctor")
             }
@@ -275,8 +276,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             },
             Ref => 1,
             Slice(slice) => slice.arity(),
-            Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
-            | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0,
+            Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
+            | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing
+            | PrivateUninhabited | Wildcard => 0,
             Or => bug!("The `Or` constructor doesn't have a fixed arity"),
         }
     }
@@ -546,6 +548,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         fields = vec![];
                         arity = 0;
                     }
+                    ty::Float(ty::FloatTy::F16) => {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                            Some(bits) => {
+                                use rustc_apfloat::Float;
+                                let value = rustc_apfloat::ieee::Half::from_bits(bits);
+                                F16Range(value, value, RangeEnd::Included)
+                            }
+                            None => Opaque(OpaqueId::new()),
+                        };
+                        fields = vec![];
+                        arity = 0;
+                    }
                     ty::Float(ty::FloatTy::F32) => {
                         ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
                             Some(bits) => {
@@ -570,6 +584,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         fields = vec![];
                         arity = 0;
                     }
+                    ty::Float(ty::FloatTy::F128) => {
+                        ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
+                            Some(bits) => {
+                                use rustc_apfloat::Float;
+                                let value = rustc_apfloat::ieee::Quad::from_bits(bits);
+                                F128Range(value, value, RangeEnd::Included)
+                            }
+                            None => Opaque(OpaqueId::new()),
+                        };
+                        fields = vec![];
+                        arity = 0;
+                    }
                     ty::Ref(_, t, _) if t.is_str() => {
                         // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
                         // with other `Deref` patterns. This could have been done in `const_to_pat`,
@@ -611,7 +637,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                         let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env));
                         let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env));
                         match fty {
-                            ty::FloatTy::F16 => unimplemented!("f16_f128"),
+                            ty::FloatTy::F16 => {
+                                use rustc_apfloat::ieee::Half;
+                                let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY);
+                                let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY);
+                                F16Range(lo, hi, end)
+                            }
                             ty::FloatTy::F32 => {
                                 use rustc_apfloat::ieee::Single;
                                 let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY);
@@ -624,7 +655,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                                 let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY);
                                 F64Range(lo, hi, end)
                             }
-                            ty::FloatTy::F128 => unimplemented!("f16_f128"),
+                            ty::FloatTy::F128 => {
+                                use rustc_apfloat::ieee::Quad;
+                                let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY);
+                                let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY);
+                                F128Range(lo, hi, end)
+                            }
                         }
                     }
                     _ => bug!("invalid type for range pattern: {}", ty.inner()),
@@ -837,7 +873,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                 "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
                 `Missing` should have been processed in `apply_constructors`"
             ),
-            F32Range(..) | F64Range(..) | Opaque(..) | Or => {
+            F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
                 bug!("can't convert to pattern: {:?}", pat)
             }
         };
diff --git a/tests/crashes/122587-1.rs b/tests/crashes/122587-1.rs
deleted file mode 100644
index ea0e843a10c..00000000000
--- a/tests/crashes/122587-1.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ known-bug: #122587
-const b: f16 = 0.0f16;
-pub fn main() {
-   let b = 0.0f16;
-}
diff --git a/tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs b/tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs
new file mode 100644
index 00000000000..99d0e472485
--- /dev/null
+++ b/tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+// issue: rust-lang/rust#122587
+
+#![feature(f128)]
+#![feature(f16)]
+#![allow(non_upper_case_globals)]
+
+const h: f16 = 0.0f16;
+const q: f128 = 0.0f128;
+
+pub fn main() {
+    let h = 0.0f16 else { unreachable!() };
+    let q = 0.0f128 else { unreachable!() };
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
index 3487bac5282..38ade060cb1 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
@@ -4,6 +4,8 @@
 // via `.contains(...)` and make sure the dynamic semantics match.
 
 #![allow(unreachable_patterns)]
+#![feature(f128)]
+#![feature(f16)]
 
 macro_rules! yes {
     ($scrutinee:expr, $($t:tt)+) => {
@@ -39,6 +41,17 @@ fn range_to_inclusive() {
     assert!(yes!('a', ..='a'));
     assert!(!yes!('b', ..='a'));
 
+    // f16; `..=X`
+    // FIXME(f16_f128): remove gate when ABI issues are resolved
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    {
+        // FIXME(f16_f128): enable infinity tests when constants are available
+        // assert!(yes!(f16::NEG_INFINITY, ..=f16::NEG_INFINITY));
+        // assert!(yes!(f16::NEG_INFINITY, ..=1.0f16));
+        assert!(yes!(1.5f16, ..=1.5f16));
+        assert!(!yes!(1.6f16, ..=-1.5f16));
+    }
+
     // f32; `..=X`
     assert!(yes!(f32::NEG_INFINITY, ..=f32::NEG_INFINITY));
     assert!(yes!(f32::NEG_INFINITY, ..=1.0f32));
@@ -50,6 +63,17 @@ fn range_to_inclusive() {
     assert!(yes!(f64::NEG_INFINITY, ..=1.0f64));
     assert!(yes!(1.5f64, ..=1.5f64));
     assert!(!yes!(1.6f64, ..=-1.5f64));
+
+    // f128; `..=X`
+    // FIXME(f16_f128): remove gate when ABI issues are resolved
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    {
+        // FIXME(f16_f128): enable infinity tests when constants are available
+        // assert!(yes!(f128::NEG_INFINITY, ..=f128::NEG_INFINITY));
+        // assert!(yes!(f128::NEG_INFINITY, ..=1.0f128));
+        assert!(yes!(1.5f128, ..=1.5f128));
+        assert!(!yes!(1.6f128, ..=-1.5f128));
+    }
 }
 
 fn range_to() {
@@ -83,6 +107,18 @@ fn range_to() {
     assert!(!yes!('a', ..'a'));
     assert!(!yes!('b', ..'a'));
 
+    // f16; `..X`
+    // FIXME(f16_f128): remove gate when ABI issues are resolved
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    {
+        // FIXME(f16_f128): enable infinity tests when constants are available
+        // assert!(yes!(f16::NEG_INFINITY, ..1.0f16));
+        assert!(!yes!(1.5f16, ..1.5f16));
+        const E16: f16 = 1.5f16 + f16::EPSILON;
+        assert!(yes!(1.5f16, ..E16));
+        assert!(!yes!(1.6f16, ..1.5f16));
+    }
+
     // f32; `..X`
     assert!(yes!(f32::NEG_INFINITY, ..1.0f32));
     assert!(!yes!(1.5f32, ..1.5f32));
@@ -96,6 +132,18 @@ fn range_to() {
     const E64: f64 = 1.5f64 + f64::EPSILON;
     assert!(yes!(1.5f64, ..E64));
     assert!(!yes!(1.6f64, ..1.5f64));
+
+    // f128; `..X`
+    // FIXME(f16_f128): remove gate when ABI issues are resolved
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    {
+        // FIXME(f16_f128): enable infinity tests when constants are available
+        // assert!(yes!(f128::NEG_INFINITY, ..1.0f128));
+        assert!(!yes!(1.5f128, ..1.5f128));
+        const E128: f128 = 1.5f128 + f128::EPSILON;
+        assert!(yes!(1.5f128, ..E128));
+        assert!(!yes!(1.6f128, ..1.5f128));
+    }
 }
 
 fn range_from() {
@@ -129,6 +177,21 @@ fn range_from() {
     assert!(!yes!('a', 'b'..));
     assert!(yes!(core::char::MAX, core::char::MAX..));
 
+    // f16; `X..`
+    // FIXME(f16_f128): remove gate when ABI issues are resolved
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    {
+        // FIXME(f16_f128): enable infinity tests when constants are available
+        // assert!(yes!(f16::NEG_INFINITY, f16::NEG_INFINITY..));
+        // assert!(yes!(f16::INFINITY, f16::NEG_INFINITY..));
+        // assert!(!yes!(f16::NEG_INFINITY, 1.0f16..));
+        // assert!(yes!(f16::INFINITY, 1.0f16..));
+        assert!(!yes!(1.0f16 - f16::EPSILON, 1.0f16..));
+        assert!(yes!(1.0f16, 1.0f16..));
+        // assert!(yes!(f16::INFINITY, 1.0f16..));
+        // assert!(yes!(f16::INFINITY, f16::INFINITY..));
+    }
+
     // f32; `X..`
     assert!(yes!(f32::NEG_INFINITY, f32::NEG_INFINITY..));
     assert!(yes!(f32::INFINITY, f32::NEG_INFINITY..));
@@ -148,6 +211,21 @@ fn range_from() {
     assert!(yes!(1.0f64, 1.0f64..));
     assert!(yes!(f64::INFINITY, 1.0f64..));
     assert!(yes!(f64::INFINITY, f64::INFINITY..));
+
+    // f128; `X..`
+    // FIXME(f16_f128): remove gate when ABI issues are resolved
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    {
+        // FIXME(f16_f128): enable infinity tests when constants are available
+        // assert!(yes!(f128::NEG_INFINITY, f128::NEG_INFINITY..));
+        // assert!(yes!(f128::INFINITY, f128::NEG_INFINITY..));
+        // assert!(!yes!(f128::NEG_INFINITY, 1.0f128..));
+        // assert!(yes!(f128::INFINITY, 1.0f128..));
+        assert!(!yes!(1.0f128 - f128::EPSILON, 1.0f128..));
+        assert!(yes!(1.0f128, 1.0f128..));
+        // assert!(yes!(f128::INFINITY, 1.0f128..));
+        // assert!(yes!(f128::INFINITY, f128::INFINITY..));
+    }
 }
 
 fn main() {
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
index 9ca8dd25ed7..a35bb51acbc 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
@@ -27,6 +27,7 @@ fn main() {
     m!(0, ..i128::MIN);
     //~^ ERROR lower range bound must be less than upper
 
+    // FIXME(f16_f128): add tests when NEG_INFINITY is available
     m!(0f32, ..f32::NEG_INFINITY);
     //~^ ERROR lower range bound must be less than upper
     m!(0f64, ..f64::NEG_INFINITY);
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
index 668b5c858f0..fb2f1841a6d 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
@@ -59,19 +59,19 @@ LL |     m!(0, ..i128::MIN);
    |           ^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:14
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:31:14
    |
 LL |     m!(0f32, ..f32::NEG_INFINITY);
    |              ^^^^^^^^^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:32:14
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14
    |
 LL |     m!(0f64, ..f64::NEG_INFINITY);
    |              ^^^^^^^^^^^^^^^^^^^
 
 error[E0579]: lower range bound must be less than upper
-  --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:13
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:13
    |
 LL |     m!('a', ..'\u{0}');
    |             ^^^^^^^^^
diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs
index f8514568d15..70283eaeec5 100644
--- a/tests/ui/match/match-float.rs
+++ b/tests/ui/match/match-float.rs
@@ -1,7 +1,22 @@
 //@ run-pass
 // Makes sure we use `==` (not bitwise) semantics for float comparison.
 
-fn main() {
+#![feature(f128)]
+#![feature(f16)]
+
+// FIXME(f16_f128): remove gates when ABI issues are resolved
+
+#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+fn check_f16() {
+    const F1: f16 = 0.0;
+    const F2: f16 = -0.0;
+    assert_eq!(F1, F2);
+    assert_ne!(F1.to_bits(), F2.to_bits());
+    assert!(matches!(F1, F2));
+    assert!(matches!(F2, F1));
+}
+
+fn check_f32() {
     const F1: f32 = 0.0;
     const F2: f32 = -0.0;
     assert_eq!(F1, F2);
@@ -9,3 +24,31 @@ fn main() {
     assert!(matches!(F1, F2));
     assert!(matches!(F2, F1));
 }
+
+fn check_f64() {
+    const F1: f64 = 0.0;
+    const F2: f64 = -0.0;
+    assert_eq!(F1, F2);
+    assert_ne!(F1.to_bits(), F2.to_bits());
+    assert!(matches!(F1, F2));
+    assert!(matches!(F2, F1));
+}
+
+#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+fn check_f128() {
+    const F1: f128 = 0.0;
+    const F2: f128 = -0.0;
+    assert_eq!(F1, F2);
+    assert_ne!(F1.to_bits(), F2.to_bits());
+    assert!(matches!(F1, F2));
+    assert!(matches!(F2, F1));
+}
+
+fn main() {
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    check_f16();
+    check_f32();
+    check_f64();
+    #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
+    check_f128();
+}
diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs
index b3d49ba8e15..0b27e33e4ef 100644
--- a/tests/ui/pattern/usefulness/floats.rs
+++ b/tests/ui/pattern/usefulness/floats.rs
@@ -1,4 +1,6 @@
 #![deny(unreachable_patterns)]
+#![feature(f128)]
+#![feature(f16)]
 
 fn main() {
     match 0.0 {
@@ -11,6 +13,32 @@ fn main() {
         0.0..=1.0 => {}
     }
 
+    match 1.0f16 {
+        0.01f16..=6.5f16 => {}
+        0.01f16 => {} //~ ERROR unreachable pattern
+        0.02f16 => {} //~ ERROR unreachable pattern
+        6.5f16 => {}  //~ ERROR unreachable pattern
+        _ => {}
+    };
+    match 1.0f16 {
+        0.01f16..6.5f16 => {}
+        6.5f16 => {} // this is reachable
+        _ => {}
+    };
+
+    match 1.0f32 {
+        0.01f32..=6.5f32 => {}
+        0.01f32 => {} //~ ERROR unreachable pattern
+        0.02f32 => {} //~ ERROR unreachable pattern
+        6.5f32 => {}  //~ ERROR unreachable pattern
+        _ => {}
+    };
+    match 1.0f32 {
+        0.01f32..6.5f32 => {}
+        6.5f32 => {} // this is reachable
+        _ => {}
+    };
+
     match 1.0f64 {
         0.01f64..=6.5f64 => {}
         0.005f64 => {}
@@ -28,16 +56,20 @@ fn main() {
         _ => {}
     };
 
-    match 1.0f32 {
-        0.01f32..=6.5f32 => {}
-        0.01f32 => {} //~ ERROR unreachable pattern
-        0.02f32 => {} //~ ERROR unreachable pattern
-        6.5f32 => {}  //~ ERROR unreachable pattern
+    match 1.0f128 {
+        0.01f128..=6.5f128 => {}
+        0.005f128 => {}
+        0.01f128 => {} //~ ERROR unreachable pattern
+        0.02f128 => {} //~ ERROR unreachable pattern
+        6.5f128 => {}  //~ ERROR unreachable pattern
+        6.6f128 => {}
+        1.0f128..=4.0f128 => {} //~ ERROR unreachable pattern
+        5.0f128..=7.0f128 => {}
         _ => {}
     };
-    match 1.0f32 {
-        0.01f32..6.5f32 => {}
-        6.5f32 => {} // this is reachable
+    match 1.0f128 {
+        0.01f128..6.5f128 => {}
+        6.5f128 => {} // this is reachable
         _ => {}
     };
 }
diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr
index 04f2fe3cd94..684f6c93a16 100644
--- a/tests/ui/pattern/usefulness/floats.stderr
+++ b/tests/ui/pattern/usefulness/floats.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/floats.rs:9:11
+  --> $DIR/floats.rs:11:11
    |
 LL |     match 0.0 {
    |           ^^^ pattern `_` not covered
@@ -12,9 +12,9 @@ LL +         _ => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/floats.rs:17:9
+  --> $DIR/floats.rs:18:9
    |
-LL |         0.01f64 => {}
+LL |         0.01f16 => {}
    |         ^^^^^^^
    |
 note: the lint level is defined here
@@ -24,41 +24,83 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:18:9
+  --> $DIR/floats.rs:19:9
+   |
+LL |         0.02f16 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:20:9
+   |
+LL |         6.5f16 => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:31:9
+   |
+LL |         0.01f32 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:32:9
+   |
+LL |         0.02f32 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:33:9
+   |
+LL |         6.5f32 => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:45:9
+   |
+LL |         0.01f64 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:46:9
    |
 LL |         0.02f64 => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:19:9
+  --> $DIR/floats.rs:47:9
    |
 LL |         6.5f64 => {}
    |         ^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:21:9
+  --> $DIR/floats.rs:49:9
    |
 LL |         1.0f64..=4.0f64 => {}
    |         ^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:33:9
+  --> $DIR/floats.rs:62:9
    |
-LL |         0.01f32 => {}
-   |         ^^^^^^^
+LL |         0.01f128 => {}
+   |         ^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:34:9
+  --> $DIR/floats.rs:63:9
    |
-LL |         0.02f32 => {}
+LL |         0.02f128 => {}
+   |         ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:64:9
+   |
+LL |         6.5f128 => {}
    |         ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/floats.rs:35:9
+  --> $DIR/floats.rs:66:9
    |
-LL |         6.5f32 => {}
-   |         ^^^^^^
+LL |         1.0f128..=4.0f128 => {}
+   |         ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0004`.