]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/simplify_branches.rs
Rollup merge of #63285 - Mark-Simulacrum:rm-await-origin, r=Centril
[rust.git] / src / librustc_mir / transform / simplify_branches.rs
1 //! A pass that simplifies branches when their condition is known.
2
3 use rustc::ty::TyCtxt;
4 use rustc::mir::*;
5 use crate::transform::{MirPass, MirSource};
6
7 use std::borrow::Cow;
8
9 pub struct SimplifyBranches { label: String }
10
11 impl SimplifyBranches {
12     pub fn new(label: &str) -> Self {
13         SimplifyBranches { label: format!("SimplifyBranches-{}", label) }
14     }
15 }
16
17 impl MirPass for SimplifyBranches {
18     fn name(&self) -> Cow<'_, str> {
19         Cow::Borrowed(&self.label)
20     }
21
22     fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
23         let param_env = tcx.param_env(src.def_id());
24         for block in body.basic_blocks_mut() {
25             let terminator = block.terminator_mut();
26             terminator.kind = match terminator.kind {
27                 TerminatorKind::SwitchInt {
28                     discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, ..
29                 } => {
30                     let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
31                     if let Some(constant) = constant {
32                         let (otherwise, targets) = targets.split_last().unwrap();
33                         let mut ret = TerminatorKind::Goto { target: *otherwise };
34                         for (&v, t) in values.iter().zip(targets.iter()) {
35                             if v == constant {
36                                 ret = TerminatorKind::Goto { target: *t };
37                                 break;
38                             }
39                         }
40                         ret
41                     } else {
42                         continue
43                     }
44                 },
45                 TerminatorKind::Assert {
46                     target, cond: Operand::Constant(ref c), expected, ..
47                 } if (c.literal.try_eval_bool(tcx, param_env) == Some(true)) == expected =>
48                     TerminatorKind::Goto { target },
49                 TerminatorKind::FalseEdges { real_target, .. } => {
50                     TerminatorKind::Goto { target: real_target }
51                 },
52                 TerminatorKind::FalseUnwind { real_target, .. } => {
53                     TerminatorKind::Goto { target: real_target }
54                 },
55                 _ => continue
56             };
57         }
58     }
59 }