Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIR: Don't generate 3-armed boolean switch from match. #33583

Merged
merged 1 commit into from
Jun 2, 2016

Conversation

luqmana
Copy link
Member

@luqmana luqmana commented May 12, 2016

Fixes #33540.

Snippet from issue:

fn foo(x: bool, y: bool) -> u32 {
    match (x, y) {
         (false, _) => 0,
         (_, false) => 1,
         (true, true) => 2,
    }
}

Generated MIR:

fn foo(arg0: bool, arg1: bool) -> u32 {
    let var0: bool;                      // "x" in scope 1 at 3bbm.rs:17:8: 17:9
    let var1: bool;                      // "y" in scope 1 at 3bbm.rs:17:17: 17:18
    let mut tmp0: (bool, bool);
    let mut tmp1: bool;
    let mut tmp2: bool;
    let mut tmp3: (&'static str, &'static str, u32);
    let mut tmp4: &'static (&'static str, &'static str, u32);

    bb0: {
        var0 = arg0;                     // scope 1 at 3bbm.rs:17:8: 17:9
        var1 = arg1;                     // scope 1 at 3bbm.rs:17:17: 17:18
        tmp1 = var0;                     // scope 5 at 3bbm.rs:18:12: 18:13
        tmp2 = var1;                     // scope 6 at 3bbm.rs:18:15: 18:16
        tmp0 = (tmp1, tmp2);             // scope 4 at 3bbm.rs:18:11: 18:17
        if((tmp0.0: bool)) -> [true: bb4, false: bb1]; // scope 3 at 3bbm.rs:19:10: 19:15
    }

    bb1: {
        return = const 0u32;             // scope 10 at 3bbm.rs:19:23: 19:24
        goto -> bb7;                     // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb2: {
        return = const 1u32;             // scope 11 at 3bbm.rs:20:23: 20:24
        goto -> bb7;                     // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb3: {
        return = const 2u32;             // scope 12 at 3bbm.rs:21:25: 21:26
        goto -> bb7;                     // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb4: {
        if((tmp0.1: bool)) -> [true: bb5, false: bb2]; // scope 3 at 3bbm.rs:20:13: 20:18
    }

    bb5: {
        if((tmp0.0: bool)) -> [true: bb3, false: bb6]; // scope 3 at 3bbm.rs:21:10: 21:14
    }

    bb6: {
        tmp4 = promoted0;                // scope 3 at 3bbm.rs:18:5: 22:6
        core::panicking::panic(tmp4);    // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb7: {
        return;                          // scope 0 at 3bbm.rs:17:1: 23:2
    }
}

Not sure about this approach. I was also thinking maybe just a standalone pass?

cc @arielb1, @nagisa

@rust-highfive
Copy link
Collaborator

r? @nikomatsakis

(rust_highfive has picked a reviewer for you, use r? to override)

.chain(Some(otherwise))
.collect();
let targets: Vec<_> = match switch_ty.sty {
ty::TyBool if options.len() == 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems...ok to me :) might be nice to be a touch more general (e.g., if there is an exhaustive u8)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, this commit alone is not enough, in that it invalidates the SwitchInt terminator's invariants. e.g. this comment on targets says:

         /// Possible branch sites. The length of this vector should be
        /// equal to the length of the `values` vector plus 1 -- the
        /// extra item is the block to branch to if none of the values
        /// fit.
        targets: Vec<BasicBlock>,

but here you are not generating the otherwise block. It'd be better to change terminator in that case I imagine?

@nagisa
Copy link
Member

nagisa commented May 12, 2016

This is already something which would break #33566.

If you want to land this you’ll have to fix #33567 in tandem.

EDIT: oh, this touches SwitchInt only, though, so I guess its fine.

@luqmana
Copy link
Member Author

luqmana commented May 12, 2016

Ok, changed SwitchInt to explicitly separate out the otherwise block and put it behind an Option. Also, made sure it actually generates valid LLVM IR this time and added a test :P

@arielb1
Copy link
Contributor

arielb1 commented May 12, 2016

I think we want to generate an If for booleans.

@nikomatsakis
Copy link
Contributor

@arielb1

I think we want to generate an If for booleans.

Or else change If to SwitchInt?

@nagisa
Copy link
Member

nagisa commented May 13, 2016

Or else change If to SwitchInt?

While not necessarily incorrect, that would result in a weird branch in trans since LLVM wants a br in boolean case.

@luqmana
Copy link
Member Author

luqmana commented May 13, 2016

We could definitely just take TestKind::SwitchInt to TerminatorKind::If for bool types

@nikomatsakis
Copy link
Contributor

