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

generate fewer basic blocks for variant switches #33999

Merged
merged 3 commits into from
Jun 5, 2016

Conversation

scottcarr
Copy link
Contributor

@scottcarr scottcarr commented Jun 1, 2016

CC #33567
Adds a new field to TestKind::Switch that tracks the variants that are actually matched against. The other candidates target a common "otherwise" block.

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Aatch (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

@nikomatsakis
Copy link
Contributor

r? @nikomatsakis

@rust-highfive rust-highfive assigned nikomatsakis and unassigned Aatch Jun 1, 2016
@nikomatsakis
Copy link
Contributor

cc @dotdash @nagisa -- this is just a minimal fix to address the O(n^2) blowup. The idea was to keep IR the same but not force the creation of one basic block per variant. On IRC, scott mentioned that if you have an enum with 52 variants, we used to generate 2800 basic blocks, but now we generate 212 (when it meets the match (a, b) { (A, A), (B, B) ... _ } pattern we saw in derive). In general the factor seems to be a linear 4x, which seems fine.

Any clever ideas how to test this? :)

@@ -266,6 +266,7 @@ enum TestKind<'tcx> {
// test the branches of enum
Switch {
adt_def: AdtDef<'tcx>,
variants: Vec<bool>,
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe a good idea to add a comment explaining what this vector represents, when it is true, etc

Copy link
Member

@nagisa nagisa Jun 1, 2016

Choose a reason for hiding this comment

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

Consider using a BitVector from librustc_data_structures.

@nikomatsakis
Copy link
Contributor

Looks good! I left some minor nits that you could correct.

(0..num_enum_variants).map(|_| self.cfg.start_new_block())
.collect();
.collect()
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I'd find something like this easier to parse:

let mut otherwise_block = None;
let mut otherwise = || { if otherwise_block.is_none() { otherwise_block = self.cfg.start_new_block()}; otherwise_block.unwrap() };
let target_blocks: Vec<_> = variants.iter().map(|&matched| {
    if matched {
        self.cfg.start_new_block()
    } else {
        otherwise()
    }
}).collect();
debug!("enum variants: {}, variants.len(): {}, otherwise_block: {:?}", num_enum_variants, variants.len(), otherwise_block);

Copy link
Contributor

@nikomatsakis nikomatsakis Jun 1, 2016

Choose a reason for hiding this comment

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

So I was going to suggest this:

let mut otherwise_block = None;
let target_blocks: Vec<_> = variants.iter().map(|&matched| {
    if matched {
        self.cfg.start_new_block()
    } else {
        otherwise_block.unwrap_or_else(|| {
            let b = self.cfg.start_new_block();
            otherwise_block = Some(b);
            b
        })
    }
}).collect();

but I figured "meh". In any case, this has the advantage of passing borrowck, I think :)

@nagisa
Copy link
Member

nagisa commented Jun 1, 2016

Any clever ideas how to test this? :)

We seriously need MIR-flavoured filecheck :)

Fixes #33567

Isn’t this PR missing changes undoing some of the trans changes introduced by #33566? If we generate good-enough MIR with this, perhaps the PR I just linked should be undone?

@dotdash
Copy link
Contributor

dotdash commented Jun 1, 2016

AFAICT this only removes the extra blocks, it doesn't actually reduce the number of switch arms, there's still one per variant. Additionally, for auto-generated code, you might still get matches that have a bunch of arms that all have no code in them. Similar (but not identical) to what the derive framework did. This patch would not change that at all, it still needs SimplifyCfg and the trans hack.

So it's IMHO a bit premature to undo any of those changes.

@nagisa
Copy link
Member

nagisa commented Jun 1, 2016

In that case its not “fixes”, but a “cc”, I think.

@nikomatsakis
Copy link
Contributor

AFAICT this only removes the extra blocks

yes

it doesn't actually reduce the number of switch arms, there's still one per variant.

yes

Additionally, for auto-generated code, you might still get matches that have a bunch of arms that all have no code in them.

yes, and I wouldn't expect MIR build to notice or optimize this case, would you?

This patch would not change that at all, it still needs SimplifyCfg and the trans hack.

I don't really consider the trans change a hack -- it seems like it's just a more efficient translation from the MIR to the LLVM. So I certainly wouldn't undo it. If we change the MIR to make 'otherwise' a more explicit notion, we could undo it and use that. Seems like an orthogonal thing to me though (it would build on this patch). And it wouldn't be as general as what we have now, given that optimization may create opportunities where you have multiple arms directed to the same block that build does not know about.

@nikomatsakis
Copy link
Contributor

In that case its not “fixes”, but a “cc”, I think.

I agree, though I'm not sure if there is a bug left to fix after this lands.

clarify comments and panic message
@dotdash
Copy link
Contributor

dotdash commented Jun 1, 2016

Additionally, for auto-generated code, you might still get matches that have a bunch of arms that all have no code in them.

yes, and I wouldn't expect MIR build to notice or optimize this case, would you?

No, that is what SimplifyCfg and other passes should handle, i.e. I was arguing that there are uses left for what we currently have, even after the changes in this PR.

This patch would not change that at all, it still needs SimplifyCfg and the trans hack.

I don't really consider the trans change a hack -- it seems like it's just a more efficient translation from the MIR to the LLVM. So I certainly wouldn't undo it. If we change the MIR to make 'otherwise' a more explicit notion, we could undo it and use that. Seems like an orthogonal thing to me though (it would build on this patch). And it wouldn't be as general as what we have now, given that optimization may create opportunities where you have multiple arms directed to the same block that build does not know about.

I called it a hack only in the way that I agree with @nagisa that it should ultimately become a MIR pass and not be handled just-in-time during trans.

IOW I was just arguing for not removing these things yet, because this is not the real replacement yet. I didn't mean to say that we should try to do it all during the build phase.

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jun 1, 2016

📌 Commit 79bf586 has been approved by nikomatsakis

@nikomatsakis
Copy link
Contributor

@dotdash

I called it a hack only in the way that I agree with @nagisa that it should ultimately become a MIR pass and not be handled just-in-time during trans.

IOW I was just arguing for not removing these things yet, because this is not the real replacement yet. I didn't mean to say that we should try to do it all during the build phase.

Seems good. :) I think ultimately I'd probably prefer to lower Switch to some combination of extracting the variant index and using SwitchInt sometimes before trans, and just let trans ignore Switch (or maybe remove Switch altogether, as I know @nagisa would prefer; I've not made up my mind on this point, I think it's handy to have the high-level notion when doing analysis).

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jun 3, 2016

📌 Commit d4551ec has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Jun 3, 2016

⌛ Testing commit d4551ec with merge 29b65ff...

@bors
Copy link
Contributor

bors commented Jun 3, 2016

💔 Test failed - auto-win-gnu-32-opt-rustbuild

@nagisa
Copy link
Member

nagisa commented Jun 3, 2016

@bors retry

@bors
Copy link
Contributor

bors commented Jun 3, 2016

⌛ Testing commit d4551ec with merge 84f1942...

bors added a commit that referenced this pull request Jun 3, 2016
generate fewer basic blocks for variant switches

CC #33567
Adds a new field to TestKind::Switch that tracks the variants that are actually matched against.  The other candidates target a common "otherwise" block.
@bors
Copy link
Contributor

bors commented Jun 4, 2016

💔 Test failed - auto-win-gnu-64-nopt-t

@nagisa
Copy link
Member

nagisa commented Jun 4, 2016

cc @alexcrichton weird failure

@bors retry

@bors
Copy link
Contributor

bors commented Jun 4, 2016

⌛ Testing commit d4551ec with merge f8916da...

@bors
Copy link
Contributor

bors commented Jun 4, 2016

💔 Test failed - auto-win-gnu-32-opt-rustbuild

@alexcrichton
Copy link
Member

@bors: retry

On Sun, Jun 5, 2016 at 12:02 AM, bors notifications@github.com wrote:

💔 Test failed - auto-win-gnu-32-opt-rustbuild
http://buildbot.rust-lang.org/builders/auto-win-gnu-32-opt-rustbuild/builds/1359


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#33999 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/AAD95C42Q0Ri9TE85Zp4edoCfnteRAAxks5qIfYDgaJpZM4IrExa
.

@bors
Copy link
Contributor

bors commented Jun 5, 2016

⌛ Testing commit d4551ec with merge 22b36c7...

bors added a commit that referenced this pull request Jun 5, 2016
generate fewer basic blocks for variant switches

CC #33567
Adds a new field to TestKind::Switch that tracks the variants that are actually matched against.  The other candidates target a common "otherwise" block.
@bors bors merged commit d4551ec into rust-lang:master Jun 5, 2016
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.

8 participants