Rollup merge of #125893 - cjgillot:gvn-newops, r=oli-obk
Handle all GVN binops in a single place. <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r? <reviewer name> --> Addresses https://github.com/rust-lang/rust/pull/125359/files#r1608185319 r? ``@oli-obk``
This commit is contained in:
commit
33c02c3712
@ -223,7 +223,6 @@ enum Value<'tcx> {
|
|||||||
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
|
NullaryOp(NullOp<'tcx>, Ty<'tcx>),
|
||||||
UnaryOp(UnOp, VnIndex),
|
UnaryOp(UnOp, VnIndex),
|
||||||
BinaryOp(BinOp, VnIndex, VnIndex),
|
BinaryOp(BinOp, VnIndex, VnIndex),
|
||||||
CheckedBinaryOp(BinOp, VnIndex, VnIndex), // FIXME get rid of this, work like MIR instead
|
|
||||||
Cast {
|
Cast {
|
||||||
kind: CastKind,
|
kind: CastKind,
|
||||||
value: VnIndex,
|
value: VnIndex,
|
||||||
@ -508,17 +507,6 @@ fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
|
|||||||
let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?;
|
let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?;
|
||||||
val.into()
|
val.into()
|
||||||
}
|
}
|
||||||
CheckedBinaryOp(bin_op, lhs, rhs) => {
|
|
||||||
let lhs = self.evaluated[lhs].as_ref()?;
|
|
||||||
let lhs = self.ecx.read_immediate(lhs).ok()?;
|
|
||||||
let rhs = self.evaluated[rhs].as_ref()?;
|
|
||||||
let rhs = self.ecx.read_immediate(rhs).ok()?;
|
|
||||||
let val = self
|
|
||||||
.ecx
|
|
||||||
.binary_op(bin_op.wrapping_to_overflowing().unwrap(), &lhs, &rhs)
|
|
||||||
.ok()?;
|
|
||||||
val.into()
|
|
||||||
}
|
|
||||||
Cast { kind, value, from: _, to } => match kind {
|
Cast { kind, value, from: _, to } => match kind {
|
||||||
CastKind::IntToInt | CastKind::IntToFloat => {
|
CastKind::IntToInt | CastKind::IntToFloat => {
|
||||||
let value = self.evaluated[value].as_ref()?;
|
let value = self.evaluated[value].as_ref()?;
|
||||||
@ -829,17 +817,10 @@ fn simplify_rvalue(
|
|||||||
let lhs = lhs?;
|
let lhs = lhs?;
|
||||||
let rhs = rhs?;
|
let rhs = rhs?;
|
||||||
|
|
||||||
if let Some(op) = op.overflowing_to_wrapping() {
|
if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) {
|
||||||
if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
|
return Some(value);
|
||||||
return Some(value);
|
|
||||||
}
|
|
||||||
Value::CheckedBinaryOp(op, lhs, rhs)
|
|
||||||
} else {
|
|
||||||
if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
|
|
||||||
return Some(value);
|
|
||||||
}
|
|
||||||
Value::BinaryOp(op, lhs, rhs)
|
|
||||||
}
|
}
|
||||||
|
Value::BinaryOp(op, lhs, rhs)
|
||||||
}
|
}
|
||||||
Rvalue::UnaryOp(op, ref mut arg) => {
|
Rvalue::UnaryOp(op, ref mut arg) => {
|
||||||
let arg = self.simplify_operand(arg, location)?;
|
let arg = self.simplify_operand(arg, location)?;
|
||||||
@ -970,7 +951,6 @@ fn simplify_unary(&mut self, op: UnOp, value: VnIndex) -> Option<VnIndex> {
|
|||||||
fn simplify_binary(
|
fn simplify_binary(
|
||||||
&mut self,
|
&mut self,
|
||||||
op: BinOp,
|
op: BinOp,
|
||||||
checked: bool,
|
|
||||||
lhs_ty: Ty<'tcx>,
|
lhs_ty: Ty<'tcx>,
|
||||||
lhs: VnIndex,
|
lhs: VnIndex,
|
||||||
rhs: VnIndex,
|
rhs: VnIndex,
|
||||||
@ -999,22 +979,39 @@ fn simplify_binary(
|
|||||||
use Either::{Left, Right};
|
use Either::{Left, Right};
|
||||||
let a = as_bits(lhs).map_or(Right(lhs), Left);
|
let a = as_bits(lhs).map_or(Right(lhs), Left);
|
||||||
let b = as_bits(rhs).map_or(Right(rhs), Left);
|
let b = as_bits(rhs).map_or(Right(rhs), Left);
|
||||||
|
|
||||||
let result = match (op, a, b) {
|
let result = match (op, a, b) {
|
||||||
// Neutral elements.
|
// Neutral elements.
|
||||||
(BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p))
|
(
|
||||||
|
BinOp::Add
|
||||||
|
| BinOp::AddWithOverflow
|
||||||
|
| BinOp::AddUnchecked
|
||||||
|
| BinOp::BitOr
|
||||||
|
| BinOp::BitXor,
|
||||||
|
Left(0),
|
||||||
|
Right(p),
|
||||||
|
)
|
||||||
| (
|
| (
|
||||||
BinOp::Add
|
BinOp::Add
|
||||||
|
| BinOp::AddWithOverflow
|
||||||
|
| BinOp::AddUnchecked
|
||||||
| BinOp::BitOr
|
| BinOp::BitOr
|
||||||
| BinOp::BitXor
|
| BinOp::BitXor
|
||||||
| BinOp::Sub
|
| BinOp::Sub
|
||||||
|
| BinOp::SubWithOverflow
|
||||||
|
| BinOp::SubUnchecked
|
||||||
| BinOp::Offset
|
| BinOp::Offset
|
||||||
| BinOp::Shl
|
| BinOp::Shl
|
||||||
| BinOp::Shr,
|
| BinOp::Shr,
|
||||||
Right(p),
|
Right(p),
|
||||||
Left(0),
|
Left(0),
|
||||||
)
|
)
|
||||||
| (BinOp::Mul, Left(1), Right(p))
|
| (BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked, Left(1), Right(p))
|
||||||
| (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p,
|
| (
|
||||||
|
BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::Div,
|
||||||
|
Right(p),
|
||||||
|
Left(1),
|
||||||
|
) => p,
|
||||||
// Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
|
// Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size.
|
||||||
(BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p))
|
(BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p))
|
||||||
if ones == layout.size.truncate(u128::MAX)
|
if ones == layout.size.truncate(u128::MAX)
|
||||||
@ -1023,10 +1020,21 @@ fn simplify_binary(
|
|||||||
p
|
p
|
||||||
}
|
}
|
||||||
// Absorbing elements.
|
// Absorbing elements.
|
||||||
(BinOp::Mul | BinOp::BitAnd, _, Left(0))
|
(
|
||||||
|
BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::BitAnd,
|
||||||
|
_,
|
||||||
|
Left(0),
|
||||||
|
)
|
||||||
| (BinOp::Rem, _, Left(1))
|
| (BinOp::Rem, _, Left(1))
|
||||||
| (
|
| (
|
||||||
BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr,
|
BinOp::Mul
|
||||||
|
| BinOp::MulWithOverflow
|
||||||
|
| BinOp::MulUnchecked
|
||||||
|
| BinOp::Div
|
||||||
|
| BinOp::Rem
|
||||||
|
| BinOp::BitAnd
|
||||||
|
| BinOp::Shl
|
||||||
|
| BinOp::Shr,
|
||||||
Left(0),
|
Left(0),
|
||||||
_,
|
_,
|
||||||
) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
|
) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty),
|
||||||
@ -1038,7 +1046,9 @@ fn simplify_binary(
|
|||||||
self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
|
self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty)
|
||||||
}
|
}
|
||||||
// Sub/Xor with itself.
|
// Sub/Xor with itself.
|
||||||
(BinOp::Sub | BinOp::BitXor, a, b) if a == b => {
|
(BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b)
|
||||||
|
if a == b =>
|
||||||
|
{
|
||||||
self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
|
self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty)
|
||||||
}
|
}
|
||||||
// Comparison:
|
// Comparison:
|
||||||
@ -1052,7 +1062,7 @@ fn simplify_binary(
|
|||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if checked {
|
if op.is_overflowing() {
|
||||||
let false_val = self.insert_bool(false);
|
let false_val = self.insert_bool(false);
|
||||||
Some(self.insert_tuple(vec![result, false_val]))
|
Some(self.insert_tuple(vec![result, false_val]))
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user