Skip to content
Merged
11 changes: 5 additions & 6 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2585,12 +2585,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.filter(|item| item.is_fn() && !item.is_method())
.filter_map(|item| {
// Only assoc fns that return `Self`
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
let ret_ty = fn_sig.output();
let ret_ty = self.tcx.normalize_erasing_late_bound_regions(
self.typing_env(self.param_env),
ret_ty,
);
let fn_sig = self
.tcx
.fn_sig(item.def_id)
.instantiate(self.tcx, self.fresh_args_for_item(span, item.def_id));
let ret_ty = self.tcx.instantiate_bound_regions_with_erased(fn_sig.output());
if !self.can_eq(self.param_env, ret_ty, adt_ty) {
return None;
}
Expand Down
137 changes: 105 additions & 32 deletions compiler/rustc_target/src/callconv/loongarch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ use crate::spec::HasTargetSpec;

#[derive(Copy, Clone)]
enum RegPassKind {
Float(Reg),
Integer(Reg),
Float { offset_from_start: Size, ty: Reg },
Integer { offset_from_start: Size, ty: Reg },
Unknown,
}

#[derive(Copy, Clone)]
enum FloatConv {
FloatPair(Reg, Reg),
FloatPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
Float(Reg),
MixedPair(Reg, Reg),
MixedPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
}

#[derive(Copy, Clone)]
Expand All @@ -37,6 +37,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
flen: u64,
field1_kind: &mut RegPassKind,
field2_kind: &mut RegPassKind,
offset_from_start: Size,
) -> Result<(), CannotUseFpConv>
where
Ty: TyAbiInterface<'a, C> + Copy,
Expand All @@ -49,16 +50,16 @@ where
}
match (*field1_kind, *field2_kind) {
(RegPassKind::Unknown, _) => {
*field1_kind = RegPassKind::Integer(Reg {
kind: RegKind::Integer,
size: arg_layout.size,
});
*field1_kind = RegPassKind::Integer {
offset_from_start,
ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
};
}
(RegPassKind::Float(_), RegPassKind::Unknown) => {
*field2_kind = RegPassKind::Integer(Reg {
kind: RegKind::Integer,
size: arg_layout.size,
});
(RegPassKind::Float { .. }, RegPassKind::Unknown) => {
*field2_kind = RegPassKind::Integer {
offset_from_start,
ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
};
}
_ => return Err(CannotUseFpConv),
}
Expand All @@ -69,12 +70,16 @@ where
}
match (*field1_kind, *field2_kind) {
(RegPassKind::Unknown, _) => {
*field1_kind =
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
*field1_kind = RegPassKind::Float {
offset_from_start,
ty: Reg { kind: RegKind::Float, size: arg_layout.size },
};
}
(_, RegPassKind::Unknown) => {
*field2_kind =
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
*field2_kind = RegPassKind::Float {
offset_from_start,
ty: Reg { kind: RegKind::Float, size: arg_layout.size },
};
}
_ => return Err(CannotUseFpConv),
}
Expand All @@ -96,13 +101,14 @@ where
flen,
field1_kind,
field2_kind,
offset_from_start,
);
}
return Err(CannotUseFpConv);
}
}
FieldsShape::Array { count, .. } => {
for _ in 0..count {
for i in 0..count {
let elem_layout = arg_layout.field(cx, 0);
should_use_fp_conv_helper(
cx,
Expand All @@ -111,6 +117,7 @@ where
flen,
field1_kind,
field2_kind,
offset_from_start + elem_layout.size * i,
)?;
}
}
Expand All @@ -121,7 +128,15 @@ where
}
for i in arg_layout.fields.index_by_increasing_offset() {
let field = arg_layout.field(cx, i);
should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
should_use_fp_conv_helper(
cx,
&field,
xlen,
flen,
field1_kind,
field2_kind,
offset_from_start + arg_layout.fields.offset(i),
)?;
}
}
},
Expand All @@ -140,14 +155,52 @@ where
{
let mut field1_kind = RegPassKind::Unknown;
let mut field2_kind = RegPassKind::Unknown;
if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
if should_use_fp_conv_helper(
cx,
arg,
xlen,
flen,
&mut field1_kind,
&mut field2_kind,
Size::ZERO,
)
.is_err()
{
return None;
}
match (field1_kind, field2_kind) {
(RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
(RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
(RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
(RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
(
RegPassKind::Integer { offset_from_start, .. }
| RegPassKind::Float { offset_from_start, .. },
_,
) if offset_from_start != Size::ZERO => {
panic!("type {:?} has a first field with non-zero offset {offset_from_start:?}", arg.ty)
}
(
RegPassKind::Integer { ty: first_ty, .. },
RegPassKind::Float { offset_from_start, ty: second_ty },
) => Some(FloatConv::MixedPair {
first_ty,
second_ty_offset_from_start: offset_from_start,
second_ty,
}),
(
RegPassKind::Float { ty: first_ty, .. },
RegPassKind::Integer { offset_from_start, ty: second_ty },
) => Some(FloatConv::MixedPair {
first_ty,
second_ty_offset_from_start: offset_from_start,
second_ty,
}),
(
RegPassKind::Float { ty: first_ty, .. },
RegPassKind::Float { offset_from_start, ty: second_ty },
) => Some(FloatConv::FloatPair {
first_ty,
second_ty_offset_from_start: offset_from_start,
second_ty,
}),
(RegPassKind::Float { ty, .. }, RegPassKind::Unknown) => Some(FloatConv::Float(ty)),
_ => None,
}
}
Expand All @@ -165,11 +218,19 @@ where
FloatConv::Float(f) => {
arg.cast_to(f);
}
FloatConv::FloatPair(l, r) => {
arg.cast_to(CastTarget::pair(l, r));
FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty } => {
arg.cast_to(CastTarget::offset_pair(
first_ty,
second_ty_offset_from_start,
second_ty,
));
}
FloatConv::MixedPair(l, r) => {
arg.cast_to(CastTarget::pair(l, r));
FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty } => {
arg.cast_to(CastTarget::offset_pair(
first_ty,
second_ty_offset_from_start,
second_ty,
));
}
}
return false;
Expand Down Expand Up @@ -233,15 +294,27 @@ fn classify_arg<'a, Ty, C>(
arg.cast_to(f);
return;
}
Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
Some(FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty })
if *avail_fprs >= 2 =>
{
*avail_fprs -= 2;
arg.cast_to(CastTarget::pair(l, r));
arg.cast_to(CastTarget::offset_pair(
first_ty,
second_ty_offset_from_start,
second_ty,
));
return;
}
Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
Some(FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty })
if *avail_fprs >= 1 && *avail_gprs >= 1 =>
{
*avail_gprs -= 1;
*avail_fprs -= 1;
arg.cast_to(CastTarget::pair(l, r));
arg.cast_to(CastTarget::offset_pair(
first_ty,
second_ty_offset_from_start,
second_ty,
));
return;
}
_ => (),
Expand Down
117 changes: 117 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,66 @@ macro_rules! int_impl {
}
}

/// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
///
/// Returns `None` if any bits that would be shifted out differ from the resulting sign bit
/// or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
/// Otherwise, returns `Some(self << rhs)`.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 2), Some(1 << ", stringify!($SelfT), "::BITS - 2));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 1), None);")]
#[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 2), Some(-0x2 << ", stringify!($SelfT), "::BITS - 2));")]
#[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 1), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
if rhs < self.leading_zeros() || rhs < self.leading_ones() {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shl(rhs) })
} else {
None
}
}

/// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
/// losslessly reversed and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
/// self.leading_ones()` i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out non-zero bits"),
(
zeros: u32 = self.leading_zeros(),
ones: u32 = self.leading_ones(),
rhs: u32 = rhs,
) => rhs < zeros || rhs < ones,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shl(rhs) }
}

/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
/// larger than or equal to the number of bits in `self`.
///
Expand Down Expand Up @@ -1534,6 +1594,63 @@ macro_rules! int_impl {
}
}

/// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
///
/// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
/// Otherwise, returns `Some(self >> rhs)`.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shr(rhs) })
} else {
None
}
}

/// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
/// losslessly reversed and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"),
(
zeros: u32 = self.trailing_zeros(),
bits: u32 = <$SelfT>::BITS,
rhs: u32 = rhs,
) => rhs <= zeros && rhs < bits,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shr(rhs) }
}

/// Checked absolute value. Computes `self.abs()`, returning `None` if
/// `self == MIN`.
///
Expand Down
Loading
Loading