Rollup merge of #146564 - cjgillot:mir-nolen, r=scottmcm
Remove Rvalue::Len again. Now that we have `RawPtrKind::FakeForPtrMetadata`, we can reimplement `Rvalue::Len` using `PtrMetadata(&raw const (fake) place)`. r? ``@scottmcm``
This commit is contained in:
commit
6473a0f02d
53 changed files with 1381 additions and 292 deletions
|
|
@ -1557,9 +1557,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
&(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
|
||||
&Rvalue::Discriminant(place) => {
|
||||
let af = match *rvalue {
|
||||
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
|
||||
Rvalue::Discriminant(..) => None,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -306,16 +306,11 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
self.consume_operand(location, op);
|
||||
}
|
||||
|
||||
&(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
|
||||
let af = match rvalue {
|
||||
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
|
||||
Rvalue::Discriminant(..) => None,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
&Rvalue::Discriminant(place) => {
|
||||
self.access_place(
|
||||
location,
|
||||
place,
|
||||
(Shallow(af), Read(ReadKind::Copy)),
|
||||
(Shallow(None), Read(ReadKind::Copy)),
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1631,7 +1631,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::RawPtr(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
|
||||
}
|
||||
|
|
@ -2201,7 +2200,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Ref(..)
|
||||
| Rvalue::RawPtr(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::Cast(..)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
|
|
|
|||
|
|
@ -834,12 +834,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
|||
fx.bcx.ins().nop();
|
||||
}
|
||||
}
|
||||
Rvalue::Len(place) => {
|
||||
let place = codegen_place(fx, place);
|
||||
let usize_layout = fx.layout_of(fx.tcx.types.usize);
|
||||
let len = codegen_array_len(fx, place);
|
||||
lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
|
||||
}
|
||||
Rvalue::ShallowInitBox(ref operand, content_ty) => {
|
||||
let content_ty = fx.monomorphize(content_ty);
|
||||
let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ use rustc_middle::{bug, mir, span_bug};
|
|||
use rustc_session::config::OptLevel;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::FunctionCx;
|
||||
use super::operand::{OperandRef, OperandRefBuilder, OperandValue};
|
||||
use super::place::{PlaceRef, PlaceValue, codegen_tag_value};
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use crate::common::{IntPredicate, TypeKind};
|
||||
use crate::traits::*;
|
||||
use crate::{MemFlags, base};
|
||||
|
|
@ -510,14 +510,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.codegen_place_to_pointer(bx, place, mk_ptr)
|
||||
}
|
||||
|
||||
mir::Rvalue::Len(place) => {
|
||||
let size = self.evaluate_array_len(bx, place);
|
||||
OperandRef {
|
||||
val: OperandValue::Immediate(size),
|
||||
layout: bx.cx().layout_of(bx.tcx().types.usize),
|
||||
}
|
||||
}
|
||||
|
||||
mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
|
||||
if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
|
||||
{
|
||||
|
|
@ -749,21 +741,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
|
||||
// ZST are passed as operands and require special handling
|
||||
// because codegen_place() panics if Local is operand.
|
||||
if let Some(index) = place.as_local()
|
||||
&& let LocalRef::Operand(op) = self.locals[index]
|
||||
&& let ty::Array(_, n) = op.layout.ty.kind()
|
||||
{
|
||||
let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen");
|
||||
return bx.cx().const_usize(n);
|
||||
}
|
||||
// use common size calculation for non zero-sized types
|
||||
let cg_value = self.codegen_place(bx, place.as_ref());
|
||||
cg_value.len(bx.cx())
|
||||
}
|
||||
|
||||
/// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref`
|
||||
fn codegen_place_to_pointer(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -573,8 +573,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
Rvalue::Use(_)
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Len(_) => {}
|
||||
| Rvalue::Discriminant(..) => {}
|
||||
|
||||
Rvalue::Aggregate(kind, ..) => {
|
||||
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
|
||||
|
|
|
|||
|
|
@ -232,9 +232,7 @@ where
|
|||
Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx))
|
||||
}
|
||||
|
||||
Rvalue::Discriminant(place) | Rvalue::Len(place) => {
|
||||
in_place::<Q, _>(cx, in_local, place.as_ref())
|
||||
}
|
||||
Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
|
||||
|
||||
Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
|
||||
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ where
|
|||
| mir::Rvalue::CopyForDeref(..)
|
||||
| mir::Rvalue::ThreadLocalRef(..)
|
||||
| mir::Rvalue::Repeat(..)
|
||||
| mir::Rvalue::Len(..)
|
||||
| mir::Rvalue::BinaryOp(..)
|
||||
| mir::Rvalue::NullaryOp(..)
|
||||
| mir::Rvalue::UnaryOp(..)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use tracing::{info, instrument, trace};
|
|||
|
||||
use super::{
|
||||
FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
|
||||
Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format,
|
||||
Projectable, interp_ok, throw_ub, throw_unsup_format,
|
||||
};
|
||||
use crate::interpret::EnteredTraceSpan;
|
||||
use crate::{enter_trace_span, util};
|
||||
|
|
@ -225,12 +225,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.write_repeat(operand, &dest)?;
|
||||
}
|
||||
|
||||
Len(place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let len = src.len(self)?;
|
||||
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
|
||||
}
|
||||
|
||||
Ref(_, borrow_kind, place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let place = self.force_allocation(&src)?;
|
||||
|
|
|
|||
|
|
@ -1062,7 +1062,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
pretty_print_const(b, fmt, false)?;
|
||||
write!(fmt, "]")
|
||||
}
|
||||
Len(ref a) => write!(fmt, "Len({a:?})"),
|
||||
Cast(ref kind, ref place, ref ty) => {
|
||||
with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -697,7 +697,6 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
| Rvalue::Ref(_, _, _)
|
||||
| Rvalue::ThreadLocalRef(_)
|
||||
| Rvalue::RawPtr(_, _)
|
||||
| Rvalue::Len(_)
|
||||
| Rvalue::Cast(
|
||||
CastKind::IntToInt
|
||||
| CastKind::FloatToInt
|
||||
|
|
@ -739,7 +738,6 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
|
||||
}
|
||||
Rvalue::Len(..) => tcx.types.usize,
|
||||
Rvalue::Cast(.., ty) => ty,
|
||||
Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
|
||||
let lhs_ty = lhs.ty(local_decls, tcx);
|
||||
|
|
|
|||
|
|
@ -1407,16 +1407,6 @@ pub enum Rvalue<'tcx> {
|
|||
/// model.
|
||||
RawPtr(RawPtrKind, Place<'tcx>),
|
||||
|
||||
/// Yields the length of the place, as a `usize`.
|
||||
///
|
||||
/// If the type of the place is an array, this is the array length. For slices (`[T]`, not
|
||||
/// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
|
||||
/// ill-formed for places of other types.
|
||||
///
|
||||
/// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only
|
||||
/// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing.
|
||||
Len(Place<'tcx>),
|
||||
|
||||
/// Performs essentially all of the casts that can be performed via `as`.
|
||||
///
|
||||
/// This allows for casts from/to a variety of types.
|
||||
|
|
|
|||
|
|
@ -717,14 +717,6 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
||||
Rvalue::Len(path) => {
|
||||
self.visit_place(
|
||||
path,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::Cast(_cast_kind, operand, ty) => {
|
||||
self.visit_operand(operand, location);
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||
|
|
|
|||
|
|
@ -229,6 +229,11 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
let source = self.parse_operand(args[0])?;
|
||||
Ok(Rvalue::Cast(CastKind::PtrToPtr, source, expr.ty))
|
||||
},
|
||||
@call(mir_cast_unsize, args) => {
|
||||
let source = self.parse_operand(args[0])?;
|
||||
let kind = CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, CoercionSource::AsCast);
|
||||
Ok(Rvalue::Cast(kind, source, expr.ty))
|
||||
},
|
||||
@call(mir_checked, args) => {
|
||||
parse_by_kind!(self, args[0], _, "binary op",
|
||||
ExprKind::Binary { op, lhs, rhs } => {
|
||||
|
|
@ -247,7 +252,6 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
let offset = self.parse_operand(args[1])?;
|
||||
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
|
||||
},
|
||||
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
|
||||
@call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
|
||||
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
|
||||
ExprKind::Borrow { borrow_kind, arg } => Ok(
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
///
|
||||
/// For arrays it'll be `Operand::Constant` with the actual length;
|
||||
/// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
|
||||
fn len_of_slice_or_array(
|
||||
pub(in crate::builder) fn len_of_slice_or_array(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
place: Place<'tcx>,
|
||||
|
|
|
|||
|
|
@ -309,7 +309,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let actual = self.temp(usize_ty, test.span);
|
||||
|
||||
// actual = len(place)
|
||||
self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place));
|
||||
let length_op = self.len_of_slice_or_array(block, place, test.span, source_info);
|
||||
self.cfg.push_assign(block, source_info, actual, Rvalue::Use(length_op));
|
||||
|
||||
// expected = <N>
|
||||
let expected = self.push_usize(block, source_info, len);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ where
|
|||
| Rvalue::Use(..)
|
||||
| Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::NullaryOp(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
|
|
|
|||
|
|
@ -413,7 +413,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
|||
Rvalue::Ref(..)
|
||||
| Rvalue::RawPtr(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::NullaryOp(
|
||||
NullOp::SizeOf
|
||||
| NullOp::AlignOf
|
||||
|
|
|
|||
|
|
@ -412,18 +412,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
state: &mut State<FlatSet<Scalar>>,
|
||||
) -> ValueOrPlace<FlatSet<Scalar>> {
|
||||
let val = match rvalue {
|
||||
Rvalue::Len(place) => {
|
||||
let place_ty = place.ty(self.local_decls, self.tcx);
|
||||
if let ty::Array(_, len) = place_ty.ty.kind() {
|
||||
Const::Ty(self.tcx.types.usize, *len)
|
||||
.try_eval_scalar(self.tcx, self.typing_env)
|
||||
.map_or(FlatSet::Top, FlatSet::Elem)
|
||||
} else if let [ProjectionElem::Deref] = place.projection[..] {
|
||||
state.get_len(place.local.into(), &self.map)
|
||||
} else {
|
||||
FlatSet::Top
|
||||
}
|
||||
}
|
||||
Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
|
||||
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
|
||||
return ValueOrPlace::Value(FlatSet::Top);
|
||||
|
|
@ -465,15 +453,23 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
let (val, _overflow) = self.binary_op(state, *op, left, right);
|
||||
val
|
||||
}
|
||||
Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(value) => self
|
||||
.ecx
|
||||
.unary_op(*op, &value)
|
||||
.discard_err()
|
||||
.map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
|
||||
FlatSet::Bottom => FlatSet::Bottom,
|
||||
FlatSet::Top => FlatSet::Top,
|
||||
},
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
if let UnOp::PtrMetadata = op
|
||||
&& let Some(place) = operand.place()
|
||||
&& let Some(len) = self.map.find_len(place.as_ref())
|
||||
{
|
||||
return ValueOrPlace::Place(len);
|
||||
}
|
||||
match self.eval_operand(operand, state) {
|
||||
FlatSet::Elem(value) => self
|
||||
.ecx
|
||||
.unary_op(*op, &value)
|
||||
.discard_err()
|
||||
.map_or(FlatSet::Top, |val| self.wrap_immediate(*val)),
|
||||
FlatSet::Bottom => FlatSet::Bottom,
|
||||
FlatSet::Top => FlatSet::Top,
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(null_op, ty) => {
|
||||
let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else {
|
||||
return ValueOrPlace::Value(FlatSet::Top);
|
||||
|
|
|
|||
|
|
@ -200,8 +200,6 @@ enum Value<'tcx> {
|
|||
Projection(VnIndex, ProjectionElem<VnIndex, ()>),
|
||||
/// Discriminant of the given value.
|
||||
Discriminant(VnIndex),
|
||||
/// Length of an array or slice.
|
||||
Len(VnIndex),
|
||||
|
||||
// Operations.
|
||||
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
|
||||
|
|
@ -477,11 +475,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?;
|
||||
discr_value.into()
|
||||
}
|
||||
Len(slice) => {
|
||||
let slice = self.evaluated[slice].as_ref()?;
|
||||
let len = slice.len(&self.ecx).discard_err()?;
|
||||
ImmTy::from_uint(len, ty).into()
|
||||
}
|
||||
NullaryOp(null_op, arg_ty) => {
|
||||
let arg_layout = self.ecx.layout_of(arg_ty).ok()?;
|
||||
if let NullOp::SizeOf | NullOp::AlignOf = null_op
|
||||
|
|
@ -841,7 +834,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
}
|
||||
|
||||
// Operations.
|
||||
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
|
||||
Rvalue::Cast(ref mut kind, ref mut value, to) => {
|
||||
return self.simplify_cast(kind, value, to, location);
|
||||
}
|
||||
|
|
@ -1049,7 +1041,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
if op == UnOp::PtrMetadata {
|
||||
let mut was_updated = false;
|
||||
loop {
|
||||
match self.get(arg_index) {
|
||||
arg_index = match self.get(arg_index) {
|
||||
// Pointer casts that preserve metadata, such as
|
||||
// `*const [i32]` <-> `*mut [i32]` <-> `*mut [f32]`.
|
||||
// It's critical that this not eliminate cases like
|
||||
|
|
@ -1061,9 +1053,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
Value::Cast { kind: CastKind::PtrToPtr, value: inner }
|
||||
if self.pointers_have_same_metadata(self.ty(*inner), arg_ty) =>
|
||||
{
|
||||
arg_index = *inner;
|
||||
was_updated = true;
|
||||
continue;
|
||||
*inner
|
||||
}
|
||||
|
||||
// We have an unsizing cast, which assigns the length to wide pointer metadata.
|
||||
Value::Cast {
|
||||
kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _),
|
||||
value: from,
|
||||
} if let Some(from) = self.ty(*from).builtin_deref(true)
|
||||
&& let ty::Array(_, len) = from.kind()
|
||||
&& let Some(to) = self.ty(arg_index).builtin_deref(true)
|
||||
&& let ty::Slice(..) = to.kind() =>
|
||||
{
|
||||
return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
|
||||
}
|
||||
|
||||
// `&mut *p`, `&raw *p`, etc don't change metadata.
|
||||
|
|
@ -1072,18 +1074,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
place.as_ref()
|
||||
&& let Some(local_index) = self.locals[local] =>
|
||||
{
|
||||
arg_index = local_index;
|
||||
was_updated = true;
|
||||
continue;
|
||||
local_index
|
||||
}
|
||||
|
||||
_ => {
|
||||
if was_updated && let Some(op) = self.try_as_operand(arg_index, location) {
|
||||
*arg_op = op;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
};
|
||||
was_updated = true;
|
||||
}
|
||||
|
||||
if was_updated && let Some(op) = self.try_as_operand(arg_index, location) {
|
||||
*arg_op = op;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1407,39 +1407,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
Some(self.insert(to, Value::Cast { kind, value }))
|
||||
}
|
||||
|
||||
fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
|
||||
// Trivial case: we are fetching a statically known length.
|
||||
let place_ty = place.ty(self.local_decls, self.tcx).ty;
|
||||
if let ty::Array(_, len) = place_ty.kind() {
|
||||
return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
|
||||
}
|
||||
|
||||
let mut inner = self.simplify_place_value(place, location)?;
|
||||
|
||||
// The length information is stored in the wide pointer.
|
||||
// Reborrowing copies length information from one pointer to the other.
|
||||
while let Value::Address { place: borrowed, .. } = self.get(inner)
|
||||
&& let [PlaceElem::Deref] = borrowed.projection[..]
|
||||
&& let Some(borrowed) = self.locals[borrowed.local]
|
||||
{
|
||||
inner = borrowed;
|
||||
}
|
||||
|
||||
// We have an unsizing cast, which assigns the length to wide pointer metadata.
|
||||
if let Value::Cast { kind, value: from } = self.get(inner)
|
||||
&& let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind
|
||||
&& let Some(from) = self.ty(*from).builtin_deref(true)
|
||||
&& let ty::Array(_, len) = from.kind()
|
||||
&& let Some(to) = self.ty(inner).builtin_deref(true)
|
||||
&& let ty::Slice(..) = to.kind()
|
||||
{
|
||||
return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
|
||||
}
|
||||
|
||||
// Fallback: a symbolic `Len`.
|
||||
Some(self.insert(self.tcx.types.usize, Value::Len(inner)))
|
||||
}
|
||||
|
||||
fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool {
|
||||
let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
|
||||
let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx);
|
||||
|
|
|
|||
|
|
@ -441,7 +441,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
| Rvalue::Use(..)
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::Cast(..)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
|
|
@ -604,20 +603,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
Len(place) => {
|
||||
let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind()
|
||||
{
|
||||
n.try_to_target_usize(self.tcx)?
|
||||
} else {
|
||||
match self.get_const(place)? {
|
||||
Value::Immediate(src) => src.len(&self.ecx).discard_err()?,
|
||||
Value::Aggregate { fields, .. } => fields.len() as u64,
|
||||
Value::Uninit => return None,
|
||||
}
|
||||
};
|
||||
ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into()
|
||||
}
|
||||
|
||||
Ref(..) | RawPtr(..) => return None,
|
||||
|
||||
NullaryOp(ref null_op, ty) => {
|
||||
|
|
|
|||
|
|
@ -437,9 +437,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
self.validate_operand(op)?
|
||||
}
|
||||
|
||||
Rvalue::Discriminant(place) | Rvalue::Len(place) => {
|
||||
self.validate_place(place.as_ref())?
|
||||
}
|
||||
Rvalue::Discriminant(place) => self.validate_place(place.as_ref())?,
|
||||
|
||||
Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
|
||||
|
||||
|
|
|
|||
|
|
@ -1064,14 +1064,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
Rvalue::Ref(..) => {}
|
||||
Rvalue::Len(p) => {
|
||||
let pty = p.ty(&self.body.local_decls, self.tcx).ty;
|
||||
check_kinds!(
|
||||
pty,
|
||||
"Cannot compute length of non-array type {:?}",
|
||||
ty::Array(..) | ty::Slice(..)
|
||||
);
|
||||
}
|
||||
Rvalue::BinaryOp(op, vals) => {
|
||||
use BinOp::*;
|
||||
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
||||
|
|
|
|||
|
|
@ -215,7 +215,6 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
|||
mutability.stable(tables, cx),
|
||||
place.stable(tables, cx),
|
||||
),
|
||||
Len(place) => crate::mir::Rvalue::Len(place.stable(tables, cx)),
|
||||
Cast(cast_kind, op, ty) => crate::mir::Rvalue::Cast(
|
||||
cast_kind.stable(tables, cx),
|
||||
op.stable(tables, cx),
|
||||
|
|
|
|||
|
|
@ -1413,6 +1413,7 @@ symbols! {
|
|||
mir_call,
|
||||
mir_cast_ptr_to_ptr,
|
||||
mir_cast_transmute,
|
||||
mir_cast_unsize,
|
||||
mir_checked,
|
||||
mir_copy_for_deref,
|
||||
mir_debuginfo,
|
||||
|
|
|
|||
|
|
@ -233,7 +233,8 @@
|
|||
//!
|
||||
//! - Operands implicitly convert to `Use` rvalues.
|
||||
//! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
|
||||
//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions.
|
||||
//! - [`CopyForDeref`], [`CastTransmute`], [`CastPtrToPtr`], [`CastUnsize`], and [`Discriminant`]
|
||||
//! have associated functions.
|
||||
//! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
|
||||
//! - The binary operation `Offset` can be created via [`Offset`].
|
||||
//! - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
|
||||
|
|
@ -401,7 +402,6 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T));
|
|||
define!("mir_assume", fn Assume(operand: bool));
|
||||
define!("mir_deinit", fn Deinit<T>(place: T));
|
||||
define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
|
||||
define!("mir_len", fn Len<T>(place: T) -> usize);
|
||||
define!(
|
||||
"mir_ptr_metadata",
|
||||
fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata
|
||||
|
|
@ -491,6 +491,13 @@ define!(
|
|||
/// This allows bypassing normal validation to generate strange casts.
|
||||
fn CastPtrToPtr<T, U>(operand: T) -> U
|
||||
);
|
||||
define!(
|
||||
"mir_cast_unsize",
|
||||
/// Emits a `CastKind::PointerCoercion(Unsize)` cast.
|
||||
///
|
||||
/// This allows bypassing normal validation to generate strange casts.
|
||||
fn CastUnsize<T, U>(operand: T) -> U
|
||||
);
|
||||
define!(
|
||||
"mir_make_place",
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ fn check_rvalue<'tcx>(
|
|||
) -> McfResult {
|
||||
match rvalue {
|
||||
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
|
||||
Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
|
||||
check_place(cx, *place, span, body, msrv)
|
||||
},
|
||||
Rvalue::CopyForDeref(place) => check_place(cx, *place, span, body, msrv),
|
||||
|
|
|
|||
|
|
@ -3,12 +3,16 @@
|
|||
fn arrays() -> usize {
|
||||
let mut _0: usize;
|
||||
let mut _1: [i32; C];
|
||||
let mut _2: usize;
|
||||
let mut _2: *const [i32; C];
|
||||
let mut _3: *const [i32];
|
||||
let mut _4: usize;
|
||||
|
||||
bb0: {
|
||||
_1 = [const 5_i32; C];
|
||||
_2 = Len(_1);
|
||||
_0 = copy _2;
|
||||
_2 = &raw const _1;
|
||||
_3 = copy _2 as *const [i32] (PointerCoercion(Unsize, AsCast));
|
||||
_4 = PtrMetadata(copy _3);
|
||||
_0 = copy _4;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ fn arrays<const C: usize>() -> usize {
|
|||
mir! {
|
||||
{
|
||||
let x = [5_i32; C];
|
||||
let c = Len(x);
|
||||
let y = &raw const x;
|
||||
let z = CastUnsize::<_, *const [i32]>(y);
|
||||
let c = PtrMetadata(z);
|
||||
RET = c;
|
||||
Return()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
// MIR for `const_array_len` after built
|
||||
|
||||
fn const_array_len(_1: [T; 5]) -> () {
|
||||
debug x => _1;
|
||||
let mut _0: ();
|
||||
let _6: ();
|
||||
let mut _7: T;
|
||||
let _8: ();
|
||||
let mut _9: T;
|
||||
let _10: ();
|
||||
let mut _11: [T; 2];
|
||||
let _12: ();
|
||||
let mut _13: T;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
debug b => _3;
|
||||
debug rest => _4;
|
||||
debug e => _5;
|
||||
let _2: T;
|
||||
let _3: T;
|
||||
let _4: [T; 2];
|
||||
let _5: T;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
falseEdge -> [real: bb2, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_2);
|
||||
_2 = move _1[0 of 5];
|
||||
StorageLive(_3);
|
||||
_3 = move _1[1 of 5];
|
||||
StorageLive(_4);
|
||||
_4 = move _1[2..4];
|
||||
StorageLive(_5);
|
||||
_5 = move _1[4 of 5];
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_7 = move _2;
|
||||
_6 = opaque::<T>(move _7) -> [return: bb3, unwind: bb17];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageLive(_8);
|
||||
StorageLive(_9);
|
||||
_9 = move _3;
|
||||
_8 = opaque::<T>(move _9) -> [return: bb4, unwind: bb16];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
_11 = move _4;
|
||||
_10 = opaque::<[T; 2]>(move _11) -> [return: bb5, unwind: bb15];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = move _5;
|
||||
_12 = opaque::<T>(move _13) -> [return: bb6, unwind: bb14];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
_0 = const ();
|
||||
drop(_5) -> [return: bb8, unwind: bb19];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_0 = const ();
|
||||
goto -> bb12;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_5);
|
||||
drop(_4) -> [return: bb9, unwind: bb20];
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_4);
|
||||
drop(_3) -> [return: bb10, unwind: bb21];
|
||||
}
|
||||
|
||||
bb10: {
|
||||
StorageDead(_3);
|
||||
drop(_2) -> [return: bb11, unwind: bb22];
|
||||
}
|
||||
|
||||
bb11: {
|
||||
StorageDead(_2);
|
||||
goto -> bb12;
|
||||
}
|
||||
|
||||
bb12: {
|
||||
drop(_1) -> [return: bb13, unwind: bb23];
|
||||
}
|
||||
|
||||
bb13: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb14 (cleanup): {
|
||||
drop(_13) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb15 (cleanup): {
|
||||
drop(_11) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb16 (cleanup): {
|
||||
drop(_9) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb17 (cleanup): {
|
||||
drop(_7) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb18 (cleanup): {
|
||||
drop(_5) -> [return: bb19, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb19 (cleanup): {
|
||||
drop(_4) -> [return: bb20, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb20 (cleanup): {
|
||||
drop(_3) -> [return: bb21, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb21 (cleanup): {
|
||||
drop(_2) -> [return: bb22, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb22 (cleanup): {
|
||||
drop(_1) -> [return: bb23, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb23 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// MIR for `const_array_len` after built
|
||||
|
||||
fn const_array_len(_1: [T; 5]) -> () {
|
||||
debug x => _1;
|
||||
let mut _0: ();
|
||||
let _6: ();
|
||||
let mut _7: T;
|
||||
let _8: ();
|
||||
let mut _9: T;
|
||||
let _10: ();
|
||||
let mut _11: [T; 2];
|
||||
let _12: ();
|
||||
let mut _13: T;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
debug b => _3;
|
||||
debug rest => _4;
|
||||
debug e => _5;
|
||||
let _2: T;
|
||||
let _3: T;
|
||||
let _4: [T; 2];
|
||||
let _5: T;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
falseEdge -> [real: bb2, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_2);
|
||||
_2 = move _1[0 of 5];
|
||||
StorageLive(_3);
|
||||
_3 = move _1[1 of 5];
|
||||
StorageLive(_4);
|
||||
_4 = move _1[2..4];
|
||||
StorageLive(_5);
|
||||
_5 = move _1[4 of 5];
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_7 = move _2;
|
||||
_6 = opaque::<T>(move _7) -> [return: bb3, unwind: bb17];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageLive(_8);
|
||||
StorageLive(_9);
|
||||
_9 = move _3;
|
||||
_8 = opaque::<T>(move _9) -> [return: bb4, unwind: bb16];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
_11 = move _4;
|
||||
_10 = opaque::<[T; 2]>(move _11) -> [return: bb5, unwind: bb15];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = move _5;
|
||||
_12 = opaque::<T>(move _13) -> [return: bb6, unwind: bb14];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
_0 = const ();
|
||||
drop(_5) -> [return: bb8, unwind: bb19];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_0 = const ();
|
||||
goto -> bb12;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_5);
|
||||
drop(_4) -> [return: bb9, unwind: bb20];
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_4);
|
||||
drop(_3) -> [return: bb10, unwind: bb21];
|
||||
}
|
||||
|
||||
bb10: {
|
||||
StorageDead(_3);
|
||||
drop(_2) -> [return: bb11, unwind: bb22];
|
||||
}
|
||||
|
||||
bb11: {
|
||||
StorageDead(_2);
|
||||
goto -> bb12;
|
||||
}
|
||||
|
||||
bb12: {
|
||||
drop(_1) -> [return: bb13, unwind: bb23];
|
||||
}
|
||||
|
||||
bb13: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb14 (cleanup): {
|
||||
drop(_13) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb15 (cleanup): {
|
||||
drop(_11) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb16 (cleanup): {
|
||||
drop(_9) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb17 (cleanup): {
|
||||
drop(_7) -> [return: bb18, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb18 (cleanup): {
|
||||
drop(_5) -> [return: bb19, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb19 (cleanup): {
|
||||
drop(_4) -> [return: bb20, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb20 (cleanup): {
|
||||
drop(_3) -> [return: bb21, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb21 (cleanup): {
|
||||
drop(_2) -> [return: bb22, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb22 (cleanup): {
|
||||
drop(_1) -> [return: bb23, unwind terminate(cleanup)];
|
||||
}
|
||||
|
||||
bb23 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
31
tests/mir-opt/building/match/array_len.rs
Normal file
31
tests/mir-opt/building/match/array_len.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
//@ compile-flags: -Zmir-opt-level=0
|
||||
|
||||
fn opaque<T>(x: T) {}
|
||||
|
||||
// EMIT_MIR array_len.const_array_len.built.after.mir
|
||||
fn const_array_len<T>(x: [T; 5]) {
|
||||
// CHECK-LABEL: fn const_array_len(
|
||||
// CHECK-NOT: Len
|
||||
// CHECK-NOT: PtrMetadata
|
||||
// CHECK: = const 5_usize;
|
||||
if let [a, b, rest @ .., e] = x {
|
||||
opaque(a);
|
||||
opaque(b);
|
||||
opaque(rest);
|
||||
opaque(e);
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR array_len.slice_len.built.after.mir
|
||||
fn slice_len<T>(x: &[T]) {
|
||||
// CHECK-LABEL: fn slice_len(
|
||||
// CHECK-NOT: Len
|
||||
// CHECK: = PtrMetadata(copy _1);
|
||||
if let [a, b, rest @ .., e] = x {
|
||||
opaque(a);
|
||||
opaque(b);
|
||||
opaque(rest);
|
||||
opaque(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// MIR for `slice_len` after built
|
||||
|
||||
fn slice_len(_1: &[T]) -> () {
|
||||
debug x => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: usize;
|
||||
let mut _3: usize;
|
||||
let mut _4: usize;
|
||||
let mut _5: bool;
|
||||
let _10: ();
|
||||
let mut _11: &T;
|
||||
let _12: ();
|
||||
let mut _13: &T;
|
||||
let _14: ();
|
||||
let mut _15: &[T];
|
||||
let _16: ();
|
||||
let mut _17: &T;
|
||||
scope 1 {
|
||||
debug a => _6;
|
||||
debug b => _7;
|
||||
debug rest => _8;
|
||||
debug e => _9;
|
||||
let _6: &T;
|
||||
let _7: &T;
|
||||
let _8: &[T];
|
||||
let _9: &T;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_3 = PtrMetadata(copy _1);
|
||||
_2 = move _3;
|
||||
_4 = const 3_usize;
|
||||
_5 = Ge(move _2, move _4);
|
||||
switchInt(move _5) -> [0: bb1, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
goto -> bb9;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb4, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageLive(_6);
|
||||
_6 = &(*_1)[0 of 3];
|
||||
StorageLive(_7);
|
||||
_7 = &(*_1)[1 of 3];
|
||||
StorageLive(_8);
|
||||
_8 = &(*_1)[2:-1];
|
||||
StorageLive(_9);
|
||||
_9 = &(*_1)[-1 of 3];
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
_11 = copy _6;
|
||||
_10 = opaque::<&T>(move _11) -> [return: bb5, unwind: bb11];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = copy _7;
|
||||
_12 = opaque::<&T>(move _13) -> [return: bb6, unwind: bb11];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
StorageLive(_14);
|
||||
StorageLive(_15);
|
||||
_15 = copy _8;
|
||||
_14 = opaque::<&[T]>(move _15) -> [return: bb7, unwind: bb11];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_15);
|
||||
StorageDead(_14);
|
||||
StorageLive(_16);
|
||||
StorageLive(_17);
|
||||
_17 = copy _9;
|
||||
_16 = opaque::<&T>(move _17) -> [return: bb8, unwind: bb11];
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_17);
|
||||
StorageDead(_16);
|
||||
_0 = const ();
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
goto -> bb10;
|
||||
}
|
||||
|
||||
bb9: {
|
||||
_0 = const ();
|
||||
goto -> bb10;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// MIR for `slice_len` after built
|
||||
|
||||
fn slice_len(_1: &[T]) -> () {
|
||||
debug x => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: usize;
|
||||
let mut _3: usize;
|
||||
let mut _4: usize;
|
||||
let mut _5: bool;
|
||||
let _10: ();
|
||||
let mut _11: &T;
|
||||
let _12: ();
|
||||
let mut _13: &T;
|
||||
let _14: ();
|
||||
let mut _15: &[T];
|
||||
let _16: ();
|
||||
let mut _17: &T;
|
||||
scope 1 {
|
||||
debug a => _6;
|
||||
debug b => _7;
|
||||
debug rest => _8;
|
||||
debug e => _9;
|
||||
let _6: &T;
|
||||
let _7: &T;
|
||||
let _8: &[T];
|
||||
let _9: &T;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_3 = PtrMetadata(copy _1);
|
||||
_2 = move _3;
|
||||
_4 = const 3_usize;
|
||||
_5 = Ge(move _2, move _4);
|
||||
switchInt(move _5) -> [0: bb1, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
goto -> bb9;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb4, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageLive(_6);
|
||||
_6 = &(*_1)[0 of 3];
|
||||
StorageLive(_7);
|
||||
_7 = &(*_1)[1 of 3];
|
||||
StorageLive(_8);
|
||||
_8 = &(*_1)[2:-1];
|
||||
StorageLive(_9);
|
||||
_9 = &(*_1)[-1 of 3];
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
_11 = copy _6;
|
||||
_10 = opaque::<&T>(move _11) -> [return: bb5, unwind: bb11];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_13 = copy _7;
|
||||
_12 = opaque::<&T>(move _13) -> [return: bb6, unwind: bb11];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
StorageLive(_14);
|
||||
StorageLive(_15);
|
||||
_15 = copy _8;
|
||||
_14 = opaque::<&[T]>(move _15) -> [return: bb7, unwind: bb11];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_15);
|
||||
StorageDead(_14);
|
||||
StorageLive(_16);
|
||||
StorageLive(_17);
|
||||
_17 = copy _9;
|
||||
_16 = opaque::<&T>(move _17) -> [return: bb8, unwind: bb11];
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_17);
|
||||
StorageDead(_16);
|
||||
_0 = const ();
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
goto -> bb10;
|
||||
}
|
||||
|
||||
bb9: {
|
||||
_0 = const ();
|
||||
goto -> bb10;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb11 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
- // MIR for `main` before DataflowConstProp
|
||||
+ // MIR for `main` after DataflowConstProp
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
let _1: u32;
|
||||
let mut _2: &[u32];
|
||||
let mut _3: &[u32; 3];
|
||||
let _4: &[u32; 3];
|
||||
let _5: [u32; 3];
|
||||
let _6: usize;
|
||||
let mut _7: usize;
|
||||
let mut _8: bool;
|
||||
let mut _10: &[u32];
|
||||
let _11: usize;
|
||||
let mut _12: usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: &[u32; 3];
|
||||
scope 1 {
|
||||
debug local => _1;
|
||||
let _9: u32;
|
||||
scope 2 {
|
||||
debug constant => _9;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_14 = const main::promoted[0];
|
||||
_4 = copy _14;
|
||||
_3 = copy _4;
|
||||
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
|
||||
StorageDead(_3);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
- _7 = PtrMetadata(copy _2);
|
||||
- _8 = Lt(copy _6, copy _7);
|
||||
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
|
||||
+ _7 = const 3_usize;
|
||||
+ _8 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = const main::SLICE;
|
||||
StorageLive(_11);
|
||||
_11 = const 1_usize;
|
||||
- _12 = PtrMetadata(copy _10);
|
||||
- _13 = Lt(copy _11, copy _12);
|
||||
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable];
|
||||
+ _12 = const 3_usize;
|
||||
+ _13 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- _9 = copy (*_10)[_11];
|
||||
+ _9 = copy (*_10)[1 of 2];
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
_0 = const ();
|
||||
StorageDead(_9);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
- // MIR for `main` before DataflowConstProp
|
||||
+ // MIR for `main` after DataflowConstProp
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
let _1: u32;
|
||||
let mut _2: &[u32];
|
||||
let mut _3: &[u32; 3];
|
||||
let _4: &[u32; 3];
|
||||
let _5: [u32; 3];
|
||||
let _6: usize;
|
||||
let mut _7: usize;
|
||||
let mut _8: bool;
|
||||
let mut _10: &[u32];
|
||||
let _11: usize;
|
||||
let mut _12: usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: &[u32; 3];
|
||||
scope 1 {
|
||||
debug local => _1;
|
||||
let _9: u32;
|
||||
scope 2 {
|
||||
debug constant => _9;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_14 = const main::promoted[0];
|
||||
_4 = copy _14;
|
||||
_3 = copy _4;
|
||||
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
|
||||
StorageDead(_3);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
- _7 = PtrMetadata(copy _2);
|
||||
- _8 = Lt(copy _6, copy _7);
|
||||
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
|
||||
+ _7 = const 3_usize;
|
||||
+ _8 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = const main::SLICE;
|
||||
StorageLive(_11);
|
||||
_11 = const 1_usize;
|
||||
- _12 = PtrMetadata(copy _10);
|
||||
- _13 = Lt(copy _11, copy _12);
|
||||
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue];
|
||||
+ _12 = const 3_usize;
|
||||
+ _13 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- _9 = copy (*_10)[_11];
|
||||
+ _9 = copy (*_10)[1 of 2];
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
_0 = const ();
|
||||
StorageDead(_9);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
- // MIR for `main` before DataflowConstProp
|
||||
+ // MIR for `main` after DataflowConstProp
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
let _1: u32;
|
||||
let mut _2: &[u32];
|
||||
let mut _3: &[u32; 3];
|
||||
let _4: &[u32; 3];
|
||||
let _5: [u32; 3];
|
||||
let _6: usize;
|
||||
let mut _7: usize;
|
||||
let mut _8: bool;
|
||||
let mut _10: &[u32];
|
||||
let _11: usize;
|
||||
let mut _12: usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: &[u32; 3];
|
||||
scope 1 {
|
||||
debug local => _1;
|
||||
let _9: u32;
|
||||
scope 2 {
|
||||
debug constant => _9;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_14 = const main::promoted[0];
|
||||
_4 = copy _14;
|
||||
_3 = copy _4;
|
||||
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
|
||||
StorageDead(_3);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
- _7 = PtrMetadata(copy _2);
|
||||
- _8 = Lt(copy _6, copy _7);
|
||||
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable];
|
||||
+ _7 = const 3_usize;
|
||||
+ _8 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = const main::SLICE;
|
||||
StorageLive(_11);
|
||||
_11 = const 1_usize;
|
||||
- _12 = PtrMetadata(copy _10);
|
||||
- _13 = Lt(copy _11, copy _12);
|
||||
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable];
|
||||
+ _12 = const 3_usize;
|
||||
+ _13 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- _9 = copy (*_10)[_11];
|
||||
+ _9 = copy (*_10)[1 of 2];
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
_0 = const ();
|
||||
StorageDead(_9);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
- // MIR for `main` before DataflowConstProp
|
||||
+ // MIR for `main` after DataflowConstProp
|
||||
|
||||
fn main() -> () {
|
||||
let mut _0: ();
|
||||
let _1: u32;
|
||||
let mut _2: &[u32];
|
||||
let mut _3: &[u32; 3];
|
||||
let _4: &[u32; 3];
|
||||
let _5: [u32; 3];
|
||||
let _6: usize;
|
||||
let mut _7: usize;
|
||||
let mut _8: bool;
|
||||
let mut _10: &[u32];
|
||||
let _11: usize;
|
||||
let mut _12: usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: &[u32; 3];
|
||||
scope 1 {
|
||||
debug local => _1;
|
||||
let _9: u32;
|
||||
scope 2 {
|
||||
debug constant => _9;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_14 = const main::promoted[0];
|
||||
_4 = copy _14;
|
||||
_3 = copy _4;
|
||||
_2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast));
|
||||
StorageDead(_3);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
- _7 = PtrMetadata(copy _2);
|
||||
- _8 = Lt(copy _6, copy _7);
|
||||
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue];
|
||||
+ _7 = const 3_usize;
|
||||
+ _8 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
_10 = const main::SLICE;
|
||||
StorageLive(_11);
|
||||
_11 = const 1_usize;
|
||||
- _12 = PtrMetadata(copy _10);
|
||||
- _13 = Lt(copy _11, copy _12);
|
||||
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue];
|
||||
+ _12 = const 3_usize;
|
||||
+ _13 = const true;
|
||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- _9 = copy (*_10)[_11];
|
||||
+ _9 = copy (*_10)[1 of 2];
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
_0 = const ();
|
||||
StorageDead(_9);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
34
tests/mir-opt/dataflow-const-prop/slice_len.rs
Normal file
34
tests/mir-opt/dataflow-const-prop/slice_len.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
//@ test-mir-pass: DataflowConstProp
|
||||
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg
|
||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||
|
||||
// EMIT_MIR slice_len.main.DataflowConstProp.diff
|
||||
|
||||
// CHECK-LABEL: fn main(
|
||||
fn main() {
|
||||
// CHECK: debug local => [[local:_.*]];
|
||||
// CHECK: debug constant => [[constant:_.*]];
|
||||
|
||||
// CHECK-NOT: {{_.*}} = Len(
|
||||
// CHECK-NOT: {{_.*}} = Lt(
|
||||
// CHECK-NOT: assert(move _
|
||||
// CHECK: {{_.*}} = const 3_usize;
|
||||
// CHECK: {{_.*}} = const true;
|
||||
// CHECK: assert(const true,
|
||||
|
||||
// CHECK: [[local]] = copy (*{{_.*}})[1 of 2];
|
||||
let local = (&[1u32, 2, 3] as &[u32])[1];
|
||||
|
||||
// CHECK-NOT: {{_.*}} = Len(
|
||||
// CHECK-NOT: {{_.*}} = Lt(
|
||||
// CHECK-NOT: assert(move _
|
||||
const SLICE: &[u32] = &[1, 2, 3];
|
||||
// CHECK: {{_.*}} = const 3_usize;
|
||||
// CHECK: {{_.*}} = const true;
|
||||
// CHECK: assert(const true,
|
||||
|
||||
// CHECK-NOT: [[constant]] = {{copy|move}} (*{{_.*}})[_
|
||||
// CHECK: [[constant]] = copy (*{{_.*}})[1 of 2];
|
||||
let constant = SLICE[1];
|
||||
}
|
||||
|
|
@ -12,8 +12,7 @@
|
|||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_3 = &(*_1);
|
||||
_2 = move _3 as &[i32] (PointerCoercion(Unsize, Implicit));
|
||||
|
|
@ -23,8 +22,7 @@
|
|||
- _0 = PtrMetadata(move _4);
|
||||
+ _0 = const 42_usize;
|
||||
StorageDead(_4);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@
|
|||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_3 = &(*_1);
|
||||
_2 = move _3 as &[i32] (PointerCoercion(Unsize, Implicit));
|
||||
|
|
@ -23,8 +22,7 @@
|
|||
- _0 = PtrMetadata(move _4);
|
||||
+ _0 = const 42_usize;
|
||||
StorageDead(_4);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
- // MIR for `norm2` before InstSimplify-after-simplifycfg
|
||||
+ // MIR for `norm2` after InstSimplify-after-simplifycfg
|
||||
|
||||
fn norm2(_1: [f32; 2]) -> f32 {
|
||||
debug x => _1;
|
||||
let mut _0: f32;
|
||||
let _2: f32;
|
||||
let _3: usize;
|
||||
let mut _4: bool;
|
||||
let _6: usize;
|
||||
let mut _7: bool;
|
||||
let mut _8: f32;
|
||||
let mut _9: f32;
|
||||
let mut _10: f32;
|
||||
let mut _11: f32;
|
||||
let mut _12: f32;
|
||||
let mut _13: f32;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
let _5: f32;
|
||||
scope 2 {
|
||||
debug b => _5;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_3 = const 0_usize;
|
||||
_4 = Lt(copy _3, const 2_usize);
|
||||
assert(move _4, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _3) -> [success: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_2 = copy _1[_3];
|
||||
StorageDead(_3);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
_7 = Lt(copy _6, const 2_usize);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_5 = copy _1[_6];
|
||||
StorageDead(_6);
|
||||
StorageLive(_8);
|
||||
StorageLive(_9);
|
||||
_9 = copy _2;
|
||||
StorageLive(_10);
|
||||
_10 = copy _2;
|
||||
_8 = Mul(move _9, move _10);
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
_12 = copy _5;
|
||||
StorageLive(_13);
|
||||
_13 = copy _5;
|
||||
_11 = Mul(move _12, move _13);
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
_0 = Add(move _8, move _11);
|
||||
StorageDead(_11);
|
||||
StorageDead(_8);
|
||||
StorageDead(_5);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
- // MIR for `norm2` before InstSimplify-after-simplifycfg
|
||||
+ // MIR for `norm2` after InstSimplify-after-simplifycfg
|
||||
|
||||
fn norm2(_1: [f32; 2]) -> f32 {
|
||||
debug x => _1;
|
||||
let mut _0: f32;
|
||||
let _2: f32;
|
||||
let _3: usize;
|
||||
let mut _4: bool;
|
||||
let _6: usize;
|
||||
let mut _7: bool;
|
||||
let mut _8: f32;
|
||||
let mut _9: f32;
|
||||
let mut _10: f32;
|
||||
let mut _11: f32;
|
||||
let mut _12: f32;
|
||||
let mut _13: f32;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
let _5: f32;
|
||||
scope 2 {
|
||||
debug b => _5;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_3 = const 0_usize;
|
||||
_4 = Lt(copy _3, const 2_usize);
|
||||
assert(move _4, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _3) -> [success: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_2 = copy _1[_3];
|
||||
StorageDead(_3);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
_7 = Lt(copy _6, const 2_usize);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_5 = copy _1[_6];
|
||||
StorageDead(_6);
|
||||
StorageLive(_8);
|
||||
StorageLive(_9);
|
||||
_9 = copy _2;
|
||||
StorageLive(_10);
|
||||
_10 = copy _2;
|
||||
_8 = Mul(move _9, move _10);
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
_12 = copy _5;
|
||||
StorageLive(_13);
|
||||
_13 = copy _5;
|
||||
_11 = Mul(move _12, move _13);
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
_0 = Add(move _8, move _11);
|
||||
StorageDead(_11);
|
||||
StorageDead(_8);
|
||||
StorageDead(_5);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
- // MIR for `normN` before InstSimplify-after-simplifycfg
|
||||
+ // MIR for `normN` after InstSimplify-after-simplifycfg
|
||||
|
||||
fn normN(_1: [f32; N]) -> f32 {
|
||||
debug x => _1;
|
||||
let mut _0: f32;
|
||||
let _2: f32;
|
||||
let _3: usize;
|
||||
let mut _4: bool;
|
||||
let _6: usize;
|
||||
let mut _7: bool;
|
||||
let mut _8: f32;
|
||||
let mut _9: f32;
|
||||
let mut _10: f32;
|
||||
let mut _11: f32;
|
||||
let mut _12: f32;
|
||||
let mut _13: f32;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
let _5: f32;
|
||||
scope 2 {
|
||||
debug b => _5;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_3 = const 0_usize;
|
||||
_4 = Lt(copy _3, const N);
|
||||
assert(move _4, "index out of bounds: the length is {} but the index is {}", const N, copy _3) -> [success: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_2 = copy _1[_3];
|
||||
StorageDead(_3);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
_7 = Lt(copy _6, const N);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", const N, copy _6) -> [success: bb2, unwind unreachable];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_5 = copy _1[_6];
|
||||
StorageDead(_6);
|
||||
StorageLive(_8);
|
||||
StorageLive(_9);
|
||||
_9 = copy _2;
|
||||
StorageLive(_10);
|
||||
_10 = copy _2;
|
||||
_8 = Mul(move _9, move _10);
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
_12 = copy _5;
|
||||
StorageLive(_13);
|
||||
_13 = copy _5;
|
||||
_11 = Mul(move _12, move _13);
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
_0 = Add(move _8, move _11);
|
||||
StorageDead(_11);
|
||||
StorageDead(_8);
|
||||
StorageDead(_5);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
- // MIR for `normN` before InstSimplify-after-simplifycfg
|
||||
+ // MIR for `normN` after InstSimplify-after-simplifycfg
|
||||
|
||||
fn normN(_1: [f32; N]) -> f32 {
|
||||
debug x => _1;
|
||||
let mut _0: f32;
|
||||
let _2: f32;
|
||||
let _3: usize;
|
||||
let mut _4: bool;
|
||||
let _6: usize;
|
||||
let mut _7: bool;
|
||||
let mut _8: f32;
|
||||
let mut _9: f32;
|
||||
let mut _10: f32;
|
||||
let mut _11: f32;
|
||||
let mut _12: f32;
|
||||
let mut _13: f32;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
let _5: f32;
|
||||
scope 2 {
|
||||
debug b => _5;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_3 = const 0_usize;
|
||||
_4 = Lt(copy _3, const N);
|
||||
assert(move _4, "index out of bounds: the length is {} but the index is {}", const N, copy _3) -> [success: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_2 = copy _1[_3];
|
||||
StorageDead(_3);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
_6 = const 1_usize;
|
||||
_7 = Lt(copy _6, const N);
|
||||
assert(move _7, "index out of bounds: the length is {} but the index is {}", const N, copy _6) -> [success: bb2, unwind continue];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_5 = copy _1[_6];
|
||||
StorageDead(_6);
|
||||
StorageLive(_8);
|
||||
StorageLive(_9);
|
||||
_9 = copy _2;
|
||||
StorageLive(_10);
|
||||
_10 = copy _2;
|
||||
_8 = Mul(move _9, move _10);
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
_12 = copy _5;
|
||||
StorageLive(_13);
|
||||
_13 = copy _5;
|
||||
_11 = Mul(move _12, move _13);
|
||||
StorageDead(_13);
|
||||
StorageDead(_12);
|
||||
_0 = Add(move _8, move _11);
|
||||
StorageDead(_11);
|
||||
StorageDead(_8);
|
||||
StorageDead(_5);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
25
tests/mir-opt/instsimplify/combine_array_len.rs
Normal file
25
tests/mir-opt/instsimplify/combine_array_len.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
//@ test-mir-pass: InstSimplify-after-simplifycfg
|
||||
|
||||
// EMIT_MIR combine_array_len.norm2.InstSimplify-after-simplifycfg.diff
|
||||
fn norm2(x: [f32; 2]) -> f32 {
|
||||
// CHECK-LABEL: fn norm2(
|
||||
// CHECK-NOT: PtrMetadata(
|
||||
let a = x[0];
|
||||
let b = x[1];
|
||||
a * a + b * b
|
||||
}
|
||||
|
||||
// EMIT_MIR combine_array_len.normN.InstSimplify-after-simplifycfg.diff
|
||||
fn normN<const N: usize>(x: [f32; N]) -> f32 {
|
||||
// CHECK-LABEL: fn normN(
|
||||
// CHECK-NOT: PtrMetadata(
|
||||
let a = x[0];
|
||||
let b = x[1];
|
||||
a * a + b * b
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0);
|
||||
assert_eq!(normN([3.0, 4.0]), 5.0 * 5.0);
|
||||
}
|
||||
|
|
@ -7,18 +7,16 @@
|
|||
let _2: &[T];
|
||||
let _3: &[T; 3];
|
||||
let _4: [T; 3];
|
||||
let mut _5: usize;
|
||||
let mut _6: bool;
|
||||
let mut _10: !;
|
||||
let mut _8: !;
|
||||
scope 1 {
|
||||
debug v => _2;
|
||||
let _5: &T;
|
||||
let _6: &T;
|
||||
let _7: &T;
|
||||
let _8: &T;
|
||||
let _9: &T;
|
||||
scope 2 {
|
||||
debug v1 => _7;
|
||||
debug v2 => _8;
|
||||
debug v3 => _9;
|
||||
debug v1 => _5;
|
||||
debug v2 => _6;
|
||||
debug v3 => _7;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,25 +25,23 @@
|
|||
_4 = [copy _1, copy _1, copy _1];
|
||||
_3 = &_4;
|
||||
_2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
|
||||
nop;
|
||||
nop;
|
||||
goto -> bb2;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable;
|
||||
_8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_5);
|
||||
_5 = &(*_2)[0 of 3];
|
||||
StorageLive(_6);
|
||||
_6 = &(*_2)[1 of 3];
|
||||
StorageLive(_7);
|
||||
_7 = &(*_2)[0 of 3];
|
||||
StorageLive(_8);
|
||||
_8 = &(*_2)[1 of 3];
|
||||
StorageLive(_9);
|
||||
_9 = &(*_2)[2 of 3];
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
_7 = &(*_2)[2 of 3];
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,18 +7,16 @@
|
|||
let _2: &[T];
|
||||
let _3: &[T; 3];
|
||||
let _4: [T; 3];
|
||||
let mut _5: usize;
|
||||
let mut _6: bool;
|
||||
let mut _10: !;
|
||||
let mut _8: !;
|
||||
scope 1 {
|
||||
debug v => _2;
|
||||
let _5: &T;
|
||||
let _6: &T;
|
||||
let _7: &T;
|
||||
let _8: &T;
|
||||
let _9: &T;
|
||||
scope 2 {
|
||||
debug v1 => _7;
|
||||
debug v2 => _8;
|
||||
debug v3 => _9;
|
||||
debug v1 => _5;
|
||||
debug v2 => _6;
|
||||
debug v3 => _7;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,25 +25,23 @@
|
|||
_4 = [copy _1, copy _1, copy _1];
|
||||
_3 = &_4;
|
||||
_2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit));
|
||||
nop;
|
||||
nop;
|
||||
goto -> bb2;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
|
||||
_8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_5);
|
||||
_5 = &(*_2)[0 of 3];
|
||||
StorageLive(_6);
|
||||
_6 = &(*_2)[1 of 3];
|
||||
StorageLive(_7);
|
||||
_7 = &(*_2)[0 of 3];
|
||||
StorageLive(_8);
|
||||
_8 = &(*_2)[1 of 3];
|
||||
StorageLive(_9);
|
||||
_9 = &(*_2)[2 of 3];
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
_7 = &(*_2)[2 of 3];
|
||||
StorageDead(_7);
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@
|
|||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = &_1;
|
||||
|
|
@ -41,8 +40,7 @@
|
|||
bb1: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
StorageDead(_7);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@
|
|||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = &_1;
|
||||
|
|
@ -41,8 +40,7 @@
|
|||
bb1: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
StorageDead(_7);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@
|
|||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = &mut _1;
|
||||
|
|
@ -38,8 +37,7 @@
|
|||
bb1: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@
|
|||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = &mut _1;
|
||||
|
|
@ -38,8 +37,7 @@
|
|||
bb1: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,15 @@
|
|||
let mut _15: std::ops::RangeFull;
|
||||
let mut _16: usize;
|
||||
let mut _17: usize;
|
||||
let mut _18: bool;
|
||||
let _23: &&mut u8;
|
||||
let _24: &mut u8;
|
||||
let mut _25: debuginfo::T;
|
||||
let mut _18: usize;
|
||||
let mut _19: bool;
|
||||
let _24: &&mut u8;
|
||||
let _25: &mut u8;
|
||||
let mut _26: debuginfo::T;
|
||||
scope 1 {
|
||||
debug ref_mut_u8 => _1;
|
||||
let _3: &u8;
|
||||
let mut _28: &debuginfo::T;
|
||||
let mut _29: &debuginfo::T;
|
||||
scope 2 {
|
||||
debug field => _3;
|
||||
let _5: &u8;
|
||||
|
|
@ -32,22 +33,22 @@
|
|||
- debug reborrow => _5;
|
||||
+ debug reborrow => _1;
|
||||
let _9: &i32;
|
||||
let _22: &&&mut u8;
|
||||
let mut _27: &std::option::Option<i32>;
|
||||
let _23: &&&mut u8;
|
||||
let mut _28: &std::option::Option<i32>;
|
||||
scope 4 {
|
||||
debug variant_field => _9;
|
||||
}
|
||||
scope 5 {
|
||||
debug constant_index => _19;
|
||||
debug subslice => _20;
|
||||
debug constant_index_from_end => _21;
|
||||
let _19: &i32;
|
||||
let _20: &[i32];
|
||||
let _21: &i32;
|
||||
let mut _26: &[i32; 10];
|
||||
debug constant_index => _20;
|
||||
debug subslice => _21;
|
||||
debug constant_index_from_end => _22;
|
||||
let _20: &i32;
|
||||
let _21: &[i32];
|
||||
let _22: &i32;
|
||||
let mut _27: &[i32; 10];
|
||||
}
|
||||
scope 6 {
|
||||
debug multiple_borrow => _22;
|
||||
debug multiple_borrow => _23;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,8 +60,8 @@
|
|||
_2 = const 5_u8;
|
||||
_1 = &mut _2;
|
||||
StorageLive(_3);
|
||||
_28 = const debuginfo::promoted[2];
|
||||
_3 = &((*_28).0: u8);
|
||||
_29 = const debuginfo::promoted[2];
|
||||
_3 = &((*_29).0: u8);
|
||||
- StorageLive(_5);
|
||||
- _5 = &(*_1);
|
||||
- StorageLive(_6);
|
||||
|
|
@ -76,8 +77,8 @@
|
|||
|
||||
bb2: {
|
||||
StorageLive(_9);
|
||||
_27 = const debuginfo::promoted[1];
|
||||
_9 = &(((*_27) as Some).0: i32);
|
||||
_28 = const debuginfo::promoted[1];
|
||||
_9 = &(((*_28) as Some).0: i32);
|
||||
- _6 = const ();
|
||||
StorageDead(_9);
|
||||
goto -> bb4;
|
||||
|
|
@ -92,11 +93,11 @@
|
|||
StorageDead(_7);
|
||||
- StorageDead(_6);
|
||||
- StorageLive(_10);
|
||||
- StorageLive(_11);
|
||||
StorageLive(_11);
|
||||
- StorageLive(_12);
|
||||
StorageLive(_13);
|
||||
_26 = const debuginfo::promoted[0];
|
||||
_13 = &(*_26);
|
||||
_27 = const debuginfo::promoted[0];
|
||||
_13 = &(*_27);
|
||||
StorageLive(_15);
|
||||
_15 = RangeFull;
|
||||
- _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> [return: bb5, unwind continue];
|
||||
|
|
@ -106,28 +107,28 @@
|
|||
bb5: {
|
||||
StorageDead(_15);
|
||||
StorageDead(_13);
|
||||
- _11 = &(*_12);
|
||||
- _16 = Len((*_11));
|
||||
+ _16 = Len((*_12));
|
||||
_17 = const 3_usize;
|
||||
_18 = Ge(move _16, move _17);
|
||||
switchInt(move _18) -> [0: bb7, otherwise: bb6];
|
||||
_11 = &(*_12);
|
||||
_17 = PtrMetadata(copy _11);
|
||||
_16 = move _17;
|
||||
_18 = const 3_usize;
|
||||
_19 = Ge(move _16, move _18);
|
||||
switchInt(move _19) -> [0: bb7, otherwise: bb6];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageLive(_19);
|
||||
- _19 = &(*_11)[1 of 3];
|
||||
+ _19 = &(*_12)[1 of 3];
|
||||
StorageLive(_20);
|
||||
- _20 = &(*_11)[2:-1];
|
||||
+ _20 = &(*_12)[2:-1];
|
||||
- _20 = &(*_11)[1 of 3];
|
||||
+ _20 = &(*_12)[1 of 3];
|
||||
StorageLive(_21);
|
||||
- _21 = &(*_11)[-1 of 3];
|
||||
- _21 = &(*_11)[2:-1];
|
||||
+ _21 = &(*_12)[2:-1];
|
||||
StorageLive(_22);
|
||||
- _22 = &(*_11)[-1 of 3];
|
||||
- _10 = const ();
|
||||
+ _21 = &(*_12)[-1 of 3];
|
||||
+ _22 = &(*_12)[-1 of 3];
|
||||
StorageDead(_22);
|
||||
StorageDead(_21);
|
||||
StorageDead(_20);
|
||||
StorageDead(_19);
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
|
|
@ -138,21 +139,21 @@
|
|||
|
||||
bb8: {
|
||||
- StorageDead(_12);
|
||||
- StorageDead(_11);
|
||||
StorageDead(_11);
|
||||
- StorageDead(_10);
|
||||
StorageLive(_22);
|
||||
StorageLive(_23);
|
||||
StorageLive(_24);
|
||||
StorageLive(_25);
|
||||
_25 = T(const 6_u8);
|
||||
_24 = &mut (_25.0: u8);
|
||||
StorageLive(_26);
|
||||
_26 = T(const 6_u8);
|
||||
_25 = &mut (_26.0: u8);
|
||||
_24 = &_25;
|
||||
_23 = &_24;
|
||||
_22 = &_23;
|
||||
_0 = const ();
|
||||
StorageDead(_26);
|
||||
StorageDead(_25);
|
||||
StorageDead(_24);
|
||||
StorageDead(_23);
|
||||
StorageDead(_22);
|
||||
- StorageDead(_5);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue