Skip to content

MIR building for match $c { true => $i, _ => $e } is slow #60571

Closed

Description

@Centril

At the time of writing, if $c { $i } else { $e } builds MIR that is simpler and therefore is ~1-3% better in terms of compile times than match $c { $i } else { $e }. However, after the early-opt MIR optimization, they are basically the same.

In #59288 we start desugaring if expressions to match and so if we optimize for the special case of two match arms we can potentially improve compiles times.

cc @oli-obk

Activity

  1. added
    I-compiletimeIssue: Problems and improvements with respect to compile times.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html
    on May 6, 2019
  2. estebank commented on May 10, 2019

    @estebank
    Contributor
  3. added a commit that references this issue on May 11, 2019
  4. added a commit that references this issue on May 26, 2019
  5. danii commented on Jul 9, 2021

    @danii
    Contributor

    May I volunteer in fixing? And can anyone help in pointing to the main file where match MIR is generated?

  6. oli-obk commented on Jul 10, 2021

    @oli-obk
    Contributor

    hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
    cond: self.mirror_expr(cond),
    then: self.mirror_expr(then),
    else_opt: else_opt.map(|el| self.mirror_expr(el)),
    },
    hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
    scrutinee: self.mirror_expr(discr),
    arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
    },
    is the entry point for if and match. we could check whether the discr is of bool type and whether both match arms are plain bool literals without a guard.

  7. c410-f3r commented on Jan 20, 2022

    @c410-f3r
    Contributor

    let chains are now de-sugared into ifs instead of matchs

  8. Mark-Simulacrum commented on Aug 23, 2022

    @Mark-Simulacrum
    Member

    It looks like today the match-generated MIR is basically the same "complexity" at least based on a visual inspection, so I'm going to go ahead and close this -- we can circle back if there's concrete results today that show otherwise.

    For

    pub fn foo_if(foo: bool) -> u32 {
        if foo {
            1
        } else {
            2
        }
    }
    
    pub fn foo_match(foo: bool) -> u32 {
        match foo {
            true => 1,
            false => 2,
        }
    }

    we get:

    $ rustc +nightly t.rs '-Zdump-mir=foo_if|foo_match' --crate-type=lib
    $ cat mir_dump/t.foo_if.000-000.SimplifyCfg-initial.before.mir
    // MIR for `foo_if` before SimplifyCfg-initial
    
    fn foo_if(_1: bool) -> u32 {
        debug foo => _1;                     // in scope 0 at t.rs:1:15: 1:18
        let mut _0: u32;                     // return place in scope 0 at t.rs:1:29: 1:32
        let mut _2: bool;                    // in scope 0 at t.rs:2:8: 2:11
    
        bb0: {
            StorageLive(_2);                 // scope 0 at t.rs:2:8: 2:11
            _2 = _1;                         // scope 0 at t.rs:2:8: 2:11
            switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at t.rs:2:8: 2:11
        }
    
        bb1: {
            _0 = const 1_u32;                // scope 0 at t.rs:3:9: 3:10
            goto -> bb4;                     // scope 0 at t.rs:2:5: 6:6
        }
    
        bb2: {
            goto -> bb3;                     // scope 0 at t.rs:2:8: 2:11
        }
    
        bb3: {
            _0 = const 2_u32;                // scope 0 at t.rs:5:9: 5:10
            goto -> bb4;                     // scope 0 at t.rs:2:5: 6:6
        }
    
        bb4: {
            StorageDead(_2);                 // scope 0 at t.rs:6:5: 6:6
            return;                          // scope 0 at t.rs:7:2: 7:2
        }
    }
    $ cat mir_dump/t.foo_match.000-000.SimplifyCfg-initial.before.mir
    // MIR for `foo_match` before SimplifyCfg-initial
    
    fn foo_match(_1: bool) -> u32 {
        debug foo => _1;                     // in scope 0 at t.rs:9:18: 9:21
        let mut _0: u32;                     // return place in scope 0 at t.rs:9:32: 9:35
    
        bb0: {
            FakeRead(ForMatchedPlace(None), _1); // scope 0 at t.rs:10:11: 10:14
            switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at t.rs:10:5: 10:14
        }
    
        bb1: {
            falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at t.rs:11:9: 11:13
        }
    
        bb2: {
            _0 = const 2_u32;                // scope 0 at t.rs:12:18: 12:19
            goto -> bb4;                     // scope 0 at t.rs:12:18: 12:19
        }
    
        bb3: {
            _0 = const 1_u32;                // scope 0 at t.rs:11:17: 11:18
            goto -> bb4;                     // scope 0 at t.rs:11:17: 11:18
        }
    
        bb4: {
            return;                          // scope 0 at t.rs:14:2: 14:2
        }
    }
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-let-chainsArea: let chains (if-let, while-let, ...)C-enhancementCategory: An issue proposing an enhancement or a PR with one.I-compiletimeIssue: Problems and improvements with respect to compile times.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions