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] Refine representation and translation of calls #30481

Merged
merged 13 commits into from Jan 6, 2016

Conversation

Projects
None yet
6 participants
@nagisa
Copy link
Contributor

nagisa commented Dec 19, 2015

r? @nikomatsakis

This is a pretty big PR conflating changes to a few different block terminators (Call, DivergingCall, Panic, Resume, Diverge), because they are somewhat closely related.

Each commit has a pretty good description on what is being changed in each commit. The end result is greatly simplified CFG and translation for calls (no success branch if the function is diverging, no cleanup branch if there’s nothing to cleanup etc).

Fixes #30480
Fixes #29767
Partialy solves #29575
Fixes #29573

match self.unreachable_block {
Some(b) => b,
None => {
let bl = self.bcx(mir::START_BLOCK).fcx.new_block(false, "unreachable", None);

This comment has been minimized.

@nagisa

nagisa Dec 19, 2015

Author Contributor

Note to self: maybe self should contain a fcx too?

@@ -92,7 +92,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// not entirely precise
if !otherwise.is_empty() {
let join_block = self.join_otherwise_blocks(otherwise);
self.panic(join_block);
self.panic(join_block, "something about matches algorithm not being precise", span);

This comment has been minimized.

@nagisa

nagisa Dec 19, 2015

Author Contributor

This looks, uh, ugly? Incorrect?

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from ffebbf1 to acc49ad Dec 19, 2015

@nagisa nagisa changed the title Refine representation and translation of MIR calls [MIR] Refine representation and translation of calls Dec 19, 2015

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch 3 times, most recently from 0f066dc to fdaa56a Dec 21, 2015

@nagisa

This comment has been minimized.

Copy link
Contributor Author

nagisa commented Dec 21, 2015

All in all, I think it is in a good enough spot now to begin reviewing it @nikomatsakis.

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from b245183 to fdaa56a Dec 21, 2015

Some(attrs),
debugloc);
if must_copy_dest {
// FIXME: What do we do here?

This comment has been minimized.

@luqmana

luqmana Dec 22, 2015

Member

AFAIK should just do the same as below: store_ty the result from Invoke to the destination.

This comment has been minimized.

@nagisa

nagisa Dec 22, 2015

Author Contributor

The problem here (is much harder than it looks at the first look!) is that invoke is a basic block terminator and thus we cannot add anything else to the current block. We would have to add, or rather, prepend a store instruction to a success branch, but… that’s tricky, because:

  1. That’s hacky (duh);
  2. I can’t seem to see anyway to do it;
  3. It would make some already-generated blocks invalid (e.g. we would have to assert that success branch has higher basic-block number and has not been translated yet).

Basically, to me it seems like we should change the MIR some more and figure out if destination must be copied (or rather, avoid copying destination altogether as well as encoding the copy, if necessary) during the MIR build phase.


EDIT: we could also generate a temporary block with a store and branch to success block in it (still doesn’t avoid 3rd issue). Sounds like a most correct hack to do, but I’ll see if anybody has better ideas.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Dec 22, 2015

As I mentioned on IRC, I'm not sure if I think that splitting out "diverging call" into its own terminator is a good idea. My concerns are:

  1. Duplication: it's harder to know that you're getting all calls.
  2. If you have foo = diverging_fn(), we need to still consider that a "write" to foo in a logical sense (i.e., for the purposes of borrowck). To do that under the approach of this PR, we'll need some marker that foo has been initialized, since DivergingCall no longer has a destination.

Basically, I'm not sure if the code for handling calls vs diverging calls will wind up being so very different in other passes. But it's a bit hard to know just now. A compromise might just be to introduce an enum into the call that is either NormalCall(BasicBlock, BasicBlock) or DivergingCall(BasicBlock).

In any case, let me read further before reaching final judgement.

@nagisa

This comment has been minimized.

Copy link
Contributor Author

nagisa commented Dec 22, 2015

As I mentioned on IRC, I'm not sure if I think that splitting out "diverging call" into its own terminator is a good idea. My concerns are:

The last commit contains conversion to inner-enum, like you proposed on IRC. Feel free to compare.

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from 6227ccc to b0832b8 Dec 22, 2015

@nagisa

This comment has been minimized.

Copy link
Contributor Author

nagisa commented Dec 22, 2015

Comments on nagisa@0c7d57d are yet to be fixed.


EDIT: changed/fixed in nagisa@1c2f0d8. @nikomatsakis the code still looks equally ugly to me, but not sure if it could be made any better.

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from 1c2f0d8 to 3c05a45 Jan 1, 2016

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Jan 4, 2016

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

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from 3c05a45 to f6d2faf Jan 4, 2016

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jan 4, 2016

In all those cases where I gave nits about exhaustive matches, we were just trying to handle converging cases -- might be that a helper function for extracting the converging cases would be good. OTOH, I guess this is why you split those cases into two to start with.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jan 4, 2016

OK, so, as you say, this is a big PR, and I feel like I could go on pointing out nits forever. But I'd rather we land it and just hack and try to clean things up. Some of these commits get pretty involved, but that may just be unavoidable if we want to generate less naive IR. Calls are just complicated. :) Anyway, so I'm leaning now towards landing this PR and then trying to keep improving things. One thing which would be nice are some more test cases for calls that generate invoke, and in particular to exercise some of those edge cases paths (like loop { c = call(); }).

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Jan 4, 2016

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

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch 3 times, most recently from e482e81 to d468ec9 Jan 4, 2016

@nagisa

This comment has been minimized.

Copy link
Contributor Author

nagisa commented Jan 5, 2016

@nikomatsakis rebased and comments addressed (I hope I didn’t miss any). I added a few more tests as well.

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch 2 times, most recently from 2e9e015 to 9e7ffb6 Jan 5, 2016

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jan 5, 2016

r=me modulo final nits (in particular, the test with graphviz attribute should really be fixed)

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from 9e7ffb6 to 559c9c5 Jan 5, 2016

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Jan 6, 2016

💔 Test failed - auto-win-msvc-64-opt

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Jan 6, 2016

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

nagisa added some commits Dec 14, 2015

Split Call into Call and DivergingCall
DivergingCall is different enough from the regular converging Call to warrant the split. This also
inlines CallData struct and creates a new CallTargets enum in order to have a way to differentiate
between calls that do not have an associated cleanup block.

Note, that this patch still does not produce DivergingCall terminator anywhere. Look for that in
the next patches.
Generate DivergingCall terminator
This simplifies CFG greatly for some cases :)
Add Resume Terminator which corresponds to resume
Diverge should eventually go away
Remove diverge terminator
Unreachable terminator can be contained all within the trans.
Have a cached unreachable block inside MIR state
It is useful for various cases where direct unreachable cannot be translated and a separate block
is necessary.
Refine call terminator translation
* Implement landing pads; and
* Implement DivergingCall translation; and
* Modernise previous implementation of Call somewhat.
Merge Call and DivergingCall diffs into CallKind
This merges two separate Call terminators and uses a separate CallKind sub-enum instead.

A little bit unrelatedly, copying into destination value for a certain kind of invoke, is also
implemented here. See the associated comment in code for various details that arise with this
implementation.
Create personality slot when translating Resume
This considerably simplifies code around calling functions and translation of Resume itself. This
removes requirement that a block containing Resume terminator is always translated after something
which creates a landing pad, thus allowing us to actually translate some valid MIRs we could not
translate before.

However, an assumption is added that translator is correct (in regards to landing pad generation)
and code will never reach the Resume terminator without going through a landing pad first. Breaking
these assumptions would pass an `undef` value into the personality functions.

@nagisa nagisa force-pushed the nagisa:mir-calls-2 branch from 559c9c5 to 36b3951 Jan 6, 2016

@Manishearth

This comment has been minimized.

Copy link
Member

Manishearth commented Jan 6, 2016

@bors r=nikomatsakis

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Jan 6, 2016

📌 Commit 36b3951 has been approved by nikomatsakis

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Jan 6, 2016

⌛️ Testing commit 36b3951 with merge d5ac1a1...

bors added a commit that referenced this pull request Jan 6, 2016

Auto merge of #30481 - nagisa:mir-calls-2, r=nikomatsakis
r? @nikomatsakis

This is a pretty big PR conflating changes to a few different block terminators (Call, DivergingCall, Panic, Resume, Diverge), because they are somewhat closely related.

Each commit has a pretty good description on what is being changed in each commit. The end result is greatly simplified CFG and translation for calls (no success branch if the function is diverging, no cleanup branch if there’s nothing to cleanup etc).

Fixes #30480
Fixes #29767
Partialy solves #29575
Fixes #29573

@bors bors merged commit 36b3951 into rust-lang:master Jan 6, 2016

1 of 2 checks passed

continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
homu Test successful
Details
pub fn destination(&self) -> Option<Lvalue<'tcx>> {
match *self {
CallKind::Converging { ref destination, .. } |
CallKind::ConvergingCleanup { ref destination, .. } => Some(destination.clone()),

This comment has been minimized.

@solson

solson Jan 7, 2016

Member

Why clone here instead of returning Option<&Lvalue<'tcx>> and letting the caller decide if it needs to clone?

This comment has been minimized.

@nagisa

nagisa Jan 7, 2016

Author Contributor

There’s two reasons, mostly, I had in mind:

  1. Cloning Lvalue is very cheap most of the time (i.e. when Lvalue is not a Projection);
  2. There’s users who want &mut lvalue and there’s users who want &lvalue. Returning a value allows to make either one easier when pattern matching (ref vs ref mut).

On the hindsight, I think this might actually be a bug to return destination by value in some cases which I didn’t think about before, thus I’ll submit a patch in a moment making these return a mutable reference instead.

bors added a commit that referenced this pull request Jan 8, 2016

Auto merge of #30771 - tsion:mir-text-terminator-fix, r=eddyb
This just removes the `Some()` that appeared around terminators in MIR text output after #30481 (cc @nagisa). The graphviz is already fixed.

r? @eddyb

nagisa added a commit to nagisa/rust that referenced this pull request Jan 9, 2016

Rollup merge of rust-lang#30771 - tsion:mir-text-terminator-fix, r=eddyb
This just removes the `Some()` that appeared around terminators in MIR text output after rust-lang#30481 (cc @nagisa). The graphviz is already fixed.

r? @eddyb

steveklabnik added a commit to steveklabnik/rust that referenced this pull request Jan 9, 2016

Rollup merge of rust-lang#30771 - tsion:mir-text-terminator-fix, r=eddyb
This just removes the `Some()` that appeared around terminators in MIR text output after rust-lang#30481 (cc @nagisa). The graphviz is already fixed.

r? @eddyb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.