Auto merge of #113858 - cjgillot:const-prop-pairs, r=oli-obk

Always const-prop scalars and scalar pairs

This removes some complexity from the pass.

The limitation to propagate ScalarPairs only for tuple comes from https://github.com/rust-lang/rust/pull/67015, when ScalarPair constant were modeled using `Rvalue::Aggregate`. Nowadays, we use `ConstValue::ByRef`, which does not care about the underlying type.

The justification for not propagating in all cases was perf. This seems not to be a clear cut any more: https://github.com/rust-lang/rust/pull/113858#issuecomment-1642396746
This commit is contained in:
bors 2023-07-20 22:22:31 +00:00
commit e2a7ba2771
58 changed files with 179 additions and 317 deletions

View File

@ -14,8 +14,7 @@
};
use rustc_middle::mir::*;
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
@ -407,51 +406,9 @@ fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, lo
ecx.machine.written_only_inside_own_block_locals.remove(&local);
}
/// Returns the value, if any, of evaluating `c`.
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<OpTy<'tcx>> {
// FIXME we need to revisit this for #67176
if c.has_param() {
return None;
}
// No span, we don't want errors to be shown.
self.ecx.eval_mir_constant(&c.literal, None, None).ok()
}
/// Returns the value, if any, of evaluating `place`.
fn eval_place(&mut self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
trace!("eval_place(place={:?})", place);
self.ecx.eval_place_to_op(place, None).ok()
}
/// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
/// or `eval_place`, depending on the variant of `Operand` used.
fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option<OpTy<'tcx>> {
match *op {
Operand::Constant(ref c) => self.eval_constant(c),
Operand::Move(place) | Operand::Copy(place) => self.eval_place(place),
}
}
fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
match *operand {
Operand::Copy(l) | Operand::Move(l) => {
if let Some(value) = self.get_const(l) && self.should_const_prop(&value) {
// FIXME(felix91gr): this code only handles `Scalar` cases.
// For now, we're not handling `ScalarPair` cases because
// doing so here would require a lot of code duplication.
// We should hopefully generalize `Operand` handling into a fn,
// and use it to do const-prop here and everywhere else
// where it makes sense.
if let interpret::Operand::Immediate(interpret::Immediate::Scalar(
scalar,
)) = *value
{
*operand = self.operand_from_scalar(scalar, value.layout.ty);
}
}
}
Operand::Constant(_) => (),
if let Some(place) = operand.place() && let Some(op) = self.replace_with_const(place) {
*operand = op;
}
}
@ -579,93 +536,45 @@ fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> Operand<'tcx> {
}))
}
fn replace_with_const(&mut self, place: Place<'tcx>, rval: &mut Rvalue<'tcx>) {
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Operand<'tcx>> {
// This will return None if the above `const_prop` invocation only "wrote" a
// type whose creation requires no write. E.g. a generator whose initial state
// consists solely of uninitialized memory (so it doesn't capture any locals).
let Some(ref value) = self.get_const(place) else { return };
if !self.should_const_prop(value) {
return;
let value = self.get_const(place)?;
if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - {value:?}")) {
return None;
}
trace!("replacing {:?}={:?} with {:?}", place, rval, value);
trace!("replacing {:?} with {:?}", place, value);
if let Rvalue::Use(Operand::Constant(c)) = rval {
match c.literal {
ConstantKind::Ty(c) if matches!(c.kind(), ConstKind::Unevaluated(..)) => {}
_ => {
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
return;
}
}
}
trace!("attempting to replace {:?} with {:?}", rval, value);
// FIXME> figure out what to do when read_immediate_raw fails
let imm = self.ecx.read_immediate_raw(value).ok();
let imm = self.ecx.read_immediate_raw(&value).ok()?;
if let Some(Right(imm)) = imm {
match *imm {
interpret::Immediate::Scalar(scalar) => {
*rval = Rvalue::Use(self.operand_from_scalar(scalar, value.layout.ty));
}
Immediate::ScalarPair(..) => {
// Found a value represented as a pair. For now only do const-prop if the type
// of `rvalue` is also a tuple with two scalars.
// FIXME: enable the general case stated above ^.
let ty = value.layout.ty;
// Only do it for tuples
if let ty::Tuple(types) = ty.kind() {
// Only do it if tuple is also a pair with two scalars
if let [ty1, ty2] = types[..] {
let ty_is_scalar = |ty| {
self.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar())
== Some(true)
};
let alloc = if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
let alloc = self
.ecx
.intern_with_temp_alloc(value.layout, |ecx, dest| {
ecx.write_immediate(*imm, dest)
})
.unwrap();
Some(alloc)
} else {
None
};
if let Some(alloc) = alloc {
// Assign entire constant in a single statement.
// We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
let const_val = ConstValue::ByRef { alloc, offset: Size::ZERO };
let literal = ConstantKind::Val(const_val, ty);
*rval = Rvalue::Use(Operand::Constant(Box::new(Constant {
span: DUMMY_SP,
user_ty: None,
literal,
})));
}
}
}
}
// Scalars or scalar pairs that contain undef values are assumed to not have
// successfully evaluated and are thus not propagated.
_ => {}
let Right(imm) = imm else { return None };
match *imm {
Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
Some(self.operand_from_scalar(scalar, value.layout.ty))
}
}
}
Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
let alloc = self
.ecx
.intern_with_temp_alloc(value.layout, |ecx, dest| {
ecx.write_immediate(*imm, dest)
})
.ok()?;
/// Returns `true` if and only if this `op` should be const-propagated into.
fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) {
return false;
}
match **op {
interpret::Operand::Immediate(Immediate::Scalar(s)) => s.try_to_int().is_ok(),
interpret::Operand::Immediate(Immediate::ScalarPair(l, r)) => {
l.try_to_int().is_ok() && r.try_to_int().is_ok()
let literal = ConstantKind::Val(
ConstValue::ByRef { alloc, offset: Size::ZERO },
value.layout.ty,
);
Some(Operand::Constant(Box::new(Constant {
span: DUMMY_SP,
user_ty: None,
literal,
})))
}
_ => false,
// Scalars or scalar pairs that contain undef values are assumed to not have
// successfully evaluated and are thus not propagated.
_ => None,
}
}
@ -810,12 +719,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
self.super_operand(operand, location);
// Only const prop copies and moves on `mir_opt_level=3` as doing so
// currently slightly increases compile time in some cases.
if self.tcx.sess.mir_opt_level() >= 3 {
self.propagate_operand(operand)
}
self.propagate_operand(operand)
}
fn process_projection_elem(
@ -825,8 +729,7 @@ fn process_projection_elem(
) -> Option<PlaceElem<'tcx>> {
if let PlaceElem::Index(local) = elem
&& let Some(value) = self.get_const(local.into())
&& self.should_const_prop(&value)
&& let interpret::Operand::Immediate(interpret::Immediate::Scalar(scalar)) = *value
&& let interpret::Operand::Immediate(Immediate::Scalar(scalar)) = *value
&& let Ok(offset) = scalar.to_target_usize(&self.tcx)
&& let Some(min_length) = offset.checked_add(1)
{
@ -852,7 +755,14 @@ fn visit_assign(
ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {
if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
self.replace_with_const(*place, rvalue);
// If this was already an evaluated constant, keep it.
if let Rvalue::Use(Operand::Constant(c)) = rvalue
&& let ConstantKind::Val(..) = c.literal
{
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
} else if let Some(operand) = self.replace_with_const(*place) {
*rvalue = Rvalue::Use(operand);
}
} else {
// Const prop failed, so erase the destination, ensuring that whatever happens
// from here on, does not know about the previous value.
@ -919,45 +829,6 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
}
}
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
self.super_terminator(terminator, location);
match &mut terminator.kind {
TerminatorKind::Assert { expected, ref mut cond, .. } => {
if let Some(ref value) = self.eval_operand(&cond)
&& let Ok(value_const) = self.ecx.read_scalar(&value)
&& self.should_const_prop(value)
{
trace!("assertion on {:?} should be {:?}", value, expected);
*cond = self.operand_from_scalar(value_const, self.tcx.types.bool);
}
}
TerminatorKind::SwitchInt { ref mut discr, .. } => {
// FIXME: This is currently redundant with `visit_operand`, but sadly
// always visiting operands currently causes a perf regression in LLVM codegen, so
// `visit_operand` currently only runs for propagates places for `mir_opt_level=4`.
self.propagate_operand(discr)
}
// None of these have Operands to const-propagate.
TerminatorKind::Goto { .. }
| TerminatorKind::Resume
| TerminatorKind::Terminate
| TerminatorKind::Return
| TerminatorKind::Unreachable
| TerminatorKind::Drop { .. }
| TerminatorKind::Yield { .. }
| TerminatorKind::GeneratorDrop
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::InlineAsm { .. } => {}
// Every argument in our function calls have already been propagated in `visit_operand`.
//
// NOTE: because LLVM codegen gives slight performance regressions with it, so this is
// gated on `mir_opt_level=3`.
TerminatorKind::Call { .. } => {}
}
}
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
self.super_basic_block_data(block, data);

View File

@ -26,8 +26,9 @@
StorageLive(_4);
StorageLive(_5);
- _5 = _1;
- _4 = foo(move _5) -> [return: bb1, unwind unreachable];
+ _5 = const 1_u8;
_4 = foo(move _5) -> [return: bb1, unwind unreachable];
+ _4 = foo(const 1_u8) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -26,8 +26,9 @@
StorageLive(_4);
StorageLive(_5);
- _5 = _1;
- _4 = foo(move _5) -> [return: bb1, unwind continue];
+ _5 = const 1_u8;
_4 = foo(move _5) -> [return: bb1, unwind continue];
+ _4 = foo(const 1_u8) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -23,7 +23,7 @@ fn main() -> () {
StorageLive(_4);
StorageLive(_5);
_5 = const 1_u8;
_4 = foo(move _5) -> [return: bb1, unwind unreachable];
_4 = foo(const 1_u8) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -23,7 +23,7 @@ fn main() -> () {
StorageLive(_4);
StorageLive(_5);
_5 = const 1_u8;
_4 = foo(move _5) -> [return: bb1, unwind continue];
_4 = foo(const 1_u8) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -38,11 +38,12 @@
+ _5 = const false;
+ _6 = const false;
+ _7 = const false;
+ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind unreachable];
+ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> [success: bb2, unwind unreachable];
}
bb2: {
_2 = Div(const 1_i32, move _3);
- _2 = Div(const 1_i32, move _3);
+ _2 = Div(const 1_i32, const 0_i32);
StorageDead(_3);
_0 = const ();
StorageDead(_2);

View File

@ -38,11 +38,12 @@
+ _5 = const false;
+ _6 = const false;
+ _7 = const false;
+ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind continue];
+ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> [success: bb2, unwind continue];
}
bb2: {
_2 = Div(const 1_i32, move _3);
- _2 = Div(const 1_i32, move _3);
+ _2 = Div(const 1_i32, const 0_i32);
StorageDead(_3);
_0 = const ();
StorageDead(_2);

View File

@ -38,11 +38,12 @@
+ _5 = const false;
+ _6 = const false;
+ _7 = const false;
+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind unreachable];
+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> [success: bb2, unwind unreachable];
}
bb2: {
_2 = Rem(const 1_i32, move _3);
- _2 = Rem(const 1_i32, move _3);
+ _2 = Rem(const 1_i32, const 0_i32);
StorageDead(_3);
_0 = const ();
StorageDead(_2);

View File

@ -38,11 +38,12 @@
+ _5 = const false;
+ _6 = const false;
+ _7 = const false;
+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind continue];
+ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> [success: bb2, unwind continue];
}
bb2: {
_2 = Rem(const 1_i32, move _3);
- _2 = Rem(const 1_i32, move _3);
+ _2 = Rem(const 1_i32, const 0_i32);
StorageDead(_3);
_0 = const ();
StorageDead(_2);

View File

@ -38,7 +38,7 @@
- _8 = Lt(_6, _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -38,7 +38,7 @@
- _8 = Lt(_6, _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -38,7 +38,7 @@
- _8 = Lt(_6, _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -38,7 +38,7 @@
- _8 = Lt(_6, _7);
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
+ _8 = const false;
+ assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -24,9 +24,10 @@
StorageLive(_3);
- _4 = SizeOf(i32);
- _5 = AlignOf(i32);
- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> [return: bb1, unwind unreachable];
+ _4 = const 4_usize;
+ _5 = const 4_usize;
_6 = alloc::alloc::exchange_malloc(move _4, move _5) -> [return: bb1, unwind unreachable];
+ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -24,9 +24,10 @@
StorageLive(_3);
- _4 = SizeOf(i32);
- _5 = AlignOf(i32);
- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> [return: bb1, unwind continue];
+ _4 = const 4_usize;
+ _5 = const 4_usize;
_6 = alloc::alloc::exchange_malloc(move _4, move _5) -> [return: bb1, unwind continue];
+ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -8,8 +8,9 @@
bb0: {
StorageLive(_1);
_1 = const _;
- _1 = const _;
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
+ _1 = const false;
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
}

View File

@ -8,8 +8,9 @@
bb0: {
StorageLive(_1);
_1 = const _;
- _1 = const _;
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
+ _1 = const false;
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
}

View File

@ -18,7 +18,7 @@
- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind unreachable];
+ _2 = const 2_u8;
+ _3 = const (3_u8, false);
+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind unreachable];
+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -18,7 +18,7 @@
- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind continue];
+ _2 = const 2_u8;
+ _3 = const (3_u8, false);
+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind continue];
+ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -23,7 +23,7 @@
- _4 = CheckedAdd(_2, _3);
- assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
+ _4 = const (0_u8, true);
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -23,7 +23,7 @@
- _4 = CheckedAdd(_2, _3);
- assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
+ _4 = const (0_u8, true);
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
+ assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -43,8 +43,9 @@
StorageLive(_5);
_5 = InvalidTag { int: const 4_u32 };
- _4 = (_5.1: E);
- _3 = [move _4];
+ _4 = const Scalar(0x00000004): E;
_3 = [move _4];
+ _3 = [const Scalar(0x00000004): E];
StorageDead(_4);
StorageDead(_5);
nop;

