Skip to content

Replace f16 and f128 pattern matching stubs with real implementations #123088

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
})
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
27 changes: 26 additions & 1 deletion compiler/rustc_pattern_analysis/src/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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.
Expand Down Expand Up @@ -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 => {
Expand Down
50 changes: 43 additions & 7 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand All @@ -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"),
}
}
Expand Down Expand Up @@ -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) => {
Expand All @@ -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`,
Expand Down Expand Up @@ -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);
Expand All @@ -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()),
Expand Down Expand Up @@ -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)
}
};
Expand Down
5 changes: 0 additions & 5 deletions tests/crashes/122587-1.rs

This file was deleted.

14 changes: 14 additions & 0 deletions tests/ui/consts/const_in_pattern/f16-f128-const-reassign.rs
Original file line number Diff line number Diff line change
@@ -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!() };
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)+) => {
Expand Down Expand Up @@ -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));
Expand All @@ -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() {
Expand Down Expand Up @@ -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));
Expand All @@ -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() {
Expand Down Expand Up @@ -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..));
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
Loading