mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
New pass to deduplicate blocks
This commit is contained in:
parent
1e865709a6
commit
2d1e0adfe9
@ -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<char>, 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,
|
||||
|
@ -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<T>` 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,
|
||||
|
@ -92,7 +92,7 @@ impl From<InjectedExpressionId> 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,
|
||||
|
@ -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<O> {
|
||||
BoundsCheck { len: O, index: O },
|
||||
Overflow(BinOp, O, O),
|
||||
@ -1174,7 +1174,17 @@ pub enum AssertKind<O> {
|
||||
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<CodeRegion>,
|
||||
@ -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<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
|
||||
}
|
||||
|
||||
#[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<ProjectionKind>,
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
193
compiler/rustc_mir/src/transform/deduplicate_blocks.rs
Normal file
193
compiler/rustc_mir/src/transform/deduplicate_blocks.rs
Normal file
@ -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<BasicBlock, BasicBlock>,
|
||||
}
|
||||
|
||||
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<BasicBlock, BasicBlock> {
|
||||
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<H: Hasher>(&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<Item = &'a Statement<'tcx>>,
|
||||
) 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<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'tcx>) {
|
||||
match rvalue {
|
||||
Rvalue::Use(op) => operand_hash(hasher, op),
|
||||
x => x.hash(hasher),
|
||||
};
|
||||
}
|
||||
|
||||
fn operand_hash<H: Hasher>(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
|
||||
}
|
@ -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() {
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
|
@ -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<A> <: T<B> iff A <: B -- e.g., function return type
|
||||
Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
|
||||
|
@ -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::<impl 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(<ZST>)) }
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
13
src/test/mir-opt/deduplicate_blocks.rs
Normal file
13
src/test/mir-opt/deduplicate_blocks.rs
Normal file
@ -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");
|
||||
}
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user