View File

@ -8,8 +8,10 @@
bb0: {
StorageLive(_2);
_2 = (const (), const 0_u8, const 0_u8);
_1 = encode(move _2) -> [return: bb1, unwind unreachable];
- _2 = (const (), const 0_u8, const 0_u8);
- _1 = encode(move _2) -> [return: bb1, unwind unreachable];
+ _2 = const ((), 0_u8, 0_u8);
+ _1 = encode(const ((), 0_u8, 0_u8)) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -8,8 +8,10 @@
bb0: {
StorageLive(_2);
_2 = (const (), const 0_u8, const 0_u8);
_1 = encode(move _2) -> [return: bb1, unwind continue];
- _2 = (const (), const 0_u8, const 0_u8);
- _1 = encode(move _2) -> [return: bb1, unwind continue];
+ _2 = const ((), 0_u8, 0_u8);
+ _1 = encode(const ((), 0_u8, 0_u8)) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -11,10 +11,12 @@
StorageLive(_2);
StorageLive(_3);
- _3 = (const 1_u8, const 2_u8);
- _2 = (move _3,);
+ _3 = const (1_u8, 2_u8);
_2 = (move _3,);
+ _2 = const ((1_u8, 2_u8),);
StorageDead(_3);
_1 = test(move _2) -> [return: bb1, unwind unreachable];
- _1 = test(move _2) -> [return: bb1, unwind unreachable];
+ _1 = test(const ((1_u8, 2_u8),)) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -11,10 +11,12 @@
StorageLive(_2);
StorageLive(_3);
- _3 = (const 1_u8, const 2_u8);
- _2 = (move _3,);
+ _3 = const (1_u8, 2_u8);
_2 = (move _3,);
+ _2 = const ((1_u8, 2_u8),);
StorageDead(_3);
_1 = test(move _2) -> [return: bb1, unwind continue];
- _1 = test(move _2) -> [return: bb1, unwind continue];
+ _1 = test(const ((1_u8, 2_u8),)) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -23,7 +23,7 @@
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ _4 = const 5000_usize;
+ _5 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -28,8 +28,9 @@
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+ _2 = const 4_usize;
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
}
bb1: {
@ -37,8 +38,9 @@
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+ _4 = const 0_usize;
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
}
bb2: {
@ -46,8 +48,9 @@
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Alpha, [2, 0]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 2_usize;
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
}
bb3: {
@ -55,8 +58,9 @@
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Alpha, [2, 1]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 3_usize;
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
}
bb4: {

View File

@ -28,8 +28,9 @@
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+ _2 = const 4_usize;
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
}
bb1: {
@ -37,8 +38,9 @@
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+ _4 = const 0_usize;
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
}
bb2: {
@ -46,8 +48,9 @@
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Alpha, [2, 0]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 2_usize;
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
}
bb3: {
@ -55,8 +58,9 @@
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Alpha, [2, 1]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 3_usize;
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
}
bb4: {

View File

@ -25,7 +25,7 @@
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -25,7 +25,7 @@
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -25,7 +25,7 @@
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
}
bb1: {

View File

@ -25,7 +25,7 @@
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
+ _5 = const 8_usize;
+ _6 = const true;
+ assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
}
bb1: {

View File

@ -16,8 +16,9 @@
StorageLive(_2);
StorageLive(_3);
- _3 = _1;
- _2 = consume(move _3) -> [return: bb1, unwind unreachable];
+ _3 = const 1_u32;
_2 = consume(move _3) -> [return: bb1, unwind unreachable];
+ _2 = consume(const 1_u32) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -16,8 +16,9 @@
StorageLive(_2);
StorageLive(_3);
- _3 = _1;
- _2 = consume(move _3) -> [return: bb1, unwind continue];
+ _3 = const 1_u32;
_2 = consume(move _3) -> [return: bb1, unwind continue];
+ _2 = consume(const 1_u32) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -30,7 +30,7 @@
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _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 {}", move _7, _6) -> [success: bb1, unwind unreachable];
+ 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: {

View File

@ -30,7 +30,7 @@
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _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 {}", move _7, _6) -> [success: bb1, unwind continue];
+ 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: {

View File

@ -30,7 +30,7 @@
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _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 {}", move _7, _6) -> [success: bb1, unwind unreachable];
+ 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: {

View File

@ -30,7 +30,7 @@
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _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 {}", move _7, _6) -> [success: bb1, unwind continue];
+ 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: {

View File

@ -17,8 +17,9 @@
StorageLive(_2);
StorageLive(_3);
- _3 = _1;
- _2 = consume(move _3) -> [return: bb1, unwind unreachable];
+ _3 = const (1_u32, 2_u32);
_2 = consume(move _3) -> [return: bb1, unwind unreachable];
+ _2 = consume(const (1_u32, 2_u32)) -> [return: bb1, unwind unreachable];
}
bb1: {

View File

@ -17,8 +17,9 @@
StorageLive(_2);
StorageLive(_3);
- _3 = _1;
- _2 = consume(move _3) -> [return: bb1, unwind continue];
+ _3 = const (1_u32, 2_u32);
_2 = consume(move _3) -> [return: bb1, unwind continue];
+ _2 = consume(const (1_u32, 2_u32)) -> [return: bb1, unwind continue];
}
bb1: {

View File

@ -12,7 +12,6 @@
+ debug rhs => _4;
+ let mut _5: u16;
+ let mut _6: bool;
+ let mut _7: u32;
+ scope 2 {
+ }
+ }
@ -28,10 +27,7 @@
- bb1: {
+ StorageLive(_5);
+ StorageLive(_6);
+ StorageLive(_7);
+ _7 = const 65535_u32;
+ _6 = Le(_4, move _7);
+ StorageDead(_7);
+ _6 = Le(_4, const 65535_u32);
+ assume(move _6);
+ StorageDead(_6);
+ _5 = _4 as u16 (IntToInt);

View File

@ -12,7 +12,6 @@
+ debug rhs => _4;
+ let mut _5: u16;
+ let mut _6: bool;
+ let mut _7: u32;
+ scope 2 {
+ }
+ }
@ -28,10 +27,7 @@
- bb1: {
+ StorageLive(_5);
+ StorageLive(_6);
+ StorageLive(_7);
+ _7 = const 65535_u32;
+ _6 = Le(_4, move _7);
+ StorageDead(_7);
+ _6 = Le(_4, const 65535_u32);
+ assume(move _6);
+ StorageDead(_6);
+ _5 = _4 as u16 (IntToInt);

View File

@ -7,25 +7,21 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
debug self => _1;
debug rhs => _2;
let mut _3: u32;
let mut _4: bool;
let mut _5: u16;
let mut _3: bool;
let mut _4: u16;
scope 2 {
}
}
bb0: {
StorageLive(_5);
StorageLive(_4);
StorageLive(_3);
_3 = const 65535_u32;
_4 = Le(_2, move _3);
_3 = Le(_2, const 65535_u32);
assume(move _3);
StorageDead(_3);
assume(move _4);
_4 = _2 as u16 (IntToInt);
_0 = ShlUnchecked(_1, move _4);
StorageDead(_4);
_5 = _2 as u16 (IntToInt);
_0 = ShlUnchecked(_1, move _5);
StorageDead(_5);
return;
}
}

View File

@ -7,25 +7,21 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 {
scope 1 (inlined core::num::<impl u16>::unchecked_shl) {
debug self => _1;
debug rhs => _2;
let mut _3: u32;
let mut _4: bool;
let mut _5: u16;
let mut _3: bool;
let mut _4: u16;
scope 2 {
}
}
bb0: {
StorageLive(_5);
StorageLive(_4);
StorageLive(_3);
_3 = const 65535_u32;
_4 = Le(_2, move _3);
_3 = Le(_2, const 65535_u32);
assume(move _3);
StorageDead(_3);
assume(move _4);
_4 = _2 as u16 (IntToInt);
_0 = ShlUnchecked(_1, move _4);
StorageDead(_4);
_5 = _2 as u16 (IntToInt);
_0 = ShlUnchecked(_1, move _5);
StorageDead(_5);
return;
}
}

View File

@ -12,7 +12,6 @@
+ debug rhs => _4;
+ let mut _5: i16;
+ let mut _6: bool;
+ let mut _7: u32;
+ scope 2 {
+ }
+ }
@ -28,10 +27,7 @@
- bb1: {
+ StorageLive(_5);
+ StorageLive(_6);
+ StorageLive(_7);
+ _7 = const 32767_u32;
+ _6 = Le(_4, move _7);
+ StorageDead(_7);
+ _6 = Le(_4, const 32767_u32);
+ assume(move _6);
+ StorageDead(_6);
+ _5 = _4 as i16 (IntToInt);

View File

@ -12,7 +12,6 @@
+ debug rhs => _4;
+ let mut _5: i16;
+ let mut _6: bool;
+ let mut _7: u32;
+ scope 2 {
+ }
+ }
@ -28,10 +27,7 @@
- bb1: {
+ StorageLive(_5);
+ StorageLive(_6);
+ StorageLive(_7);
+ _7 = const 32767_u32;
+ _6 = Le(_4, move _7);
+ StorageDead(_7);
+ _6 = Le(_4, const 32767_u32);
+ assume(move _6);
+ StorageDead(_6);
+ _5 = _4 as i16 (IntToInt);

View File

@ -7,25 +7,21 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
debug self => _1;
debug rhs => _2;
let mut _3: u32;
let mut _4: bool;
let mut _5: i16;
let mut _3: bool;
let mut _4: i16;
scope 2 {
}
}
bb0: {
StorageLive(_5);
StorageLive(_4);
StorageLive(_3);
_3 = const 32767_u32;
_4 = Le(_2, move _3);
_3 = Le(_2, const 32767_u32);
assume(move _3);
StorageDead(_3);
assume(move _4);
_4 = _2 as i16 (IntToInt);
_0 = ShrUnchecked(_1, move _4);
StorageDead(_4);
_5 = _2 as i16 (IntToInt);
_0 = ShrUnchecked(_1, move _5);
StorageDead(_5);
return;
}
}

View File

@ -7,25 +7,21 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 {
scope 1 (inlined core::num::<impl i16>::unchecked_shr) {
debug self => _1;
debug rhs => _2;
let mut _3: u32;
let mut _4: bool;
let mut _5: i16;
let mut _3: bool;
let mut _4: i16;
scope 2 {
}
}
bb0: {
StorageLive(_5);
StorageLive(_4);
StorageLive(_3);
_3 = const 32767_u32;
_4 = Le(_2, move _3);
_3 = Le(_2, const 32767_u32);
assume(move _3);
StorageDead(_3);
assume(move _4);
_4 = _2 as i16 (IntToInt);
_0 = ShrUnchecked(_1, move _4);
StorageDead(_4);
_5 = _2 as i16 (IntToInt);
_0 = ShrUnchecked(_1, move _5);
StorageDead(_5);
return;
}
}

View File

@ -7,25 +7,24 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
scope 1 (inlined core::num::<impl u32>::checked_shl) {
debug self => _1;
debug rhs => _2;
let mut _7: bool;
let mut _6: bool;
scope 2 {
debug a => _5;
debug b => _6;
debug a => _4;
debug b => _5;
}
scope 3 (inlined core::num::<impl u32>::overflowing_shl) {
debug self => _1;
debug rhs => _2;
let mut _5: u32;
let mut _6: bool;
let mut _4: u32;
let mut _5: bool;
scope 4 (inlined core::num::<impl u32>::wrapping_shl) {
debug self => _1;
debug rhs => _2;
let mut _3: u32;
let mut _4: u32;
scope 5 {
scope 6 (inlined core::num::<impl u32>::unchecked_shl) {
debug self => _1;
debug rhs => _4;
debug rhs => _3;
scope 7 {
}
}
@ -35,26 +34,23 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
}
bb0: {
StorageLive(_5);
StorageLive(_6);
StorageLive(_4);
StorageLive(_5);
StorageLive(_3);
_3 = const 31_u32;
_4 = BitAnd(_2, move _3);
_3 = BitAnd(_2, const 31_u32);
_4 = ShlUnchecked(_1, _3);
StorageDead(_3);
_5 = ShlUnchecked(_1, _4);
StorageDead(_4);
_6 = Ge(_2, const _);
StorageLive(_7);
_7 = unlikely(move _6) -> [return: bb1, unwind unreachable];
_5 = Ge(_2, const _);
StorageLive(_6);
_6 = unlikely(move _5) -> [return: bb1, unwind unreachable];
}
bb1: {
switchInt(move _7) -> [0: bb2, otherwise: bb3];
switchInt(move _6) -> [0: bb2, otherwise: bb3];
}
bb2: {
_0 = Option::<u32>::Some(_5);
_0 = Option::<u32>::Some(_4);
goto -> bb4;
}
@ -64,9 +60,9 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
}
bb4: {
StorageDead(_7);
StorageDead(_6);
StorageDead(_5);
StorageDead(_4);
return;
}
}

View File

@ -2,22 +2,18 @@
fn f_u64() -> () {
let mut _0: ();
let mut _1: u64;
scope 1 (inlined f_dispatch::<u64>) {
debug t => const 0_u64;
let _2: ();
let _1: ();
scope 2 (inlined std::mem::size_of::<u64>) {
}
}
bb0: {
StorageLive(_1);
_1 = const 0_u64;
_2 = f_non_zst::<u64>(move _1) -> [return: bb1, unwind unreachable];
_1 = f_non_zst::<u64>(const 0_u64) -> [return: bb1, unwind unreachable];
}
bb1: {
StorageDead(_1);
return;
}
}