New pass to deduplicate blocks

This commit is contained in:
Simon Vandel Sillesen 2020-10-04 15:52:14 +02:00
parent 1e865709a6
commit 2d1e0adfe9
14 changed files with 422 additions and 37 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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>,

View File

@ -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 },

View File

@ -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,

View 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
}

View File

@ -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.

View File

@ -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),

View File

@ -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

View File

@ -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
}
}

View 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");
}

View File

@ -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: {