]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/simplify_branches.rs
a1c3fec32fcf1b202c03f363fdae9d4e1f2565bd
[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, ParamEnv};
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<'a>(&'a self) -> Cow<'a, str> {
19         Cow::Borrowed(&self.label)
20     }
21
22     fn run_pass<'tcx>(
23         &self,
24         tcx: TyCtxt<'tcx, 'tcx>,
25         _src: MirSource<'tcx>,
26         body: &mut Body<'tcx>,
27     ) {
28         for block in body.basic_blocks_mut() {
29             let terminator = block.terminator_mut();
30             terminator.kind = match terminator.kind {
31                 TerminatorKind::SwitchInt {
32                     discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, ..
33                 } => {
34                     let switch_ty = ParamEnv::empty().and(switch_ty);
35                     let constant = c.literal.assert_bits(tcx, switch_ty);
36                     if let Some(constant) = constant {
37                         let (otherwise, targets) = targets.split_last().unwrap();
38                         let mut ret = TerminatorKind::Goto { target: *otherwise };
39                         for (&v, t) in values.iter().zip(targets.iter()) {
40                             if v == constant {
41                                 ret = TerminatorKind::Goto { target: *t };
42                                 break;
43                             }
44                         }
45                         ret
46                     } else {
47                         continue
48                     }
49                 },
50                 TerminatorKind::Assert {
51                     target, cond: Operand::Constant(ref c), expected, ..
52                 } if (c.literal.assert_bool(tcx) == Some(true)) == expected =>
53                     TerminatorKind::Goto { target },
54                 TerminatorKind::FalseEdges { real_target, .. } => {
55                     TerminatorKind::Goto { target: real_target }
56                 },
57                 TerminatorKind::FalseUnwind { real_target, .. } => {
58                     TerminatorKind::Goto { target: real_target }
59                 },
60                 _ => continue
61             };
62         }
63     }
64 }