-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
[MIR] Implement Inlining #39648
Conversation
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh.
@@ -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)] |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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, .. } | |
There was a problem hiding this comment.
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 ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
src/librustc/mir/mod.rs
Outdated
use mir::TerminatorKind::*; | ||
|
||
match self.kind { | ||
If { ref cond, .. } => cond.visit_with(visitor), |
There was a problem hiding this comment.
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>>> { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this 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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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> { |
There was a problem hiding this comment.
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
.
There was a problem hiding this 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); |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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).
src/librustc_mir/transform/inline.rs
Outdated
const INSTR_COST : usize = 5; | ||
const CALL_PENALTY : usize = 25; | ||
|
||
const UNKNOWN_SIZE_COST : usize = 10; |
There was a problem hiding this comment.
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, .. } => { |
There was a problem hiding this comment.
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.
src/librustc_mir/transform/inline.rs
Outdated
targets.1 = self.update_target(targets.1); | ||
} | ||
TerminatorKind::Switch { ref mut targets, .. } | | ||
TerminatorKind::SwitchInt { ref mut targets, .. } => { |
There was a problem hiding this comment.
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, .. } => { |
There was a problem hiding this comment.
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.
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. |
☔ The latest upstream changes (presumably #40008) made this pull request unmergeable. Please resolve the merge conflicts. |
@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. |
There was a problem hiding this comment.
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).
Somebody ought to rebase this =) |
@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.
@bors r+ |
📌 Commit 3eb26d1 has been approved by |
⌛ Testing commit 3eb26d1 with merge 3123793... |
💔 Test failed - status-appveyor |
@bors retry
|
⌛ Testing commit 3eb26d1 with merge 1b53cd3... |
💔 Test failed - status-travis |
@bors retry
|
[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
⌛ Testing commit 3eb26d1 with merge 38aa079... |
@bors: retry (prioritizing rollup) |
⌛ Testing commit 3eb26d1 with merge b37de9c... |
@bors: retry (prioritizing rollup) |
[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
[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
☀️ Test successful - status-appveyor, status-travis |
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