summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_transform/src/instcombine.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:29 +0000
commit631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch)
treea1b87c8f8cad01cf18f7c5f57a08f102771ed303 /compiler/rustc_mir_transform/src/instcombine.rs
parentAdding debian version 1.69.0+dfsg1-1. (diff)
downloadrustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz
rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_transform/src/instcombine.rs')
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs68
1 files changed, 64 insertions, 4 deletions
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index 4182da195..3d06a0a49 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -3,12 +3,14 @@
use crate::MirPass;
use rustc_hir::Mutability;
use rustc_middle::mir::{
- BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
- SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
+ BinOp, Body, CastKind, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem,
+ Rvalue, SourceInfo, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, UnOp,
};
use rustc_middle::ty::layout::ValidityRequirement;
+use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
use rustc_span::symbol::Symbol;
+use rustc_target::abi::FieldIdx;
pub struct InstCombine;
@@ -44,6 +46,7 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
&mut block.terminator.as_mut().unwrap(),
&mut block.statements,
);
+ ctx.combine_duplicate_switch_targets(&mut block.terminator.as_mut().unwrap());
}
}
}
@@ -144,9 +147,53 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
}
fn combine_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
- if let Rvalue::Cast(_kind, operand, ty) = rvalue {
- if operand.ty(self.local_decls, self.tcx) == *ty {
+ if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
+ let operand_ty = operand.ty(self.local_decls, self.tcx);
+ if operand_ty == *cast_ty {
*rvalue = Rvalue::Use(operand.clone());
+ } else if *kind == CastKind::Transmute {
+ // Transmuting an integer to another integer is just a signedness cast
+ if let (ty::Int(int), ty::Uint(uint)) | (ty::Uint(uint), ty::Int(int)) = (operand_ty.kind(), cast_ty.kind())
+ && int.bit_width() == uint.bit_width()
+ {
+ // The width check isn't strictly necessary, as different widths
+ // are UB and thus we'd be allowed to turn it into a cast anyway.
+ // But let's keep the UB around for codegen to exploit later.
+ // (If `CastKind::Transmute` ever becomes *not* UB for mismatched sizes,
+ // then the width check is necessary for big-endian correctness.)
+ *kind = CastKind::IntToInt;
+ return;
+ }
+
+ // Transmuting a fieldless enum to its repr is a discriminant read
+ if let ty::Adt(adt_def, ..) = operand_ty.kind()
+ && adt_def.is_enum()
+ && adt_def.is_payloadfree()
+ && let Some(place) = operand.place()
+ && let Some(repr_int) = adt_def.repr().int
+ && repr_int.to_ty(self.tcx) == *cast_ty
+ {
+ *rvalue = Rvalue::Discriminant(place);
+ return;
+ }
+
+ // Transmuting a transparent struct/union to a field's type is a projection
+ if let ty::Adt(adt_def, substs) = operand_ty.kind()
+ && adt_def.repr().transparent()
+ && (adt_def.is_struct() || adt_def.is_union())
+ && let Some(place) = operand.place()
+ {
+ let variant = adt_def.non_enum_variant();
+ for (i, field) in variant.fields.iter().enumerate() {
+ let field_ty = field.ty(self.tcx, substs);
+ if field_ty == *cast_ty {
+ let place = place.project_deeper(&[ProjectionElem::Field(FieldIdx::from_usize(i), *cast_ty)], self.tcx);
+ let operand = if operand.is_move() { Operand::Move(place) } else { Operand::Copy(place) };
+ *rvalue = Rvalue::Use(operand);
+ return;
+ }
+ }
+ }
}
}
}
@@ -217,6 +264,19 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
terminator.kind = TerminatorKind::Goto { target: destination_block };
}
+ fn combine_duplicate_switch_targets(&self, terminator: &mut Terminator<'tcx>) {
+ let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind
+ else { return };
+
+ let otherwise = targets.otherwise();
+ if targets.iter().any(|t| t.1 == otherwise) {
+ *targets = SwitchTargets::new(
+ targets.iter().filter(|t| t.1 != otherwise),
+ targets.otherwise(),
+ );
+ }
+ }
+
fn combine_intrinsic_assert(
&self,
terminator: &mut Terminator<'tcx>,