diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3550055ac10..1d2f1f694cf 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1979,7 +1979,7 @@ bitflags::bitflags! { } } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, PartialOrd, Encodable, Decodable, Debug, Hash, HashStable_Generic)] pub enum InlineAsmTemplatePiece { String(String), Placeholder { operand_idx: usize, modifier: Option, span: Span }, @@ -2067,7 +2067,7 @@ pub struct InlineAsm { /// Inline assembly dialect. /// /// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`. -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic)] +#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Hash, HashStable_Generic)] pub enum LlvmAsmDialect { Att, Intel, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4df8c44e62b..61586dd1a1c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1281,7 +1281,18 @@ impl Body<'hir> { } /// The type of source expression that caused this generator to be created. -#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)] +#[derive( + Clone, + PartialEq, + PartialOrd, + Eq, + Hash, + HashStable_Generic, + Encodable, + Decodable, + Debug, + Copy +)] pub enum GeneratorKind { /// An explicit `async` block or the body of an async function. Async(AsyncGeneratorKind), @@ -1313,7 +1324,18 @@ impl GeneratorKind { /// /// This helps error messages but is also used to drive coercions in /// type-checking (see #60424). -#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)] +#[derive( + Clone, + PartialEq, + PartialOrd, + Eq, + Hash, + HashStable_Generic, + Encodable, + Decodable, + Debug, + Copy +)] pub enum AsyncGeneratorKind { /// An explicit `async` block written by the user. Block, @@ -2308,7 +2330,7 @@ pub struct InlineAsm<'hir> { pub line_spans: &'hir [Span], } -#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)] pub struct LlvmInlineAsmOutput { pub constraint: Symbol, pub is_rw: bool, @@ -2319,7 +2341,7 @@ pub struct LlvmInlineAsmOutput { // NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR, // it needs to be `Clone` and `Decodable` and use plain `Vec` instead of // arena-allocated slice. -#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, PartialEq)] +#[derive(Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)] pub struct LlvmInlineAsmInner { pub asm: Symbol, pub asm_str_style: StrStyle, diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 95096d0fb71..eae02a8cbfc 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -92,7 +92,7 @@ impl From for ExpressionOperandId { } } -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub enum CoverageKind { Counter { function_source_hash: u64, @@ -148,7 +148,18 @@ impl Debug for CoverageKind { } } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, PartialEq, Eq, PartialOrd, Ord)] +#[derive( + Clone, + TyEncodable, + TyDecodable, + Hash, + HashStable, + TypeFoldable, + PartialEq, + Eq, + PartialOrd, + Ord +)] pub struct CodeRegion { pub file_name: Symbol, pub start_line: u32, @@ -167,7 +178,7 @@ impl Debug for CodeRegion { } } -#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub enum Op { Subtract, Add, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 718e81c84ed..84766fc7861 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -594,7 +594,7 @@ impl SourceInfo { // Borrow kinds #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(HashStable)] +#[derive(Hash, HashStable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -1163,7 +1163,7 @@ pub struct BasicBlockData<'tcx> { } /// Information about an assertion failure. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] pub enum AssertKind { BoundsCheck { len: O, index: O }, Overflow(BinOp, O, O), @@ -1174,7 +1174,17 @@ pub enum AssertKind { ResumedAfterPanic(GeneratorKind), } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive( + Clone, + Debug, + PartialEq, + PartialOrd, + TyEncodable, + TyDecodable, + Hash, + HashStable, + TypeFoldable +)] pub enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, @@ -1449,7 +1459,7 @@ impl Statement<'_> { } } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Place. Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>), @@ -1517,7 +1527,7 @@ impl<'tcx> StatementKind<'tcx> { } /// Describes what kind of retag is to be performed. -#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)] +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)] pub enum RetagKind { /// The initial retag when entering a function. FnEntry, @@ -1530,7 +1540,7 @@ pub enum RetagKind { } /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. -#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, HashStable, PartialEq)] +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] pub enum FakeReadCause { /// Inject a fake read of the borrowed input at the end of each guards /// code. @@ -1572,7 +1582,7 @@ pub enum FakeReadCause { ForIndex, } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub struct LlvmInlineAsm<'tcx> { pub asm: hir::LlvmInlineAsmInner, pub outputs: Box<[Place<'tcx>]>, @@ -1619,7 +1629,7 @@ impl Debug for Statement<'_> { } } -#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, HashStable, TypeFoldable)] +#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] pub struct Coverage { pub kind: CoverageKind, pub code_region: Option, @@ -1915,7 +1925,7 @@ pub struct SourceScopeLocalData { /// These are values that can appear inside an rvalue. They are intentionally /// limited to prevent rvalues from being nested in one another. -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)] pub enum Operand<'tcx> { /// Copy: The value must be available for use afterwards. /// @@ -2023,7 +2033,7 @@ impl<'tcx> Operand<'tcx> { /////////////////////////////////////////////////////////////////////////// /// Rvalues -#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub enum Rvalue<'tcx> { /// x (either a move or copy, depending on type of x) Use(Operand<'tcx>), @@ -2069,13 +2079,13 @@ pub enum Rvalue<'tcx> { Aggregate(Box>, Vec>), } -#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum CastKind { Misc, Pointer(PointerCast), } -#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum AggregateKind<'tcx> { /// The type is of the element Array(Ty<'tcx>), @@ -2092,7 +2102,7 @@ pub enum AggregateKind<'tcx> { Generator(DefId, SubstsRef<'tcx>, hir::Movability), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum BinOp { /// The `+` operator (addition) Add, @@ -2137,7 +2147,7 @@ impl BinOp { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum NullOp { /// Returns the size of a value of that type SizeOf, @@ -2145,7 +2155,7 @@ pub enum NullOp { Box, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum UnOp { /// The `!` operator for logical inversion Not, @@ -2315,7 +2325,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// this does not necessarily mean that they are `==` in Rust. In /// particular, one must be wary of `NaN`! -#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)] pub struct Constant<'tcx> { pub span: Span, @@ -2449,7 +2459,7 @@ impl<'tcx> UserTypeProjections { /// * `let (x, _): T = ...` -- here, the `projs` vector would contain /// `field[0]` (aka `.0`), indicating that the type of `s` is /// determined by finding the type of the `.0` field from `T`. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, pub projs: Vec, diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 709ffc3049a..b51a87f63b2 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -17,7 +17,7 @@ use std::slice; pub use super::query::*; -#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] +#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] pub struct SwitchTargets { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. @@ -98,7 +98,7 @@ impl<'a> Iterator for SwitchTargetsIter<'a> { impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {} -#[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] pub enum TerminatorKind<'tcx> { /// Block should have one successor in the graph; we jump there. Goto { target: BasicBlock }, diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 89d0e139551..a50dda69a0f 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -6,7 +6,7 @@ use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; use rustc_span::Span; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum PointerCast { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs new file mode 100644 index 00000000000..5f09159e91b --- /dev/null +++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs @@ -0,0 +1,193 @@ +//! This pass finds basic blocks that are completely equal, +//! and replaces all uses with just one of them. + +use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher}; + +use crate::transform::MirPass; + +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +use super::simplify::simplify_cfg; + +pub struct DeduplicateBlocks; + +impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + return; + } + debug!("Running DeduplicateBlocks on `{:?}`", body.source); + let duplicates = find_duplicates(body); + let has_opts_to_apply = !duplicates.is_empty(); + + if has_opts_to_apply { + let mut opt_applier = OptApplier { tcx, duplicates }; + opt_applier.visit_body(body); + simplify_cfg(body); + } + } +} + +struct OptApplier<'tcx> { + tcx: TyCtxt<'tcx>, + duplicates: FxHashMap, +} + +impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + for target in terminator.successors_mut() { + if let Some(replacement) = self.duplicates.get(target) { + debug!("SUCCESS: Replacing: `{:?}` with `{:?}`", target, replacement); + *target = *replacement; + } + } + + self.super_terminator(terminator, location); + } +} + +fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap { + let mut duplicates = FxHashMap::default(); + + let bbs_to_go_through = + body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count(); + + let mut same_hashes = + FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default()); + + // Go through the basic blocks backwards. This means that in case of duplicates, + // we can use the basic block with the highest index as the replacement for all lower ones. + // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes. + // Then we will see that bb2 is a duplicate of bb3, + // and insert bb2 with the replacement bb3 in the duplicates list. + // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list + // with replacement bb3. + // When the duplicates are removed, we will end up with only bb3. + for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup) + { + // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks + // that are unlikely to have duplicates, we stop early. The early bail number has been + // found experimentally by eprintln while compiling the crates in the rustc-perf suite. + if bbd.statements.len() > 10 { + continue; + } + + let to_hash = BasicBlockHashable { basic_block_data: bbd }; + let entry = same_hashes.entry(to_hash); + match entry { + Entry::Occupied(occupied) => { + // The basic block was already in the hashmap, which means we have a duplicate + let value = *occupied.get(); + debug!("Inserting {:?} -> {:?}", bb, value); + duplicates.insert(bb, value).expect_none("key was already inserted"); + } + Entry::Vacant(vacant) => { + vacant.insert(bb); + } + } + } + + duplicates +} + +struct BasicBlockHashable<'tcx, 'a> { + basic_block_data: &'a BasicBlockData<'tcx>, +} + +impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> { + fn hash(&self, state: &mut H) { + hash_statements(state, self.basic_block_data.statements.iter()); + // Note that since we only hash the kind, we lose span information if we deduplicate the blocks + self.basic_block_data.terminator().kind.hash(state); + } +} + +impl<'tcx, 'a> Eq for BasicBlockHashable<'tcx, 'a> {} + +impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> { + fn eq(&self, other: &Self) -> bool { + self.basic_block_data.statements.len() == other.basic_block_data.statements.len() + && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind + && self + .basic_block_data + .statements + .iter() + .zip(&other.basic_block_data.statements) + .all(|(x, y)| statement_eq(&x.kind, &y.kind)) + } +} + +fn hash_statements<'a, 'tcx, H: Hasher>( + hasher: &mut H, + iter: impl Iterator>, +) where + 'tcx: 'a, +{ + for stmt in iter { + statement_hash(hasher, &stmt.kind); + } +} + +fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) { + match stmt { + StatementKind::Assign(box (place, rvalue)) => { + place.hash(hasher); + rvalue_hash(hasher, rvalue) + } + x => x.hash(hasher), + }; +} + +fn rvalue_hash(hasher: &mut H, rvalue: &Rvalue<'tcx>) { + match rvalue { + Rvalue::Use(op) => operand_hash(hasher, op), + x => x.hash(hasher), + }; +} + +fn operand_hash(hasher: &mut H, operand: &Operand<'tcx>) { + match operand { + Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher), + x => x.hash(hasher), + }; +} + +fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> bool { + let res = match (lhs, rhs) { + ( + StatementKind::Assign(box (place, rvalue)), + StatementKind::Assign(box (place2, rvalue2)), + ) => place == place2 && rvalue_eq(rvalue, rvalue2), + (x, y) => x == y, + }; + debug!("statement_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); + res +} + +fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool { + let res = match (lhs, rhs) { + (Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2), + (x, y) => x == y, + }; + debug!("rvalue_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); + res +} + +fn operand_eq(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool { + let res = match (lhs, rhs) { + ( + Operand::Constant(box Constant { user_ty: _, literal, span: _ }), + Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }), + ) => literal == literal2, + (x, y) => x == y, + }; + debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res); + res +} diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index d9b004978e7..92b4ae397ae 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -46,7 +46,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { let def_id = body.source.def_id(); let param_env = tcx.param_env(def_id); - + let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); let mut should_cleanup = false; 'outer: for bb_idx in bbs.indices() { diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 2786127513d..6e264240f2e 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -25,6 +25,7 @@ pub mod const_debuginfo; pub mod const_prop; pub mod coverage; pub mod deaggregator; +pub mod deduplicate_blocks; pub mod dest_prop; pub mod dump_mir; pub mod early_otherwise_branch; @@ -510,6 +511,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &const_debuginfo::ConstDebugInfo, &simplify::SimplifyLocals, &multiple_return_terminators::MultipleReturnTerminators, + &deduplicate_blocks::DeduplicateBlocks, ]; // Optimizations to run even if mir optimizations have been disabled. diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 3c65c84b0de..dfc0989a9f8 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -13,7 +13,7 @@ macro_rules! def_reg_class { $class:ident, )* }) => { - #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] + #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] #[allow(non_camel_case_types)] pub enum $arch_regclass { $($class,)* @@ -62,7 +62,7 @@ macro_rules! def_regs { )* }) => { #[allow(unreachable_code)] - #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] + #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, PartialOrd, Hash, HashStable_Generic)] #[allow(non_camel_case_types)] pub enum $arch_reg { $($reg,)* @@ -207,7 +207,18 @@ impl FromStr for InlineAsmArch { } } -#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] +#[derive( + Copy, + Clone, + Encodable, + Decodable, + Debug, + Eq, + PartialEq, + PartialOrd, + Hash, + HashStable_Generic +)] pub enum InlineAsmReg { X86(X86InlineAsmReg), Arm(ArmInlineAsmReg), @@ -313,7 +324,18 @@ impl InlineAsmReg { } } -#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] +#[derive( + Copy, + Clone, + Encodable, + Decodable, + Debug, + Eq, + PartialEq, + PartialOrd, + Hash, + HashStable_Generic +)] pub enum InlineAsmRegClass { X86(X86InlineAsmRegClass), Arm(ArmInlineAsmRegClass), @@ -458,7 +480,18 @@ impl InlineAsmRegClass { } } -#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] +#[derive( + Copy, + Clone, + Encodable, + Decodable, + Debug, + Eq, + PartialEq, + PartialOrd, + Hash, + HashStable_Generic +)] pub enum InlineAsmRegOrRegClass { Reg(InlineAsmReg), RegClass(InlineAsmRegClass), diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 7e70af21c03..fccd8b795ef 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -427,7 +427,7 @@ impl UnifyKey for FloatVid { } } -#[derive(Copy, Clone, PartialEq, Decodable, Encodable)] +#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type Invariant, // T <: T iff B == A -- e.g., type of mutable cell diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff new file mode 100644 index 00000000000..b6e4469e870 --- /dev/null +++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff @@ -0,0 +1,101 @@ +- // MIR for `is_line_doc_comment_2` before DeduplicateBlocks ++ // MIR for `is_line_doc_comment_2` after DeduplicateBlocks + + fn is_line_doc_comment_2(_1: &str) -> bool { + debug s => _1; // in scope 0 at $DIR/deduplicate_blocks.rs:2:36: 2:37 + let mut _0: bool; // return place in scope 0 at $DIR/deduplicate_blocks.rs:2:48: 2:52 + let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + let mut _3: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + let mut _4: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + let mut _5: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + let mut _6: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + scope 1 (inlined core::str::::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23 + debug self => _7; // in scope 1 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + let mut _7: &str; // in scope 1 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + scope 2 { + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + _7 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 +- _2 = transmute::<&str, &[u8]>(move _7) -> bb14; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 ++ _2 = transmute::<&str, &[u8]>(move _7) -> bb12; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + // mir::Constant + // + span: $DIR/deduplicate_blocks.rs:3:11: 3:23 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {std::intrinsics::transmute::<&str, &[u8]>}, val: Value(Scalar()) } + } + + bb1: { + switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:10: 4:14 + } + + bb2: { + switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:16: 4:20 + } + + bb3: { + switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:22: 4:26 + } + + bb4: { +- switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:28: 4:32 ++ switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:4:28: 4:32 + } + + bb5: { + _3 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + _4 = Ge(move _3, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + switchInt(move _4) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 + } + + bb6: { + switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:10: 5:14 + } + + bb7: { + switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:16: 5:20 + } + + bb8: { +- switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:22: 5:26 ++ switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:5:22: 5:26 + } + + bb9: { +- _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:7:14: 7:19 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6 +- } +- +- bb10: { + _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:4:41: 4:46 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6 ++ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6 + } + +- bb11: { +- _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:5:35: 5:39 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6 +- } +- +- bb12: { ++ bb10: { + _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:6:35: 6:39 +- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6 ++ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:3:5: 8:6 + } + +- bb13: { ++ bb11: { + StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:9:1: 9:2 + return; // scope 0 at $DIR/deduplicate_blocks.rs:9:2: 9:2 + } + +- bb14: { ++ bb12: { + _5 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + _6 = Ge(move _5, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + switchInt(move _6) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 + } + } + diff --git a/src/test/mir-opt/deduplicate_blocks.rs b/src/test/mir-opt/deduplicate_blocks.rs new file mode 100644 index 00000000000..f8f7361dc0d --- /dev/null +++ b/src/test/mir-opt/deduplicate_blocks.rs @@ -0,0 +1,13 @@ +// EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff +pub const fn is_line_doc_comment_2(s: &str) -> bool { + match s.as_bytes() { + [b'/', b'/', b'/', b'/', ..] => false, + [b'/', b'/', b'/', ..] => true, + [b'/', b'/', b'!', ..] => true, + _ => false, + } +} + +fn main() { + is_line_doc_comment_2("asd"); +} diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 07994eb3c16..e945629b613 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -46,7 +46,7 @@ + _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_7); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + _7 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22 ++ goto -> bb1; // scope 4 at $DIR/inline-diverging.rs:22:5: 22:22 } bb1: {