@luqmana

We could definitely just take TestKind::SwitchInt to TerminatorKind::If for bool types

I'd be happier with that...

@nikomatsakis
Copy link
Contributor

...though I imagine we could make SwitchInt examine the type of the "int" it is matching against?

@luqmana
Copy link
Member Author

luqmana commented May 15, 2016

@nikomatsakis

...though I imagine we could make SwitchInt examine the type of the "int" it is matching against?

As in, SwitchInt during build::matches::test?

@nikomatsakis
Copy link
Contributor

@luqmana I think I meant in the trans code. But I'm happy either with using a distinct If terminator or with melding SwitchInt and If.

@nikomatsakis
Copy link
Contributor

@luqmana do you plan to update this PR to one of those two strategies? :)

@bors
Copy link
Contributor

bors commented May 25, 2016

☔ The latest upstream changes (presumably #33667) made this pull request unmergeable. Please resolve the merge conflicts.

@luqmana
Copy link
Member Author

luqmana commented May 28, 2016

@nikomatsakis Yup sorry, just got occupied with some other work. Anyways, updated the patch to just generate an If terminator for boolean types.

// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn foo(x: bool, y: bool) -> u32 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this test should have #[rustc_mir]? And a comment explaining what it's all about?

@luqmana
Copy link
Member Author

luqmana commented Jun 2, 2016

Added attribute and comment to test.

@arielb1
Copy link
Contributor

arielb1 commented Jun 2, 2016

@bors r+

@bors
Copy link
Contributor

bors commented Jun 2, 2016

📌 Commit a97f6b3 has been approved by arielb1

@bors
Copy link
Contributor

bors commented Jun 2, 2016

⌛ Testing commit a97f6b3 with merge 12d1653...

bors added a commit that referenced this pull request Jun 2, 2016
MIR: Don't generate 3-armed boolean switch from match.

Fixes #33540.

Snippet from issue:
```Rust
fn foo(x: bool, y: bool) -> u32 {
    match (x, y) {
         (false, _) => 0,
         (_, false) => 1,
         (true, true) => 2,
    }
}
```

Generated MIR:
```
fn foo(arg0: bool, arg1: bool) -> u32 {
    let var0: bool;                      // "x" in scope 1 at 3bbm.rs:17:8: 17:9
    let var1: bool;                      // "y" in scope 1 at 3bbm.rs:17:17: 17:18
    let mut tmp0: (bool, bool);
    let mut tmp1: bool;
    let mut tmp2: bool;
    let mut tmp3: (&'static str, &'static str, u32);
    let mut tmp4: &'static (&'static str, &'static str, u32);

    bb0: {
        var0 = arg0;                     // scope 1 at 3bbm.rs:17:8: 17:9
        var1 = arg1;                     // scope 1 at 3bbm.rs:17:17: 17:18
        tmp1 = var0;                     // scope 5 at 3bbm.rs:18:12: 18:13
        tmp2 = var1;                     // scope 6 at 3bbm.rs:18:15: 18:16
        tmp0 = (tmp1, tmp2);             // scope 4 at 3bbm.rs:18:11: 18:17
        if((tmp0.0: bool)) -> [true: bb4, false: bb1]; // scope 3 at 3bbm.rs:19:10: 19:15
    }

    bb1: {
        return = const 0u32;             // scope 10 at 3bbm.rs:19:23: 19:24
        goto -> bb7;                     // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb2: {
        return = const 1u32;             // scope 11 at 3bbm.rs:20:23: 20:24
        goto -> bb7;                     // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb3: {
        return = const 2u32;             // scope 12 at 3bbm.rs:21:25: 21:26
        goto -> bb7;                     // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb4: {
        if((tmp0.1: bool)) -> [true: bb5, false: bb2]; // scope 3 at 3bbm.rs:20:13: 20:18
    }

    bb5: {
        if((tmp0.0: bool)) -> [true: bb3, false: bb6]; // scope 3 at 3bbm.rs:21:10: 21:14
    }

    bb6: {
        tmp4 = promoted0;                // scope 3 at 3bbm.rs:18:5: 22:6
        core::panicking::panic(tmp4);    // scope 3 at 3bbm.rs:18:5: 22:6
    }

    bb7: {
        return;                          // scope 0 at 3bbm.rs:17:1: 23:2
    }
}
```

Not sure about this approach. I was also thinking maybe just a standalone pass?

cc @arielb1, @nagisa
@bors bors merged commit a97f6b3 into rust-lang:master Jun 2, 2016
@luqmana luqmana deleted the tri-bool-mir branch July 8, 2016 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants