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] Implement Inlining #39648

Merged
merged 5 commits into from
Mar 11, 2017
Merged

[MIR] Implement Inlining #39648

merged 5 commits into from
Mar 11, 2017

Conversation

Aatch
Copy link
Contributor

@Aatch Aatch commented Feb 8, 2017

Fairly basic implementation of inlining for MIR. Uses conservative
heuristics for inlining.

Doesn't handle a number of cases, but can be extended later. This is basically the same as the previous inlining PR, but without the span-related changes (as the bugs it was dealing with have since been fixed).

/cc @rust-lang/compiler

@rust-highfive
Copy link
Collaborator

r? @pnkfelix

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

@@ -647,11 +647,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
}

tcx.layout_depth.set(depth+1);
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps it would make sense to have some sort of guard for this instead?

Copy link
Member

Choose a reason for hiding this comment

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

Eh.

@nikomatsakis nikomatsakis self-requested a review February 12, 2017 11:50
@@ -63,8 +64,7 @@ macro_rules! newtype_index {
}

/// Lowered representation of a single function.
// Do not implement clone for Mir, which can be accidently done and kind of expensive.
#[derive(RustcEncodable, RustcDecodable, Debug)]
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought 'Clone' was removed for a reason. Is there a good reason for bringing it back?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's required for the TypeFoldable impl.


match self.kind {
Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
SetDiscriminant { ref lvalue, .. } |
Copy link
Contributor

Choose a reason for hiding this comment

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

according to comments from the previous PR, listing fields and using _ is preferable to ..

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

use mir::TerminatorKind::*;

match self.kind {
If { ref cond, .. } => cond.visit_with(visitor),
Copy link
Contributor

Choose a reason for hiding this comment

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

same

@@ -2322,6 +2322,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}).borrow()
}

/// Given the DefId of an item, returns its MIR, borrowed immutably.
/// Returns None if there is no MIR for the DefId
pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
Copy link
Contributor

Choose a reason for hiding this comment

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

can't you use item_mir?

Copy link
Contributor Author

@Aatch Aatch Feb 16, 2017

Choose a reason for hiding this comment

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

Not all functions have a MIR available and item_mir panics if there isn't a MIR available for that def id.

let def_id = callgraph.def_id(node);

// Don't inspect functions from other crates
let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
Copy link
Contributor

Choose a reason for hiding this comment

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

wouldn't if !def_id.is_local() {} do the trick?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need the node id anyway, this combines that check.

};
let src = MirSource::from_node(self.tcx, id);
if let MirSource::Fn(_) = src {
if let Some(mir) = self.tcx.maybe_item_mir(def_id) {
Copy link
Contributor

Choose a reason for hiding this comment

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

we know at least that def_id is local, maybe maybe_ isn't necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Being a local doesn't mean a MIR is available. The obvious case is intrinsics, since you can define those locally.

Copy link
Contributor

@mrhota mrhota left a comment

Choose a reason for hiding this comment

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

Several comments from the original PR should probably be addressed here, like these.

The code lacks descriptions of approach or rationale. I get the impression (from the previous PR) that you intend for this code to be a kind of first strike at this problem. There are lots of details here, and it's hard to work out what's going on when there's not even a high-level description of how this pass works (or should work).

Moreover, it'd be nice to have tests verifying the efficacy of this new pass. Performance comparisons would be nice, too, since you mentioned improvements in the previous PR.

@@ -1031,6 +1031,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));

// No lifetime analysis based on borrowing can be done from here on out.
passes.push_pass(box mir::transform::inline::Inline);
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this invalidate the comment in line 1033?

Copy link
Member

Choose a reason for hiding this comment

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

That comment is about line 1031, i.e. nothing below the comment can invalidate it.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok, I thought it might refer to what is now line 1035

*
* [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
*/
pub struct SCCIterator<'g> {
Copy link
Contributor

Choose a reason for hiding this comment

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

From comments in the previous version of this PR, this should be generified and moved into the graph algos module. Obviously, the same goes for StackElement.

Copy link
Member

@eddyb eddyb left a comment

Choose a reason for hiding this comment

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

r=me with comments addressed (mine and others')

@@ -1031,6 +1031,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));

// No lifetime analysis based on borrowing can be done from here on out.
passes.push_pass(box mir::transform::inline::Inline);
Copy link
Member

Choose a reason for hiding this comment

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

That comment is about line 1031, i.e. nothing below the comment can invalidate it.

graph: graph::Graph::new()
};

for def_id in def_ids {
Copy link
Member

Choose a reason for hiding this comment

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

Need to filter by .is_local(), cross-crate MIR should always be inspected on-demand (and not by accident).

const INSTR_COST : usize = 5;
const CALL_PENALTY : usize = 25;

const UNKNOWN_SIZE_COST : usize = 10;
Copy link
Member

Choose a reason for hiding this comment

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

Pretty sure the accepted style doesn't have a space before :.

let mut is_drop = false;
match term.kind {
TerminatorKind::Drop { ref location, target, unwind } |
TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => {
Copy link
Member

Choose a reason for hiding this comment

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

You shouldn't be seeing DropAndReplace anymore at this point.

targets.1 = self.update_target(targets.1);
}
TerminatorKind::Switch { ref mut targets, .. } |
TerminatorKind::SwitchInt { ref mut targets, .. } => {
Copy link
Member

Choose a reason for hiding this comment

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

Need to rebase I suppose.

}
}
TerminatorKind::Drop { ref mut target, ref mut unwind, .. } |
TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
Copy link
Member

Choose a reason for hiding this comment

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

Again, DropAndReplace shouldn't show up anymore at this point.

@nikomatsakis
Copy link
Contributor

@mrhota

The code lacks descriptions of approach or rationale.

I agree this would make the code stronger. At the same time, I don't want to raise the bar too high for this patch -- I'm afraid it will bitrot like last time, and I think I'd rather have something in-tree with which we can iterate than nothing (particularly since it is not enabled by default). It feels like we need to get a series of quality benchmarks and start tuning these MIR optimizations, and documenting the results of that tuning. Trying to divine rules in advance without benchmarks feels risky.

@bors
Copy link
Contributor

bors commented Feb 28, 2017

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

@mrhota
Copy link
Contributor

mrhota commented Mar 1, 2017

@Aatch ping?

// `i : &mut usize`, then just duplicating the `a[*i]`
// Lvalue could result in two different locations if `f`
// writes to `i`. To prevent this we need to create a temporary
// borrow of the lvalue and pass the destination as `*temp` instead.
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought the semantics was that any such *i is "borrow-locked" for the duration of the call, so any unexpected assignments during function call evaluation result in UB (certainly, MIR construction always copies indexes to a temporary).

@nikomatsakis
Copy link
Contributor

Somebody ought to rebase this =)

@mrhota
Copy link
Contributor

mrhota commented Mar 9, 2017

@Aatch ping again... 😦

Adds `get`/`get_mut` accessors and `drain`/`drain_enumerated` iterators
to IndexVec.

Implements TypeFoldable for IndexVec.
Fairly basic implementation of inlining for MIR. Uses conservative
heuristics for inlining.
@eddyb
Copy link
Member

eddyb commented Mar 10, 2017

@bors r+

@bors
Copy link
Contributor

bors commented Mar 10, 2017

📌 Commit 3eb26d1 has been approved by eddyb

@bors
Copy link
Contributor

bors commented Mar 10, 2017

⌛ Testing commit 3eb26d1 with merge 3123793...

@bors
Copy link
Contributor

bors commented Mar 10, 2017

💔 Test failed - status-appveyor

@eddyb
Copy link
Member

eddyb commented Mar 10, 2017

@bors retry

  • appveyor llvm build failed

@bors
Copy link
Contributor

bors commented Mar 10, 2017

⌛ Testing commit 3eb26d1 with merge 1b53cd3...

@bors
Copy link
Contributor

bors commented Mar 10, 2017

💔 Test failed - status-travis

@eddyb
Copy link
Member

eddyb commented Mar 10, 2017

@bors retry

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Mar 10, 2017
[MIR] Implement Inlining

Fairly basic implementation of inlining for MIR. Uses conservative
heuristics for inlining.

Doesn't handle a number of cases, but can be extended later. This is basically the same as the previous inlining PR, but without the span-related changes (as the bugs it was dealing with have since been fixed).

/cc @rust-lang/compiler
@bors
Copy link
Contributor

bors commented Mar 10, 2017

⌛ Testing commit 3eb26d1 with merge 38aa079...

@alexcrichton
Copy link
Member

@bors: retry

(prioritizing rollup)

@bors
Copy link
Contributor

bors commented Mar 10, 2017

⌛ Testing commit 3eb26d1 with merge b37de9c...

@alexcrichton
Copy link
Member

@bors: retry

(prioritizing rollup)

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Mar 10, 2017
[MIR] Implement Inlining

Fairly basic implementation of inlining for MIR. Uses conservative
heuristics for inlining.

Doesn't handle a number of cases, but can be extended later. This is basically the same as the previous inlining PR, but without the span-related changes (as the bugs it was dealing with have since been fixed).

/cc @rust-lang/compiler
@bors
Copy link
Contributor

bors commented Mar 11, 2017

⌛ Testing commit 3eb26d1 with merge 8c72b76...

bors added a commit that referenced this pull request Mar 11, 2017
[MIR] Implement Inlining

Fairly basic implementation of inlining for MIR. Uses conservative
heuristics for inlining.

Doesn't handle a number of cases, but can be extended later. This is basically the same as the previous inlining PR, but without the span-related changes (as the bugs it was dealing with have since been fixed).

/cc @rust-lang/compiler
@bors
Copy link
Contributor

bors commented Mar 11, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: eddyb
Pushing 8c72b76 to master...

@bors bors merged commit 3eb26d1 into rust-lang:master Mar 11, 2017
@bors bors mentioned this pull request Mar 11, 2017
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.

10 participants